Skip to content

release: To Prod#1314

Merged
eskp merged 150 commits into
prodfrom
staging
May 20, 2026
Merged

release: To Prod#1314
eskp merged 150 commits into
prodfrom
staging

Conversation

@suisuss

@suisuss suisuss commented May 20, 2026

Copy link
Copy Markdown

No description provided.

Adds three tables to persist Safe smart-account state per organization:

- safe_wallets: one row per (org, chain) Safe deployment, owned by the
  org's Turnkey EOA at threshold 1. Stores address, salt nonce, deploy
  tx hash, factory/singleton pointers.
- safe_module_installations: tracks which Safe modules are enabled per
  Safe. module_type is free-form text (seeded with "allowance") so
  future modules (Zodiac Roles, Transaction Guard) can coexist without
  schema churn.
- safe_token_limits: per (safe, delegate, token) spending caps enforced
  by the Allowance Module. amount_wei is text-encoded uint256,
  period_minutes maps to the module's resetTimeMin field.

All three are covered by the new 0052_typical_zarek migration chained
after staging's 0051_rename_aave_slug_to_v3.
Introduces lib/safe/contracts.ts as the single source of truth for
Safe's deployed contracts. All addresses are Nick's deterministic
deployer addresses, identical across every EVM chain we support
(Ethereum, Optimism, Base, Arbitrum), so one canonical map covers
every target chain.

- Registers Safe v1.4.1 singleton (L2 variant for event emission),
  proxy factory, compatibility fallback handler, MultiSend,
  MultiSendCallOnly
- Registers the Safe Allowance Module v0.1.0 for later use in the
  spending-limits flow
- Exposes getSafeContracts(chainId), getSafeSingletonForDeploy, and
  getAllowanceModuleAddress helpers with a CHAIN_OVERRIDES hook for
  the rare chain that ships non-canonical deployments
- SUPPORTED_SAFE_CHAIN_IDS + isSafeSupportedChain() narrow chain IDs
  to the four we gate Safe operations to today

Source: github.com/safe-global/safe-deployments
Adds the deploy flow for organization Safes: one Safe per (org, chain),
owned by the org's Turnkey EOA at threshold 1. Same CREATE2 salt
produces the same Safe address on every supported chain.

- lib/safe/address.ts: pure helpers for setup() calldata, salt nonce
  derivation (keccak256 of org + chain), and ProxyCreation event
  parsing
- lib/safe/deployment.ts: deployOrgSafe orchestrator that reuses the
  existing transaction-manager pipeline (nonce session, adaptive gas,
  RPC failover). Idempotent via (org, chain) uniqueness
- app/api/user/safe/route.ts: admin-gated GET list + POST deploy
- components/safe/deploy-safe-card.tsx: chain picker + deploy button +
  list of deployed Safes, rendered in the wallet overlay
- tests/unit/safe-address.test.ts: 12 tests covering calldata encoding,
  salt determinism, and event parsing
Layers on-chain spending caps on top of deployed Safes via Safe's
canonical Allowance Module. Limits are per (org, chain, token),
enforced by the module contract, and show natively under the
Spending Limits tab on app.safe.global.

- lib/safe/allowance-module.ts: pure calldata helpers for
  enableModule, addDelegate, setAllowance, deleteAllowance, and the
  pre-validated-signature execTransaction wrapper for threshold-1
  Safes
- lib/safe/modules.ts: install + set + revoke orchestrators, plus
  listSafeAllowancesWithChainState which reads the module on-chain
  on every list call and drops DB rows that were externally
  revoked (reconcile-on-read)
- lib/safe/auth.ts: validateSafeAdmin + getSafeForOrg helpers shared
  across the allowance routes
- Three admin-gated API routes: POST /modules/allowance (install),
  GET+POST /allowances (list+set), DELETE /allowances/:token (revoke)
- components/safe/spending-limits-card.tsx: renders per-safe limits
  with live "spent / cap", period label, and reset countdown; Add +
  Edit dialog share the same POST endpoint; Revoke calls DELETE
- Wires the card into DeploySafeCard for every deployed Safe
- tests/unit/safe-allowance.test.ts: 12 tests covering calldata
  round-trips, uint96/uint16 bounds, pre-validated sig format, and
  getTokenAllowance decoding
logSystemError forwards its context object into a Prometheus counter
whose label set is fixed at init time: error_category, error_context,
is_user_error, error_type, plugin_name, action_name, service, chain_id,
table, endpoint, component, workflow_id, execution_id, integration_id,
status_code.

