EIP-1559 Gas 费计算与 Python 转账清仓脚本

EIP-1559 的 Gas 费有三个参数,容易写错导致交易失败或余额卡住。

三个参数的含义

参数含义
baseFee当前区块的基础 Gas 价格,由网络自动调整,不能低于这个值
maxPriorityFeePerGas给矿工的小费(Tip),影响打包速度
maxFeePerGas用户愿意支付的最高单价,节点用 max(baseFee + tip, maxFeePerGas) 结算

实际每笔交易扣费:gasUsed × (baseFee + tip),多余部分退还。

常见错误写法

# 问题:maxFee 等于 baseFee + priority,baseFee 稍微上涨就失效
max_fee_per_gas = base_fee + priority_fee

如果在你签名到广播之间的时间里,下一个区块的 baseFee 上涨,节点会拒绝交易(因为 maxFeePerGas < baseFee)。

推荐写法

base_fee = web3.eth.get_block("pending")["baseFeePerGas"]

try:
    priority_fee = web3.eth.max_priority_fee
except Exception:
    priority_fee = web3.to_wei(0.1, "gwei")

# baseFee 乘以 2 留有余量(MetaMask 等钱包的标准做法)
max_fee_per_gas = base_fee * 2 + priority_fee

清仓转账(全额转出)

把钱包余额全部转出时,amount = balance - fee 看起来简单,但有几个坑:

from web3 import Web3

def transfer_all(web3, private_key, dst_address):
    account = web3.eth.account.from_key(private_key)
    from_address = account.address

    balance = web3.eth.get_balance(from_address)
    nonce = web3.eth.get_transaction_count(from_address, "pending")

    base_fee = web3.eth.get_block("pending")["baseFeePerGas"]
    try:
        priority_fee = web3.eth.max_priority_fee
    except Exception:
        priority_fee = web3.to_wei(0.1, "gwei")
    max_fee_per_gas = base_fee * 2 + priority_fee

    # estimate_gas 比写死 30000 更准确
    gas_limit = web3.eth.estimate_gas({
        "from": from_address,
        "to": dst_address,
        "value": 1
    })
    gas_limit = int(gas_limit * 1.2)

    fee = gas_limit * max_fee_per_gas
    # 额外留安全余量,防止 baseFee 微小变化导致不足
    reserve = web3.to_wei(0.00000001, "ether")
    amount = balance - fee - reserve

    if amount <= 0:
        print("余额不足支付 Gas 费")
        return None

    tx = {
        "from": from_address,
        "to": Web3.to_checksum_address(dst_address),
        "value": amount,
        "gas": gas_limit,
        "maxFeePerGas": max_fee_per_gas,
        "maxPriorityFeePerGas": priority_fee,
        "nonce": nonce,
        "chainId": web3.eth.chain_id,
        "type": 2,
    }

    signed = web3.eth.account.sign_transaction(tx, private_key)
    tx_hash = web3.eth.send_raw_transaction(signed.raw_transaction)

    print(f"发送地址: {from_address}")
    print(f"转出: {web3.from_wei(amount, 'ether')} ETH")
    print(f"Gas 费: {web3.from_wei(fee, 'ether')} ETH")
    print(f"TX: {tx_hash.hex()}")

    return tx_hash.hex()

关键细节

nonce 用 "pending" 而非 "latest":如果有未确认交易,用 "latest" 得到的 nonce 偏小,新交易会被拒绝。

gas_limit 用 estimateGas:普通 ETH 转账是 21000,但某些链可能不同,estimate_gas * 1.2 更稳妥。

chainId 用 web3.eth.chain_id 获取:不要硬编码,避免接错链。

确认当前链 ID

print(web3.eth.chain_id)

Gravity L1 Mainnet 的 Chain ID 是 127001,支持 EIP-1559。

两步计算更可靠

对于高精度要求的清仓场景,建议:

  1. 先构造 value=0 估算 gasLimit
  2. 计算 fee = gasLimit × maxFeePerGas,加安全余量
  3. 签名广播
  4. 如果仍然报 insufficient funds(baseFee 变化导致),重新读取参数再签一次