1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
use anchor_lang::prelude::*;
use anchor_lang::solana_program::borsh::get_instance_packed_len;
use crate::{TransactionMessage, VaultTransactionMessage};
/// Stores data required for serial execution of a batch of multisig vault transactions.
/// Vault transaction is a transaction that's executed on behalf of the multisig vault PDA
/// and wraps arbitrary Solana instructions, typically calling into other Solana programs.
/// The transactions themselves are stored in separate PDAs associated with the this account.
#[account]
#[derive(InitSpace)]
pub struct Batch {
/// The multisig this belongs to.
pub multisig: Pubkey,
/// Member of the Multisig who submitted the batch.
pub creator: Pubkey,
/// Index of this batch within the multisig transactions.
pub index: u64,
/// PDA bump.
pub bump: u8,
/// Index of the vault this batch belongs to.
pub vault_index: u8,
/// Derivation bump of the vault PDA this batch belongs to.
pub vault_bump: u8,
/// Number of transactions in the batch.
pub size: u32,
/// Index of the last executed transaction within the batch.
/// 0 means that no transactions have been executed yet.
pub executed_transaction_index: u32,
}
impl Batch {
pub fn invariant(&self) -> Result<()> {
// Just a sanity check.
require_gte!(self.size, self.executed_transaction_index);
Ok(())
}
}
/// Stores data required for execution of one transaction from a batch.
#[account]
pub struct VaultBatchTransaction {
/// PDA bump.
pub bump: u8,
/// Derivation bumps for additional signers.
/// Some transactions require multiple signers. Often these additional signers are "ephemeral" keypairs
/// that are generated on the client with a sole purpose of signing the transaction and be discarded immediately after.
/// When wrapping such transactions into multisig ones, we replace these "ephemeral" signing keypairs
/// with PDAs derived from the transaction's `transaction_index` and controlled by the Multisig Program;
/// during execution the program includes the seeds of these PDAs into the `invoke_signed` calls,
/// thus "signing" on behalf of these PDAs.
pub ephemeral_signer_bumps: Vec<u8>,
/// data required for executing the transaction.
pub message: VaultTransactionMessage,
}
impl VaultBatchTransaction {
pub fn size(ephemeral_signers_length: u8, transaction_message: &[u8]) -> Result<usize> {
let transaction_message: VaultTransactionMessage =
TransactionMessage::deserialize(&mut &transaction_message[..])?.try_into()?;
let message_size = get_instance_packed_len(&transaction_message).unwrap_or_default();
Ok(
8 + // anchor account discriminator
1 + // bump
(4 + usize::from(ephemeral_signers_length)) + // ephemeral_signers_bumps vec
message_size, // message
)
}
}