The Safe code was passing organizationId and operation, neither of
which is in that label set, which caused prom-client to throw:

  Added label "organization_id" is not included in initial labelset

Moves the org/safe/token identifiers into the log message string so
they still appear in Sentry/Loki output, and replaces the operation
label with the existing component convention. Applies to all four
Safe API routes and the three orchestrator catch blocks.
Adds every EVM mainnet + testnet where (a) KeeperHub already has RPC
and chain metadata seeded and (b) Safe v1.4.1 + Allowance Module are
deployed at the canonical Nick's-deployer addresses.

Mainnets added: BNB Smart Chain (56), Polygon (137), Avalanche (43114).
Testnets added: Sepolia (11155111), Base Sepolia (84532), Arbitrum
Sepolia (421614), BSC testnet (97), Polygon Amoy (80002), Avalanche
Fuji (43113).

Optimism (10) removed: it was in the previous SUPPORTED list but no
KeeperHub chain seed row exists for it, so chainIsEnabled() would
always reject it.

- SUPPORTED_SAFE_CHAIN_IDS reworked with inline comments per chain
- DeploySafeCard CHAIN_LABELS covers all new chains so the UI shows
  proper names instead of "Chain 56"
- spending-limits-card COMMON_TOKENS pre-populates USDC/USDT/DAI for
  each mainnet and Circle testnet USDC for Sepolia / Base Sepolia /
  Arbitrum Sepolia. Remaining testnets (BSC / Amoy / Fuji) ship with
  empty arrays; admins can still deploy + enable module, just no
  preset token picker until Circle canonicalizes their testnets or
  we add chain-specific defaults
Commit 36e87a5 narrowed SUPPORTED_SAFE_CHAIN_IDS and also dropped
Optimism from the CHAIN_LABELS map. If anything ever surfaces a
chain-10 row (legacy Safe rows, stale caches, or the list is later
reopened) the UI fell back to "Chain 10".

Broadens CHAIN_LABELS to cover every chain we might render -- not
just the deploy-supported subset -- so the label is always correct.
Adds Optimism (10) and Optimism Sepolia (11155420) while I'm in here.
Wires Optimism (10) and Optimism Sepolia (11155420) end-to-end so
chainIsEnabled() no longer rejects Safe deploys on these chains.

- lib/rpc/rpc-config.ts: adds OP_MAINNET / OP_MAINNET_FALLBACK /
  OP_SEPOLIA / OP_SEPOLIA_FALLBACK public RPCs and the two CHAIN_CONFIG
  entries mapping chain IDs to the op-mainnet / op-sepolia keys
- scripts/seed/seed-chains.ts: adds chain rows for both networks plus
  matching Etherscan V2 explorer configs and the canonical name map
- lib/safe/contracts.ts: re-adds 10 and 11155420 to
  SUPPORTED_SAFE_CHAIN_IDS now that the backend resolves them; drops
  the "Optimism intentionally excluded" comment that is no longer true

Seeding is idempotent; running pnpm seed-chains on any env picks up
the new rows without impact on existing orgs.
logUserError forwards its context object into a Prometheus counter
whose label set is fixed at init time: error_category, error_context,
is_user_error, error_type, plugin_name, action_name, service,
chain_id, table, endpoint, component, workflow_id, execution_id,
integration_id, status_code.

executeTransaction and executeContractTransaction were passing `nonce`
and `method` which blow up with:

  Added label "nonce" is not included in initial labelset

Moves those identifiers into the log message string so they still
appear in Sentry/Loki output, and keeps only approved metric labels.
Affects any write-tx error path, not just Safe; surfaced while
testing the Safe deploy flow.
Three related fixes to the per-token spending-limits flow:

Decimals: lib/contracts/tokens.ts had no Sepolia/Base-Sepolia/
Arbitrum-Sepolia/OP-Sepolia entries. When an admin set a limit on
testnet USDC the server fell back to decimals=18, so "200 USDC"
got stored as 200e6 wei paired with decimals=18 and the edit
dialog later showed 0.0000000002. Adds the four Circle testnet
USDC rows so new limits resolve correctly.

Reconcile on read: the allowances GET now overlays fresh
getTokenInfo output on each row so previously-miscoded rows (from
before the fix above) display with correct symbol/decimals without
a DB repair. Known tokens in the server registry always win over
the DB cache.

