Skip to main content

remix + viem + userop 谈 gasfees

不同交易类型,计算方式不同

  1. EIP-1559 交易
  2. Legacy 交易
  3. userOp交易

remix 源码中 gasEstimationForceSend

alt text

tx.type

这段代码涉及到以太坊交易的 gas 估算和发送过程。以下是对这段代码的详细解释:

代码解释

gasEstimationForceSend(null, () => {
/*
* gasLimit 是一个可以在 UI 中设置的值,用于限制交易中可以使用的最大 gas 数量。
* 例如,如果 gas 估算值高于 gasLimit,则会提示用户提高 gas 限制。
*/
if (gasLimit !== '0x0' && gasEstimation > gasLimit) {
return callback(`estimated gas for this transaction (${gasEstimation}) is higher than gasLimit set in the configuration (${gasLimit}). Please raise the gas limit.`)
}

if (gasLimit === '0x0') {
tx['gas'] = gasEstimation; // 如果 gasLimit 为 '0x0',则使用估算的 gas 值
} else {
tx['gas'] = gasLimit; // 否则,使用设置的 gasLimit
}

// 检查是否配置了不显示交易确认的选项
if (this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) {
return this._executeTx(tx, network, null, this._api, promptCb, callback); // 直接执行交易
}

// 否则,显示交易确认界面
confirmCb(network, tx, tx['gas'], (txFee) => {
return this._executeTx(tx, network, txFee, this._api, promptCb, callback); // 用户确认后执行交易
}, (error) => {
callback(error); // 处理确认过程中产生的错误
});
}, callback);

详细步骤

  1. Gas 估算

    • 调用 gasEstimationForceSend 函数来估算交易所需的 gas。
    • gasEstimationForceSend 是一个异步函数,完成后会执行回调函数。
  2. 检查 Gas 估算值

    • 如果 gasLimit 不为 '0x0'gasEstimation 大于 gasLimit,则调用回调函数并返回错误信息,提示用户提高 gas 限制。
    • 如果 gasLimit'0x0',则将交易的 gas 字段设置为估算的 gas 值。
    • 否则,将交易的 gas 字段设置为 gasLimit
  3. 检查是否跳过交易确认

    • 调用 this._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain') 检查配置是否设置了跳过交易确认。
    • 如果设置了跳过交易确认,则直接调用 _executeTx 函数执行交易。
  4. 显示交易确认界面

    • 如果没有设置跳过交易确认,则调用 confirmCb 函数显示交易确认界面。
    • confirmCb 函数接收 networktxgas 作为参数,并在用户确认后调用回调函数。
    • 在用户确认后,回调函数会调用 _executeTx 函数执行交易。
    • 如果确认过程中发生错误,则调用回调函数并传递错误信息。

总结

这段代码的主要功能是估算交易的 gas 并根据用户配置和确认情况决定是否执行交易。它首先估算交易所需的 gas,然后根据配置和用户输入设置交易的 gas 字段,最后根据是否跳过确认来决定是否直接执行交易或显示确认界面。

viem

https://viem.sh/docs/actions/public/estimateFeesPerGas

Returns an estimate for the fees per gas (in wei) for a transaction to be likely included in the next block.

If chain.fees.estimateFeesPerGas is set on the Client Chain or override Chain, it will use the returned value.

Otherwise, for EIP-1559 Transactions, viem will estimate the fees using a combination of the block's base fee per gas (to derive maxFeePerGas) + the estimateMaxPriorityFeePerGas Action (to derive maxPriorityFeePerGas). For Legacy Transactions, viem will estimate the fee based on the gas price (via the getGasPrice Action).

这段文字描述了如何估算以太坊交易的费用,具体分为两种情况:EIP-1559 交易和传统(Legacy)交易。以下是详细解释:

1. 使用 chain.fees.estimateFeesPerGas

如果在客户端链(Client Chain)或覆盖链(Override Chain)上设置了 chain.fees.estimateFeesPerGas,则会使用该设置的返回值作为交易费用的估算值。这意味着你可以通过配置链上的参数来直接控制交易费用的估算。

2. EIP-1559 交易

对于 EIP-1559 交易,费用估算是基于以下两部分:

  • Base Fee Per Gas:这是当前区块链网络的基础费用,由区块的 baseFeePerGas 字段提供。这个基础费用是所有交易必须支付的最低费用。
  • Max Priority Fee Per Gas:这是用户愿意支付给矿工的小费,以便优先处理他们的交易。这个值通过 estimateMaxPriorityFeePerGas 动作来估算。

