Skip to main content
The withdraw_vault instruction completes a withdrawal by burning the escrowed LP tokens and transferring the underlying assets back to the user. This is the second step of the two-step withdrawal process.
This instruction will fail with WithdrawalNotYetAvailable if the vault’s withdrawal_waiting_period has not passed since the request_withdraw_vault call.

Discriminator

/// sha256("global:withdraw_vault")[0..8]
fn get_withdraw_vault_discriminator() -> [u8; 8] {
    [135, 7, 237, 120, 149, 94, 95, 7]
}

Parameters

This instruction takes no parameters beyond the discriminator.

Accounts

AccountMutabilitySignerDescription
user_transfer_authorityMutableYesThe user finalizing the withdrawal
protocolImmutableNoGlobal Voltr protocol state account
vaultMutableNoThe vault state account
vault_asset_mintImmutableNoThe mint of the asset being withdrawn
vault_lp_mintMutableNoThe vault’s LP mint
request_withdraw_lp_ataMutableNoThe receipt’s ATA holding escrowed LP tokens
vault_asset_idle_ataMutableNoThe vault’s idle asset token account
vault_asset_idle_authMutableNoPDA authority over vault_asset_idle_ata
user_asset_ataMutableNoThe user’s asset token account (destination)
request_withdraw_vault_receiptMutableNoThe PDA receipt account (closed after withdrawal)
asset_token_programImmutableNoToken Program or Token-2022 for assets
lp_token_programImmutableNoToken Program for LP tokens
system_programImmutableNoSolana System Program

CPI Struct

pub struct WithdrawVaultParams<'info> {
    pub user_transfer_authority: AccountInfo<'info>,
    pub protocol: AccountInfo<'info>,
    pub vault: AccountInfo<'info>,
    pub vault_asset_mint: AccountInfo<'info>,
    pub vault_lp_mint: AccountInfo<'info>,
    pub request_withdraw_lp_ata: AccountInfo<'info>,
    pub vault_asset_idle_ata: AccountInfo<'info>,
    pub vault_asset_idle_auth: AccountInfo<'info>,
    pub user_asset_ata: AccountInfo<'info>,
    pub request_withdraw_vault_receipt: AccountInfo<'info>,
    pub asset_token_program: AccountInfo<'info>,
    pub lp_token_program: AccountInfo<'info>,
    pub system_program: AccountInfo<'info>,
    pub voltr_vault_program: AccountInfo<'info>,
}

Implementation

use anchor_lang::prelude::*;
use anchor_lang::solana_program::{
    account_info::AccountInfo,
    instruction::{ AccountMeta, Instruction },
    program::invoke,
};

impl<'info> WithdrawVaultParams<'info> {
    pub fn withdraw_vault(&self) -> Result<()> {
        let instruction_data = get_withdraw_vault_discriminator().to_vec();

        let account_metas = vec![
            AccountMeta::new(*self.user_transfer_authority.key, true),
            AccountMeta::new_readonly(*self.protocol.key, false),
            AccountMeta::new(*self.vault.key, false),
            AccountMeta::new_readonly(*self.vault_asset_mint.key, false),
            AccountMeta::new(*self.vault_lp_mint.key, false),
            AccountMeta::new(*self.request_withdraw_lp_ata.key, false),
            AccountMeta::new(*self.vault_asset_idle_ata.key, false),
            AccountMeta::new(*self.vault_asset_idle_auth.key, false),
            AccountMeta::new(*self.user_asset_ata.key, false),
            AccountMeta::new(*self.request_withdraw_vault_receipt.key, false),
            AccountMeta::new_readonly(*self.asset_token_program.key, false),
            AccountMeta::new_readonly(*self.lp_token_program.key, false),
            AccountMeta::new_readonly(*self.system_program.key, false),
        ];

        let instruction = Instruction {
            program_id: *self.voltr_vault_program.key,
            accounts: account_metas,
            data: instruction_data,
        };

        invoke(&instruction, &self.to_account_infos())
            .map_err(|_| ErrorCodes::CpiToVoltrVaultFailed.into())
    }
}
After a successful withdraw_vault call, the request_withdraw_vault_receipt account is closed and its rent is returned. The user can then create a new withdrawal request if needed.
Full reference implementation: withdraw_vault.rs