Case-insensitive catalog match: the DB stores lowercase addresses
while the UI catalog uses EIP-55 checksummed ones, which broke the
Edit dialog's <Select /> pre-fill. Normalizes both sides when
matching and when pre-filling the selection.

Custom token support: adds a "Custom token..." entry at the bottom
of the picker that reveals address + symbol + decimals inputs.
Validated client-side (address format, decimals range, symbol
required); the POST body forwards the client-supplied metadata and
the server uses it only when the token is not in its registry.

Also adds USDS (Sky Protocol) to the Ethereum mainnet and Base
catalogs.
# Conflicts:
#	components/overlays/wallet-overlay.tsx
Adds the per-(org, chain) signing switch infrastructure so workflow
writes can execute from the Safe instead of the Turnkey EOA. This
commit lands only the backend plumbing; UI toggle + balance display +
transfer step wiring follow in separate commits.

Schema:
- safe_wallets.is_signing_active boolean, default false. Additive,
  zero-risk migration; every existing row defaults to eoa mode.

Resolver (lib/safe/signer-resolver.ts):
- resolveSignerMode(orgId, chainId) returns either "eoa" (current
  behavior) or "safe" (Safe address + owner address) based on the
  new flag plus status = "deployed".

Execution helper (lib/safe/execute-as-safe.ts):
- executeContractCallAsSafe and executeNativeTransferAsSafe wrap
  an inner call in safe.execTransaction using the existing
  buildExecTransactionCalldata + pre-validated signature plumbing
  from the Allowance Module helpers. Turnkey EOA signs the outer
  tx and still pays gas; on-chain msg.sender at the target becomes
  the Safe.

API:
- PATCH /api/user/safe/[safeId] admin-gated toggle endpoint with
  body { isSigningActive: boolean }. Rejects activation when the
  Safe is not yet status = "deployed".
- GET /api/user/safe now includes is_signing_active per Safe.

Write-contract-core wiring:
- Resolves signer mode early. In safe mode we skip the ERC-4337
  sponsored path (would change msg.sender away from the Safe) and
  route through executeContractCallAsSafe inside the existing
  nonce session. EOA path is unchanged.

Transfer-funds / transfer-token / approve-token cores still execute
from the EOA and will be wired in subsequent commits.
Adds the same EOA vs Safe branching landed for write-contract-core to
the three remaining web3 write steps. In safe mode each step wraps the
inner call in safe.execTransaction via executeContractCallAsSafe (or
executeNativeTransferAsSafe for native value), skips the ERC-4337
sponsored path (the bundler would change msg.sender away from the
Safe), and submits the outer tx with the Turnkey EOA as signer.

- transfer-funds-core.ts: native transfer from the Safe's balance
- transfer-token-core.ts: ERC-20 transfer from the Safe's token balance
- approve-token-core.ts: ERC-20 approval where the Safe is the owner
  whose allowance the spender gets

All four web3 writes now respect the per-(org, chain) signing toggle.
Ships the Phase 3 UI on top of the backend routing committed earlier.

SafeSigningToggle component:
- Per (org, chain) switch in each deployed Safe card
- PATCH /api/user/safe/[safeId] { isSigningActive }
- Admin-gated; disabled while in-flight; toasts on success/failure
- Explanatory copy about where funds need to live and who pays gas

DeploySafeCard rework:
- Each deployed Safe is an inner DeployedSafeRow component
- Safe address row has copy button, explorer link, and "View on Safe"
  deep-link (app.safe.global/home?safe=<prefix>:<addr>)
- "Active signer" badge appears next to chain label when the toggle
  is on
- Status chip uses the same muted badge style as other wallet cards
- "Deploy on new chain" is now a single button that opens a Dialog
  with the chain picker, matching the Add-Token flow on the balances
  tab

chain-prefixes module:
- getSafeAppUrl(chainId, address) maps to app.safe.global EIP-3770
  slugs (eth, base, arb1, oeth, sep, basesep, etc.)
- getExplorerAddressUrl / getExplorerTxUrl return the canonical
  Etherscan V2 / Snowtrace / BscScan URL; unknown chains return null
  and the UI hides the link

SpendingLimitsCard polish:
- Limit rows are flex-col with three zones: amount line, period +
  reset, token address + copy/explorer links
- Period labels capitalized (Daily / Weekly / Monthly)
- Token address renders as font-mono code with copy + explorer-link
  icons, matching the wallet-address-card pattern

Tests:
- tests/unit/safe-signer-resolver.test.ts covers eoa/safe branching
  based on row presence, status, and flag; plus chain-prefix helpers
- tests/unit/approve-token.test.ts mocks the two new Safe modules so
  the existing tests continue to exercise the eoa path
- Filter the Add dialog's token dropdown to exclude tokens that already
  have a limit. Allowance Module stores one row per (delegate, token),
  so picking an already-limited token silently overwrote the existing
  one -- users should Edit an existing row instead. Custom token option
  still appears regardless.
- Dropdown alignment: both Token and Period selects open with their
  start edge anchored to the trigger's left edge (align="start")
  rather than the default center-ish popper alignment.
Same fix applied to approve-token.test.ts -- the core now imports
resolveSignerMode and executeContractCallAsSafe which transitively
load ethers.Interface() at module init, and the test's lightweight
ethers mock doesn't support the constructor shape. Add shallow mocks
for the two Safe modules so the core's eoa path exercises normally
and the CI test-unit job goes green.
Drops the ceremonial Allowance Module (it did not enforce anything
on-chain beyond a per-token cap) in favour of the Zodiac Roles Modifier
v2, which scopes every workflow call through a pre-audited permission
tree: per-target contract allowlist, per-function selector allowlist,
per-parameter conditions (recipient pinned to the Safe, token in the
allowed set, amount within the role allowance).

Adds:
- lib/safe/roles-orchestrator.ts: installs Roles proxy, assigns role
  to Turnkey EOA, applies per-protocol permissions and per-token
  allowances in a single MultiSend. Flattens the new per-protocol
  TokenLimitInput[] payload with max-amount / min-period conflict
  resolution.
- lib/safe/condition-templates.ts: per-protocol preset builders
  backed by karpatkey's defi-kit, plus a target-only fallback and a
  trivial WETH template.
- lib/safe/protocol-registry.ts: 18-entry catalog with enforcement
  level (full / target-only) and per-chain availability.
- lib/safe/protocol-targets.ts: per-chain target contract addresses
  consumed by the target-only fallback.
- lib/safe/zodiac-contracts.ts / zodiac-roles.ts: canonical address
  registry, calldata builders, MultiSend packing.
- lib/safe/simulate.ts: desired-role builder used by the SDK's
  diffing path.
- lib/safe/chain-state.ts: on-chain reconciliation helpers for role
  and allowance state.
- lib/safe/price-oracle.ts: Chainlink native/USD conversion for the
  simulate endpoint gas breakdown.
- app/api/user/safe/[safeId]/role: GET / POST / allowances CRUD /
  simulate routes. Accept both the new ProtocolInput[] shape and
  the legacy shape during the wizard migration.

Routes workflow steps through the Safe when signing is active:
transfer-funds, transfer-token, approve-token, write-contract now
delegate to the orchestrator path when the Safe has an active role.
execute-as-safe and signer-resolver updated accordingly.

