use crate::errors::*;
use crate::instructions::*;
use crate::state::*;
use anchor_lang::{prelude::*, system_program};
#[derive(Accounts)]
pub struct VaultTransactionCreateFromBuffer<'info> {
pub vault_transaction_create: VaultTransactionCreate<'info>,
#[account(
mut,
close = creator,
// Only the creator can turn the buffer into a transaction and reclaim
// the rent
constraint = transaction_buffer.creator == creator.key() @ MultisigError::Unauthorized,
seeds = [
SEED_PREFIX,
vault_transaction_create.multisig.key().as_ref(),
SEED_TRANSACTION_BUFFER,
creator.key().as_ref(),
&transaction_buffer.buffer_index.to_le_bytes(),
],
bump
)]
pub transaction_buffer: Box<Account<'info, TransactionBuffer>>,
#[account(
mut,
address = vault_transaction_create.creator.key(),
)]
pub creator: Signer<'info>,
}
impl<'info> VaultTransactionCreateFromBuffer<'info> {
pub fn validate(&self, args: &VaultTransactionCreateArgs) -> Result<()> {
let transaction_buffer_account = &self.transaction_buffer;
require!(
args.transaction_message == vec![0, 0, 0, 0, 0, 0],
MultisigError::InvalidInstructionArgs
);
transaction_buffer_account.validate_hash()?;
transaction_buffer_account.validate_size()?;
Ok(())
}
#[access_control(ctx.accounts.validate(&args))]
pub fn vault_transaction_create_from_buffer(
ctx: Context<'_, '_, 'info, 'info, Self>,
args: VaultTransactionCreateArgs,
) -> Result<()> {
let vault_transaction_account_info = &ctx
.accounts
.vault_transaction_create
.transaction
.to_account_info();
let rent_payer_account_info = &ctx
.accounts
.vault_transaction_create
.rent_payer
.to_account_info();
let system_program = &ctx.accounts.vault_transaction_create.system_program.to_account_info();
let transaction_buffer = &ctx.accounts.transaction_buffer;
let new_len =
VaultTransaction::size(args.ephemeral_signers, transaction_buffer.buffer.as_slice())?;
let rent_exempt_lamports = Rent::get().unwrap().minimum_balance(new_len).max(1);
let top_up_lamports =
rent_exempt_lamports.saturating_sub(vault_transaction_account_info.lamports());
let transfer_context = CpiContext::new(
system_program.to_account_info(),
system_program::Transfer {
from: rent_payer_account_info.clone(),
to: vault_transaction_account_info.clone(),
},
);
system_program::transfer(transfer_context, top_up_lamports)?;
AccountInfo::realloc(&vault_transaction_account_info, new_len, true)?;
let create_args = VaultTransactionCreateArgs {
vault_index: args.vault_index,
ephemeral_signers: args.ephemeral_signers,
transaction_message: transaction_buffer.buffer.clone(),
memo: args.memo,
};
let context = Context::new(
ctx.program_id,
&mut ctx.accounts.vault_transaction_create,
ctx.remaining_accounts,
ctx.bumps.vault_transaction_create,
);
VaultTransactionCreate::vault_transaction_create(context, create_args)?;
Ok(())
}
}