0

I would like to return structs keys from my contract to display on the frontend, ideally 10 at a time. I understand that if I make keyByOwner public I can return a single key at a time with the getter that is created, but I need 10 keys and don't want to call the getter function 10 times.

I've tried to use the approach detailed here to return a tuple of arrays: https://medium.com/coinmonks/solidity-tutorial-returning-structs-from-public-functions-e78e48efb378 I think this would be the way to proceed, except that it doesn't seem to work with the Key's data field being of type bytes(it works fine if I change type byes to type bytes32), giving me this error:

TypeError: This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature.
    returns (uint[], bytes[])
                     ^-----^

Is there any way to return multiple structs (or the fields from them) in Solidity when one of the struct fields is of type bytes?

Here is my function:

struct Key {
  uint expirationTimestamp;
  bytes data;
 }

 mapping (address => Key) internal keyByOwner;

 address[] public owners;

  function getKeysByPage(uint _startIndex)
    external
    view
    returns (uint[], bytes[])
  {
    require(outstandingKeys() > 0, "No keys to retrieve");
    require(_startIndex >= 0 && _startIndex < outstandingKeys(), "Index must be in-bounds");
    uint endOfPageIndex;

    if (_startIndex + 9 > owners.length) {
      endOfPageIndex = owners.length - 1;
    } else {
      endOfPageIndex = _startIndex + 9;
    }

    address[] memory ownersByPage = new address[](10);
    uint[] memory timestampsArray = new uint[](10);
    bytes[] memory keyDataArray = new bytes[](10);
    Key memory tempKey;
    uint pageIndex = 0;

    // Build the specified set of owners into a new temporary array
    for (uint256 i = _startIndex; i <= endOfPageIndex; i++) {
      ownersByPage[pageIndex] = owners[i];
      pageIndex++;
    }

    // Loop through ownersByPage & build the requested keys into 2 new temporary arrays
    for (uint256 n = 0; n < ownersByPage.length; n++) {
      tempKey = keyByOwner[ownersByPage[n]];
      timestampsArray[n] = tempKey.expirationTimestamp;
      keyDataArray[n] = tempKey.data;
    }

    return(timestampsArray, keyDataArray);
  }
0

Returning structs and tuples of structs is not possible with the current ABI. If you add pragma experimental ABIEncoderV2 right after your pragma solidity line though, it will compile just fine. Unfortunately, it is not recommended to go to production with an experimental feature, hence the only viable alternative now is to returns the primitive types of each struct in a row.

Specifically for your scenario, you need to temporarily use a compatible type. For instance, you could convert your dynamic byte array to bytes32.

  • Thanks Paul. I was aware that it works with the pragma experimental ABIEncoderV2 header, but as you said, not good enough for production. I am able to return tuples of arrays, but it doesn't seem to work if one of the arrays in the tuple is of type bytes or of type string, likely because they're both dynamic arrays. Can you elaborate on "the only viable alternative now is to returns the primitive types of each struct in a row."? – Nick Furfaro Nov 23 '18 at 21:30
  • Oh sorry, I was generally referring to structs. I updated the answer. – Paul Berg Nov 23 '18 at 21:37
  • So yeah, sadly, that's the only thing you can do for now. – Paul Berg Nov 23 '18 at 21:39
  • No worries, that was what my original question asked. In my example, I've taken the fields from 10 structs and recomposed them into 2 new arrays, one for each of the fields. I was hoping that maybe Solidity 0.5 would solve this, but for now, I will look at the link you posted on converting dynamic byte arrays to bytes32. – Nick Furfaro Nov 23 '18 at 21:45

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.