fix(evm): buffer arbitrum gasPrice/maxFeePerGas to prevent base-fee-drift tx failures#1282
Conversation
…rift tx failures Arbitrum's sequencer orders transactions first-come-first-served and ignores priority fees, so eth_feeHistory reports 0 rewards at every percentile. That collapsed all three fee tiers to identical values and, more importantly, set gasPrice to the bare base fee with zero headroom. Clients submitting that gasPrice failed with "max fee per gas less than block base fee" on any upward base-fee tick. Make the base fee and gas price tier multipliers configurable per chain (defaulting to the previous behavior, so no other coinstack changes) and opt Arbitrum into per-tier buffers: modest headroom on gasPrice to survive base-fee drift without overpaying legacy txs, and larger cap-only headroom on maxFeePerGas. Verified Optimism and Base have non-zero priority fees and stable base fees, so they are unaffected and unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Warning Review limit reached
Next review available in: 42 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthrough
ChangesGas multiplier configuration
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@node/coinstacks/common/api/src/evm/moralisService.ts`:
- Around line 398-399: Add constructor-time validation in the relevant Moralis
service class to ensure the user-supplied baseFeeMultiplier and
gasPriceMultiplier arrays each have at least REWARD_PERCENTILES.length entries
before getGasFees() can index them; reject invalid configurations with a clear
error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0f483718-d873-4c26-bd0a-3eff12de4ed6
📒 Files selected for processing (2)
node/coinstacks/arbitrum/api/src/controller.tsnode/coinstacks/common/api/src/evm/moralisService.ts
Type baseFeeMultiplier and gasPriceMultiplier as [number, number, number] so a wrong-length array is caught at compile time rather than silently producing NaN fees when getGasFees indexes a missing tier. Addresses CodeRabbit review feedback. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Problem
Arbitrum
/feeswas occasionally returning suspect data (identical slow/average/fast tiers,maxPriorityFeePerGas: 0), and clients were hitting transaction failures:Root cause
Arbitrum's sequencer orders transactions first-come-first-served and ignores priority fees, so
eth_feeHistoryreports 0 rewards at every percentile (confirmed against a live RPC — 0/100 blocks non-zero at percentiles 50/70/90). Two consequences ingetGasFees:maxPriorityFeePerGasfalls back tominPriorityFee(0for Arbitrum), collapsing all three tiers to identical values.gasPrice = baseFee + 0 = baseFee— pinned to the bare base fee with zero headroom. Arbitrum's base fee jitters ~1% block-to-block, so any upward tick between estimation and inclusion rejects the tx. The rejected value20072000matchesgasPriceexactly (notmaxFeePerGas, which wasbaseFee × 2 ≈ 40M), confirming the client consumes thegasPricefield for Arbitrum.This is a regression from the Blocknative →
eth_feeHistoryswap (#1281); Blocknative'spricecarried predictive headroom.Fix
Make the base-fee and gas-price tier multipliers configurable per chain (same pattern as
minPriorityFee), defaulting to the exact prior behavior so no other coinstack changes. Arbitrum opts into per-tier buffers:gasPriceMultiplier: [1.1, 1.2, 1.5]— modest headroom so legacy/gasPrice txs stay above the base fee as it drifts, without meaningfully overpaying (gasPrice is the amount actually paid).baseFeeMultiplier: [1.5, 2, 3]— larger cap-only headroom onmaxFeePerGas(a cap, so no overpay) and restores tier differentiation.In the failing scenario,
slow.gasPricebecomes22079200, comfortably above the20110000base fee that rejected the tx. Invariants verified:maxFeePerGas ≥ gasPrice,gasPrice > baseFee, and tiers monotonically increasing.Scope
Validated against live RPCs that Optimism and Base are unaffected — both show non-zero priority fees at every percentile (100/100 blocks) and stable base fees, so
gasPricealready has ample headroom there. Change is Arbitrum-only; all other chains keep their current behavior via the defaults.🤖 Generated with Claude Code
Summary by CodeRabbit