在 EIP-1559 之前,ETH 上的 gas fee 采用的是简单的竞拍模式,出价高者的交易优先被验证。这样的计算模式会导致 gas fee 因为人为因素(出价)而产生剧烈波动。EIP-1559 就是为了解决 gas fee 难以预测以及波动大的问题。
许多应用程序喜欢为用户提供设置自己的汽油费出价的选项,包括“慢速”、“平均”和“快速”选项。在本文中,我们将了解如何使用伦敦分叉后的 API 构建这些选项。
01
Gas Fee 的计算公式
其中:
02
Base Fee | 基础费
首先,base fee 是根据上一个区块的 base fee 而来的。由 eth 节点自动完成计算,本质上区别于之前的竞拍模式。粗略来说 上一个区块交易量大,则提高当前区块的 base fee,反之降低。这样的动态调整。也就是说这个 base fee 完全可以精准的计算出来。
EIP-1559 源代码
上述代码基于 golang,我们将他转化为一段简单的 python 代码:
from web3 import Web3
eth_json_rpc_endpoint = "https://services.tokenview.io/vipapi/nodeservice/eth?apikey=xxx"
ElasticityMultiplier = 2 # EIP-1559 对区块大小进行了扩容,最大倍数是 2
BaseFeeChangeDenominator = 8 # 基本费用在区块之间可以改变的金额
def calc_base_fee_of_next_block(parent_block):
parent_gas_target = parent_block.gasLimit // ElasticityMultiplier
print('parent_gas_target',parent_gas_target)
print('parent_block.gasUsed',parent_block.gasUsed)
print('parent_block.baseFeePerGas',parent_block.baseFeePerGas)
if parent_block.gasUsed == parent_gas_target:
# 如果父块的 gasUsed 与目标相同,则 baseFee 保持不变
return parent_block.baseFeePerGas
if parent_block.gasUsed > parent_gas_target:
# 如果父块使用的 gas 大于目标值,则 baseFee 应增加
gas_used_delta = parent_block.gasUsed - parent_gas_target
x = parent_block.baseFeePerGas * gas_used_delta
y = x // parent_gas_target
base_fee_delta = max(
y // BaseFeeChangeDenominator,
1
)
return parent_block.baseFeePerGas + base_fee_delta
else:
# 否则,如果父块使用的 gas 小于目标值,则 baseFee 应减少
gas_used_delta = parent_gas_target - parent_block.gasUsed
x = parent_block.baseFeePerGas * gas_used_delta
y = x // parent_gas_target
base_fee_delta = y // BaseFeeChangeDenominator
return max(
parent_block.baseFeePerGas - base_fee_delta,
0
)
def main():
ethClient = Web3(Web3.HTTPProvider(eth_json_rpc_endpoint))
block_number = ethClient.eth.block_number
block = ethClient.eth.get_block(block_number)
#计算下个区块的 base fee
base_fee_of_next_block = calc_base_fee_of_next_block(block)
print(f"Base fee for block {block_number + 1} will be {base_fee_of_next_block}")
03
Priority Fee | 优先费
与基础费不同,优先费是人为设定的值。对于需要在同一区块中优先执行的交易,需要提供更高的小费。要预测优先费,得扫描过去一段时间的区块,看看其他人都在用多少的费用。
我们将会用到这个 API:eth_feeHistory
from web3 import Web3
eth_json_rpc_endpoint = "https://services.tokenview.io/vipapi/nodeservice/eth?apikey=xxx"
ethClient = Web3(Web3.HTTPProvider(eth_json_rpc_endpoint))
print(ethClient.eth.fee_history(4,"pending", [25, 50, 75]))
上述调用的意思是,“向我提供从待处理区块开始并向后查看 4 个区块的费用历史信息。对于每个区块,还向我提供该区块中交易的优先费用的第 25、50 和 75 个百分点”。原始结果如下所示:
{
"oldestBlock": 17913327, //4 个区块中 最老的块高
"reward": [ //4 个区块 分别列出他们第 25%、50% 和 75% 的优先费 priorityFeePerGas
[39519672,100000000,2000000000],
[100000000,1000000000,3000000000],
[100000000,365064718,1000000000],
100000000,570000000,3000000000]
],
"baseFeePerGas": [ // 基础费
21121728416,
21666906452,
20742307151,
19782866894,
17762883032
],
"gasUsedRatio": [ // 区块的填充程度,判断交易量用的
0.6032449666666667,
0.3293066333333333,
0.31497906666666664,
0.09156903333333333
]
}
为了让我们的计算更加容易,让我们编写一段格式化方法,将上述结果按块进行分组:
def format_fee_history(result, include_pending):
block_num = result['oldestBlock']
index = 0
blocks = []
historical_blocks = len(result['reward'])
while block_num < result['oldestBlock'] + historical_blocks:
blocks.append({
'number': block_num,
'baseFeePerGas': float(result['baseFeePerGas'][index]),
'gasUsedRatio': float(result['gasUsedRatio'][index]),
'priorityFeePerGas': [float(x) for x in result['reward'][index]],
})
block_num += 1
index += 1
if include_pending:
blocks.append({
'number': 'pending',
'baseFeePerGas': float(result['baseFeePerGas'][historical_blocks]),
'gasUsedRatio': float('nan'),
'priorityFeePerGas': [],
})
return blocks
接下来我们可以得到这样格式的数据:
blocks = format_fee_history(ethClient.eth.fee_history(4,"latest", [25, 50, 75]),False)
print(blocks)
->>
[
{
number: 17913335,
baseFeePerGas: 315777006840,
gasUsedRatio: 0.9922326809477219,
priorityFeePerGas: [ 34222993160, 34222993160, 63222993160 ]
},
{
number: 17913336,
baseFeePerGas: 354635947504,
gasUsedRatio: 0.22772779167798343,
priorityFeePerGas: [ 20000000000, 38044555767, 38364052496 ]
},
{
number: 17913337,
baseFeePerGas: 330496570085,
gasUsedRatio: 0.8876034775653597,
priorityFeePerGas: [ 9503429915, 19503429915, 36503429915 ]
},
{
number: 17913338,
baseFeePerGas: 362521975057,
gasUsedRatio: 0.9909446241177369,
priorityFeePerGas: [ 18478024943, 37478024943, 81478024943 ]
}
]
可读性大大提高!其中baseFeePerGas
gasUsedRatio
是用于计算 base fee 的。我们现在只关注priorityFeePerGas
继续我们的需求,要估算出 priority fee 我们需要确定两个值:
i.要用多少的历史数据来进行估算;
ii.希望自己的交易有多大的优先级。
对于 i ,我们将值设为 4 个区块,大概一分钟的时长算是比较合理。
对于 ii ,我们将期望定为25%, 50%, 75% 对应 低,中,高 的小费。
blocks = format_fee_history(ethClient.eth.fee_history(4,"latest", [25, 50, 75]),False)
low_percential_priority_fees = [b['priorityFeePerGas'][0] for b in blocks]
mid_percential_priority_fees = [b['priorityFeePerGas'][1] for b in blocks]
high_percential_priority_fees = [b['priorityFeePerGas'][2] for b in blocks]
low_average = sum(low_percential_priority_fees) / len(low_percential_priority_fees)
mid_average = sum(mid_percential_priority_fees) / len(mid_percential_priority_fees)
high_average = sum(high_percential_priority_fees) / len(high_percential_priority_fees)
print(low_average,' | ',mid_average,' | ',high_average)
Tokenview 使用的算法是简单地将过去 4 个历史块的 priorityFeePerGas 求平均值。当然 您如果有更好的估算方式,比如将历史区块数量增加到 20 个块,或者是只考虑最便宜的几个成功交易。您可以构建您自己的 gas fee 估算器。
感谢您从头到尾阅读🎉🎉🎉
认识 Tokenview
联系 Tokenview
【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。