结合这两部分,EIP-1559 交易的费用估算公式如下:

  • Max Fee Per Gas = Base Fee Per Gas + Max Priority Fee Per Gas

3. Legacy 交易

对于传统(Legacy)交易,费用估算是基于 gasPrice,这个值可以通过 getGasPrice 动作来获取。传统交易不使用 EIP-1559 的费用机制,而是直接使用 gasPrice 字段来指定交易费用。

具体流程

  1. 检查 chain.fees.estimateFeesPerGas

    • 如果设置了 chain.fees.estimateFeesPerGas,则直接使用该返回值作为交易费用的估算值。
  2. EIP-1559 交易

    • 获取当前区块的 baseFeePerGas
    • 使用 estimateMaxPriorityFeePerGas 动作来估算 maxPriorityFeePerGas
    • 计算 maxFeePerGas = baseFeePerGas + maxPriorityFeePerGas
  3. Legacy 交易

    • 使用 getGasPrice 动作来估算 gasPrice

代码示例

假设你在编写一个以太坊客户端,这段代码展示了如何根据上述逻辑来估算交易费用:

async function estimateFees(tx, chain) {
let fees;

// 检查是否设置了 chain.fees.estimateFeesPerGas
if (chain.fees && chain.fees.estimateFeesPerGas) {
fees = await chain.fees.estimateFeesPerGas();
} else {
// 判断交易类型
if (tx.type === '0x2') { // EIP-1559 交易
const baseFeePerGas = await getBaseFeePerGas();
const maxPriorityFeePerGas = await estimateMaxPriorityFeePerGas();
fees = {
maxFeePerGas: baseFeePerGas + maxPriorityFeePerGas,
maxPriorityFeePerGas: maxPriorityFeePerGas
};
} else { // Legacy 交易
const gasPrice = await getGasPrice();
fees = { gasPrice: gasPrice };
}
}

return fees;
}

总结

这段文字解释了如何估算以太坊交易的费用,分别针对 EIP-1559 交易和传统交易提供了不同的估算方法。通过设置 chain.fees.estimateFeesPerGas,可以直接控制费用的估算值;否则,将根据区块的基础费用和用户愿意支付的小费来估算 EIP-1559 交易的费用,或通过 gasPrice 来估算传统交易的费用。

userop gas fee

对于一个eip4337 userOp交易是否是eip-1559还是 Legacy 交易 ?

EIP-4337(Account Abstraction via Entry Point Contract)引入了一种新的交易类型,称为 User Operation(UserOp)。这种交易类型与传统的 EIP-1559 和 Legacy 交易有所不同,因为它旨在实现账户抽象,即将账户逻辑从以太坊协议中抽象出来,允许更灵活的账户管理和交易处理。

EIP-4337 UserOp 交易的特点

  1. Account Abstraction:EIP-4337 通过引入 Entry Point 合约来实现账户抽象,允许用户使用智能合约来管理账户和签名交易。
  2. User Operation:UserOp 是一种新的交易格式,与传统的 EIP-1559 和 Legacy 交易不同。它包含了更多的字段,用于描述用户操作的详细信息。

EIP-4337 UserOp 与 EIP-1559 和 Legacy 交易的区别

  • EIP-1559 交易:这些交易使用了新的费用市场机制,包括 maxFeePerGasmaxPriorityFeePerGas 字段,以提高费用估算的稳定性和效率。
  • Legacy 交易:这些是传统的以太坊交易,使用 gasPrice 字段来指定交易费用。
  • EIP-4337 UserOp 交易:这些交易通过 Entry Point 合约来处理,不直接使用 EIP-1559 或 Legacy 交易的费用机制。相反,UserOp 包含了一个新的费用计算方法,通常由 Entry Point 合约来管理和处理。

具体实现

在 EIP-4337 中,UserOp 交易的费用估算和支付方式是由 Entry Point 合约和用户合约共同决定的。以下是一个简化的示例,展示了如何处理 UserOp 交易:

// Entry Point 合约示例
contract EntryPoint {
function handleOps(UserOperation[] calldata ops) external {
for (uint i = 0; i < ops.length; i++) {
UserOperation memory op = ops[i];
// 处理 UserOp 交易,包括费用计算和支付
// 具体实现取决于合约逻辑
}
}
}

