在EIP-1559之前,ETH上的 gas fee 采用的是简单的竞拍模式,出价高者的交易优先被验证。这样的计算模式会导致 gas fee 因为人为因素(出价)而产生剧烈波动。EIP-1559 就是为了解决 gas fee 难以预测以及波动大的问题。
许多应用程序喜欢为用户提供设置自己的汽油费出价的选项,包括“慢速”、“平均”和“快速”选项。在本文中,我们将了解如何使用伦敦分叉后的 API 构建这些选项。
首先,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 The block size has been expanded, the maximum multiple is 2
BaseFeeChangeDenominator = 8 # The amount the base fee can change between blocks
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:
# parent block's gasUsed is the same as the target, baseFee remains unchanged
return parent_block.baseFeePerGas
if parent_block.gasUsed > parent_gas_target:
# parent block uses gas greater than the target value, baseFee increase
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:
# the gas used by the parent block is less than the target value, baseFee reduce
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_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}")与基础费不同,优先费是人为设定的值。对于需要在同一区块中优先执行的交易,需要提供更高的小费。要预测优先费,得扫描过去一段时间的区块,看看其他人都在用多少的费用
我们将会用到这个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,
"reward": [
[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 估算器
感谢您从头到尾阅读 🎉🎉🎉