Multiple values returned by Solidity function (JavaScript)

How do you access the values returned by a Smart Contract call? This is straightforward when they return a single value. But how do you read multiple values returned by the Solidity function using JavaScript?

Solidity allows you to return multiple separate values of different types through the same method. When wanting to read these values through your JavaScript code, there are two elements that matter:

  • the “receiver” data type
  • the way you call your function

This post will cover the methods through which you can read the values returned by such a function in your JavaScript tests (when working with Truffle). These depend on the type of function you are dealing with:

  1. View/Constant/Pure function
  2. Non-view function

1. Read multiple variables returned by a VIEW/PURE function

This solution is dedicated to Solidity functions that do not modify the state of the contract and are marked as view/pure. If the state mutability is mentioned, Truffle knows what value type it should expect to be returned.

To receive multiple values from a function and be able to reference them, you have to use a JS dictionary. This is the only way to go about it.

If you use something like this:

const (variable_1, variable_2) = await contractInstance.yourFunction();
OR 
const [variable_1,variable_2] = await contractInstance.yourFunction();

you will get an ERROR. Either a syntax one or something like this:

TypeError: (intermediate value) is not iterable

The result of calling a function with multiple variables is a dictionary. So the simple solution for this is the following:

const result = await contractInstance.yourFunction();
const {0: variable_1, 1: variable_2} = result;
assert.equal(variable_1, expectedValue1, "value 1 incorrect");
assert.equal(variable_2, expectedValue2, "value 2 incorrect");

2. Non-view functions

To read multiple values returned by a Solidity function, firstly check exactly what it does. There are 2 scenarios you could be in and each one has a different solution.

View/pure function with mutability not mentioned

If the function you are calling is not modifying the state variables of the contract but you forgot to mark it as view/pure, then simply add the state mutability.

In case you cannot modify the contract, you should let Truffle know that you do not intend to change the state variables. Use the .call() suffix and do the same thing as in the previous section:

const result = await contractInstance.yourFunction.call();
....

Read more about how and when to use the .call() suffix!


Actual non-view function

If you wish to modify the state of your contract by calling the Solidity function, then .call() should not be used.

The following code will result in a transaction receipt which is not what we are looking for:

const result = await contractInstance.yourFunction(param1, param2,...);

Instead, we want to parse through the response as follows:

contractInstance.yourFunction(param1, param2,...).then(function(res){
      var variable_1 = res[0];
      var variable_2 = res[1];
      assert.equal(variable_1, expectedValue1, "value 1 incorrect");
      assert.equal(variable_2, expectedValue2, "value 2 incorrect");
})

***Although, there is a special functionality of .call(). In Truffle, when calling a non-view function using this suffix, you are able to simulate the state modification and get the correct result, but the actual changes will not be registered on the chain:

const result = await contractInstance.yourFunction.call();
const {0: variable_1, 1: variable_2} = result;

Read more about this in the When to use .call() for Solidity functions (Truffle) blog post.


I hope this was helpful. Any suggestions are more than welcomed in the comments!

Leave a Reply