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]
43pub struct VaultBatchTransaction {
44 /// PDA bump.
45 pub bump: u8,
46 /// Derivation bumps for additional signers.
47 /// Some transactions require multiple signers. Often these additional signers are "ephemeral" keypairs
48 /// that are generated on the client with a sole purpose of signing the transaction and be discarded immediately after.
49 /// When wrapping such transactions into multisig ones, we replace these "ephemeral" signing keypairs
50 /// with PDAs derived from the transaction's `transaction_index` and controlled by the Multisig Program;
51 /// during execution the program includes the seeds of these PDAs into the `invoke_signed` calls,
52 /// thus "signing" on behalf of these PDAs.
53 pub ephemeral_signer_bumps: Vec<u8>,
54 /// data required for executing the transaction.
55 pub message: VaultTransactionMessage,
56}
57
58impl VaultBatchTransaction {
59 pub fn size(ephemeral_signers_length: u8, transaction_message: &[u8]) -> Result<usize> {
60 let transaction_message: VaultTransactionMessage =
61 TransactionMessage::deserialize(&mut &transaction_message[..])?.try_into()?;
62
63 let message_size = get_instance_packed_len(&transaction_message).unwrap_or_default();
64
65 Ok(
66 8 + // anchor account discriminator
67 1 + // bump
68 (4 + usize::from(ephemeral_signers_length)) + // ephemeral_signers_bumps vec
69 message_size, // message
70 )
71 }
72}