如何正确构造ERC-20小数位数与符号的Multicall ABI解码存根测试响应?
如何正确构造ERC-20小数位数与符号的Multicall ABI解码存根测试响应?
我明白你在手动构造Multicall存根响应时踩的坑——ABI的嵌套编码尤其是动态数组和字符串,确实很容易搞混。让我一步步帮你理清正确的构造方式,针对你要测试的3个代币(BNB/Cake/USDC,均为18位小数)拆解清楚:
核心误区先理清
你之前出错的关键是没搞懂Multicall返回值的结构:aggregate函数返回的bytes[] returnData里,每一个元素都是对应单个ERC-20调用的完整ABI编码结果,而不是把所有调用的返回值直接拼接在一起。
举个例子:你调用了3个代币的decimals()和symbol(),总共6次调用,那returnData数组就有6个元素,每个元素单独对应一次调用的ABI编码返回值。
第一步:单独编码每个ERC-20调用的返回值
先把单个函数的返回编码搞对,再组合进Multicall的结果里:
decimals() returns (uint8)的编码:uint8是值类型,ABI编码后是32字节的填充值,18对应的十六进制是0x12,所以完整编码是:0x0000000000000000000000000000000000000000000000000000000000000012symbol() returns (string)的编码:字符串是动态类型,需要三步编码:- 偏移量(固定为
0x20,表示字符串内容从下一个32字节开始) - 字符串长度(比如BNB是3个字符?不对,你示例里用的是WBNB,长度4,对应十六进制
0x04) - 字符串的ASCII十六进制(后面补零到32字节)
以WBNB为例,完整编码是:
0x0000000000000000000000000000000000000000000000000000000000000020 0000000000000000000000000000000000000000000000000000000000000004 57424e4200000000000000000000000000000000000000000000000000000000- 偏移量(固定为
第二步:组合成完整的Multicall返回编码
Multicall的返回是(uint256 blockNumber, bytes[] returnData),按ABI规则完整编码如下(带注释,你可以直接复制用):
0x // 1. blockNumber(示例用你之前的58256789,十六进制0x378CC49,填充到32字节) 000000000000000000000000000000000000000000000000000000000378CC49 // 2. bytes[] returnData的ABI编码 0000000000000000000000000000000000000000000000000000000000000040 // 数组偏移量:从第64字节开始 0000000000000000000000000000000000000000000000000000000000000006 // 数组长度:6个调用结果 // 3. 每个数组元素的偏移量(指向对应调用结果的起始位置) 0000000000000000000000000000000000000000000000000000000000000100 // 代币1 decimals结果的偏移 0000000000000000000000000000000000000000000000000000000000000120 // 代币1 symbol结果的偏移 0000000000000000000000000000000000000000000000000000000000000180 // 代币2 decimals结果的偏移 00000000000000000000000000000000000000000000000000000000000001A0 // 代币2 symbol结果的偏移 0000000000000000000000000000000000000000000000000000000000000200 // 代币3 decimals结果的偏移 0000000000000000000000000000000000000000000000000000000000000220 // 代币3 symbol结果的偏移 // 4. 每个调用结果的实际编码内容 0000000000000000000000000000000000000000000000000000000000000012 // 代币1 decimals(18) 0000000000000000000000000000000000000000000000000000000000000020 // 代币1 symbol(WBNB) 0000000000000000000000000000000000000000000000000000000000000004 57424e4200000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000012 // 代币2 decimals(18) 0000000000000000000000000000000000000000000000000000000000000020 // 代币2 symbol(Cake) 0000000000000000000000000000000000000000000000000000000000000004 43616b6500000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000012 // 代币3 decimals(18) 0000000000000000000000000000000000000000000000000000000000000020 // 代币3 symbol(USDC) 0000000000000000000000000000000000000000000000000000000000000004 5553444300000000000000000000000000000000000000000000000000000000
验证小技巧
如果怕手动编码出错,你可以在Remix里写个简单的Solidity测试函数,用abi.encode生成标准模板:
function generateMulticallResponse() public pure returns (bytes memory) { uint256 blockNumber = 58256789; bytes[] memory returnData = new bytes[](6); // 填充每个调用的编码结果 returnData[0] = abi.encode(uint8(18)); returnData[1] = abi.encode(string("WBNB")); returnData[2] = abi.encode(uint8(18)); returnData[3] = abi.encode(string("Cake")); returnData[4] = abi.encode(uint8(18)); returnData[5] = abi.encode(string("USDC")); return abi.encode(blockNumber, returnData); }
编译后调用这个函数,复制返回的十六进制字符串作为WireMock的存根响应,绝对不会出错。
内容来源于stack exchange
相关产品推荐
相关产品推荐

