2

Update2: Ismael highlighted that upgrading drizzle and Web3 were crucial. I was using drizzle 1.3 and Web3 1.0. So, using the same Solidity code, I can now read a string array into a webpage, using drizzle 1.5.3 and Web3 1.3.

Update: I found a note on this forum by goodvibration that noted

And so there is no way for you to return an array of strings. Perhaps on solc 0.6, but I doubt it. –

Therefore, instead of pulling an array, I created a function in my Solidity contract that returned only elements from a string array. This worked. If anyone knows how to pull string arrays, that would be great, but it appears impossible. ...

I can call getter functions on an Ethereum smart contract that reads an array of uints, but when I just change my target to a string, my javascript file fails to read it.

My Solidity getters look like this; they are identical except one array is uint the other a string. They both work in Remix on Rinkeby (the strings have items with about 10 characters, all English letters).

function showUint() external view returns (uint[16] memory) {return teamScheduleU;} 

 function showString() external view returns (string[16] memory) {return teamScheduleS;}

My javascript code looks like this

  this.scheduleKey = this.contracts[this.contractDict].methods.showUint.cacheCall()}
...
 myArray = this.props.contracts[this.contractDict].
showUint[this.scheduleKey].value;

When I pull in the uint array in javascript with showUint as above, it works. When I replace with showString it does not. The error reads:

   Error: Invalid UTF-8 detected
    at decodeSymbol (utf8.js:194)
    at Object.utf8decode [as decode] (utf8.js:206)
    at Object.hexToUtf8 (utils.js:218)

I get this same error when trying to read an event log that contains a string array (I can read event logs from the same contract that do not contain strings). Interestingly, I get this same error even if I do not process the string variable from the event log, just that the event log contains a string (it has the same "Invalid UTF-8" descriptor).

4
  • Can you amend your question to include the full code of the getter and setter in solidity and also the javascript code you are using to retrieve it Dec 7 '20 at 15:58
  • I thought it was an error elsewhere, but that turned out unrelated. My Solidity getters look like this: Dec 8 '20 at 2:54
  • 1
    @EricFalkenstein The repo linked below uses drizzle v1.4 which uses web3 1.0, I'm pretty sure that version doesn't support ABIEncoderV2. There is a new drizzle version you might want to take a look at github.com/trufflesuite/drizzle.
    – Ismael
    Dec 14 '20 at 15:24
  • Interesting! Non-trivial for me given my competency, but a good pointer. Dec 15 '20 at 21:39
0

I have implemented your 2 functions and returned the expected values. Please find below the complete code:

Step 1: Smart contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.6.12;
pragma experimental ABIEncoderV2;

contract Test {

   uint[16] public teamScheduleU;
   string[16] public teamScheduleS;

   function init() external {
     // Sample values for array of integers
     for (uint i=0; i<15; i++) {
         teamScheduleU[i] = i;
     }
    
     // Sample values for array of strings
     teamScheduleS[0]='a';
     teamScheduleS[1]='b';
     teamScheduleS[2]='c';
     teamScheduleS[3]='d';
   }

   function showUint() external view returns (uint[16] memory) {
     return teamScheduleU;
   } 

   function showString() external view returns (string[16] memory) {
     return teamScheduleS;
   }
}

Step 2: Node.js script:

const Web3 = require('web3');
const Test = require('./build/contracts/Test.json');
const web3 = new Web3(new Web3.providers.HttpProvider('http://127.0.0.1:7545'));  // Local Ganache
const contract = new web3.eth.Contract(Test.abi, 'YOUR_CONTRACT_ADDRESS');

const main = async () => {

   await contract.methods.showUint()
     .call()
     .then((res) => {
        console.log('Result integer array:', res);
     });


   await contract.methods.showString()
     .call()
     .then((res) => {
        console.log('Result string array:', res);
    });
};

main();

Step 3: Initialise values in smart contract

In Remix, you can just call the init function to add the sample values.

Step 4: Run script

Finally, run the JavaScript file (for this example, using Node.Js):

$ node test.js

And you should see the expected values:

enter image description here

3
  • Maybe a Rinkeby issue, or my node packages? I have the project at github.com/efalken/test. If you clone, do a "yarn install" and then "yarn add escope", it should work. Click on the first page and it takes you to "betpage.js," Note the two 'console.log' statements: one for the uint (works), one for the string (result: undefined). The solidity file is in the project (Betting.sol), which you can see on Rinkeby at 0x477eef0bfB13821F731f768e9ceb445C2C19fcDc. Dec 9 '20 at 14:18
  • Did you try my proposal? I suggest you remove the cacheCall() when calling the contract to retrieve the arrays, and once you get the whole array in JS, you can access and manipulate it as you need. Dec 9 '20 at 19:17
  • My ignorance is large here, as I am trying to extend something made two years ago with Drizzle, and apply it to a new contract. Thus, on a stand-alone web3, it might work, but I cannot avoid the cacheCall() within the drizzle throughout my code. Dec 10 '20 at 17:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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