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。
两步计算更可靠
对于高精度要求的清仓场景,建议:
- 先构造
value=0估算 gasLimit - 计算
fee = gasLimit × maxFeePerGas,加安全余量 - 签名广播
- 如果仍然报
insufficient funds(baseFee 变化导致),重新读取参数再签一次
