Solidity: decode byte data into two structs

Viewed 1782

I have a function call which only accepts bytes data (dydx _getCallActions)

_getCallAction(bytes memory data)

During contract execution the data is passed to a user defined function named: "callFunction"

When decoding into a single struct, it works, however I want to to decode the data into two separate structs.

function callFunction(bytes calldata _data){
// This works, when passed in encoded data matching Struct1Type
Struct1Type memory data1 = abi.decode(_data, (Struct1Type));
}


function callFunction(bytes calldata _data){
// Doesnt work
Struct1Type memory data1, Struct2Type memory data2 = abi.decode(_data, (Struct1Type,Struct2Type));
}

I could decode the data into a single struct and then selectively cast it into the two desired structs, but this seems gas inefficient

1 Answers

You can split the array by the total byte length of the first struct rounded up to a multiplier of 32 - the slot length - and then decode each chunk separately.

In the example below, the length of Struct1Type is just 8 bytes, but the memory and storage slots take up the whole 32byte word. That's why we're splitting at the 32nd index.

Code:

pragma solidity ^0.8;

contract MyContract {
    struct Struct1Type {
        uint8 number;
    }

    struct Struct2Type {
        uint16 number;
    }

    function callFunction(bytes calldata _data) external pure returns (Struct1Type memory, Struct2Type memory) {
        // `:32` returns a chunk "from the beginning to the 32nd index"
        Struct1Type memory data1 = abi.decode(_data[:32], (Struct1Type));

        // `32:` returns a chunk "from the 32nd index to the end"
        Struct2Type memory data2 = abi.decode(_data[32:], (Struct2Type));

        return (data1, data2);
    }
}

Input:

# two values: `1` and `2`
0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002

Output:

0: tuple(uint8): 1
1: tuple(uint16): 2
Related