Skip to content

feat: dispatch spend permissions to SpendRouter when onchain spender matches#686

Open
amiecorso wants to merge 3 commits into
coinbase:mainfrom
amiecorso:amie/spend-router-cdp
Open

feat: dispatch spend permissions to SpendRouter when onchain spender matches#686
amiecorso wants to merge 3 commits into
coinbase:mainfrom
amiecorso:amie/spend-router-cdp

Conversation

@amiecorso
Copy link
Copy Markdown

@amiecorso amiecorso commented May 7, 2026

Summary

Implements the SDK-side half of the SpendRouter integration. useSpendPermission now automatically detects whether a permission's onchain spender is the SpendRouter contract and dispatches to SpendRouter.spendAndRoute instead of SpendPermissionManager.spend accordingly.

Cross-version compatibility

Dispatch is driven entirely by permission.spender, with no API-version negotiation, no response-field dependency, and no SDK release coordination required. This means:

  • Old SDK versions still work against legacy permissions. No behavior change for spenders that aren't the SpendRouter address.
  • New SDK versions handle both legacy permissions and SpendRouter permissions transparently in the same call site.
  • Old SDK versions consuming responses from the new API do not regress. Permissions whose spender is the SpendRouter contract will fail to execute with old SDKs (they'd send a spend call to the router contract, which doesn't expose that selector), but legacy permissions still work fine. Encouraging SDK upgrades is the right migration path; no API-side gating needed.
  • Even before this SDK ships, integrators consuming the new API can detect SpendRouter permissions themselves via permission.spender and dispatch manually if needed.

Changes

TypeScript (24/24 tests pass; lint + format + type-check clean):

  • New SPEND_ROUTER_ADDRESS and minimal SPEND_ROUTER_ABI (just spendAndRoute) in typescript/src/spend-permissions/constants.ts.
  • New isSpendRouterPermission and buildSpendCalldata helpers in typescript/src/spend-permissions/utils.ts — single dispatch decision shared by both hooks.
  • account.use.ts and smartAccount.use.ts now delegate calldata construction to buildSpendCalldata. Each hook is ~10 lines smaller and contains zero hardcoded contract references.
  • Added 3 dispatch tests (router path on both hooks, plus case-insensitive address matching).

Python (14/14 tests pass; ruff lint + format clean):

  • Mirror constants in python/cdp/spend_permissions/constants.py.
  • Mirror is_spend_router_permission and build_spend_call helpers in python/cdp/spend_permissions/utils.py.
  • account_use.py and smart_account_use.py now delegate calldata construction to build_spend_call. Each ~25 lines smaller.
  • Existing tests refactored to mock the new boundary (build_spend_call) instead of patching Web3 on the action module. Added 2 dispatch tests (router path on each hook).

Java/Go/Rust: No changes. These SDK languages do not yet expose spend-permission actions.

Verification

  • TS: pnpm vitest run src/actions/evm/spend-permissions src/spend-permissions — 24 pass
  • TS: npx tsc --noEmit -p tsconfig.json clean
  • TS: pnpm lint and pnpm format:check clean
  • Python: uv run pytest cdp/test/spend_permissions cdp/test/actions/evm/spend_permissions — 14 pass
  • Python: make lint and make format-check clean

End-to-end verified on Base Sepolia

A real successful tx where the SDK's dispatch logic targets SpendRouter.spendAndRoute() (not SpendPermissionManager.spend()) against a permission produced by cdp-service:

Tx 0x6025f0bf...to = SpendRouter (0x1a672dE4...), function = spendAndRoute

Reproducible test harness: coinbase/spend-permissions#84 (lands at examples/cdp-integration-test/ once merged). Coinbase-internal methodology writeup linked from the harness README.

@cb-heimdall
Copy link
Copy Markdown

cb-heimdall commented May 7, 2026

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 1
Sum 2

@amiecorso amiecorso marked this pull request as ready for review May 13, 2026 00:12
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