如何在Python中将Solidity合约函数返回值转换为列表
Python解析eth_call返回的ABI编码数组结果
问题场景
Solidity合约函数支持定义数组类型返回值,常见形式包括:returns(address [] memory, string [] memory)、returns (address[][] memory)
通过RPC接口调用合约时,构造的eth_call请求参数示例:
method='eth_call', params=[{ 'to': config['arbContract'], 'data': c.encodeABI(fn_name='getTokensInfo', args=[tokens]), }]
接口响应的result字段为0x开头的十六进制ABI编码字节串,需要解析为Python原生列表/元组结构。
解决方案
不要手动按32字节偏移拆分解析编码结果,动态类型(string、变长数组、嵌套数组)的偏移计算逻辑复杂,手动实现极易出现边界错误,直接使用web3.py内置的ABI解码能力即可,和构造请求时用的encodeABI逻辑完全匹配,不会出现编解码不一致问题。
方法1:使用合约实例自动解码(最推荐)
如果已经通过ABI初始化了合约实例(即代码中用来调用encodeABI的对象c),直接调用对应函数的解码方法即可,不需要手动声明返回类型,类型信息会自动从ABI读取:
# resp为RPC接口返回的响应对象 raw_result = resp['result'] # 直接解码得到结构化结果,顺序和Solidity定义的返回值一一对应 decoded_result = c.getTokensInfo.decodeABI(raw_result) # 例:如果返回值是(address[] memory, string[] memory),可以直接解包 address_list, token_name_list = decoded_result
方法2:手动指定类型解码
如果没有初始化合约实例,也可以直接调用web3的底层解码方法,手动传入和Solidity定义完全一致的返回类型列表:
from web3 import Web3 w3 = Web3() # 替换为你合约实际的返回类型,必须和Solidity声明完全匹配 # 例1:返回(address[] memory, string[] memory) 时写为 return_types = ['address[]', 'string[]'] # 例2:返回(address[][] memory) 时写为 # return_types = ['address[][]'] raw_result = resp['result'] # 去掉0x前缀后转字节串传入解码 decoded_result = w3.codec.decode_abi(return_types, bytes.fromhex(raw_result[2:]))
注意事项
- 解码后得到的是元组结构,顺序和Solidity函数定义的返回值顺序完全一致
- 地址类型会自动转为标准EIP-55校验和格式的字符串,string类型自动解码为Python原生str,嵌套数组会自动解析为对应层级的Python列表,不需要额外做类型转换
- 不要尝试手动切片十六进制串做解析:动态类型的ABI编码采用偏移量指向实际数据存储位置,并非按顺序线性排列,在字符串长度不固定、数组嵌套层级深的场景,手动解析的出错概率极高。
内容的提问来源于stack exchange,提问作者sbb7311
相关产品推荐
相关产品推荐

