Web3.py调用swapTokensForExactTokens报参数类型不匹配错误
web3.py调用swapTokensForExactTokens参数类型不匹配问题修复
报错核心提示:无法匹配
swapTokensForExactTokens函数参数类型,传入参数类型为(<class 'int'>, <class 'int'>, <class 'list'>, <class 'str'>, <class 'int'>),目标函数签名为swapTokensForExactTokens(uint256,uint256,address[],address,uint256)。
这个问题是web3.py合约调用的常见问题,按以下顺序排查修复即可:
- 首先核对合约ABI准确性
单独提取Router合约ABI中swapTokensForExactTokens的定义,确认参数类型完全匹配:- 第1位参数:
uint256(amountOut) - 第2位参数:
uint256(amountInMax) - 第3位参数:
address[](注意是动态数组,不能写成固定长度的address[2],对应path路径) - 第4位参数:
address(对应收款地址to) - 第5位参数:
uint256(对应deadline过期时间)
网上流传的公开ABI经常出现参数类型写错的问题,比如把address标成string、把动态数组标成固定长度数组,直接导致类型匹配逻辑错位。
- 第1位参数:
- 显式做全参数类型转换,跳过自动推断
web3.py的自动类型推断经常失效,不要依赖自动转换,所有参数手动显式转成对应类型:
所有地址类值(path内的两个代币地址、to收款地址、交易发起from地址)必须用当前连接节点的w3实例的toChecksumAddress()方法转换,不要传全小写/全大写地址,也不要用其他工具生成的校验和地址;所有数值类值(两个金额、deadline)显式套int()转换,禁止传浮点数、字符串格式数字。
参考写法:import time amount_out = int(1) amount_in_max = int(1) path = [ w3.toChecksumAddress("0x15F517ccAa1420A0bf882052A41A81a152D1A285"), w3.toChecksumAddress("0x72C262985366cf25Cc81629d01393CE3213C4F79") ] to_addr = w3.toChecksumAddress(acct.address) deadline = int(time.time()) + 100000 - 补全交易构造参数
原代码的buildTransaction缺失必填的chainId参数,虽然不会直接触发当前的类型报错,但会导致后续签名失败,chainId直接通过接口获取即可,不需要硬编码:tx_params = { 'from': w3.toChecksumAddress(acct.address), "nonce": nonce, "gas": 200000, 'gasPrice': gasprice, 'chainId': w3.eth.chain_id } - 排查web3.py版本兼容性问题
beta版web3.py、6.0以上新版本的类型检测逻辑存在已知bug,和大部分EVM兼容链节点兼容性最好的稳定版本是5.31.4,执行以下命令安装固定版本:pip install web3==5.31.4 - 绕过自动重载匹配逻辑
如果以上操作后仍报错,可以直接指定函数签名发起调用,跳过web3的自动重载类型匹配,从根源避免类型检测错误:# 直接通过签名获取目标函数,跳过自动匹配 swap_func = Router.get_function_by_signature('swapTokensForExactTokens(uint256,uint256,address[],address,uint256)') # 传入参数构造调用 contract_call = swap_func(amount_out, amount_in_max, path, to_addr, deadline) # 构造交易 tx = contract_call.buildTransaction(tx_params)
完整修正后的调用代码参考:
ChecksumA = w3.toChecksumAddress("0x15F517ccAa1420A0bf882052A41A81a152D1A285") ChecksumB = w3.toChecksumAddress("0x72C262985366cf25Cc81629d01393CE3213C4F79") amount_out = int(1) amount_in_max = int(1) to_addr = w3.toChecksumAddress(acct.address) deadline = int(time.time()) + 100000 tx = w3.eth.account.sign_transaction( Router.functions.swapTokensForExactTokens( amount_out, amount_in_max, [ChecksumA, ChecksumB], to_addr, deadline ).buildTransaction( { 'from': w3.toChecksumAddress(acct.address), "nonce": nonce, "gas": 200000, 'gasPrice': gasprice, 'chainId': w3.eth.chain_id } ), priv ) txsigned = w3.eth.send_raw_transaction(tx.rawTransaction) tx_receipt = w3.eth.waitForTransactionReceipt(txsigned)
内容的提问来源于stack exchange,提问作者creeperQ7
相关产品推荐
相关产品推荐

