I’m trying to understand ABI decoding of multicall RPC calls so I can create stubbed tests using WireMock for my Rust EVM application.
The multicall function signature is:
function aggregate(Call[] calldata calls) external payable returns (uint256 blockNumber, bytes[] memory returnData); The two ERC-20 functions I’m calling inside it are:
function symbol() public view returns (string); function decimals() public view returns (uint8); What I Tried
I attempted to manually construct the encoded response.
For three tokens I tried this:
0x 1 - 000000000000000000000000000000000000000000000000000000000378cc49 // block number 2 - 0000000000000000000000000000000000000000000000000000000000000040 // Offset to start of array 3 - 0000000000000000000000000000000000000000000000000000000000000006 // Length of array 4 - 0000000000000000000000000000000000000000000000000000000000000080 // Offset to string 1 5 - 00000000000000000000000000000000000000000000000000000000000000e0 // Offset to string 2 6 - 0000000000000000000000000000000000000000000000000000000000000140 // Offset to string 3 7 - 0000000000000000000000000000000000000000000000000000000000000012 // Decimals for coin 1 8 - 0000000000000000000000000000000000000000000000000000000000000004 // Length of string 1 9 - 57424e4200000000000000000000000000000000000000000000000000000000 // String contents 10 - 0000000000000000000000000000000000000000000000000000000000000012 // Decimals for coin 11 - 0000000000000000000000000000000000000000000000000000000000000004 // Length of string 12 - 43616b6500000000000000000000000000000000000000000000000000000000 // String contents 13 - 0000000000000000000000000000000000000000000000000000000000000012 // Decimals for coin 14 - 0000000000000000000000000000000000000000000000000000000000000004 // Length of string 15 - 5553444300000000000000000000000000000000000000000000000000000000 // String contents Then this failed so I tried to do this for a single return:
"0x 000000000000000000000000000000000000000000000000000000000378cc49 // Block number 0000000000000000000000000000000000000000000000000000000000000040 // Offset to array 0000000000000000000000000000000000000000000000000000000000000002 // Length of array 0000000000000000000000000000000000000000000000000000000000000040 // Offset to string 0000000000000000000000000000000000000000000000000000000000000012 // Decimals 0000000000000000000000000000000000000000000000000000000000000004 // String Length 57424e4200000000000000000000000000000000000000000000000000000000" // String contents But when I run these through WireMock and hit them from Rust, I get:
type check failed for "offset (usize)" with data: 0000000000000000000000000040000000000000000000000000000000000000
What Actually Happens
When I make a real multicall, the response looks like this:
aggregateReturn { blockNumber: 58256789, returnData: [ "0x0000000000000000000000000000000000000000000000000000000000000012", "0x0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000004 57424e4200000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000012", "0x0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000004 43616b6500000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000012", "0x0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000004 5553444300000000000000000000000000000000000000000000000000000000" ] }
My Question
How should I correctly construct a stubbed multicall response for testing (e.g. for 3 tokens with decimals = 18 and symbols "BNB", "Cake", "USDC")?
Thanks in advance
Edit: I tried to follow this as a tutorial so really can't see what I am missing: