Skip to content

Forward optional gas override on sendTransaction / sendCalls#14

Open
psmiratisu wants to merge 1 commit into
mainfrom
feat/sendtx-gas-override
Open

Forward optional gas override on sendTransaction / sendCalls#14
psmiratisu wants to merge 1 commit into
mainfrom
feat/sendtx-gas-override

Conversation

@psmiratisu
Copy link
Copy Markdown

@psmiratisu psmiratisu commented May 29, 2026

Summary

  • IEvmProviderAdapter.sendTransaction / sendCalls currently let viem / Alchemy auto-estimate gas. For complex routes the auto-estimate runs too tight and txs revert with ~95% gas utilization (out-of-gas mid-execution).
  • Add an optional gas?: bigint on the Call shape (EvmCall) and forward it through both methods in PrivyAlchemyEvmProviderAdapter. Backward-compatible — omitting gas preserves current behaviour.

Motivation

Observed on Base mainnet while integrating LiFi quotes through this adapter:

txHash gasLimit gasUsed utilization status
0x30b19449… 549,099 522,654 95.2% reverted
0x17142457… 515,171 491,293 95.4% reverted
0x445a73d0… 434,657 409,803 94.3% reverted

Aggregators like LiFi return a padded transactionRequest.gasLimit in their quote response, but the adapter destructures only to/data/value from the Call object and drops it. Result: gas is estimated by the bundler with no margin and the tx OOMs partway through.

Changes

  • providers/types.ts: new EvmCall = Call<unknown, { gas?: bigint }> type; IEvmProviderAdapter.sendTransaction and sendCalls use it.
  • providers/evm/privyAlchemyEvmProviderAdapter.ts:
    • sendTransaction: forward call.gas to walletClient.sendTransaction when set.
    • sendCalls: forward call.gas per-call into the Alchemy smart-wallet sendCalls payload (best-effort — Alchemy ignores it if unsupported, same behaviour as today).
  • providers/evm/viemProviderAdapter.ts: abstract stubs updated to the new EvmCall type.

Backward compatibility

Fully backward-compatible. Existing callers that pass plain { to, data, value } get the same auto-estimated gas behaviour. Only callers that set gas see a change.

Suggested caller pattern

For LiFi or similar aggregators that return a gasLimit:

const quote = await getLifiQuote(...);
const gas = quote.transactionRequest.gasLimit
  ? (BigInt(quote.transactionRequest.gasLimit) * 12n) / 10n  // +20% safety
  : undefined;

await provider.sendTransaction(chainId, {
  to: quote.transactionRequest.to,
  data: quote.transactionRequest.data,
  value: BigInt(quote.transactionRequest.value ?? "0"),
  ...(gas !== undefined ? { gas } : {}),
});

Test plan

  • Existing sendTransaction callers (no gas field) continue to broadcast successfully on Base mainnet.
  • Callers passing gas: <padded value> see the limit reflected in the on-chain receipt (gas utilization drops below ~85%).
  • LiFi swap that previously OOM'd lands cleanly when gas is passed from transactionRequest.gasLimit * 1.2.

🤖 Generated with Claude Code


Note

Medium Risk
Changes the on-chain broadcast path for EVM txs; risk is mitigated because gas is optional and defaults preserve existing auto-estimation.

Overview
Adds an optional gas limit on the EVM provider call type (EvmCall) and threads it through sendTransaction and sendCalls so callers can supply aggregator-recommended limits instead of relying on the wallet/bundler auto-estimate.

PrivyAlchemyEvmProviderAdapter now forwards call.gas to viem’s walletClient.sendTransaction and per-call into Alchemy smart-wallet sendCalls when set; omitting gas keeps today’s estimate-only behavior. The shared IEvmProviderAdapter contract and ViemProviderAdapter stubs use EvmCall instead of viem’s plain Call.

This targets out-of-gas reverts on heavy routes (e.g. LiFi multi-hop) where bundled estimates ran near ~95% utilization while quote payloads already included a padded gasLimit that was previously dropped.

Reviewed by Cursor Bugbot for commit c291333. Bugbot is set up for automated code reviews on this repo. Configure here.

The PrivyAlchemy EVM adapter currently lets viem auto-estimate
gasLimit when broadcasting a tx. For complex routes (e.g. LiFi
multi-hop via FeeCollector + a DEX) the auto-estimate runs too
tight and txs revert at ~95% utilization. Observed on Base mainnet:

  0x30b19449...  gasLimit 549,099  gasUsed 522,654  (95.2%)  reverted
  0x17142457...  gasLimit 515,171  gasUsed 491,293  (95.4%)  reverted
  0x445a73d0...  gasLimit 434,657  gasUsed 409,803  (94.3%)  reverted

Aggregators like LiFi return a padded `gasLimit` in their quote
response, but the adapter destructures only `to`/`data`/`value` from
the Call and drops it.

Changes:

- Introduce `EvmCall` (re-export of viem's `Call` with an additional
  optional `gas?: bigint` field) for IEvmProviderAdapter's
  `sendTransaction` and `sendCalls` signatures.
- `PrivyAlchemyEvmProviderAdapter.sendTransaction`: forward
  `call.gas` to walletClient.sendTransaction when set.
- `PrivyAlchemyEvmProviderAdapter.sendCalls`: forward `call.gas`
  per-call into the Alchemy smart-wallet `sendCalls` payload.
- `ViemProviderAdapter` (abstract): update the not-implemented stubs
  to use the new EvmCall type.

Fully backward-compatible: omitting `gas` preserves current behaviour
(viem/Alchemy estimates). Callers that want to pin the limit can now
do so by setting `gas` on the call object.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant