Composition
Shugo is one Anchor program that composes with Solana’s Subscriptions & Allowances program rather than reimplementing token custody. The only thing Shugo’s program ever does to a token balance is CPI into S&A’s owntransfer_fixed instruction — it never moves a token directly.
The first three calls can be bundled into a single transaction — this is exactly what the CLI’s create-policy command and the SDK’s createPolicyAndDelegation do.
The Policy account
One Policy PDA exists per(human, mint, policy_id) triple. Its own address is what gets registered as delegatee on the real S&A delegation — that registration is the entire mechanism. From that point on, S&A will only accept a transfer_fixed call where the signer is this exact address, and the only way to produce that signature is through Shugo’s own execute_pull, which runs the policy checks first.
PDA seeds:
["policy", human, mint, policy_id.to_le_bytes()].
Instructions
Why the destination check lives in Shugo, not S&A
S&A’s owntransfer_fixed takes a receiver token account as a plain argument with no constraint tying it to anything set when the delegation was created — by design, S&A caps how much and until when, not where to. A delegatee can redirect a pull to any token account of the right mint. Shugo’s execute_pull adds exactly the check that’s missing: the requested destination must be one of the policy’s up-to-four allowlisted accounts, checked before the CPI ever happens, independent of anything S&A itself validates.
Deployed addresses (devnet)
What’s deliberately out of scope today
Two gaps are real and intentional, not oversights — see the FAQ for the full reasoning.execute_pull does not yet forward Token-2022 transfer-hook accounts, so hook-enabled mints aren’t supported yet. init_policy does not yet validate that a mint is one Shugo can actually handle. Both are scoped, both have a clear extension point already built into the SDK (resolveExtraAccountsForMint and checkMintSupported in @shugo/sdk), and neither is a correctness or security gap in what’s already shipped — a pull against an unsupported mint fails cleanly at the S&A CPI boundary rather than misbehaving.(1).png?fit=max&auto=format&n=qzWg2aQwcoMXkrks&q=85&s=7bd9594b6c05a51ce5a41a26f4cb7e42)
(1).png?fit=max&auto=format&n=qzWg2aQwcoMXkrks&q=85&s=f7ad867613529ca7109dfe0b0dabd815)