主网运行DeFi套利交易代码遇Gas及交易透支错误求助
DeFi跨交易所套利主网部署错误解决方案
错误原因拆解
1. replacement transaction underpriced
手动指定nonce = get_transaction_count(...) +1是核心问题:主网交易拥堵时,账户可能存在pending状态的未确认交易,新交易用相同nonce但gas price未比原交易高至少10%(以太坊主网规则),就会触发该错误。测试网交易少,pending交易概率低,因此未暴露。
2. exceeds block gas limit
硬编码gas:200000完全不合理:主网区块gas上限是动态调整的,固定值可能超过当前区块上限;且swap交易实际需要的gas远低于该值,硬写过高直接触发限制报错。
3. transaction would cause overdraft
- 账户ETH余额不足以支付主网gas费用(主网gas成本远高于测试网);
- USDT小数处理错误:USDT是6位小数,代码中用
Web3.to_wei(..., 'ether')(对应18位)会把金额放大10^12倍,导致approve或swap请求的金额远超账户实际余额; - swap参数逻辑错误:卖出交易传入未转成uint256的浮点数
sell_token_amount,而非正确的整数金额,合约执行时直接判定余额不足。
核心修复方案
1. 正确获取Nonce
放弃手动加1,改用包含pending状态的nonce查询,确保每次交易用正确的下一个序号:
nonce = web3M.eth.get_transaction_count(account_address, 'pending')
2. 动态估算Gas
删除硬编码gas值,用estimate_gas估算实际需求后加10%缓冲,避免超出区块上限:
approve_tx = usdt_contract.functions.approve(pair_contract.address, usdt_amount_scaled).build_transaction({ 'from': account_address, 'gasPrice': web3M.to_wei('50', 'gwei'), 'nonce': nonce, 'chainId': 1 }) # 估算gas并加缓冲 try: estimated_gas = web3M.eth.estimate_gas(approve_tx) approve_tx['gas'] = int(estimated_gas * 1.1) except Exception as e: print("Gas估算失败:", e) return
3. 修正USDT小数处理
USDT是6位小数,转换时指定'mwei'而非'ether':
# USDT金额转uint256(6位小数) usdt_amount_scaled = Web3.to_wei(usdt_amount, 'mwei') # 其他18位小数ERC20用ether token0_amount_uint = Web3.to_wei(token0_amount, 'ether')
4. 优化交易等待逻辑
删除固定sleep,改用wait_for_transaction_receipt等待交易确认,避免提前执行后续交易:
approve_tx_hash = web3M.eth.send_raw_transaction(signed_approve_tx.rawTransaction) # 等待交易确认,超时300秒 approve_receipt = web3M.eth.wait_for_transaction_receipt(approve_tx_hash, timeout=300) if approve_receipt.status != 1: print("Approve交易失败") return print("Approve交易成功确认")
5. 前置余额检查
执行交易前先检查ETH(够付所有交易gas)和USDT(够交易金额)余额:
# 检查ETH余额 eth_balance = web3M.eth.get_balance(account_address) gas_cost = approve_tx['gas'] * approve_tx['gasPrice'] if eth_balance < gas_cost * 3: # 留够三次交易的gas余量 print("ETH余额不足,无法支付gas") return # 检查USDT余额 usdt_balance = usdt_contract.functions.balanceOf(account_address).call() if usdt_balance < usdt_amount_scaled: print("USDT余额不足") return
6. 修正Swap参数
卖出交易必须传入正确的uint256金额,且符合交易所swap接口规范(以Uniswap V2为例,卖出token时需设置对应输出金额的滑点):
# 卖出交易示例(Uniswap V2) sell_tx = pair_contract.functions.swap(0, int(token0_amount_uint * 0.99), account_address, b'').build_transaction({ 'from': account_address, 'gasPrice': web3M.to_wei('50', 'gwei'), 'nonce': nonce, 'chainId': 1 })
修正后的核心代码片段
def execute_trade(pair_contract, token0_address, token1_address, token0_price_usdt, token1_price_usdt, token0_symbol, token1_symbol, exchange_name, token0_price_1, token1_price_1, token0_symbol_1, token1_symbol_1, exchange_name_1, price_ratio_1, price_percentage_1): usdt_amount = 10 # 修正USDT小数处理 usdt_amount_scaled = Web3.to_wei(usdt_amount, 'mwei') token0_amount = usdt_amount / token0_price_usdt token1_amount = usdt_amount / token1_price_usdt token0_amount_uint = Web3.to_wei(token0_amount, 'ether') token1_amount_uint = Web3.to_wei(token1_amount, 'ether') usdt_contract = web3M.eth.contract(address='0xdAC17F958D2ee523a2206206994597C13D831ec7', abi=usdt_abi) # 余额检查 eth_balance = web3M.eth.get_balance(account_address) usdt_balance = usdt_contract.functions.balanceOf(account_address).call() if usdt_balance < usdt_amount_scaled: print("USDT余额不足") return # Approve交易 nonce = web3M.eth.get_transaction_count(account_address, 'pending') approve_tx = usdt_contract.functions.approve(pair_contract.address, usdt_amount_scaled).build_transaction({ 'from': account_address, 'gasPrice': web3M.to_wei('50', 'gwei'), 'nonce': nonce, 'chainId': 1 }) # 估算gas try: estimated_gas = web3M.eth.estimate_gas(approve_tx) approve_tx['gas'] = int(estimated_gas * 1.1) except Exception as e: print("Gas估算失败:", e) return # 检查ETH gas余额 gas_cost = approve_tx['gas'] * approve_tx['gasPrice'] if eth_balance < gas_cost * 3: print("ETH余额不足,无法支付所有交易gas") return signed_approve_tx = web3M.eth.account.sign_transaction(approve_tx, private_key=private_key) try: approve_tx_hash = web3M.eth.send_raw_transaction(signed_approve_tx.rawTransaction) print(f"Approve交易已发送: {web3M.to_hex(approve_tx_hash)}") # 等待交易确认 approve_receipt = web3M.eth.wait_for_transaction_receipt(approve_tx_hash, timeout=300) if approve_receipt.status != 1: print("Approve交易失败") return print("Approve交易成功确认") except ValueError as e: if "already known" in str(e): print("交易已存在,跳过approve") else: print("发送Approve交易失败:", e) return # 买入交易逻辑 nonce = web3M.eth.get_transaction_count(account_address, 'pending') if token0_price_usdt <= token1_price_usdt: buy_token_address = token0_address min_amount_out = int(token0_amount_uint * 0.99) # 设置1%滑点 else: buy_token_address = token1_address min_amount_out = int(token1_amount_uint * 0.99) # 构建swap交易(Uniswap V2示例) buy_tx = pair_contract.functions.swap(0, min_amount_out, account_address, b'').build_transaction({ 'from': account_address, 'gasPrice': web3M.to_wei('50', 'gwei'), 'nonce': nonce, 'chainId': 1 }) try: estimated_gas = web3M.eth.estimate_gas(buy_tx) buy_tx['gas'] = int(estimated_gas * 1.1) except Exception as e: print("买入交易Gas估算失败:", e) return signed_buy_tx = web3M.eth.account.sign_transaction(buy_tx, private_key=private_key) buy_tx_hash = web3M.eth.send_raw_transaction(signed_buy_tx.rawTransaction) print(f"买入交易已发送: {web3M.to_hex(buy_tx_hash)}") buy_receipt = web3M.eth.wait_for_transaction_receipt(buy_tx_hash, timeout=300) if buy_receipt.status != 1: print("买入交易失败") return print("买入交易成功确认") # 卖出交易逻辑参考买入逻辑修正,注意参数和滑点设置 # ... print(f"买入 {token0_amount:.6f} {token0_symbol} 花费 {usdt_amount:.2f} USDT") print(f"卖出 {token0_amount:.6f} {token0_symbol} 预计获得 {usdt_amount:.2f} USDT")
内容的提问来源于stack exchange,提问作者kabir tanveer
相关产品推荐
相关产品推荐

