Dynamically Sized 2-Dimensional Arrays & ABIEncoderV2

Hello everyone. I peeked my head into the Slack chatroom and was referred here kindly by @nventuro ,on to my question…

Could anyone offer clarification on whether or not the ABIEncoder(v2) is experimental or if there are workarounds to the usage of it in production-grade contract code? My team and I want to have methods containing the ‘view’ keyword return dynamically-sized 2-D arrays…

Thanks in advance!

P.S. Here is an error code to give additional insight into the necessary use of ABIEncoderV2:

TypeError: This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature. string[] memory descriptions, string[] memory objectives, uint256[] index) { ^--------------------------^

1 Like

Welcome @pynchmeister! Glad to have you here.

I don't have a definitive answer, unfortunately, but I've found the following comment by @chriseth from the Solidity team:

The encoder should not cause any security issues (of course we can never be sure). The main reason it is marked experimental is because it causes higher gas usage.

I personally wouldn't use the feature in production. Because of its experimental status I don't think it has been vetted thoroughly by many people. I've forwarded this question to Zeppelin's research team to see if we can do something about that. :slightly_smiling_face:

Due to being experimental and undocumented (at least I couldn't find any), I would also consider the encoding to be unstable. If the encoding changes in the future and your contract is immutably deployed, it might be cumbersome to interact with it. You could ask the Solidity team directly if they consider the encoder stable, but I'd be wary anyway

2 Likes

Oh, and as for workarounds, could you share more of your code? I’m not sure I understand the situation from the error you posted.

1 Like

Here is the function unable to be returned:

function getAllListings() public view returns(address[] memory addresses, uint256[] memory amounts, bytes32[] memory subjects, bytes32[] memory topics, string[] memory descriptions, string[] memory objectives, uint256[] index) {

Hope this helps @frangio!

Hey @pynchmeister, I’m Martin, researcher @ Zeppelin.
I’ve run some super quick tests both in Remix and locally, with Truffle 5 and solc 0.5, and everything seems to run ok, so at first sight using that experimental feature should work fine. Bear in mind that this is the first time I actually use it, so I’m not that familiar with it.
Nevertheless, agreeing with everything @frangio said above, the feature is still labeled as experimental. A keyword saying “experimental”, along with a compiler warning, should be enough red flags to avoid deploying to mainnet using the ABIEncoderV2 feature until it’s more battle-tested both from functional and security standpoints.

You can find open issues regarding this feature in Solidity’s Github repo (https://github.com/ethereum/solidity/search?q=ABIEncoderV2&state=open&type=Issues). According to issue#4700, end-to-end testing with this feature enabled hasn’t been accomplished yet (though they seem to be pretty close according to the related PR https://github.com/ethereum/solidity/pull/5102). I haven’t found issues related to security vulnerabilities though, which does not mean that there aren’t any.

It’s hard to think of workarounds without further context. From the top of my head (probably you’ve already thought of these):

  • If strings are short enough, just return an array of statically-sized arrays (i.e bytes32[] instead of string[]) and throw away the pragma experimental ABIEncoderV2. When calling that function and reading the returned values, it would be just a matter of calling web3.utils.hexToUtf8 to get a readable form of the string.
  • If strings are longer than 32 bytes (which I think should be your case), a more cumbersome approach would be to build an array of hashes for each string, thus just returning the hashes in a bytes32[] array. To save the corresponding original string for each hash, you could emit an event such as MyEvent(bytes32 indexed hash, string originalString). This way, you can log both the original and hashed string, and then you’d just need to search through the logs to obtain the original text for a given hash.
  • Lastly, a far simpler approach would be to remove the string[] return values from your function and have one separate getter that returns each element of the string[] arrays (no idea if that’s somehow in storage or how it’s built) and do subsequent calls to the getter to rebuild the whole array outside the contract.
3 Likes

@pynchmeister Chris (leader of the Solidity team) just tweeted this:

1 Like

Awesome @nventuro thanks for the update! I tend to stay off Twitter, so it is much appreciated.

@pynchmeister Be careful though, as a bug has just been discovered in the ABIEncoderV2 https://blog.ethereum.org/2019/03/26/solidity-optimizer-and-abiencoderv2-bug/ . Fixes have been already addressed in Solidity v0.5.7, so you should take a look at the article, see if the bug affects your contracts, and update to latest version of Solidity.

5 Likes