You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

主网运行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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:57:01