Tezos Asked on August 20, 2021
When calling a smart contract entrypoint, it is required to pass the needed entrypoint parameters. This is done through a message that must be sent in JSON/Pairs format. My doubt is: Is there a formula to build these parameter messages to be passed to smart contract entrypoints?
For example, when calling the addCustomer entrypoint from SmartPy Explorer:
It generates the correspondent Michelson message:
(Left (Left (Pair (Pair 8000000 "0001") (Pair Älice"99999897))))
Is there a formula to calculate programmatically the number of LEFTs and RIGHTs, maybe according to the number of entrypoints or even parameters?
Any information will be much appreciated. Thanks in advance.
There are two ways to indicate which entrypoint you want to call:
call it by its name using the --entrypoint
command-line argument of tezos-client transfer
or the entrypoint
optional parameter of the corresponding RPCs. If you do this, you can simply pass the argument of the expected entrypoint type without the leading Left
s and Right
s.
call it by its position in the parameter
type of the smart contract: the parameter type can be seen as a binary tree whose nodes are labeled by or
, you can indicate an entrypoint by a giving the path composed of Left
s and Right
s from the root of this tree. An example is given in the Michelson documentation.
Correct answer by Raphaël Cauderlier on August 20, 2021
After this important discussion I've ended with a functional solution which I am sharing here with whoever might find useful. This code is in Java. Details of it might be found on TezosJ_plainJava github repository.
The method "solvePair" transforms recursively a "Pair" of parameters into the expected JSON/Pairs format that is needed to be passed to Tezos smart contracts entrypoints, making it easy for developers to interact with Tezos blockchain.
Example:
INPUT:
Pair : (([1000000],[2000000,003]),([001],[005,002]))
Datatypes : [ "int", "int", "String", "String", "String", "String" ]
OUTPUT:
{ "prim": "Pair", "args": [ { "prim": "Pair", "args": [ { "int": "1000000" }, { "prim": "Pair", "args": [ { "int": "2000000" }, { "string": "003" } ] } ] }, { "prim": "Pair", "args": [ { "string": "001" }, { "prim": "Pair", "args": [ { "string": "005" }, { "string": "002" } ] } ] } ] }
Here are the routines:
private Object solvePair(Object pair, List datatypes) throws Exception
{
Object result = null;
// Extract and check contents.
if (hasPairs((Pair) pair) == false)
{
// Here we've got List in both sides. But they might have more than one element.
Object jsonLeft = ((Pair) pair).getLeft() == null ? null : toJsonFormat((List)((Pair) pair).getLeft(), datatypes, 0);
Object jsonRight = ((Pair) pair).getRight() == null ? null : toJsonFormat((List)((Pair) pair).getRight(), datatypes, ((Pair) pair).getLeft() == null ? 0 : ((List)((Pair) pair).getLeft()).size() );
// Test if there is only one parameter.
if (jsonLeft == null)
if (jsonRight == null)
throw new Exception("Pair cannot be (null, null)");
else
return jsonRight;
else if (jsonRight == null)
return jsonLeft;
// Build json outter pair.
JSONObject jsonPair = new JSONObject();
jsonPair.put("prim", "Pair");
// Create pair contents array.
JSONArray pairContents = new JSONArray();
pairContents.put(jsonLeft);
pairContents.put(jsonRight);
jsonPair.put("args", pairContents);
return jsonPair;
}
else
{
Object jsonLeft = solvePair(((Pair<Pair, List>) pair).getLeft(), datatypes);
Object jsonRight = solvePair(((Pair<Pair, List>) pair).getRight(), datatypes.subList( countPairElements((Pair) ((Pair) pair).getLeft()), datatypes.size()) );
// Build json outter pair.
JSONObject jsonPair = new JSONObject();
jsonPair.put("prim", "Pair");
// Create pair contents array.
JSONArray pairContents = new JSONArray();
pairContents.put(jsonLeft);
pairContents.put(jsonRight);
jsonPair.put("args", pairContents);
return jsonPair;
}
}
private Integer countPairElements(Pair pair)
{
Integer leftCount = 0;
Integer rightCount = 0;
Object left = pair.getLeft();
Object right = pair.getRight();
if(left instanceof Pair)
{
leftCount = countPairElements((Pair) left);
}
else
{
leftCount = ((List)left).size();
}
if(right instanceof Pair)
{
rightCount = countPairElements((Pair) right);
}
else
{
rightCount = ((List)right).size();
}
return leftCount+rightCount;
}
private Boolean hasPairs(Pair pair)
{
Object left = pair.getLeft();
Object right = pair.getRight();
if( (left instanceof Pair) || (right instanceof Pair) )
{
return true;
}
else
{
return false;
}
}
private JSONObject toJsonFormat(List list, List datatypes, Integer firstElement)
{
JSONArray result = new JSONArray();
for(int i=0;i<list.size();i++)
{
JSONObject element = new JSONObject();
element.put((String) datatypes.get(firstElement + i), list.get(i));
// Add element to array.
result.put(element);
}
if (result.length() > 1)
{
// Wrap json result in outter pair.
JSONObject jsonPair = new JSONObject();
jsonPair.put("prim", "Pair");
jsonPair.put("args", result);
return jsonPair;
}
else
{
return (JSONObject)result.get(0);
}
}
And if you wish to build a Pair object from a String[] parameter array, you might use the routine below.
INPUT: empty JSONObject, empty Pair, List of your parameters values (like String[] {"param1", "param2", "param3"} ).
OUTPUT: (param1,(param2,param3))
private Pair buildParameterPairs(JSONObject jsonObj, Pair pair, List<String> parameters,
String[] contractEntryPointParameters,
Boolean doSolveLeft) throws Exception
{
// Test parameters validity.
if (parameters.isEmpty())
{
throw new Exception("Missing parameters to pass to contract entrypoint");
}
List<String> left = new ArrayList<String>();
List<String> right = new ArrayList<String>();
Pair newPair = null;
if(parameters.size() == 1)
{
// If number of parameters is only 1.
newPair = new MutablePair<>(null, new ArrayList<String>(Arrays.asList(parameters.get(0))));
}
else
{
if (pair == null)
{
Integer half = ( Math.abs(parameters.size() / 2) );
left = parameters.subList(0, half);
right = parameters.subList(half, parameters.size());
newPair = new MutablePair<>(left, right);
}
else
{
List<String> newList;
if (doSolveLeft == true)
{
newList = ((List<String>) pair.getLeft());
}
else
{
newList = ((List<String>) pair.getRight());
}
Integer half = ( Math.abs( newList.size() / 2) );
left = newList.subList(0, half);
right = newList.subList(half, newList.size());
newPair = new MutablePair<>(left, right);
}
if ( (((List)newPair.getRight()).size() > 2) || (((List)newPair.getLeft()).size() > 2) )
{
newPair = new MutablePair<>(buildParameterPairs(jsonObj, newPair, parameters, contractEntryPointParameters, true),
buildParameterPairs(jsonObj, newPair, parameters, contractEntryPointParameters, false));
}
else
{
return newPair;
}
}
return newPair;
}
Answered by Luiz Milfont on August 20, 2021
If we could do a logic schematics for this specific case, do you sirs think it could be described like this? :
parameter (or (or (pair %addCustomer (pair (mutez %balance) (string %id)) (pair (string %name) (nat %phoneNumber))) (string %removeCustomer)) (or (pair %transfer (mutez %amount) (pair (string %idFrom) (string %idTo))) (pair %updateBalance (mutez %amount) (string %id)))) :
Answered by Luiz Milfont on August 20, 2021
You need to follow the path to the corresponding entry point in the Michelson parameter type. ‘Left’ when you go to the left branch of a ‘or’ and ‘Right’ for the right branch.
Answered by FFF on August 20, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP