Skip to content

fix(checkout): price gas units before using them as a balance requirement - #2956

Merged
allan-almeida-imtbl merged 2 commits into
mainfrom
allanalmeida/bloc-683-gas-calculator-units
Sep 30, 2026
Merged

allan-almeida-imtbl merged 2 commits into
mainfrom
allanalmeida/bloc-683-gas-calculator-units

Conversation

@allan-almeida-imtbl

@allan-almeida-imtbl allan-almeida-imtbl commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Smart Checkout's gas affordability check has never been able to fail: it compares gas units against a wei balance. The gas estimate is now priced at the current gas price before it becomes a balance requirement.

Linear: BLOC-683 (parent BLOC-678, Fee model vector, zkEVM → OP Stack migration).

The bug, by example

A wallet holding 1.001 IMX buys a 1.0 IMX item. The purchase needs one approval plus the fulfilment. The node estimates 50,000 + 150,000 = 200,000 gas units, and the gas price is 10 gwei.

Today's code Real cost
Item 1.0 IMX 1.0 IMX
Gas 200,000 wei = 0.0000000000002 IMX 200,000 × 10 gwei = 0.002 IMX
Total needed 1.0000000000002 IMX 1.002 IMX
Wallet 1.001 IMX 1.001 IMX
Check says sufficient insufficient

Today the check passes, the widget proceeds to signing, and the transaction is rejected at submission with an out-of-funds error. Smart Checkout never gets the chance to route the user to a top-up. The gas figure it adds is ten billion times too small to change the outcome, so in effect the check only tests the item price.

With this change the same wallet is told it is 0.001 IMX short and offered the insufficient-funds routes (on-ramp / swap) before anything is signed.

Detail and impact of the change

Fixed

gasCalculator (packages/checkout/sdk/src/smartCheckout/gas/gasCalculator.ts) summed the estimateGas results for the approvals and the fulfilment transaction and returned that sum as a native ItemRequirement with isFee: true. estimateGas answers in gas units. The sum is now multiplied by getGasPriceInWei(feeData), fetched once alongside the estimates. The caller-supplied gas-limit branch (TransactionOrGasType.GAS) already did this multiplication; both branches now use the one price. If the node returns no usable fee data the calculator returns null (no gas requirement), which is what the gas-limit branch already did in that case.

Changed

Visible to integrators using external wallets: a wallet that cannot cover gas now fails the affordability check and gets the insufficient-funds routes instead of a submission failure, and the routes' top-up amounts include real gas.

Passport wallets (review feedback). A Passport wallet does not pay gas from its native balance; the relayer prices and collects the fee. With the requirement now correctly sized, buy would have asked a Passport user holding 50 USDC and no IMX to top up 0.002 IMX for gas they are never charged. buy now runs Smart Checkout for Passport without a transaction or gas limit, which skips only the gas requirement: the item-price check and the top-up routes stay. This differs from sell, which skips Smart Checkout entirely for Passport, because listing needs no funds and buying does. Test added: a Passport provider reaches smartCheckout with undefined as the gas argument.

Anything else worth calling out?

  • Why it never surfaced. The wrong number is a valid amount, so nothing throws. Gas on zkEVM today is a fraction of a cent, so the band of wallets that pass and then fail is very thin, and when it happens the error appears at the wallet as "insufficient funds", which reads as a user problem. After the migration the L1 data fee makes gas material on cheap items and that band widens, and the L1 fee is added to this same requirement by BLOC-697; a correct L1 fee on a wrong base would still be wrong, so the base lands first.
  • Tests. The existing cases used a 1 wei gas price, where units and wei are the same number, which is why they agreed with the bug. They now supply fee data explicitly. New cases price the estimates and a caller-supplied limit at 10 gwei and cover the no-fee-data path.
  • Out of scope, noted for later. For an ERC-20 gas token the requirement amount is still the native-wei cost assigned to the ERC-20. That predates this change and is unrelated to the units bug.

🤖 Generated with Claude Code

…ment

gasCalculator summed the estimateGas results, which are gas units, and
returned the sum as a wei amount for the native balance check. 200,000 gas
became 200,000 wei, so the gas half of the affordability check could never
fail and a wallet holding only the item price passed, then failed at
submission with an out-of-funds error. The units are now multiplied by the
current gas price, the same price the caller-supplied gas-limit branch
already used, before they become a requirement.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@allan-almeida-imtbl
allan-almeida-imtbl requested a review from a team as a code owner September 29, 2026 23:39
@nx-cloud

nx-cloud Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

View your CI Pipeline Execution ↗ for commit 4903e74

Command Status Duration Result
nx affected -t build,test ✅ Succeeded 1m 25s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-09-30 00:24:22 UTC

… Passport wallets

Now that the gas requirement is priced correctly it would ask a Passport
wallet to hold native IMX for gas the relayer prices and collects instead.
buy still runs Smart Checkout for Passport so the item price is checked and
top-up routes offered, but passes no transaction or gas limit, which skips
the gas requirement. sell already skipped Smart Checkout entirely for
Passport; buy cannot, because buying needs funds.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@allan-almeida-imtbl
allan-almeida-imtbl added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 21cfff3 Sep 30, 2026
8 checks passed
@allan-almeida-imtbl
allan-almeida-imtbl deleted the allanalmeida/bloc-683-gas-calculator-units branch September 30, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants