The Collateral Vault smart contract is built using the Anchor framework on Solana. It provides secure, non-custodial management of USDT collateral for a decentralized perpetual futures exchange.
Program ID: ACU6ToU65HNU9nFbFzhA4BqZfZUFryri7UnhwS1FvxyH
Main vault account storing user collateral and balance information.
pub struct CollateralVault {
pub owner: Pubkey, // Owner of the vault
pub token_account: Pubkey, // Associated token account holding USDT
pub total_balance: u64, // Total balance in vault
pub locked_balance: u64, // Locked balance (used as collateral)
pub available_balance: u64, // Available balance (total - locked)
pub total_deposited: u64, // Total amount ever deposited
pub total_withdrawn: u64, // Total amount ever withdrawn
pub created_at: i64, // Creation timestamp
pub bump: u8, // PDA bump seed
}PDA Derivation: [b"vault", user_pubkey]
Size: 137 bytes
Manages authorized programs that can lock/unlock collateral.
pub struct VaultAuthority {
pub authorized_programs: Vec<Pubkey>, // Authorized programs
pub admin: Pubkey, // Admin pubkey
pub bump: u8, // PDA bump seed
}PDA Derivation: [b"vault_authority"]
Max Authorized Programs: 10
Multi-signature vault configuration requiring M-of-N signatures for withdrawals.
pub struct MultiSigVault {
pub vault: Pubkey, // Base vault account
pub threshold: u8, // Required signatures
pub signers: Vec<Pubkey>, // List of signers
pub bump: u8, // PDA bump seed
}PDA Derivation: [b"multi_sig_vault", vault_pubkey]
Security configuration for enhanced protection.
pub struct SecurityConfig {
pub vault: Pubkey, // Vault this config applies to
pub withdrawal_delay: i64, // Withdrawal delay in seconds
pub withdrawal_whitelist: Vec<Pubkey>, // Whitelisted addresses
pub daily_withdrawal_limit: u64, // Max withdrawal per day
pub withdrawn_today: u64, // Amount withdrawn today
pub last_withdrawal_day: i64, // Last withdrawal date
pub paused: bool, // Emergency pause flag
pub bump: u8, // PDA bump seed
}PDA Derivation: [b"security_config", vault_pubkey]
Creates a new vault for a user.
Accounts:
owner(signer, mut): Vault ownervault(mut): Vault PDA to initializemint: USDT mintvault_token_account(mut): Associated token account for vaulttoken_program: SPL Token programassociated_token_program: Associated Token programsystem_program: System programrent: Rent sysvar
Arguments: None
Events Emitted: VaultInitialized
Deposits USDT collateral into vault.
Accounts:
user(signer, mut): User making depositvault(mut): User's vault PDAowner: Vault owner (for validation)user_token_account(mut): User's USDT token accountvault_token_account(mut): Vault's USDT token accounttoken_program: SPL Token program
Arguments:
amount: u64: Amount to deposit
CPI: Transfers tokens from user to vault
Events Emitted: DepositEvent
Withdraws USDT collateral from vault.
Accounts:
user(signer, mut): User making withdrawalvault(mut): User's vault PDAowner: Vault owneruser_token_account(mut): User's USDT token accountvault_token_account(mut): Vault's USDT token accounttoken_program: SPL Token program
Arguments:
amount: u64: Amount to withdraw
Validations:
available_balance >= amount- No locked collateral preventing withdrawal
CPI: Transfers tokens from vault to user (with PDA signer)
Events Emitted: WithdrawalEvent
Locks collateral for margin requirements (called by authorized programs).
Accounts:
caller_program: Program invoking this instructionvault(mut): Vault to lock collateral invault_authority: Authority PDA
Arguments:
amount: u64: Amount to lock
Validations:
- Caller is authorized
- Sufficient available balance
Events Emitted: LockEvent
Unlocks collateral when position is closed.
Accounts:
caller_program: Program invoking this instructionvault(mut): Vault to unlock collateral invault_authority: Authority PDA
Arguments:
amount: u64: Amount to unlock
Validations:
- Caller is authorized
- Sufficient locked balance
Events Emitted: UnlockEvent
Transfers collateral between vaults (for settlements/liquidations).
Accounts:
caller_program: Program invoking this instructionfrom_vault(mut): Source vaultto_vault(mut): Destination vaultvault_authority: Authority PDA
Arguments:
amount: u64: Amount to transfer
Validations:
- Caller is authorized
- Sufficient available balance in source vault
- No self-transfer
Events Emitted: TransferEvent
pub enum VaultError {
InvalidAmount, // Invalid amount specified
InsufficientBalance, // Insufficient balance for operation
Overflow, // Arithmetic overflow
Underflow, // Arithmetic underflow
Unauthorized, // Unauthorized program
ProgramNotAuthorized, // Program not authorized
ProgramAlreadyAuthorized, // Program already authorized
TooManyAuthorizedPrograms, // Too many authorized programs
InvalidUnlockAmount, // Invalid unlock amount
HasLockedCollateral, // Cannot withdraw with locked collateral
InvalidVaultAuthority, // Invalid vault authority
InvalidTokenAccount, // Invalid token account
TokenAccountMismatch, // Token account mismatch
InvalidOwner, // Invalid owner
DailyLimitExceeded, // Daily withdrawal limit exceeded
NotWhitelisted, // Address not whitelisted
VaultPaused, // Vault operations paused
WithdrawalDelayNotSatisfied, // Withdrawal delay not satisfied
// ... more error codes
}pub struct VaultInitialized {
pub vault: Pubkey,
pub owner: Pubkey,
pub token_account: Pubkey,
pub timestamp: i64,
}pub struct DepositEvent {
pub vault: Pubkey,
pub user: Pubkey,
pub amount: u64,
pub new_balance: u64,
pub timestamp: i64,
}pub struct WithdrawalEvent {
pub vault: Pubkey,
pub user: Pubkey,
pub amount: u64,
pub new_balance: u64,
pub timestamp: i64,
}pub struct LockEvent {
pub vault: Pubkey,
pub program: Pubkey,
pub amount: u64,
pub locked_balance: u64,
pub available_balance: u64,
pub timestamp: i64,
}External programs can lock/unlock collateral via CPI:
use anchor_lang::prelude::*;
// In external program
pub fn open_position(ctx: Context<OpenPosition>, size: u64) -> Result<()> {
// Calculate required collateral
let collateral_needed = size / leverage;
// CPI to lock collateral
let cpi_program = ctx.accounts.vault_program.to_account_info();
let cpi_accounts = LockCollateral {
caller_program: ctx.program_id.to_account_info(),
vault: ctx.accounts.vault.to_account_info(),
vault_authority: ctx.accounts.vault_authority.to_account_info(),
};
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts);
collateral_vault::cpi::lock_collateral(cpi_ctx, collateral_needed)?;
// Open position logic...
Ok(())
}Programs must be added to the authorized list:
# Add program to authorized list
anchor run add-program <PROGRAM_ID>- PDA Signer: Withdrawals use PDA as signer for token transfers
- Atomic Updates: All balance updates are atomic
- Overflow Protection: Checked arithmetic prevents overflow/underflow
- Authority Validation: Only authorized programs can lock/unlock
- Owner Validation: Only vault owner can deposit/withdraw
- Balance Verification: Always verify sufficient balance before operations
See tests/collateral-vault.ts for comprehensive test suite covering:
- Vault initialization
- Deposits and withdrawals
- Collateral locking/unlocking
- Multi-sig operations
- Security features
- Error cases
- Get authorized by vault authority admin
- Call
lock_collateralwhen opening positions - Call
unlock_collateralwhen closing positions - Call
transfer_collateralfor liquidations
- Initialize vault for new users
- Use deposit/withdraw for fund management
- Query vault state for balance display
- Subscribe to events for real-time updates