Skip to main content
The Swig program is role-based. Each role has:
  • one authority
  • one stable role_id
  • one or more permission actions
If an operation succeeds or fails, these are the fields that decide it.

Authority types

Swig currently supports these authority families: Session-based authorities keep the same role and permission model, but switch authentication to a time-bounded session key or session rule.

What ProgramExec means

ProgramExec is the least familiar authority type, but it matters for recovery and other protocol-controlled flows. Instead of authenticating a user signature directly, it authenticates against another instruction in the same transaction. The configured authority stores:
  • the expected program ID
  • an instruction-prefix match
  • optional instruction-index targeting through the authority payload
This makes it useful when a separate program is allowed to trigger a narrow wallet behavior without becoming a general-purpose signer.

Permission families

Actions are typed permission records attached to roles.

Time-based limits are measured in slots

Every time-bounded permission in Swig counts slots, not seconds. This applies to SolRecurringLimit, TokenRecurringLimit, StakeRecurringLimit, their destination variants, and session durations on *Session authorities.
Solana is reducing slot time from 400ms to 200ms in four steps (SIMD-0525). The first step is live: mainnet moved to 350ms at epoch 1020. Any window sized against a 400ms assumption is already elapsing early, and will elapse in half the intended wall-clock time once the rollout completes.
A window is stored as a fixed slot count and does not rescale when slot time changes. A monthly subscription sized at 400ms already resets closer to every 26 days, and will reset every 15 days once slot time reaches 200ms. This affects wallets that already exist as well as new ones.

Which way the drift cuts

The two permission families fail in opposite directions, so round accordingly:
  • Recurring spend limits reset more often than intended. The role can spend more per calendar month than you granted. This is the over-permissive direction — size for 200ms to stay conservative.
  • Session durations expire sooner than intended. Sessions are shorter, not longer, so the risk is a broken flow rather than a widened one. Size for 400ms and re-issue sessions on expiry.

Working with the drift

  • Do not hardcode a slots-per-second constant. Derive it at configuration time by sampling getBlockTime across a known slot delta, or read it from a config value you can update without redeploying.
  • Prefer shorter windows that you renew, over long windows sized once. A one-day window drifts by hours; a one-year window drifts by months.
  • If a permission must track a real calendar period, enforce that period in your own service and use the on-chain window as an upper bound, not as the clock.
  • Re-check windows on existing wallets at each rollout step. Updating a role’s actions requires ManageAuthority.

Permission distinctions that matter

  • All is the broadest role marker.
  • AllButManageAuthority still allows broad execution, but excludes authority and sub-account management.
  • ManageAuthority is for adding, removing, or updating authorities.
  • RecoveryAuthority is narrower than ManageAuthority. It only grants access to the dedicated recovery path.
  • ProgramAll grants effectively unrestricted CPI access and should be treated as highly privileged.
  • ProgramCurated is looser than per-program rules, but still not fully open.
  • ProgramScope is the narrowest program control. It binds a program, a target account, and numeric field offsets so the program can enforce scoped limits.

Common role shapes

Most real integrations end up with some mix of:
  • an admin role that can manage authorities
  • an execution role that carries spend and program permissions
  • one or more session-capable roles for short-lived delegated access
  • an optional recovery role with RecoveryAuthority

How this maps to higher-level SDKs

Higher-level SDKs may hide the byte layout, but they still depend on the same rules:
  • a wallet operation eventually targets one role
  • that role authenticates through one authority type
  • that role’s actions decide whether execution is allowed
If you need the full instruction-builder surface, use TypeScript Actions.