Skip to content

refactor(web3): migrate gas sponsorship from Pimlico to Turnkey (KEEP-464)#1221

Draft
joelorzet wants to merge 8 commits into
stagingfrom
feat/keep-464-turnkey-gas-sponsorship
Draft

refactor(web3): migrate gas sponsorship from Pimlico to Turnkey (KEEP-464)#1221
joelorzet wants to merge 8 commits into
stagingfrom
feat/keep-464-turnkey-gas-sponsorship

Conversation

@joelorzet
Copy link
Copy Markdown

Summary

  • Replace the ERC-4337 + Pimlico sponsorship pipeline with Turnkey's native Gas Station (ethSendTransaction with sponsor: true). Turnkey signs and sponsors the underlying EVM transaction in one activity, so the whole UserOperation / EntryPoint 0.8 / permissionless stack is gone on the sponsored path.
  • New chain allowlist (Ethereum, Base, Polygon, Arbitrum + their testnets). Optimism is dropped since Turnkey's Gas Station does not cover it.
  • Bills against on-chain gasUsed * effectiveGasPrice from the broadcast receipt, same gas-credits ledger as before.
  • Surface the sponsored networks in the UI: a dedicated "Sponsored networks" section on the billing-status gas-credits card (with mainnet badges always visible and an info-icon tooltip for testnets / fallback), plus a "Sponsored gas" row in the plan comparison table showing each plan's monthly USD cap and the same tooltip.

Open flags (need confirmation before merge)

  • Arbitrum support is speculative. The Turnkey SDK v5.2.0 CAIP-2 enum lists only eip155:1 / 8453 / 137 (+ their testnets) for ethSendTransaction. Arbitrum is included in the allowlist with a runtime cast through that enum; Turnkey's API will either accept or reject it. Drop from SUPPORTED_SPONSORSHIP_CHAINS if rejected once enterprise credentials are live.
  • Optimism sponsored volume. The Linear ticket flagged confirming Optimism volume on the sponsored path as a prerequisite. This PR drops Optimism; double check there are no production workflows relying on it before merge.
  • Turnkey enterprise credentials. Sponsorship is gated to Turnkey's Enterprise tier and requires a sales conversation. None of this code has been exercised end-to-end yet; the unit tests cover the wiring, but a live integration test should run once the API key, billing webhooks, and refund-on-revert semantics are confirmed.

Files changed

New

  • lib/web3/turnkey-sponsorship-config.ts chain allowlist + CAIP-2 mapping
  • lib/web3/turnkey-sponsored-tx.ts ethSendTransaction(sponsor: true) wrapper, polls getSendTransactionStatus for the broadcast txHash

Rewritten

  • lib/web3/sponsored-client.ts thin preflight, resolves the org's Turnkey subOrgId + walletAddress
  • lib/web3/sponsored-transaction-manager.ts calls the Turnkey wrapper, keeps waitForTransactionReceipt + gas-credits metering
  • tests/unit/sponsored-client.test.ts, tests/unit/sponsored-transaction-manager.test.ts
  • components/billing/billing-status.tsx, components/billing/pricing-table/index.tsx network info UI

Deleted

  • lib/web3/pimlico-config.ts
  • lib/web3/sponsored-fee-clamp.ts (KEEP-394 fee-inversion clamp is dead, Turnkey fills gas itself)
  • lib/web3/eip7702-delegation.ts (no inline 4337 delegation any more)
  • lib/para/viem-account-adapter.ts (sponsored-client was the last caller)
  • tests/unit/sponsored-fee-clamp.test.ts, tests/integration/eip7702-spike.test.ts

Modified plugin steps

  • plugins/web3/steps/{transfer-funds,transfer-token,approve-token,write-contract}-core.ts import path swap from pimlico-config to turnkey-sponsorship-config, comment refresh

Follow-up

  • permissionless is now a dead dependency in package.json. It was kept in this PR because the repo's minimumReleaseAge pnpm constraint blocked a clean lockfile regeneration; remove it in a separate PR once the constraint is sorted.
  • The gasSponsorshipDelegations table is no longer written to. Leaving the table for historical audit data; can be dropped via migration in a follow-up if desired.

🤖 Generated with Claude Code

joelorzet added 5 commits May 11, 2026 19:39
…(KEEP-464)

Switch the gas sponsorship pipeline from ERC-4337 + Pimlico to Turnkey's
native Transaction Management (Gas Station). Turnkey signs and sponsors
the underlying EVM transaction in a single ethSendTransaction activity,
so the whole UserOperation pipeline goes away on the sponsored path.

Adds turnkey-sponsorship-config (chain allowlist: ETH, Base, Polygon
mainnet + their testnets, Arbitrum probed at runtime; drops Optimism)
and turnkey-sponsored-tx (wraps ethSendTransaction + polls
getSendTransactionStatus for the broadcast txHash). sponsored-client
becomes a thin Turnkey-wallet preflight; sponsored-transaction-manager
calls the wrapper and continues to meter on-chain gasUsed against
gas-credit balances.

