Skip to main content

squads_multisig_program/state/
batch.rs

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