Delegation policy
A Sup Wallet is a smart-contract vault. Delegation lets someone other than the owner spend from it — but only under rules the owner sets. A delegate isn't just an address: it is whoever or whatever can satisfy the rules attached to the wallet — an address, a transferable capability object, another contract, a ZK proof, a machine, or an AI agent.
This is the Sui TransferPolicy model applied to spending: a delegated spend produces a SpendRequest hot potato that confirm_spend only cashes out once the owner's rules approve it.
#Two kinds of rule
- Auth rules (OR) — prove who the principal is. At least one must pass. Built-in:
CapAuth(holds aDelegateCap),ScopedAuth(holds a budgetedScopedCap). - Caveat rules (AND) — prove the spend is allowed. Every one must pass. Built-in:
ScopedBudget(per-cap budget),RecipientAllowlist(reference third-party rule).
A spend is released iff: policy version current ∧ ≥1 auth rule stamped ∧ every caveat rule stamped. A rule can only read the request and stamp (or abort) — it can never change the amount or recipient, so a buggy or malicious rule can only block the people who opted into it.
#The principal ladder — "a delegate can be anything"
| Delegate is… | Rule |
|---|---|
| an address | AddressAuth |
| a key / agent / zkSend link | CapAuth (holds a DelegateCap) |
| a contract | CapAuth (the cap lives in the contract's field) |
| a sub-delegate (attenuated) | ScopedAuth (budget ≤ parent) |
| a ZK proof / 8183 assessor | a custom rule |
#Quickstart (SDK)
Owner turns on the policy and issues a cap-based delegate:
const sup = createSupWalletClient({ network: "testnet", runtime });
await sign(sup.initializePolicy({ walletId }));
await sign(sup.addAuthRule({ walletId, ruleType: sup.capAuthRuleType() }));
// mint a bearer cap to the delegate (an address, an agent, a contract that stores it…)
await sign(sup.mintDelegateCap({ walletId, recipient: agentAddress }));
The delegate spends by holding the cap:
await sign(sup.capSpend({ walletId, capId, coinType: SUI, amount: 30n, recipient }));
Add a condition (a third-party caveat rule):
await sign(sup.addCaveatRule({ walletId, ruleType: sup.recipientAllowlistRuleType() }));
await sign(sup.createAllowlist({ walletId }));
await sign(sup.allowlistAllow({ allowlistId, recipient }));
// spends must now satisfy CapAuth AND the allowlist:
await sign(sup.capSpendWithAllowlist({ walletId, capId, allowlistId, coinType: SUI, amount: 30n, recipient }));
#Sub-delegation (attenuation)
A ScopedCap carries a per-coin budget. Its holder can subdelegate part of it to a child cap (budget moved from parent, depth + 1), so a child can never outspend its grant and no chain exceeds the root.
await sign(sup.mintScopedRoot({ walletId, coinType: SUI, budget: 100n, maxDepth: 2, recipient: agent }));
await sign(sup.subdelegate({ capId, amount: 40n, recipient: subAgent }));
await sign(sup.scopedSpend({ walletId, capId: childCapId, coinType: SUI, amount: 25n, recipient }));
#Revocation
await sign(sup.revokeAllPolicies({ walletId })); // bumps version — kills every outstanding cap at once
#Recipes — policies worth building
Auth (OR) and caveat (AND) rules compose, so a handful of small rules cover a surprising range of real arrangements. Each row is a policy you can ship today:
| You want… | Compose |
|---|---|
| An AI trading desk | ScopedCap (daily budget) + recipient allowlist (only approved DEX contracts) + a time window |
| Payroll / treasury ops | a bearer/scoped cap per payee + recipient allowlist + a monthly velocity limit |
| A subscription keeper | scoped budget + recipient = the service + a per-period cadence caveat |
| A family allowance | a scoped cap per member + a kid's daily cap + spend-category envelopes |
| A DAO sub-treasury | sub-delegated scoped caps down a hierarchy + a quorum (co-sign) caveat over a threshold |
| Inheritance / dead-man switch | a cap-gated unmetered payout + an inactivity gate (releases after N silent days) |
| Milestone escrow | a caveat that only stamps once an oracle/attestation marks delivery |
| In-app / gaming spend | a small bearer cap to the game contract + a recipient allowlist |
The pattern to internalize: start from the tightest cap that still works (a scoped budget, not a bare bearer cap), then add caveats to express the "but only if…". A bearer cap with no caveats is unlimited — treat it like a hot wallet, not a policy.
#Open by design
Auth and caveat rules are separately deployed packages anyone can write and list in the rule marketplace. See Build a policy rule. Historical address + allowance data remains preserved while the TEE policy path is completed.
#Design it with an agent
Composing a safe policy (which auth/caveat rules, recipes, the foot-guns) is packaged as an installable skill so your coding agent designs it with you.
📥 View / download the skill → /llms/delegation-design.md
· on GitHub: view ·
raw
Save it for your agent: curl -sL $SUP/llms/delegation-design.md -o SKILL.md. For your wallet's actual policy, the 🛡 Delegation policy panel has an in-app "✨ Ask AI" assistant grounded in its live state.
