Skip to main content

squads_multisig_program/instructions/
transaction_buffer_create.rs

1use anchor_lang::prelude::*;
2
3use crate::errors::*;
4use crate::state::MAX_BUFFER_SIZE;
5use crate::state::*;
6
7#[derive(AnchorSerialize, AnchorDeserialize)]
8pub struct TransactionBufferCreateArgs {
9    /// Index of the buffer account to seed the account derivation
10    pub buffer_index: u8,
11    /// Index of the vault this transaction belongs to.
12    pub vault_index: u8,
13    /// Hash of the final assembled transaction message.
14    pub final_buffer_hash: [u8; 32],
15    /// Final size of the buffer.
16    pub final_buffer_size: u16,
17    /// Initial slice of the buffer.
18    pub buffer: Vec<u8>,
19}
20
21#[derive(Accounts)]
22#[instruction(args: TransactionBufferCreateArgs)]
23pub struct TransactionBufferCreate<'info> {
24    #[account(
25        seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
26        bump = multisig.bump,
27    )]
28    pub multisig: Account<'info, Multisig>,
29
30    #[account(
31        init,
32        payer = rent_payer,
33        space = TransactionBuffer::size(args.final_buffer_size)?,
34        seeds = [
35            SEED_PREFIX,
36            multisig.key().as_ref(),
37            SEED_TRANSACTION_BUFFER,
38            creator.key().as_ref(),
39            &args.buffer_index.to_le_bytes(),
40        ],
41        bump
42    )]
43    pub transaction_buffer: Account<'info, TransactionBuffer>,
44
45    /// The member of the multisig that is creating the transaction.
46    pub creator: Signer<'info>,
47
48    /// The payer for the transaction account rent.
49    #[account(mut)]
50    pub rent_payer: Signer<'info>,
51
52    pub system_program: Program<'info, System>,
53}
54
55impl TransactionBufferCreate<'_> {
56    fn validate(&self, args: &TransactionBufferCreateArgs) -> Result<()> {
57        let Self {
58            multisig, creator, ..
59        } = self;
60
61        // creator is a member in the multisig
62        require!(
63            multisig.is_member(creator.key()).is_some(),
64            MultisigError::NotAMember
65        );
66        // creator has initiate permissions
67        require!(
68            multisig.member_has_permission(creator.key(), Permission::Initiate),
69            MultisigError::Unauthorized
70        );
71
72        // Final Buffer Size must not exceed 4000 bytes
73        require!(
74            args.final_buffer_size as usize <= MAX_BUFFER_SIZE,
75            MultisigError::FinalBufferSizeExceeded
76        );
77        Ok(())
78    }
79
80    /// Create a new vault transaction.
81    #[access_control(ctx.accounts.validate(&args))]
82    pub fn transaction_buffer_create(
83        ctx: Context<Self>,
84        args: TransactionBufferCreateArgs,
85    ) -> Result<()> {
86        // Mutable Accounts
87        let transaction_buffer = &mut ctx.accounts.transaction_buffer;
88
89        // Readonly Accounts
90        let multisig = &ctx.accounts.multisig;
91        let creator = &mut ctx.accounts.creator;
92
93        // Get the buffer index.
94        let buffer_index = args.buffer_index;
95
96        // Initialize the transaction fields.
97        transaction_buffer.multisig = multisig.key();
98        transaction_buffer.creator = creator.key();
99        transaction_buffer.vault_index = args.vault_index;
100        transaction_buffer.buffer_index = buffer_index;
101        transaction_buffer.final_buffer_hash = args.final_buffer_hash;
102        transaction_buffer.final_buffer_size = args.final_buffer_size;
103        transaction_buffer.buffer = args.buffer;
104
105        // Invariant function on the transaction buffer
106        transaction_buffer.invariant()?;
107
108        Ok(())
109    }
110}