// UserOperation 结构示例
struct UserOperation {
address sender;
uint256 nonce;
bytes callData;
uint256 maxFeePerGas;
uint256 maxPriorityFeePerGas;
// 其他字段
}

总结

EIP-4337 UserOp 交易是一种新的交易类型,与 EIP-1559 和 Legacy 交易不同。它通过 Entry Point 合约实现账户抽象,允许更灵活的账户管理和交易处理。UserOp 交易不直接使用 EIP-1559 或 Legacy 交易的费用机制,而是通过 Entry Point 合约来管理和处理费用估算和支付。因此,EIP-4337 UserOp 交易既不是 EIP-1559 交易,也不是 Legacy 交易,而是一种独立的交易类型。

但是 为什么 UserOperation 参数 需要 maxFeePerGas, maxPriorityFeePerGas 这个是根据 EIP-1559 交易 计算还是根据 Legacy 交易 ?

EIP-4337 的 UserOperation(UserOp)虽然是一种新的交易类型,但它仍然需要处理以太坊网络的交易费用。为了与现有的费用机制兼容,UserOp 引入了 maxFeePerGasmaxPriorityFeePerGas 这两个参数,这些参数的计算方式与 EIP-1559 交易类似。

为什么 UserOperation 需要 maxFeePerGasmaxPriorityFeePerGas

  • 兼容性:以太坊网络已经广泛采用了 EIP-1559 的费用机制。通过使用 maxFeePerGasmaxPriorityFeePerGas,UserOp 可以更好地与当前网络的费用市场机制兼容。
  • 费用估算:这些参数可以帮助估算交易费用,使得用户可以更好地控制他们愿意支付的最大费用和优先费用。

参数计算

EIP-1559 交易计算方式

对于 EIP-1559 交易,费用估算是基于以下两个部分:

  1. Base Fee Per Gas:当前区块的基础费用。
  2. Max Priority Fee Per Gas:用户愿意支付给矿工的小费。

结合这两部分,EIP-1559 交易的费用估算公式如下:

Max Fee Per Gas=Base Fee Per Gas+Max Priority Fee Per Gas\text{Max Fee Per Gas} = \text{Base Fee Per Gas} + \text{Max Priority Fee Per Gas}

UserOperation 中的费用计算

UserOperation 的 maxFeePerGasmaxPriorityFeePerGas 参数也是基于类似的计算方式:

  • maxFeePerGas:用户愿意支付的最大费用,包括基础费用和优先费用。
  • maxPriorityFeePerGas:用户愿意支付给矿工的小费。

这些参数可以通过以下方式估算:

  1. 获取当前区块的 Base Fee Per Gas
    const baseFeePerGas = await getBaseFeePerGas();
  2. 估算 Max Priority Fee Per Gas
    const maxPriorityFeePerGas = await estimateMaxPriorityFeePerGas();
  3. 计算 Max Fee Per Gas
    const maxFeePerGas = baseFeePerGas + maxPriorityFeePerGas;

代码示例

以下是一个示例代码,展示了如何为 UserOperation 估算 maxFeePerGasmaxPriorityFeePerGas

async function estimateUserOpFees() {
// 获取当前区块的 Base Fee Per Gas
const baseFeePerGas = await getBaseFeePerGas();

// 估算 Max Priority Fee Per Gas
const maxPriorityFeePerGas = await estimateMaxPriorityFeePerGas();

// 计算 Max Fee Per Gas
const maxFeePerGas = baseFeePerGas + maxPriorityFeePerGas;

return {
maxFeePerGas: maxFeePerGas,
maxPriorityFeePerGas: maxPriorityFeePerGas
};
}

// 示例调用
estimateUserOpFees().then(fees => {
console.log("Max Fee Per Gas:", fees.maxFeePerGas);
console.log("Max Priority Fee Per Gas:", fees.maxPriorityFeePerGas);
});

总结

虽然 EIP-4337 的 UserOperation 是一种新的交易类型,但它的 maxFeePerGasmaxPriorityFeePerGas 参数的计算方式与 EIP-1559 交易类似。这是为了确保 UserOperation 可以与现有的以太坊费用市场机制兼容,并且能够准确地估算和支付交易费用。因此,UserOperation 的费用估算基于 EIP-1559 的机制,而不是 Legacy 交易的 gasPrice 机制。