This document describes the Zex Asset Manager Solana program, its account structures, instructions, and security considerations.
- Overview
- Program Constants
- PDAs and Account Structures
- Instruction Methods
- Replay Protection and Signature Verification
- Access Control
- Rent Awareness
- Potential Risks and Security Notes
The Zex Asset Manager is a Solana program to manage deposits and withdrawals of SOL and SPL tokens.
- Users deposit funds into user-specific PDAs (
USER_VAULTS_SEED+ salt). - Funds are transferred into the main vault PDA (
MAIN_VAULTS_SEED) for custody. - Withdrawals require off-chain signature verification using a trusted
frost_pubkey. - Replay protection is implemented via withdraw_id PDAs (
WITHDRAW_ID_SEED).
| Constant | Description |
|---|---|
ASSETMAN_CONFIG_V1_SEEDS |
PDA seed for v1 config account |
ASSETMAN_CONFIG_SEEDS |
PDA seed for v2 config account |
MAIN_VAULTS_SEED |
PDA seed for the main vault |
USER_VAULTS_SEED |
PDA seed for per-user vaults |
WITHDRAW_ID_SEED |
PDA seed for tracking used withdraw IDs |
MAX_WITHDRAWER_LEN |
Maximum number of authorized withdrawers |
-
ConfigsV1(old version)admin: Admin Pubkeywithdrawers: List of Pubkeys authorized to withdrawfrost_pubkey: Off-chain signer Pubkey
-
Configs(v2)adminwithdrawersfrost_pubkeypaused: Boolean flag to pause the program
Security Notes:
- Admin-only methods enforce constraints based on
configs.admin. - Withdrawer methods enforce constraints based on
configs.withdrawers.
user_vaultPDAs: Derived using[USER_VAULTS_SEED, salt]. Each user has their own PDA.main_vaultPDA: Derived using[MAIN_VAULTS_SEED]. Stores consolidated funds.
- Tracks usage of withdraw IDs to prevent replay attacks.
- Fields:
used: bool
- SPL tokens are managed via Anchor's Associated Token Accounts (
AssociatedToken). - Each vault and destination account for SPL transfers is a token account tied to a specific mint.
- Creates the main config PDA.
- Stores admin and
frost_pubkey. - Checks that
frost_pubkeyis not default.
- Migrates old v1 configs to v2.
- Copies admin, withdrawers, frost_pubkey.
- Sets
paused= false.
- Pauses/unpauses program.
- Only callable by admin.
- Paused program disables withdrawals.
- Changes admin Pubkey.
- Only callable by current admin.
- Cannot set default Pubkey.
- Adds a new withdrawer.
- Only admin.
- Checks duplicates and maximum length.
- Removes a withdrawer.
- Only admin.
- Updates the off-chain signer Pubkey.
- Only admin.
- Checks that new
frost_pubkeyis not default.
- Transfers all SOL from user vault PDA to main vault PDA.
- Anyone can call (open function).
- Uses PDA as authority via seeds
[USER_VAULTS_SEED, salt, bump].
- Withdraw SOL from main vault.
- Only authorized withdrawers.
- Requires off-chain signature verification (
frost_pubkey) includingwithdraw_id. - Checks
withdraw_id_recordto prevent replay. - Rent-exempt aware transfer.
- Transfers all SPL tokens from user's token account to main vault token account.
- Anyone can call.
- Uses PDA authority with seeds
[USER_VAULTS_SEED, salt, bump].
- Withdraw SPL tokens from main vault to destination.
- Only authorized withdrawers.
- Off-chain signature verification with
withdraw_id. - Checks sufficient balance in main vault token account.
- Admin-only SOL withdrawal from main vault.
- Rent-exempt aware transfer.
- Emits
EmergencyWithdrawevent.
- Admin-only SPL withdrawal.
- Emits
EmergencyWithdrawevent.
- Uses
WithdrawIDRecordPDAs to mark each withdraw ID as used. - Off-chain signature verification ensures only authorized withdrawals are processed.
- Messages include
withdraw_idto prevent replay.
| Action | Authorized Role |
|---|---|
| Pause/unpause program | Admin |
| Add/remove withdrawers | Admin |
| Update frost_pubkey | Admin |
| Emergency withdrawals | Admin |
| Withdraw SOL/SPL | Registered withdrawer |
| Transfer user vault to main vault | Anyone |
Note: Transfer from user vault → main vault is intentionally open, as the main vault consolidates funds.
- SOL withdrawals subtract the rent-exempt minimum from the main vault balance.
- Ensures the main vault remains rent-exempt and cannot be drained entirely.
-
Open user vault transfer:
- Anyone can call
transfer_sol_to_main_vaultortransfer_spl_to_main_vault. - Funds always go to main vault PDA (program-controlled), so safe.
- Anyone can call
-
Signature verification:
- Withdrawals require a valid off-chain
frost_pubkeysignature. - Includes
withdraw_idfor replay protection.
- Withdrawals require a valid off-chain
-
Replay protection:
- Each withdraw ID has a dedicated PDA (
WITHDRAW_ID_SEED + withdraw_id). - Prevents double spending of the same withdrawal request.
- Each withdraw ID has a dedicated PDA (
-
SPL mint checks:
InvalidMinterror prevents empty or invalid token accounts.
-
PDAs:
MAIN_VAULTS_SEEDandUSER_VAULTS_SEEDuse seeds + bump for program authority.- Only program can sign via PDA seeds.
-
Paused state:
- When paused, withdrawals are disabled.
- Only admin can pause/unpause.
- Deposits: Users deposit into user-specific PDAs → anyone moves funds to main vault.
- Withdrawals: Require off-chain signature, replay protection, and authorized withdrawer.
- Emergency Withdrawals: Admin-only, ensures liquidity control in emergencies.
- Security: PDAs, rent-exempt awareness, signature verification, replay protection, access controls.