squads_multisig_program/instructions/
config_transaction_create.rs

1use anchor_lang::prelude::*;
2
3use crate::errors::*;
4use crate::state::*;
5
6#[derive(AnchorSerialize, AnchorDeserialize)]
7pub struct ConfigTransactionCreateArgs {
8    pub actions: Vec<ConfigAction>,
9    pub memo: Option<String>,
10}
11
12#[derive(Accounts)]
13#[instruction(args: ConfigTransactionCreateArgs)]
14pub struct ConfigTransactionCreate<'info> {
15    #[account(
16        mut,
17        seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
18        bump = multisig.bump,
19    )]
20    pub multisig: Account<'info, Multisig>,
21
22    #[account(
23        init,
24        payer = rent_payer,
25        space = ConfigTransaction::size(&args.actions),
26        seeds = [
27            SEED_PREFIX,
28            multisig.key().as_ref(),
29            SEED_TRANSACTION,
30            &multisig.transaction_index.checked_add(1).unwrap().to_le_bytes(),
31        ],
32        bump
33    )]
34    pub transaction: Account<'info, ConfigTransaction>,
35
36    /// The member of the multisig that is creating the transaction.
37    pub creator: Signer<'info>,
38
39    /// The payer for the transaction account rent.
40    #[account(mut)]
41    pub rent_payer: Signer<'info>,
42
43    pub system_program: Program<'info, System>,
44}
45
46impl ConfigTransactionCreate<'_> {
47    fn validate(&self, args: &ConfigTransactionCreateArgs) -> Result<()> {
48        // multisig
49        require_keys_eq!(
50            self.multisig.config_authority,
51            Pubkey::default(),
52            MultisigError::NotSupportedForControlled
53        );
54
55        // creator
56        require!(
57            self.multisig.is_member(self.creator.key()).is_some(),
58            MultisigError::NotAMember
59        );
60        require!(
61            self.multisig
62                .member_has_permission(self.creator.key(), Permission::Initiate),
63            MultisigError::Unauthorized
64        );
65
66        // args
67
68        // Config transaction must have at least one action
69        require!(!args.actions.is_empty(), MultisigError::NoActions);
70
71        // time_lock must not exceed the maximum allowed.
72        for action in &args.actions {
73            if let ConfigAction::SetTimeLock { new_time_lock, .. } = action {
74                require!(
75                    *new_time_lock <= MAX_TIME_LOCK,
76                    MultisigError::TimeLockExceedsMaxAllowed
77                );
78            }
79        }
80
81        Ok(())
82    }
83
84    /// Create a new config transaction.
85    #[access_control(ctx.accounts.validate(&args))]
86    pub fn config_transaction_create(
87        ctx: Context<Self>,
88        args: ConfigTransactionCreateArgs,
89    ) -> Result<()> {
90        let multisig = &mut ctx.accounts.multisig;
91        let transaction = &mut ctx.accounts.transaction;
92        let creator = &mut ctx.accounts.creator;
93
94        let multisig_key = multisig.key();
95
96        // Increment the transaction index.
97        let transaction_index = multisig.transaction_index.checked_add(1).unwrap();
98
99        // Initialize the transaction fields.
100        transaction.multisig = multisig_key;
101        transaction.creator = creator.key();
102        transaction.index = transaction_index;
103        transaction.bump = ctx.bumps.transaction;
104        transaction.actions = args.actions;
105
106        // Updated last transaction index in the multisig account.
107        multisig.transaction_index = transaction_index;
108
109        multisig.invariant()?;
110
111        // Logs for indexing.
112        msg!("transaction index: {}", transaction_index);
113
114        Ok(())
115    }
116}