squads_multisig_program/instructions/
proposal_create.rs1use anchor_lang::prelude::*;
2
3use crate::errors::*;
4use crate::state::*;
5
6#[derive(AnchorSerialize, AnchorDeserialize)]
7pub struct ProposalCreateArgs {
8 pub transaction_index: u64,
10 pub draft: bool,
12}
13
14#[derive(Accounts)]
15#[instruction(args: ProposalCreateArgs)]
16pub struct ProposalCreate<'info> {
17 #[account(
18 seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
19 bump = multisig.bump,
20 )]
21 pub multisig: Account<'info, Multisig>,
22
23 #[account(
24 init,
25 payer = rent_payer,
26 space = Proposal::size(multisig.members.len()),
27 seeds = [
28 SEED_PREFIX,
29 multisig.key().as_ref(),
30 SEED_TRANSACTION,
31 &args.transaction_index.to_le_bytes(),
32 SEED_PROPOSAL,
33 ],
34 bump
35 )]
36 pub proposal: Account<'info, Proposal>,
37
38 pub creator: Signer<'info>,
40
41 #[account(mut)]
43 pub rent_payer: Signer<'info>,
44
45 pub system_program: Program<'info, System>,
46}
47
48impl ProposalCreate<'_> {
49 fn validate(&self, args: &ProposalCreateArgs) -> Result<()> {
50 let Self {
51 multisig, creator, ..
52 } = self;
53 let creator_key = creator.key();
54
55 require!(
58 args.transaction_index <= multisig.transaction_index,
59 MultisigError::InvalidTransactionIndex
60 );
61
62 require!(
64 args.transaction_index > multisig.stale_transaction_index,
65 MultisigError::StaleProposal
66 );
67
68 require!(
71 self.multisig.is_member(self.creator.key()).is_some(),
72 MultisigError::NotAMember
73 );
74
75 require!(
77 self.multisig
78 .member_has_permission(creator_key, Permission::Initiate)
79 || self
80 .multisig
81 .member_has_permission(creator_key, Permission::Vote),
82 MultisigError::Unauthorized
83 );
84
85 Ok(())
86 }
87
88 #[access_control(ctx.accounts.validate(&args))]
90 pub fn proposal_create(ctx: Context<Self>, args: ProposalCreateArgs) -> Result<()> {
91 let proposal = &mut ctx.accounts.proposal;
92
93 proposal.multisig = ctx.accounts.multisig.key();
94 proposal.transaction_index = args.transaction_index;
95 proposal.status = if args.draft {
96 ProposalStatus::Draft {
97 timestamp: Clock::get()?.unix_timestamp,
98 }
99 } else {
100 ProposalStatus::Active {
101 timestamp: Clock::get()?.unix_timestamp,
102 }
103 };
104 proposal.bump = ctx.bumps.proposal;
105 proposal.approved = vec![];
106 proposal.rejected = vec![];
107 proposal.cancelled = vec![];
108
109 Ok(())
110 }
111}