Adding an Advisory Account
An advisory account is the on-chain link between a client (owner) and their advisor. It’s a PDA that tracks the relationship status, fee rate, proposal counts, and encryption keys.
Account lifecycle
Section titled “Account lifecycle”Created (Pending) → Accepted (Active) → Revoked or ClosedStep 1: Client creates the account
Section titled “Step 1: Client creates the account”The client calls createAdvisoryAccount with:
- Their x25519 public key (for encrypted proposals)
- The advisor’s Solana wallet pubkey
const [pda, bump] = PublicKey.findProgramAddressSync( [Buffer.from("advisory"), ownerPubkey.toBuffer()], PROGRAM_ID,);Each owner can have one advisory account at a time. If one already exists, the client must close it before creating a new one.
Initial state:
| Field | Value |
|---|---|
status | Pending |
advisor_fee_bps | 0 |
proposal_count | 0 |
active_proposals | 0 |
owner_encryption_key | Client’s x25519 pubkey |
Step 2: Advisor accepts
Section titled “Step 2: Advisor accepts”The advisor signs acceptAdvisoryAccount to activate the relationship:
- Verifies the advisor field matches their pubkey
- Sets
advisor_fee_bps(0-100 bps, max 1%) - Transitions status:
Pending->Active
If the advisor doesn’t recognize or want the client, they simply don’t accept. There is no explicit reject — the account stays in Pending until accepted or closed by the owner.
Step 3: Active operations
Section titled “Step 3: Active operations”Once active, the full proposal lifecycle is available:
- Advisor creates proposal — encrypted payload stored on-chain,
active_proposalsincremented - Client approves/rejects — if approved, sets execution parameters and deadline
- Advisor executes — swaps tokens via Raydium CPI, fees deducted
- Either party closes proposal — reclaims rent once in terminal state
Step 4: Ending the relationship
Section titled “Step 4: Ending the relationship”Revoke (owner only):
- Sets status to
Revoked - No new proposals can be created
- Existing approved proposals with time remaining can still be executed
Close (owner only):
- Closes the account and returns rent to the owner
- All proposals must already be closed (terminal state)
- Works with both legacy (94-byte) and current (126-byte) account sizes
Encryption key rotation
Section titled “Encryption key rotation”If a client needs to rotate their x25519 key (e.g., if they suspect compromise), they can call setEncryptionKey:
import { setEncryptionKey } from "./lib/program/client";
const txSig = await setEncryptionKey( wallet, connection, newOwnerEncryptionKey, // Uint8Array, 32 bytes sendTransaction,);After rotation, the advisor must use the new key for future proposals. Previously encrypted proposals remain decryptable with the old key (which the client still derives from the same wallet signature).
Vaults
Section titled “Vaults”Each token has a separate vault PDA:
seeds = ["vault", advisory_account_pubkey, token_mint_pubkey]Vaults are token accounts owned by the program’s authority PDA. They are created lazily — either explicitly via initVault or automatically during the first deposit.
Key properties:
- Only the owner can deposit and withdraw
- The advisor can only move funds between vaults via approved, executed proposals
- Vaults persist independently of the advisory account — close them separately to reclaim rent