TransWikia.com

Is there a formula to build parameter messages to be passed to smart contract entrypoints?

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:

enter image description here

enter image description here

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?

enter image description here

Any information will be much appreciated. Thanks in advance.

4 Answers

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 Lefts and Rights.

  • 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 Lefts and Rights 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)))) :

enter image description here

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

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP