squads_multisig_program/instructions/
vault_transaction_create.rs1use anchor_lang::prelude::*;
2use anchor_lang::system_program;
3
4use crate::errors::*;
5use crate::state::*;
6use crate::utils::*;
7
8#[derive(AnchorSerialize, AnchorDeserialize)]
9pub struct VaultTransactionCreateArgs {
10 pub vault_index: u8,
12 pub ephemeral_signers: u8,
14 pub transaction_message: Vec<u8>,
15 pub memo: Option<String>,
16}
17
18#[derive(Accounts)]
19#[instruction(args: VaultTransactionCreateArgs)]
20pub struct VaultTransactionCreate<'info> {
21 #[account(
22 mut,
23 seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
24 bump = multisig.bump,
25 )]
26 pub multisig: Account<'info, Multisig>,
27
28 #[account(
29 init,
30 payer = rent_payer,
31 space = VaultTransaction::size(args.ephemeral_signers, &args.transaction_message)?,
32 seeds = [
33 SEED_PREFIX,
34 multisig.key().as_ref(),
35 SEED_TRANSACTION,
36 &multisig.transaction_index.checked_add(1).unwrap().to_le_bytes(),
37 ],
38 bump
39 )]
40 pub transaction: Account<'info, VaultTransaction>,
41
42 pub creator: Signer<'info>,
44
45 #[account(mut)]
47 pub rent_payer: Signer<'info>,
48
49 pub system_program: Program<'info, System>,
50}
51
52impl<'info> VaultTransactionCreate<'info> {
53 pub fn validate(&self) -> Result<()> {
54 let Self {
55 multisig, creator, ..
56 } = self;
57
58 require!(
60 multisig.is_member(creator.key()).is_some(),
61 MultisigError::NotAMember
62 );
63 require!(
64 multisig.member_has_permission(creator.key(), Permission::Initiate),
65 MultisigError::Unauthorized
66 );
67
68 Ok(())
69 }
70
71 #[access_control(ctx.accounts.validate())]
73 pub fn vault_transaction_create(
74 ctx: Context<Self>,
75 args: VaultTransactionCreateArgs,
76 ) -> Result<()> {
77 let multisig = &mut ctx.accounts.multisig;
78 let transaction = &mut ctx.accounts.transaction;
79 let creator = &mut ctx.accounts.creator;
80
81 let transaction_message =
82 TransactionMessage::deserialize(&mut args.transaction_message.as_slice())?;
83
84 let multisig_key = multisig.key();
85 let transaction_key = transaction.key();
86
87 let vault_seeds = &[
88 SEED_PREFIX,
89 multisig_key.as_ref(),
90 SEED_VAULT,
91 &args.vault_index.to_le_bytes(),
92 ];
93 let (_, vault_bump) = Pubkey::find_program_address(vault_seeds, ctx.program_id);
94
95 let ephemeral_signer_bumps: Vec<u8> = (0..args.ephemeral_signers)
96 .map(|ephemeral_signer_index| {
97 let ephemeral_signer_seeds = &[
98 SEED_PREFIX,
99 transaction_key.as_ref(),
100 SEED_EPHEMERAL_SIGNER,
101 &ephemeral_signer_index.to_le_bytes(),
102 ];
103
104 let (_, bump) =
105 Pubkey::find_program_address(ephemeral_signer_seeds, ctx.program_id);
106 bump
107 })
108 .collect();
109
110 let transaction_index = multisig.transaction_index.checked_add(1).unwrap();
112
113 transaction.multisig = multisig_key;
115 transaction.creator = creator.key();
116 transaction.index = transaction_index;
117 transaction.bump = ctx.bumps.transaction;
118 transaction.vault_index = args.vault_index;
119 transaction.vault_bump = vault_bump;
120 transaction.ephemeral_signer_bumps = ephemeral_signer_bumps;
121 transaction.message = transaction_message.try_into()?;
122
123 multisig.transaction_index = transaction_index;
125
126 multisig.invariant()?;
127
128 msg!("transaction index: {}", transaction_index);
130
131 Ok(())
132 }
133}
134
135#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
137pub struct TransactionMessage {
138 pub num_signers: u8,
140 pub num_writable_signers: u8,
142 pub num_writable_non_signers: u8,
144 pub account_keys: SmallVec<u8, Pubkey>,
146 pub instructions: SmallVec<u8, CompiledInstruction>,
148 pub address_table_lookups: SmallVec<u8, MessageAddressTableLookup>,
151}
152
153#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
155pub struct CompiledInstruction {
156 pub program_id_index: u8,
157 pub account_indexes: SmallVec<u8, u8>,
159 pub data: SmallVec<u16, u8>,
161}
162
163#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
166pub struct MessageAddressTableLookup {
167 pub account_key: Pubkey,
169 pub writable_indexes: SmallVec<u8, u8>,
171 pub readonly_indexes: SmallVec<u8, u8>,
173}