EIP-1559 Gas 费结构
EIP-1559 交易有两个关键字段:
maxFeePerGas:你愿意支付的最高单价(base fee + priority fee)maxPriorityFeePerGas:给矿工的小费(“tip”)
节点在验证交易时检查:
balance >= value + gasLimit × maxFeePerGas
实际扣费是:
gasUsed × (baseFeePerGas + priorityFeePerGas)
其中 baseFeePerGas 由网络自动调整,gasUsed <= gasLimit。
典型实现(web3.py)
from web3 import Web3
w3 = Web3(Web3.HTTPProvider("https://mainnet-rpc.example.xyz"))
def send_max(private_key, dst_address, chain_id):
account = w3.eth.account.from_key(private_key)
from_address = account.address
balance = w3.eth.get_balance(from_address)
nonce = w3.eth.get_transaction_count(from_address)
# 动态读取 baseFee
base_fee = w3.eth.get_block("latest")["baseFeePerGas"]
# 用节点推荐的 priority fee,更可靠
priority_fee = w3.eth.max_priority_fee
# maxFee 加 buffer,防 baseFee 上涨
max_fee_per_gas = base_fee * 2 + priority_fee
# 估算 gas,比写死更安全
gas_limit = w3.eth.estimate_gas({
"from": from_address,
"to": dst_address,
"value": 1,
})
gas_limit = int(gas_limit * 1.2) # 20% buffer
fee = gas_limit * max_fee_per_gas
# 预留少量 wei 防止因 baseFee 微小波动导致余额不足
reserve = w3.to_wei(0.000001, "ether")
amount = balance - fee - reserve
if amount <= 0:
print(f"余额不足,balance={balance}, fee={fee}")
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": chain_id,
"type": 2,
}
signed = w3.eth.account.sign_transaction(tx, private_key)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
return tx_hash.hex()
常见坑
坑一:maxFee 太紧,baseFee 上涨就失败
# 错误写法:maxFee 刚好等于 baseFee + priority
max_fee = base_fee + priority_fee # 一旦下一个区块 baseFee 上涨,交易立即失效
改为:
max_fee = base_fee * 2 + priority_fee # 留足余量,只多花极少的钱
坑二:写死 gasLimit
gas_limit = 21000 # ETH 原生转账是这个值,但其他链可能不同
更安全的方式:
gas_limit = w3.eth.estimate_gas({"from": from_addr, "to": dst, "value": 1})
gas_limit = int(gas_limit * 1.2)
坑三:不预留 reserve 导致余额精确到 wei 后失败
节点验证 balance >= value + gasLimit × maxFeePerGas。如果 amount = balance - fee 算完后 baseFee 微涨,条件就不满足。
预留 0.000001 ETH(约 1,000,000,000,000 wei)几乎没有损失但能避免大量边缘失败。
坑四:priority_fee 写死
priority_fee = w3.to_wei(0.1, "gwei") # 可能太低导致交易迟迟不确认
改为从节点获取推荐值:
priority_fee = w3.eth.max_priority_fee # 节点返回当前合理的 tip