mcpField
G
gas

gas

github.com/therealharpaljadeja开发14230 次安装2 周前更新
代码仓库

关于 gas

面向 Monad 应用开发者的 gas 机制参考技能,说明交易定价、限制和 opcode 成本差异。重点是 Monad 按 gas limit 而非实际消耗收费,以及如何设置限额和展示费用。

主要功能

  1. 01说明按 gas limit 收费
  2. 02介绍 EIP-1559 定价规则
  3. 03列出区块与交易限制
  4. 04解释基础费控制器
  5. 05汇总 opcode 与预编译成本差异
  6. 06提供 gas 限额与费用计算建议

适用场景

  1. 01为 Monad 交易设置 gas limit
  2. 02在界面计算并展示 gas 费用
  3. 03估算合约冷存储访问成本
  4. 04评估签名或 ZK 预编译费用

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/therealharpaljadeja/monskills --skill gas

安装后在 Claude Code 中输入/gas确认已加载。

附带文件SKILL.zh.md

详细介绍

Monad 的 Gas 定价兼容 EIP-1559,但与 Ethereum 有一些关键差异。如果你正在构建会提交交易、估算 Gas 或显示 Gas 费用的应用,就需要了解这些差异。

关键差异:Monad 按 Gas 上限收费,而不是按 Gas 用量收费

在 Ethereum 上,用户按交易实际消耗的 Gas 付费。在 Monad 上,用户根据自己设置的 Gas 上限 付费:

gas_paid = gas_limit * price_per_gas

这是因为 Monad 使用异步执行:区块领导者会先构建区块,再执行区块,因此交易被纳入区块时无法得知实际 Gas 消耗量。这样可以防止拒绝服务(DOS)攻击,即交易声称 Gas 费用低廉,却消耗昂贵的计算资源。

这对开发者意味着:

  • 设置过高的 Gas 上限会直接让用户多花 MON。
  • 务必设置严格且准确的 Gas 上限,尤其是成本固定的交易。
  • 对于原生 MON 转账,Gas 费用始终为 21,000。请直接将此值硬编码,而不要依赖 eth_estimateGas。

EIP-1559 交易定价

Monad 使用 type 2(EIP-1559)交易:

price_per_gas = min(base_price_per_gas + priority_price_per_gas, max_price_per_gas)

用户签名时需指定两个值:

  • priority_price_per_gas — 用于提高交易在区块中优先级的小费
  • max_price_per_gas — Gas 总价格的安全上限

网络控制 base_price_per_gas,该值对区块中的所有交易都相同。

区块和交易上限

参数值
区块 Gas 上限200M Gas
交易 Gas 上限30M Gas
最低基础费用100 MON-gwei(100 x 10^-9 MON)

这些上限远高于 Ethereum 的 30M 区块 Gas 上限,因此 Monad 区块可以容纳更多交易。

基础费用控制器

Monad 的基础费用控制器与 Ethereum 的不同。它提高得更慢、降低得更快,以避免定价过高导致区块空间利用不足。

控制器参数:

  • max_step_size = 1/28
  • target = 160M Gas(区块容量的 80%)
  • beta = 0.96
  • epsilon = 160M

基础费用会在每个区块中更新,并根据区块相对于目标值的使用程度进行指数调整。此公式使用指数平滑(beta = 0.96)追踪区块使用量的历史波动,因此费用变动比 Ethereum 的简单机制更平稳。

实际上,这意味着 Monad 上的 Gas 价格更稳定,并能在价格飙升后更快恢复。

交易排序

默认的 Monad 客户端使用优先 Gas 拍卖对交易排序,按 Gas 总价格(基础费用 + 优先费)降序排列。

开发者指南

务必为已知成本设置明确的 Gas 上限

对于 Gas 成本固定的操作,请在提交给钱包之前明确设置 Gas 上限:

// Good: explicit gas limit for a native transfer
const tx = {
  to: recipient,
  value: parseEther("1.0"),
  gasLimit: 21000n,
};

这一点很重要,因为某些钱包(例如 MetaMask)会使用 eth_estimateGas 来确定 Gas 上限。如果该调用回滚(例如合约调用会失败),钱包可能会回退到一个非常高的 Gas 上限。在 Monad 上,用户会因此按整个虚高的上限付费,因为Gas 按上限收费,而非按实际用量收费。

前端代码中的 Gas 估算

使用 viem 或 wagmi 估算 Gas 时,请记住,估算值就是用户实际支付的数值,而不是下限。如有需要,只添加少量缓冲:

// If you must estimate, keep the buffer small
const estimate = await publicClient.estimateGas({ ... });
const gasLimit = estimate + (estimate / 10n); // 10% buffer at most
向用户显示 Gas 费用

在 UI 中显示 Gas 费用时,请根据 Gas 上限计算,而不是使用其他链上收据中的“Gas 用量”:

const gasCost = gasLimit * gasPrice;
智能合约注意事项
  • Monad 的 30M 交易 Gas 上限与 Ethereum 的区块 Gas 上限相同,因此单笔交易可以非常大。
  • 优化合约以减少其在 Monad 上的 Gas 用量,这会直接为用户省钱,因为用户按上限付费;更准确的估算也意味着可以设置更严格的上限。
  • 如果合约中有 Gas 成本可预测的函数,请记录这些成本,以便前端设置明确的上限。

操作码定价差异

Monad 上调了少数操作码的价格,而不是对所有操作都打折。这样能以最小的改动达到相同的相对效果。这些调整反映了 Monad 高性能架构中资源稀缺程度的差异,尤其是基于磁盘的状态操作。

冷状态访问的成本高得多
操作EthereumMonad增幅
账户访问(冷)2,600 gas10,100 gas+7,500
存储访问(冷)2,100 gas8,100 gas+6,000
账户访问(热)100 gas100 gas不变
存储访问(热)100 gas100 gas不变

受影响的操作码:

  • 账户访问:BALANCE、EXTCODESIZE、EXTCODECOPY、EXTCODEHASH、CALL、CALLCODE、DELEGATECALL、STATICCALL、SELFDESTRUCT
  • 存储访问:SLOAD、SSTORE

这对开发者意味着:

  • 访问许多冷存储槽或调用许多外部合约的合约,在 Monad 上的成本会显著增加。
  • 热访问与 Ethereum 完全相同,因此在一笔交易中重复访问同一个槽位或账户不会产生额外成本。
  • 只访问一次存储槽(冷访问),随后重复使用该槽位(热访问)的批处理操作没有问题。但在许多不同槽位上分别进行单次冷读取的模式,成本会更高。
  • 如果合约在一次调用中读取许多不同的存储槽,在 Monad 上的 gas 估算会更高。设置 gas 限额时请将此因素考虑在内。
预编译合约重新定价

在 Monad 上,密码学预编译合约的成本会提高 2 到 5 倍:

预编译合约地址EthereumMonad倍数
ecRecover0x013,0006,0002 倍
ecAdd0x061503002 倍
ecMul0x076,00030,0005 倍
ecPairing0x0845,000225,0005 倍
blake2f0x09rounds x 1rounds x 22 倍
点求值0x0a50,000200,0004 倍

这对开发者意味着:

  • 严重依赖签名验证(ecRecover)的合约,这些操作的 gas 消耗将增加到原来的 2 倍。
  • 与 ZK 相关的操作(ecMul、ecPairing、点求值)成本会提高到原来的 4 到 5 倍。如果合约在链上验证 ZK 证明,基于 Ethereum 得出的 gas 估算会有很大偏差。
  • 如果合约使用这些预编译合约,请在计算 gas 限额时考虑更高的成本。

评论

支持 Markdown