fix(sdk): skip outer-tx gas check for SCA / relayed steps#377
Merged
Conversation
6 tasks
effie-ms
approved these changes
Apr 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which Linear task is linked to this PR?
https://linear.app/lifi-linear/issue/JUM-868/safe-app-balance-check-uses-connected-wallet-instead-of-safe-wallet
Why was it implemented this way?
CheckBalanceTaskenforced that the funding wallet hold enough native token to pay outer-tx gas. For Safe Apps and other smart-contract wallets that's wrong — the SCA executor / 4337 bundler / paymaster pays gas, not the Safe — so a Safe with sufficient USDC but no ETH was incorrectly rejected with "The balance is too low". Same story for relayed steps.checkBalancenow partitions per-token requirements intosource/gas/feeand gains awalletPaysGasopt-in (defaulttrue, preserving today's strict behavior). Whenfalse, gas is excluded from the sufficiency check and the slippage-rescue reservation; pure-gas entries are pre-filtered out so the RPC isn't queried for them. Source amount and non-included native fees (e.g. LayerZeromsg.value) are still verified.CheckBalanceTaskexposes aprotected getCheckBalanceOptions(context)hook so chain-specific subclasses decide per step. Default returns{}— no behavior change for any provider that doesn't override.EthereumCheckBalanceTaskoverrides the hook: short-circuits relayer steps, otherwise readseth_getCode(via a shared, deliberately uncachedgetAccountCode) onstep.action.fromChainIdforstep.action.fromAddressand OR-s the verdict with EIP-7702 detection — delegated EOAs still pay their own gas.canAccountUseNativePermits(extracted fromgetNativePermit.ts) andisSafeWallet(which previously took an optionalviemClientand rangetCodeinline).isSafeWalletstill falls through to the Safe Transaction Service on RPC failure as an independent fallback.Skip-bias is intentional: a wrong skip surfaces immediately as a wallet rejection; a wrong enforce silently blocks a valid tx.
Visual showcase (Screenshots or Videos)
N/A — backend logic change. Manual repro per the Linear ticket: USDC bridge from a Safe whose signer holds no ETH no longer trips the balance check.
Checklist before requesting a review
Test plan
pnpm check— greenpnpm check:types— greenpnpm test:unit— 381 passing / 5 skipped (no regressions); 67 insdk-provider-ethereum, 220 insdkcore