- The owner adds a delegated role with
ManageAuthorizationLocksand a spending limit. - The delegate locks part of the wallet’s balance. Every other role, the owner included, can now spend only the rest.
- The delegate captures the hold by spending through
SignV2, which lowers the lock by the amount spent. It can release whatever is left. Otherwise the hold expires. - Once the delegate’s holds are inactive, the owner can remove its role, which also deletes its lock records.
Rust Protocol SDK
These examples target the auth-lock draft ofswig-protocol-sdk/solana/rust/sdk.
Use that branch through Git or a local checkout while reviewing it. The published
swig-sdk, swig-interface, and swig-state 3.0.0 crates do not yet include
these lock APIs. The direct swig_interface examples also require wallet
revision 4628591963a1f6d9196bae67b25fba6c4a9fb0ab.
The hosted Developer SDK has separate
TypeScript, Python, and Rust APIs for preparing backend-built transactions.
Grant the delegated role
The delegate can lock an asset up to its remaining spending allowance for that mint, minus its existing active holds. The new hold must also fit the asset account’s unreserved, lockable balance; native SOL excludes the rent-exempt minimum. Each hold lasts at mostmax_duration_slots.
A role with All or AllButManageAuthority also needs
ManageAuthorizationLocks to lock. Its cap is the asset account’s unreserved,
lockable balance, still within max_duration_slots. A non-root role cannot set
or change its own duration bound; the root role can. To let the root role lock,
have it grant itself the permission:
Place a hold
With the wallet switched to the delegate’s role:add_authorization_lock(asset_account, mint.to_bytes(), amount, expiry_slot)
directly. For native SOL, pass the wallet address and an all-zero mint.
Read holds
display_swig() also prints an AUTHORIZATION LOCKS section and shows each
role’s ManageAuthorizationLocks bound.
Capture a hold
The holder captures by spending. With the wallet switched to the delegate’s role, spend from the locked account throughSignV2. No other instruction is
needed:
SignV2 the delegate signs, the net amount that left each locked
account is taken off its locks on that account, oldest first. Spending more
than the hold takes the rest from free balance, within the role’s limits. The
role’s spending limits are charged here, not when it locked.
A lock captured to 0 stays stored with amount == 0. It no longer binds and
get_active_authorization_locks skips it.
Other roles, the owner’s All role included, can only spend the balance minus
the delegate’s remaining hold. If they try to spend into it, the transaction
fails with AuthorizationLockViolated.
Release or prune a hold
Setlock_id to the existing hold you selected from get_authorization_locks()
or the active-hold output above. Creation returns a transaction signature, not
the lock ID.
All,
AllButManageAuthority, ManageAuthority, or ManageAuthorizationLocks can
prune it to reclaim its rent.
Remove the delegate
Once all of the delegate’s holds are inactive (expired or fully captured), the owner can remove its role. The removal also deletes the delegate’s lock records and refunds their rent with the role’s:AuthorizationLockActive, even if its other holds have expired. Release the
remaining holds as the delegate, or wait for them to expire.
Lock from a program (ProgramExec)
A ProgramExec role can hold ManageAuthorizationLocks too, so an on-chain
program can place and release holds. The program spends a hold through
SignV2 as usual. The SDK lock helpers work with a
ProgramExecClientRole. To build the instructions directly, use the
swig_interface builders. The program’s instruction must pass the Swig config
and the wallet address as its first two accounts.
The authorizing program must also validate the exact Swig lock instruction and
its account metas before approving it: add/remove operation, acting role,
asset/mint, amount and expiry for add, or lock ID and rent recipient for remove.
Bind those values to the caller’s authorization, for example by inspecting the
following instruction through the instructions sysvar. A matching prefix and
wallet pair alone do not authorize a particular hold; a generic approval could
otherwise be reused with a changed amount, expiry, or lock ID.
The builder example assumes authorize_hold_data and the authorizing program
implement that binding:
CLI
These commands require a CLI build containing wallet PR #240, which has merged. Build that revision or a later one until a CLI release includes it. The CLI remains inswig-wallet; the Rust SDK lives in the Protocol SDK repository.
The swig CLI has the same operations. Each command also takes
--authority-type, --authority, and --authority-kp, or falls back to the
saved default authority.
Grant the delegated role. Repeat --permissions once per permission:
SignV2 spend command, so capture holds by
spending through the SDK as shown above. list-authorization-locks --all shows
fully captured holds as fully captured.
Revoke the delegate’s ability to place new holds. This is allowed even while it
holds active locks:
swig -i), use the Authorization Locks menu.
Common errors
See Error Types for codes.