Deletes pimlico-config, sponsored-fee-clamp (Turnkey fills gas itself,
no KEEP-394 fee-inversion clamp needed), eip7702-delegation (no inline
4337 delegation), and the Para viem-account adapter (the sponsored path
was its only remaining caller; Para wallets fall through to direct
signing via the existing wallet-helpers guard).
Update the four web3 step files that gate sponsorship on chain support
to import isSponsorshipSupported from turnkey-sponsorship-config instead
of the deleted pimlico-config. Refresh inline comments to describe
Turnkey Gas Station rather than ERC-4337 / Pimlico bundler mechanics.
The KEEP-137 private-mempool exclusion still applies because Turnkey
broadcasts via its own infrastructure, not through Flashbots.
Add a one-line note under the gas-sponsorship credits bar listing the
networks Turnkey Gas Station covers today: Ethereum, Base, Polygon,
Arbitrum (plus Sepolia, Base Sepolia, and Polygon Amoy testnets). Lets
users see at a glance which chains are eligible for sponsorship and
which fall back to wallet-paid gas.
Rewrite sponsored-client and sponsored-transaction-manager unit tests
to mock the Turnkey config and ethSendTransaction wrapper instead of
the Pimlico client and Para viem adapter. Update approve-token to point
at turnkey-sponsorship-config. Delete sponsored-fee-clamp tests (the
fee-clamp module is gone) and the eip7702-spike integration test, which
exercised the Pimlico ERC-4337 path that no longer exists.
… table

Gas-credits card on the billing status page gets a dedicated
"Sponsored networks" section under the usage bar, with mainnet badges
(Ethereum, Base, Polygon, Arbitrum) always visible and an Info-icon
tooltip listing testnets and the off-list fallback behavior.

Plan comparison table gains a "Sponsored gas" row right after
"Triggers". The Info-icon tooltip beside the label lists the Turnkey
mainnets and testnets; cell values show the per-plan monthly USD cap
(resolved from the live gasCreditCaps env overrides, falling back to
PLANS defaults), so the comparison table and the per-plan cards stay
in sync.
Turnkey support confirmed Ethereum, Base, Polygon, and Arbitrum on
mainnet for sponsored EVM transactions. Drop the speculative hedging
from the chain-allowlist comment and from the runtime cast at the
ethSendTransaction call site. The cast itself stays in place because
the @turnkey/sdk-server v5.2.0 CAIP-2 enum has not been regenerated to
include eip155:42161; once it does, the cast can be removed.
Use the structured revert info Turnkey returns on getSendTransactionStatus
to give users the real revert reason and stop falling back to direct
signing when the underlying call has already failed on-chain.

A new SponsoredTxRevertError carries the txHash, sendTransactionStatusId,
and the v1RevertChainEntry list from Turnkey. The polling wrapper raises
this error only when a txHash is present (the call is already mined);
pre-broadcast failures (policy denial, gas-cap exhaustion, simulation
errors) still yield null so callers fall through to direct signing as
before.

formatRevertChain walks the chain outermost-to-innermost and prefers
decoded custom error names plus their JSON params, then native Solidity
messages, then the raw 4-byte selector, with "execution reverted" as
the last-resort fallback.

The four web3 plugin steps that try sponsorship log the revert with
txHash, sendTransactionStatusId, and revert_chain_depth as metadata,
then short-circuit with the formatted revert message instead of
falling back. Users do not pay gas twice on a call that is guaranteed
to revert again, and operators still see every sponsored revert in
Sentry / log search.
@github-actions
Copy link
Copy Markdown

🧹 PR Environment Cleaned Up

The PR environment has been successfully deleted.

Deleted Resources:

  • Namespace: pr-1221
  • All Helm releases (Keeperhub, Scheduler, Event services)
  • PostgreSQL Database (including data)
  • LocalStack, Redis
  • All associated secrets and configs

All resources have been cleaned up and will no longer incur costs.

@github-actions
Copy link
Copy Markdown

ℹ️ No PR Environment to Clean Up

No PR environment was found for this PR. This is expected if:

  • The PR never had the deploy-pr-environment label
  • The environment was already cleaned up
  • The deployment never completed successfully

Resolve conflicts between the Pimlico -> Turnkey gas sponsorship migration
and staging's Safe signer-routing and billing reworks:

- sponsored-client: keep the Turnkey preflight; drop the removed `provider`
  column and gate sponsorship on the Turnkey sub-org id alone (Para wallets
  are gone in staging)
- web3 steps: keep the Turnkey sponsorship path while preserving staging's
  `signerMode.kind === "eoa"` guard so Safe-routed writes skip sponsorship
- sponsorship chains: make the runtime allowlist derive from the shared
  sponsorship-chains-meta and reconcile it to Turnkey's actual Gas Station
  coverage (Ethereum, Base, Polygon, Arbitrum + their testnets); drop
  Optimism and BNB, add Arbitrum Sepolia
- billing pricing table: keep per-plan gas credit caps and the Turnkey
  tooltip, sourcing the chain names from the shared metadata
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