Web3开发PancakeSwap测试网交易机器人遇LengthMismatch错误求助
问题排查与解决:PancakeSwap Universal Router交易触发LengthMismatch错误
错误原因
你调用PancakeSwap Universal Router的execute函数时,参数格式完全不符合合约要求,这是触发LengthMismatch错误的核心原因。
从合约ABI可以看到,execute函数的正确签名是:
function execute(bytes calldata commands, bytes[] calldata inputs, uint256 deadline) external payable;
而你的代码错误地传入了sender地址、代币路径数组作为前两个参数,参数的数量、类型和合约要求完全不匹配,导致合约校验时抛出长度不匹配的错误。
解决方案
需要按照Universal Router的规范构造commands(命令字节串,指定要执行的操作类型)和inputs(对应每个命令的参数数组),然后正确调用execute函数。以下是针对你需求(用BNB兑换指定代币)的修正代码:
修正后的完整代码片段
from web3 import Web3 import json import config import time bsc = 'https://data-seed-prebsc-1-s1.binance.org:8545' web3 = Web3(Web3.HTTPProvider(bsc)) print(web3.is_connected()) # PancakeSwap Universal Router 测试网地址 UniversalRouter = '0xd77C2afeBf3dC665af07588BF798bd938968c72E' # 合约ABI(保持你原有的ABI即可) panabi = '[{"inputs":[{"components":[{"internalType":"address","name":"permit2","type":"address"},{"internalType":"address","name":"weth9","type":"address"},{"internalType":"address","name":"seaportV1_5","type":"address"},{"internalType":"address","name":"seaportV1_4","type":"address"},{"internalType":"address","name":"openseaConduit","type":"address"},{"internalType":"address","name":"x2y2","type":"address"},{"internalType":"address","name":"looksRareV2","type":"address"},{"internalType":"address","name":"routerRewardsDistributor","type":"address"},{"internalType":"address","name":"looksRareRewardsDistributor","type":"address"},{"internalType":"address","name":"looksRareToken","type":"address"},{"internalType":"address","name":"v2Factory","type":"address"},{"internalType":"address","name":"v3Factory","type":"address"},{"internalType":"address","name":"v3Deployer","type":"address"},{"internalType":"bytes32","name":"v2InitCodeHash","type":"bytes32"},{"internalType":"bytes32","name":"v3InitCodeHash","type":"bytes32"},{"internalType":"address","name":"stableFactory","type":"address"},{"internalType":"address","name":"stableInfo","type":"address"},{"internalType":"address","name":"pancakeNFTMarket","type":"address"}],"internalType":"struct RouterParameters","name":"params","type":"tuple"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BalanceTooLow","type":"error"},{"inputs":[],"name":"BuyPancakeNFTFailed","type":"error"},{"inputs":[],"name":"BuyPunkFailed","type":"error"},{"inputs":[],"name":"ContractLocked","type":"error"},{"inputs":[],"name":"ETHNotAccepted","type":"error"},{"inputs":[{"internalType":"uint256","name":"commandIndex","type":"uint256"},{"internalType":"bytes","name":"message","type":"bytes"}],"name":"ExecutionFailed","type":"error"},{"inputs":[],"name":"FromAddressIsNotOwner","type":"error"},{"inputs":[],"name":"InsufficientETH","type":"error"},{"inputs":[],"name":"InsufficientToken","type":"error"},{"inputs":[],"name":"InvalidBips","type":"error"},{"inputs":[{"internalType":"uint256","name":"commandType","type":"uint256"}],"name":"InvalidCommandType","type":"error"},{"inputs":[],"name":"InvalidOwnerERC1155","type":"error"},{"inputs":[],"name":"InvalidOwnerERC721","type":"error"},{"inputs":[],"name":"InvalidPath","type":"error"},{"inputs":[],"name":"InvalidPoolAddress","type":"error"},{"inputs":[],"name":"InvalidPoolLength","type":"error"},{"inputs":[],"name":"InvalidReserves","type":"error"},{"inputs":[],"name":"InvalidSpender","type":"error"},{"inputs":[],"name":"LengthMismatch","type":"error"},{"inputs":[],"name":"SliceOutOfBounds","type":"error"},{"inputs":[],"name":"StableInvalidPath","type":"error"},{"inputs":[],"name":"StableTooLittleReceived","type":"error"},{"inputs":[],"name":"StableTooMuchRequested","type":"error"},{"inputs":[],"name":"TransactionDeadlinePassed","type":"error"},{"inputs":[],"name":"UnableToClaim","type":"error"},{"inputs":[],"name":"UnsafeCast","type":"error"},{"inputs":[],"name":"V2InvalidPath","type":"error"},{"inputs":[],"name":"V2TooLittleReceived","type":"error"},{"inputs":[],"name":"V2TooMuchRequested","type":"error"},{"inputs":[],"name":"V3InvalidAmountOut","type":"error"},{"inputs":[],"name":"V3InvalidCaller","type":"error"},{"inputs":[],"name":"V3InvalidSwap","type":"error"},{"inputs":[],"name":"V3TooLittleReceived","type":"error"},{"inputs":[],"name":"V3TooMuchRequested","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"factory","type":"address"},{"indexed":true,"internalType":"address","name":"info","type":"address"}],"name":"SetStableSwap","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[{"internalType":"bytes","name":"looksRareClaim","type":"bytes"}],"name":"collectRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"bytes[]","name":"inputs","type":"bytes[]"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"commands","type":"bytes"},{"internalType":"bytes[]","name":"inputs","type":"bytes[]"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"execute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"pancakeV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_info","type":"address"}],"name":"setStableSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stableSwapFactory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"stableSwapInfo","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]' sender = '0x4182692466cF31f1EdbF6E06A7181CF0450F0fe6' balance = web3.eth.get_balance(sender) humanReadable = web3.from_wei(balance,'ether') # 输入要购买的代币地址 tokenToBuy = web3.to_checksum_address(input("Enter TokenAddress: ")) # 测试网WBNB地址 weth9 = web3.to_checksum_address('0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd') # 初始化合约 contract = web3.eth.contract(address=UniversalRouter, abi=panabi) nonce = web3.eth.get_transaction_count(sender) deadline = int(time.time()) + 10000 # -------------------------- 核心修正部分 -------------------------- # 1. 构造命令:0x00 代表 V2_SWAP_EXACT_IN(精确输入兑换) commands = b'\x00' # 2. 构造V2_SWAP_EXACT_IN的参数 # 参数说明:recipient, amountIn, amountOutMinimum, path, payer # - recipient: 接收代币的地址 # - amountIn: 要兑换的BNB数量(已转成wei) # - amountOutMinimum: 最小接收代币数量(这里设为0,实际建议根据滑点计算) # - path: 兑换路径 [WBNB, 目标代币] # - payer: 支付BNB的地址(即sender) amount_in = web3.to_wei(0.003555283, 'ether') amount_out_min = 0 # 实际使用时建议设置合理的滑点阈值 path = [weth9, tokenToBuy] # 编码参数为bytes swap_input = web3.codec.encode_abi( ['address', 'uint256', 'uint256', 'address[]', 'address'], [sender, amount_in, amount_out_min, path, sender] ) # 3. inputs数组:每个命令对应一个参数bytes inputs = [swap_input] # 4. 正确调用execute函数 pancakeswap2_txn = contract.functions.execute(commands, inputs, deadline).build_transaction({ 'from': sender, 'value': amount_in, # 因为是用BNB支付,直接传入对应的wei数量 'gas': 300000, # 适当提高gas上限,避免gas不足 'gasPrice': web3.to_wei('5', 'gwei'), 'nonce': nonce, }) # ----------------------------------------------------------------- # 签名并发送交易 signed_txn = web3.eth.account.sign_transaction(pancakeswap2_txn, private_key=config.private) tx_hash = web3.eth.send_raw_transaction(signed_txn.rawTransaction) print(f"交易哈希: {web3.to_hex(tx_hash)}")
关键说明
- 命令字节(commands):
0x00对应Universal Router的V2_SWAP_EXACT_IN操作,如果你需要其他操作(比如V2_SWAP_EXACT_OUT),需要替换对应的命令码。 - 参数编码:使用
web3.codec.encode_abi将兑换参数编码成合约要求的bytes格式,确保参数类型和顺序完全匹配。 - 滑点设置:示例中
amount_out_min设为0,实际生产环境中建议根据滑点计算合理的最小值(比如允许1%滑点,则计算当前价格的99%作为最小接收量),避免因价格波动导致交易失败。 - Gas上限:适当提高gas上限到300000,确保交易有足够的gas完成兑换操作。
内容的提问来源于stack exchange,提问作者Halil Uysal
相关产品推荐
相关产品推荐

