Skip to main content

squads_multisig_program/instructions/
transaction_buffer_extend.rs

1use anchor_lang::prelude::*;
2
3use crate::errors::*;
4use crate::state::*;
5
6#[derive(AnchorSerialize, AnchorDeserialize)]
7pub struct TransactionBufferExtendArgs {
8    // Buffer to extend the TransactionBuffer with.
9    pub buffer: Vec<u8>,
10}
11
12#[derive(Accounts)]
13#[instruction(args: TransactionBufferExtendArgs)]
14pub struct TransactionBufferExtend<'info> {
15    #[account(
16        seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
17        bump = multisig.bump,
18    )]
19    pub multisig: Account<'info, Multisig>,
20
21    #[account(
22        mut,
23        // Only the creator can extend the buffer
24        constraint = transaction_buffer.creator == creator.key() @ MultisigError::Unauthorized,
25        seeds = [
26            SEED_PREFIX,
27            multisig.key().as_ref(),
28            SEED_TRANSACTION_BUFFER,
29            creator.key().as_ref(),
30            &transaction_buffer.buffer_index.to_le_bytes()
31        ],
32        bump
33    )]
34    pub transaction_buffer: Account<'info, TransactionBuffer>,
35
36    /// The member of the multisig that created the TransactionBuffer.
37    pub creator: Signer<'info>,
38}
39
40impl TransactionBufferExtend<'_> {
41    fn validate(&self, args: &TransactionBufferExtendArgs) -> Result<()> {
42        let Self {
43            multisig,
44            creator,
45            transaction_buffer,
46            ..
47        } = self;
48
49        // creator is still a member in the multisig
50        require!(
51            multisig.is_member(creator.key()).is_some(),
52            MultisigError::NotAMember
53        );
54
55        // creator still has initiate permissions
56        require!(
57            multisig.member_has_permission(creator.key(), Permission::Initiate),
58            MultisigError::Unauthorized
59        );
60
61        // Extended Buffer size must not exceed final buffer size
62        // Calculate remaining space in the buffer
63        let current_buffer_size = transaction_buffer.buffer.len() as u16;
64        let remaining_space = transaction_buffer
65            .final_buffer_size
66            .checked_sub(current_buffer_size)
67            .unwrap();
68
69        // Check if the new data exceeds the remaining space
70        let new_data_size = args.buffer.len() as u16;
71        require!(
72            new_data_size <= remaining_space,
73            MultisigError::FinalBufferSizeExceeded
74        );
75
76        Ok(())
77    }
78
79    /// Create a new vault transaction.
80    #[access_control(ctx.accounts.validate(&args))]
81    pub fn transaction_buffer_extend(
82        ctx: Context<Self>,
83        args: TransactionBufferExtendArgs,
84    ) -> Result<()> {
85        // Mutable Accounts
86        let transaction_buffer = &mut ctx.accounts.transaction_buffer;
87
88        // Required Data
89        let buffer_slice_extension = args.buffer;
90
91        // Extend the Buffer inside the TransactionBuffer
92        transaction_buffer
93            .buffer
94            .extend_from_slice(&buffer_slice_extension);
95
96        // Invariant function on the transaction buffer
97        transaction_buffer.invariant()?;
98
99        Ok(())
100    }
101}