fn process_withdraw(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    amount: u64,
    expected_decimals: u8,
    new_decryptable_available_balance: pod::AeCiphertext,
    proof_instruction_offset: i64,
) -> ProgramResult {
    let account_info_iter = &mut accounts.iter();
    let token_account_info = next_account_info(account_info_iter)?;
    let dest_token_account_info = next_account_info(account_info_iter)?;
    let mint_info = next_account_info(account_info_iter)?;
    let instructions_sysvar_info = next_account_info(account_info_iter)?;
    let authority_info = next_account_info(account_info_iter)?;
    let authority_info_data_len = authority_info.data_len();

    check_program_account(mint_info.owner)?;
    let mint_data = &mint_info.data.borrow_mut();
    let mint = StateWithExtensions::<Mint>::unpack(mint_data)?;

    if expected_decimals != mint.base.decimals {
        return Err(TokenError::MintDecimalsMismatch.into());
    }

    let previous_instruction =
        get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?;

    let proof_data = decode_proof_instruction::<WithdrawData>(
        ProofInstruction::VerifyWithdraw,
        &previous_instruction,
    )?;

    // Process source account
    {
        check_program_account(token_account_info.owner)?;
        let token_account_data = &mut token_account_info.data.borrow_mut();
        let mut token_account = StateWithExtensionsMut::<Account>::unpack(token_account_data)?;

        Processor::validate_owner(
            program_id,
            token_account_info.owner,
            authority_info,
            authority_info_data_len,
            account_info_iter.as_slice(),
        )?;

        if token_account.base.is_frozen() {
            return Err(TokenError::AccountFrozen.into());
        }

        if token_account.base.mint != *mint_info.key {
            return Err(TokenError::MintMismatch.into());
        }

        let mut ct_token_account =
            token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
        ct_token_account.approved()?;

        ct_token_account.available_balance =
            ops::subtract_from(&ct_token_account.available_balance, amount)
                .ok_or(TokenError::Overflow)?;

        if ct_token_account.available_balance != proof_data.final_ciphertext {
            return Err(TokenError::ConfidentialTransferAvailableBalanceMismatch.into());
        }

        ct_token_account.decryptable_available_balance = new_decryptable_available_balance;
    }

    //
    // Finished with the source token account at this point. Drop all references to it to avoid a
    // double borrow if the source and destination accounts are the same
    //

    // Process destination account
    {
        check_program_account(dest_token_account_info.owner)?;
        let dest_token_account_data = &mut dest_token_account_info.data.borrow_mut();
        let mut dest_token_account =
            StateWithExtensionsMut::<Account>::unpack(dest_token_account_data)?;

        if dest_token_account.base.is_frozen() {
            return Err(TokenError::AccountFrozen.into());
        }

        if dest_token_account.base.mint != *mint_info.key {
            return Err(TokenError::MintMismatch.into());
        }

        // Wrapped SOL withdrawals are not supported because lamports cannot be apparated.
        assert!(!dest_token_account.base.is_native());
        dest_token_account.base.amount = dest_token_account
            .base
            .amount
            .checked_add(amount)
            .ok_or(TokenError::Overflow)?;

        dest_token_account.pack_base();
    }

    Ok(())
}
/// Processes a [Withdraw] instruction.
Processes a [Withdraw] instruction.
Processes a [ Withdraw ] instruction .
fn process_withdraw(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    amount: u64,
    expected_decimals: u8,
    new_decryptable_available_balance: pod::AeCiphertext,
    proof_instruction_offset: i64,
) -> ProgramResult {
    let account_info_iter = &mut accounts.iter();
    let token_account_info = next_account_info(account_info_iter)?;
    let dest_token_account_info = next_account_info(account_info_iter)?;
    let mint_info = next_account_info(account_info_iter)?;
    let instructions_sysvar_info = next_account_info(account_info_iter)?;
    let authority_info = next_account_info(account_info_iter)?;
    let authority_info_data_len = authority_info.data_len();
    check_program_account(mint_info.owner)?;
    let mint_data = &mint_info.data.borrow_mut();
    let mint = StateWithExtensions::<Mint>::unpack(mint_data)?;
    if expected_decimals != mint.base.decimals {
        return Err(TokenError::MintDecimalsMismatch.into());
    }
    let previous_instruction =
        get_instruction_relative(proof_instruction_offset, instructions_sysvar_info)?;
    let proof_data = decode_proof_instruction::<WithdrawData>(
        ProofInstruction::VerifyWithdraw,
        &previous_instruction,
    )?;
    // Process source account
    {
        check_program_account(token_account_info.owner)?;
        let token_account_data = &mut token_account_info.data.borrow_mut();
        let mut token_account = StateWithExtensionsMut::<Account>::unpack(token_account_data)?;
        Processor::validate_owner(
            program_id,
            token_account_info.owner,
            authority_info,
            authority_info_data_len,
            account_info_iter.as_slice(),
        )?;
        if token_account.base.is_frozen() {
            return Err(TokenError::AccountFrozen.into());
        }
        if token_account.base.mint != *mint_info.key {
            return Err(TokenError::MintMismatch.into());
        }
        let mut ct_token_account =
            token_account.get_extension_mut::<ConfidentialTransferAccount>()?;
        ct_token_account.approved()?;
        ct_token_account.available_balance =
            ops::subtract_from(&ct_token_account.available_balance, amount)
                .ok_or(TokenError::Overflow)?;
        if ct_token_account.available_balance != proof_data.final_ciphertext {
            return Err(TokenError::ConfidentialTransferAvailableBalanceMismatch.into());
        }
        ct_token_account.decryptable_available_balance = new_decryptable_available_balance;
    }
    //
    // Finished with the source token account at this point. Drop all references to it to avoid a
    // double borrow if the source and destination accounts are the same
    //
    // Process destination account
    {
        check_program_account(dest_token_account_info.owner)?;
        let dest_token_account_data = &mut dest_token_account_info.data.borrow_mut();
        let mut dest_token_account =
            StateWithExtensionsMut::<Account>::unpack(dest_token_account_data)?;
        if dest_token_account.base.is_frozen() {
            return Err(TokenError::AccountFrozen.into());
        }
        if dest_token_account.base.mint != *mint_info.key {
            return Err(TokenError::MintMismatch.into());
        }
        // Wrapped SOL withdrawals are not supported because lamports cannot be apparated.
        assert!(!dest_token_account.base.is_native());
        dest_token_account.base.amount = dest_token_account
            .base
            .amount
            .checked_add(amount)
            .ok_or(TokenError::Overflow)?;
        dest_token_account.pack_base();
    }
    Ok(())
}
fn process_withdraw ( program_id : & Pubkey , accounts : & [ AccountInfo ] , amount : u64 , expected_decimals : u8 , new_decryptable_available_balance : pod :: AeCiphertext , proof_instruction_offset : i64 , ) -> ProgramResult { let account_info_iter = & mut accounts . iter ( ) ; let token_account_info = next_account_info ( account_info_iter ) ? ; let dest_token_account_info = next_account_info ( account_info_iter ) ? ; let mint_info = next_account_info ( account_info_iter ) ? ; let instructions_sysvar_info = next_account_info ( account_info_iter ) ? ; let authority_info = next_account_info ( account_info_iter ) ? ; let authority_info_data_len = authority_info . data_len ( ) ; check_program_account ( mint_info . owner ) ? ; let mint_data = & mint_info . data . borrow_mut ( ) ; let mint = StateWithExtensions :: < Mint > :: unpack ( mint_data ) ? ; if expected_decimals != mint . base . decimals { return Err ( TokenError :: MintDecimalsMismatch . into ( ) ) ; } let previous_instruction = get_instruction_relative ( proof_instruction_offset , instructions_sysvar_info ) ? ; let proof_data = decode_proof_instruction :: < WithdrawData > ( ProofInstruction :: VerifyWithdraw , & previous_instruction , ) ? ; // Process source account { check_program_account ( token_account_info . owner ) ? ; let token_account_data = & mut token_account_info . data . borrow_mut ( ) ; let mut token_account = StateWithExtensionsMut :: < Account > :: unpack ( token_account_data ) ? ; Processor :: validate_owner ( program_id , token_account_info . owner , authority_info , authority_info_data_len , account_info_iter . as_slice ( ) , ) ? ; if token_account . base . is_frozen ( ) { return Err ( TokenError :: AccountFrozen . into ( ) ) ; } if token_account . base . mint != * mint_info . key { return Err ( TokenError :: MintMismatch . into ( ) ) ; } let mut ct_token_account = token_account . get_extension_mut :: < ConfidentialTransferAccount > ( ) ? ; ct_token_account . approved ( ) ? ; ct_token_account . available_balance = ops :: subtract_from ( & ct_token_account . available_balance , amount ) . ok_or ( TokenError :: Overflow ) ? ; if ct_token_account . available_balance != proof_data . final_ciphertext { return Err ( TokenError :: ConfidentialTransferAvailableBalanceMismatch . into ( ) ) ; } ct_token_account . decryptable_available_balance = new_decryptable_available_balance ; } // // Finished with the source token account at this point. Drop all references to it to avoid a // double borrow if the source and destination accounts are the same // // Process destination account { check_program_account ( dest_token_account_info . owner ) ? ; let dest_token_account_data = & mut dest_token_account_info . data . borrow_mut ( ) ; let mut dest_token_account = StateWithExtensionsMut :: < Account > :: unpack ( dest_token_account_data ) ? ; if dest_token_account . base . is_frozen ( ) { return Err ( TokenError :: AccountFrozen . into ( ) ) ; } if dest_token_account . base . mint != * mint_info . key { return Err ( TokenError :: MintMismatch . into ( ) ) ; } // Wrapped SOL withdrawals are not supported because lamports cannot be apparated. assert ! ( dest_token_account base is_native ( ) ) ; dest_token_account . base . amount = dest_token_account . base . amount . checked_add ( amount ) . ok_or ( TokenError :: Overflow ) ? ; dest_token_account . pack_base ( ) ; } Ok ( ( ) ) }
Processes a [Withdraw] instruction.
Processes a [ Withdraw ] instruction .
program_id
&Pubkey
accounts
&[AccountInfo]
amount
u64
expected_decimals
u8
new_decryptable_available_balance
pod::AeCiphertext
proof_instruction_offset
i64
program_id
&Pubkey
accounts
&[AccountInfo]
amount
u64
expected_decimals
u8
new_decryptable_available_balance
pod::AeCiphertext
proof_instruction_offset
i64