17

I have the following Solidity function:

function func(bytes32[2] data) external {
        bytes32 x;
        bytes32 y;

        x = data[0];
        y = data[1];
}

I'm trying to call it from Javascript (using web3), but passing an array a parameter doesn't work. I tried the following methods:

var arr = ["field1", "field2"];
contracts['MyContract'].contract.func(arr);

or:

contracts['MyContract'].contract.func(["field1", "field2"]);

or:

contracts['MyContract'].contract.func("field1", "field2");

None of those methods work.

Is there a way to pass an array as a parameter from Javascript to a Solidity function?

6
  • passing an array ["field1", "field2"] works in my example. did you deploy the contract first, using new or sendTransaction?
    – kobigurk
    Commented Aug 28, 2016 at 10:00
  • I deployed it using 'sendTransaction. I used it often, and it works fine for any other contract. Did my second option works for you? How did you verify that indeed the right values were passed? I don't get a compilation error, but the values in x,y in the end are "undefined".
    – Eyal Ron
    Commented Aug 28, 2016 at 11:30
  • got you now. how would you know if they're undefined? they're local to the execution of this function. I made sure it's OK by using an event: event Hello(bytes32 x, bytes32 y) and then in the func add: Hello(x,y);
    – kobigurk
    Commented Aug 28, 2016 at 12:22
  • I run a simulation using Mix-IDE, it shows the local account while debugging. I tried the event, and in addition made 'x,y' global contract variables, and read with with a constant function - in both cases x and y are empty variables. I'm puzzled.
    – Eyal Ron
    Commented Aug 28, 2016 at 12:39
  • Maybe try a similar example on browser-solidity? ethereum.github.io/browser-solidity
    – kobigurk
    Commented Aug 28, 2016 at 12:49

1 Answer 1

3

Here's what works for me using getData to populate a transaction data: field

The contract is an array getter setter:

pragma solidity ^0.4.0;

contract SetGetArray {

  uint[] someNumbers;

  function getArray() public constant returns (uint[]) {
    return someNumbers;
  }

  function setArray(uint[] setNumbers) public  {

    someNumbers = setNumbers;

  }

}

// After Deploying (in Kovan)
txHash:0x1cc74caab5c64c493a67cf8e3a8de656ba0db1d6f59c634e3c68e27a41afe7bf
// Successfully deployed Contract with address: 
// 0x1e1300614978efe2bf5c4b532daef69441314205

The gotcha is that if you are changing state your array needs to be in storage and modified with a transaction...

This is a verbose ( includes gas estimation) but hopefully clear way to set it in web3, I am using Node.js and Parity:

console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./SetGetArray.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
var contract = web3.eth.contract(contractABI).at("0x1e1300614978efe2bf5c4b532daef69441314205");
var receiverAddress = '0x1e1300614978efe2bf5c4b532daef69441314205';

var setNumbers = [5,2,4,1];
var setData = contract.setArray.getData(setNumbers);

// console.log(setData);

var gasEstimate = web3.eth.estimateGas({
    from: web3.eth.coinbase,
    to: receiverAddress,
    data: setData
});

var gasPrice = web3.eth.gasPrice;

console.log('gas Price: ' + gasPrice);
console.log('Estimated Transaction gas: ' + gasEstimate);


console.log('unlocking Coinbase account');
const password = "yourPassword";
try {
  web3.personal.unlockAccount(web3.eth.coinbase, password);
} catch(e) {
  console.log(e);
  return;
}

console.log ('sending Transaction to the contract');

const transaction = {
  from: web3.eth.coinbase,
  to:receiverAddress,
  value: '0x00',
  gas: gasEstimate + 1,
  gasPrice: gasPrice + 1,
  data: setData
}


web3.eth.sendTransaction( transaction, function(err, txHash) {
  if (err != null) {
         console.error("Error while sending transaction: " + err);
       }
       else{
         console.log("Transaction Sent here's you  txHash: " + txHash);
       }
});

And getting the Array value:

console.log('Setting up...');
const solc = require ('solc');
const Web3 = require ('web3');
console.log('Reading abi');
const contractABI = require("./SetGetArray.json");
console.log('Connecting');
const web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
console.log('Creating contract instance');
var contract = web3.eth.contract(contractABI).at("0x1e1300614978efe2bf5c4b532daef69441314205");

console.log ('calling contract');
var getArray = contract.getArray();
console.log('Get Array : ' + getArray);
// Get Array : 5,2,4,1
// getArray[2] = 4

You could also just call a contract's function with parameters, but the function needs to be pure, which is not enforced yet( i.e. your compiler might not compile the contract).

function passArray(uint[] otherNumbers) pure public returns (uint[]) {
    return otherNumbers;
}

and calling it :

  var otherNumbers = [4,3,2,1];
  var passArray = contract.passArray(otherNumbers);
  console.log('Pass Array : ' + passArray);
  // Pass Array : 4,3,2,1

The above works with compilers 0.4.17 and above (just update solc) , below you are back to calling it with a transaction that costs gas...

function passArray(uint[] otherNumbers) public returns (uint[]) {
    return otherNumbers;
}

Check both in remix the one on top doesn't incur in gas, while the one in the bottom does.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.