Removes the superseded surface:
- app/api/user/safe/[safeId]/allowances/* and modules/allowance
- components/safe/spending-limits-card.tsx
- lib/safe/modules.ts
- tests/unit/safe-allowance.test.ts
…ement badges

Consolidates the deploy-with-policies flow and the post-deploy install
dialog behind one component, PolicyWizard. Both render the same UI for
the 18-protocol catalog and emit the same payload shape:

  { protocols: [{ slug, tokens: [{ tokenAddress, tokenSymbol,
    tokenDecimals, amountHuman, periodSeconds }] }] }

Per-protocol cards show:
- Full policy / Target-only enforcement badge sourced from the catalog
- Target-contract list with explorer Verify links (built via
  buildAddressUrl + the chain's explorer config)
- A structured token row editor: symbol badge, truncated address with
  explorer link, amount input, Daily / Weekly / Monthly period select,
  remove. Replaces the CSV-of-symbols textbox.

Token selection goes through a shared TokenPicker that merges the
system supportedTokens list, the org's organizationTokens for that
chain, and offers a Paste-custom-address fallback wired to
POST /api/user/wallet/tokens (reads symbol / name / decimals on-chain
and persists).

Deploy wizard deletes the duplicated policies step and renders the
shared PolicyWizard inside step 2, so deploy + install behave
identically. Review step surfaces applied / skipped / conflictedTokens
returned by the simulate and install endpoints.

Files:
- New: policy-wizard.tsx, policy-protocol-card.tsx, policy-token-row.tsx,
  token-picker.tsx, role-permissions-card.tsx
- Modified: deploy-safe-card.tsx
Replace role-wide-per-token allowance buckets with per-(protocol, token)
buckets so each enabled protocol owns its own spending cap on chain.
Removes the cross-protocol conflict-resolution path; each protocol card
in the wizard now persists independent allowances.

- tokenAllowanceKey now hashes (roleKey, protocolSlug, tokenAddress)
- safe_role_allowances gains a protocol_slug column; unique index swaps
  to (role_id, protocol_slug, token_address)
- flattenInstallInput emits one allowance per (protocol, token) with no
  cross-protocol dedup; ConflictedToken removed from the install result
  and every API response
- setRoleTokenAllowance + revokeRoleTokenAllowance now require a
  protocolSlug; revoke endpoint takes it as a ?protocolSlug= query
- role + simulate route schemas updated; simulate's enforcement-level
  comparison repaired against the renamed "contract-allowlist" value

Migration drops existing safe_role_allowances rows and the old unique
index; greenfield drop authorised since no production rows exist.
…onflict UI

- Extract `ProtocolTokenAllowances` so the Add-token + token-rows pattern
  can be reused outside the wizard. Fully controlled, all state lives in
  the parent.
- Refactor `PolicyProtocolCard` so the chevron collapses the entire body
  (token rows + scoped-contracts list). Tokens persist through any
  combination of expand/collapse/enable/disable. Newly enabling a
  protocol auto-expands its card so the seeded tokens are visible.
- Cap the deploy and install dialogs at 85vh with vertical scroll so the
  modal does not overflow the viewport.
- Drop the conflict UI now that allowances are per-(protocol, token):
  the "Token conflicts resolved" review block, the SimulationPlan
  conflictedTokens field, the install-toast warning, and the obsolete
  bullet in the wizard's "How this works" panel. Replaces the bullet
  with copy explaining per-protocol independence.
…g merge

Staging shipped its own 0052_agentic_wallets and 0053_sleepy_franklin_richards
under the same numbers we used for Safe role tables and per-protocol
allowances. Those numbers are about to collide on merge.

Drop our 0052_military_photon and 0053_futuristic_living_lightning, fix the
broken journal entry for idx 51 (was pointing at a tag whose .sql had been
renamed to 0051_rename_aave_slug_to_v3), and let staging land cleanly. The
Safe schema will be re-emitted as a single consolidated migration after the
merge.
…-wallet-integration

# Conflicts:
#	.gitignore
#	components/overlays/wallet/manage-tab.tsx
#	plugins/web3/steps/approve-token-core.ts
#	plugins/web3/steps/transfer-funds-core.ts
#	plugins/web3/steps/transfer-token-core.ts
#	plugins/web3/steps/write-contract-core.ts
#	pnpm-lock.yaml
Replaces the two branch-only migrations dropped pre-merge (military_photon
+ futuristic_living_lightning) with one migration that creates safe_wallets,
safe_roles, safe_role_protocols, safe_role_allowances against staging's
post-0064 baseline. The per-(role, protocol_slug, token_address) unique
index on safe_role_allowances is part of this migration; no separate
ALTER step needed since the column lands at table-creation time.

Also two post-merge fixups:

- lib/db/schema-agentic-wallets.ts: bigint default switched from BigInt(0)
  to sql\`0\`. Identical runtime semantics, but JSON-serialisable so
  drizzle-kit generate can emit a snapshot. Pre-existing issue surfaced
  while generating this migration; the staging code path that uses this
  column never hit it because no new generate ran.
- lib/safe/execute-as-safe.ts: RpcProviderManager import path moved to
  @/lib/rpc/providers (canonical export site after staging's RPC refactor).
…own overlay sub-view

Two fixes plus a UI restructure.

Direct rules
- The wizard's Direct transfers and approvals section already collected ERC20
  transfer / ERC20 approve / native transfer rules into PolicyConfig.directRules.
  Both /role install and /simulate-deploy were silently ignoring them, so any
  rule configured there was lost on the way to chain. Threading them now:
  - InstallRoleInput grows a directRules field; flattenInstallInput emits
    one allowance per ERC20 rule keyed by (role, "direct", token).
  - installRolesWithInitialConfig adds target-level permissions for each
    rule (ERC20 contract for transfer/approve; recipient address for
    native) on top of the protocol presets, before the MultiSend.
  - /api/user/safe/[safeId]/role POST validates and forwards the new
    directRules body field.
  - /api/user/safe/simulate-deploy adds a "Scope N direct rules"
    operation summary so the wizard's review step shows them.
  - Per-parameter calldata constraints on transfer/approve are a
    follow-up; today the on-chain enforcement is target-only, matching
    the existing native-transfer banner.

Token selector
- The Direct rule's token chip looked like a static label; users could not
  tell it was clickable. Replaced with a proper select-styled trigger:
  full-width row with chevron, hover/focus states, "Pick a token" placeholder.

Manage tab restructure
- The Safe section was rendered inline inside the Manage tab and grew
  linearly with the chain count. Moved it into its own wallet-overlay
  sub-view ("safe" tab) reachable via a new SafeWalletsEntryCard summary
  in Manage. Back arrow returns to Manage. No new modal, the overlay
  stays open.

Stale conflict toast
- deploy-safe-card no longer reads installData.conflictedTokens (the
  field was dropped on the server back when allowances became
  per-(protocol, token)).
Tighten the Zodiac Roles orchestrator and the workflow signer routing
so the install / read / execution paths all converge on the same
on-chain state instead of trusting a possibly-stale DB cache.

Install path now wraps the post-tx DB writes in db.transaction with
onConflictDoUpdate upserts keyed by the existing unique constraints,
so a partial failure rolls back instead of leaving the chain ahead of
the cache. ERC-20 direct rules are now scoped via FunctionPermission
+ matches([eq(counterparty), withinAllowance(key)]) so the recipient
or spender is pinned at the calldata level, not just the target.

Adds reconcileSafeRoleFromChain that probes the Roles modifier on
chain, upserts every live allowance bucket, and marks revoked targets.
The role read path (getSafeRoleWithBackfill) auto-runs reconcile when
the DB has a role row but no protocols/allowances, recovering from
silent-write failures without user interaction. resolveSignerMode
gains a parallel chain-probe so workflows hitting a Safe whose role
row was lost route through execTransactionWithRole and a background
reconcile fills the cache for next time.

Includes a new updateRolesConfig orchestrator path that diffs current
DB state against desired input via callsPlannedForApplyRole, applies
the delta in a single Safe.execTransaction, and persists row-level
deltas inside one db.transaction.
POST /api/user/safe/[safeId]/role/reconcile: runs the orchestrator's
reconcile-from-chain path so admins can repair a drifted DB cache
without redeploying the modifier.

POST /api/user/safe/[safeId]/role/update: accepts the full desired
state and routes through updateRolesConfig, which computes the diff
against current DB rows and submits one Safe.execTransaction.

GET /api/user/safe/[safeId]/role now uses getSafeRoleWithBackfill so
the response always reflects on-chain state, falling back to a
synchronous reconcile when the DB cache is empty but a modifier is
enabled on chain.

Simulate routes:
- /role/simulate detects an active safe_roles row and switches to
  diff mode -- skips deploy / enable / assign / setDefault gas, only
  counts new protocols and changed allowance buckets so the wizard
  preview matches what the orchestrator's diff actually submits.
- /safe/simulate-deploy uses per-kind direct-rule gas constants
  (transfer / approve scopeFunction vs native scopeTarget) instead
  of one flat estimate.

Allowance and period formatting moved into lib/safe/format-allowance
so both simulate routes show "1 USDC every week" instead of raw wei.
fix(mcp): correct validate_workflow false-positive on flat outputMapping
joelorzet added 2 commits May 20, 2026 12:36
Adds BNB mainnet plus 4 testnets (BNB Testnet, Polygon Amoy,
Arbitrum Sepolia, OP Sepolia) to SUPPORTED_SPONSORSHIP_CHAINS.
Each addition is verified to have Pimlico bundler coverage and
EIP-7702 support.

Extracts the chain list to a client-safe meta module so the UI
can render network names without importing server-only code.

Surfaces the supported networks in two places:
- Info tooltip next to "Gas sponsorship credits" on the billing
  status card.
- New "Sponsored gas" row in the pricing comparison table, with
  an info tooltip listing mainnets and testnets.
…ip-chains

feat(web3): expand sponsored gas chains, surface in billing UI
…nction-name-alias

fix(web3): KEEP-371 reject missing abiFunction with descriptive error
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.

4 participants