Skip to content

feat(sdk): delegate permissions — guardrail widening + type export - #37

Open
aroralanuk wants to merge 7 commits into
mainfrom
feat/delegate-permissions
Open

feat(sdk): delegate permissions — guardrail widening + type export#37
aroralanuk wants to merge 7 commits into
mainfrom
feat/delegate-permissions

Conversation

@aroralanuk

Copy link
Copy Markdown
Contributor

Summary

Completes the DelegatePermissions feature so the passkey demo can express richer, chain-enforced guardrails while staying a pure SDK consumer. Two token guardrails that swig-ts already supports are surfaced through the SDK's buildDelegateActions mapper, and the type is re-exported from the package root so consumers stop mirroring it.

  • tokenRecurringLimit — recurring per-mint SPL cap over a slot window (subscriptions).
  • tokenDestinationLimit — restrict token spends to one payee. The caller passes an owner-level address; the SDK derives the ATA internally (via findAssociatedTokenPda), so demo callers never touch swig/ATA derivation. This makes buildDelegateActions async, rippling only to actionsForAuthority / buildCreateMultiAuthoritySwigTx.
  • Root export of DelegatePermissions from src/index.ts — the demo imports it directly instead of keeping a local mirror.

Test plan

  • bun test src/__tests__/passkey/permissions.test.ts — new cases for both fields (incl. asserting the SDK-derived ATA), existing cases converted to async / .rejects.
  • Full SDK suite: 219 pass / 0 fail.
  • bun run build clean; dist/index.d.ts re-exports DelegatePermissions.
  • Downstream solana-passkey-e2e relinked + tsc --noEmit clean.

🤖 Generated with Claude Code

aroralanuk and others added 7 commits June 5, 2026 01:57
passkeySignerToSigningFn built the secp256r1 authority payload via swig-ts
`getWebAuthnPrefix`, which stamps swig's WebAuthn (=1) template-reconstruct
path. That path rebuilds clientDataJSON from a fixed
{type,challenge,origin,crossOrigin} template and cannot reproduce extra fields
some authenticators emit (e.g. Chromium intermittently appends
"other_keys_can_be_added_here":...), so the program's keccak of the
reconstructed JSON != the signed message -> Secp256r1InvalidMessageHash
(custom error 3026).

Build the WebAuthnRawClientDataJson (=2) prefix instead, embedding the verbatim
clientDataJSON. swig then extracts `challenge` by field name
(extract_top_level_string_field) and tolerates extra fields. Format:
[2B auth_type=2][2B authDataLen][authData][2B jsonLen][clientDataJSON].

Updates the signing-fn and software-signer-roundtrip tests that asserted the
old getWebAuthnPrefix output.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ePermissions

- buildCreateMultiAuthoritySwigTx now throws when guardrail permissions
  are applied to a session-only wallet (no 'direct' authority): guardrail
  actions omit ManageAuthority/.all(), so the wallet would have no
  authority able to add authorities or escalate, permanently bricking it.
- Re-export DelegatePermissions from src/passkey/index.ts so consumers
  can import the type instead of mirroring its shape structurally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
buildDelegateActions becomes async and derives the destination ATA from
the owner address so demo callers never touch swig/ATA derivation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Lets the passkey demo import the guardrail shape directly instead of
mirroring it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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