Ethers.js: Function returns dynamic arrays in remix, but ethers returns an empty array

Created on 18 Feb 2021  路  12Comments  路  Source: ethers-io/ethers.js

Hello.
First of all I would like to thank you for your great contribution to the community.

My issue is the following:
Two functions of my contracts return dynamic arrays.

However, only one of these returns the appropriate result with ethers.

"function vratiPrijaveUIR() public view returns (uint[], string[], bool[],bool[],uint[])"
(ABI for the function)
This one is OK, it returns the same result as in Remix

However, I can't make this one work no matter what I try:

"function preuzmiIspitnePrijave(string sifraPredmeta) public view returns (uint[],address[],bool[])"
This one returns an empty array.
But if I add the exact number of elements that is going to be returned
"function preuzmiIspitnePrijave(string sifraPredmeta) public view returns (uint[2],address[2],bool[2])"
the function returns the results I am looking for.

I am interacting with the same instance of the contract in Remix and in JS.

Thanks in advance!

discussion

All 12 comments

It would be helpful for reproducing this issue if you could provide the contract address, sample input for sifraPredmeta, and the network the contract is on.

Thank you so much for such a fast reply!

Contract is at address: 0xa942934972D753C109a8328d0301Af430299bA9e at Kovan testnet

sifraPredmeta sample input: "2OER0000"

My mistake, in ethers, it doesn't return any right value (I think it gives some default values for these types) if you change the ABI to "function preuzmiIspitnePrijave(string sifraPredmeta) public view returns (uint[2],address[2],bool[2])".

However, if you would change the ABI to
"function preuzmiIspitnePrijave(string sifraPredmeta) public view returns (uint[],address[],bool[2])"
it gives the right values only for the bool array.

What is the expected result? i.e. what values do you expect for the uint[], address[], and bool[]?

From the JSON RPC call and result below, it looks like the result should be "empty" for your sample input.

Call:
{"method":"eth_call","params":[{"to":"0xa942934972d753c109a8328d0301af430299ba9e",
"data":"0xf8d3710800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000008324f455230303030000000000000000000000000000000000000000000000000"},"latest"],"id":42,"jsonrpc":"2.0"}

Result:
{"jsonrpc":"2.0","id":42,
"result":"0x0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}

decode the result:

result:
0000000000000000000000000000000000000000000000000000000000000060 <= 1st dynamic array value location
0000000000000000000000000000000000000000000000000000000000000080 <= 2nd array value location
00000000000000000000000000000000000000000000000000000000000000a0 <= 3rd location
0000000000000000000000000000000000000000000000000000000000000000 <= 1st array is emtpy
0000000000000000000000000000000000000000000000000000000000000000 <= 2nd array is empty
0000000000000000000000000000000000000000000000000000000000000000 <= 3rd array is empty

if you change the abi to return (uint[2], address[2], and bool[2]), which just causes ethers to decode the result incorrectly. i.e, it incorrectly returns the locations as the values for uint[2] and the first address value like the following

result [
  [
    BigNumber { _hex: '0x60', _isBigNumber: true },
    BigNumber { _hex: '0x80', _isBigNumber: true }
  ],
  [
    '0x00000000000000000000000000000000000000a0',
    '0x0000000000000000000000000000000000000000'
  ],
  [ false, false ]
]

Hmm.. just read your previous comment about ethers not returning correct values. In fact, I think bool[2] was incorrect too. You could test it by setting bool[] to [true,true].

Are you sure you're testing the same contract on remix?

Also, can you verify the contract on etherscan? That will help make sure the correct version being executed is what you expect?

Hmm.. just read your previous comment about ethers not returning correct values. In fact, I think bool[2] was incorrect too. You could test it by setting bool[] to [true,true].

Are you sure you're testing the same contract on remix?
You're right, I toggled the value in Remix, so both are [true, true] in remix now, but in JS it's still showing [true, false].
Thank you.

Attached are the screenshots for the outputs that I get in remix and in JS.

Also, can you verify the contract on etherscan? That will help make sure the correct version being executed is what you expect?
I have modified the source code since then, without using version control. I will try to verify a newer instance, but I am unsure how I will manage to do that cause another contract is creating this contract that is causing the issue. I will keep you posted if I manage to do it.

original abi
remix
js
jsconsole

Does the function return different value depending on the requester (msg.sender) value? i.e. Try calling the function in ethers using a signer with the same account as in remix?

Thank you a lot, you solved my issue partly.

There's a double msg.sender constraint on the backend (arrays are passed through 2 contracts), and I managed to localize the one of them that gives the error, and after I commented out that constraint it gives me the expected results on the frontend. However, I still don't get it why it doesn't work. I am using the same account in remix and in ethers. (I don't change accounts while interacting with the contract in remix and JS, and I am interacting with the same instance of the contract).

Did you try

ProfessorWithSigner.preuzmiIspitnePrijave("2OER0000");

ProfessorContract is attached to a provider ==> no account info
ProfessorWithSigner is attached to a signer ===> has account info

Oh! I didn't know that the provider doesn't carry the account info!
I thought we just use it to authorize transactions.
A big thanks for this revelation!
I'm sorry I wasted your time!

I am closing the issue now

One last note as to why you likely saw a difference in behaviour, for others that happen across this in the future.

Some Providers are non-standards-compliant. The Provider is supposed to use the from of 0x0000000000000000000000000000000000000000 if unspecified, but some Providers try to be "helpful", which is my guess what the re-mix Provider was doing. It seems helpful in concept, except leads to non-consistent behaviour in cases like your own. So the re-mix Provider was probably feeding in the default account address.

Thanks @yuetloo for your investigation! :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Levino picture Levino  路  35Comments

Tower450 picture Tower450  路  25Comments

cloudonshore picture cloudonshore  路  25Comments

fmsouza picture fmsouza  路  44Comments

bpierre picture bpierre  路  43Comments