squads_multisig_program/instructions/
multisig_config.rs1use anchor_lang::prelude::*;
2
3use crate::errors::*;
4use crate::state::*;
5
6#[derive(AnchorSerialize, AnchorDeserialize)]
7pub struct MultisigAddMemberArgs {
8 pub new_member: Member,
9 pub memo: Option<String>,
11}
12
13#[derive(AnchorSerialize, AnchorDeserialize)]
14pub struct MultisigRemoveMemberArgs {
15 pub old_member: Pubkey,
16 pub memo: Option<String>,
18}
19
20#[derive(AnchorSerialize, AnchorDeserialize)]
21pub struct MultisigChangeThresholdArgs {
22 pub new_threshold: u16,
23 pub memo: Option<String>,
25}
26
27#[derive(AnchorSerialize, AnchorDeserialize)]
28pub struct MultisigSetTimeLockArgs {
29 pub time_lock: u32,
30 pub memo: Option<String>,
32}
33
34#[derive(AnchorSerialize, AnchorDeserialize)]
35pub struct MultisigSetConfigAuthorityArgs {
36 pub config_authority: Pubkey,
37 pub memo: Option<String>,
39}
40
41#[derive(AnchorSerialize, AnchorDeserialize)]
42pub struct MultisigSetRentCollectorArgs {
43 pub rent_collector: Option<Pubkey>,
44 pub memo: Option<String>,
46}
47
48#[derive(Accounts)]
49pub struct MultisigConfig<'info> {
50 #[account(
51 mut,
52 seeds = [SEED_PREFIX, SEED_MULTISIG, multisig.create_key.as_ref()],
53 bump = multisig.bump,
54 )]
55 multisig: Account<'info, Multisig>,
56
57 pub config_authority: Signer<'info>,
59
60 #[account(mut)]
64 pub rent_payer: Option<Signer<'info>>,
65
66 pub system_program: Option<Program<'info, System>>,
68}
69
70impl MultisigConfig<'_> {
71 fn validate(&self) -> Result<()> {
72 require_keys_eq!(
73 self.config_authority.key(),
74 self.multisig.config_authority,
75 MultisigError::Unauthorized
76 );
77
78 Ok(())
79 }
80
81 #[access_control(ctx.accounts.validate())]
86 pub fn multisig_add_member(ctx: Context<Self>, args: MultisigAddMemberArgs) -> Result<()> {
87 let MultisigAddMemberArgs { new_member, .. } = args;
88
89 let multisig = &mut ctx.accounts.multisig;
90
91 require!(
93 multisig.is_member(new_member.key).is_none(),
94 MultisigError::DuplicateMember
95 );
96
97 multisig.add_member(new_member);
98
99 Multisig::realloc_if_needed(
101 multisig.to_account_info(),
102 multisig.members.len(),
103 ctx.accounts
104 .rent_payer
105 .as_ref()
106 .map(ToAccountInfo::to_account_info),
107 ctx.accounts
108 .system_program
109 .as_ref()
110 .map(ToAccountInfo::to_account_info),
111 )?;
112
113 multisig.invalidate_prior_transactions();
114
115 multisig.invariant()?;
116
117 Ok(())
118 }
119
120 #[access_control(ctx.accounts.validate())]
125 pub fn multisig_remove_member(
126 ctx: Context<Self>,
127 args: MultisigRemoveMemberArgs,
128 ) -> Result<()> {
129 let multisig = &mut ctx.accounts.multisig;
130
131 require!(multisig.members.len() > 1, MultisigError::RemoveLastMember);
132
133 multisig.remove_member(args.old_member)?;
134
135 multisig.invalidate_prior_transactions();
136
137 multisig.invariant()?;
138
139 Ok(())
140 }
141
142 #[access_control(ctx.accounts.validate())]
145 pub fn multisig_change_threshold(
146 ctx: Context<Self>,
147 args: MultisigChangeThresholdArgs,
148 ) -> Result<()> {
149 let MultisigChangeThresholdArgs { new_threshold, .. } = args;
150
151 let multisig = &mut ctx.accounts.multisig;
152
153 multisig.threshold = new_threshold;
154
155 multisig.invalidate_prior_transactions();
156
157 multisig.invariant()?;
158
159 Ok(())
160 }
161
162 #[access_control(ctx.accounts.validate())]
167 pub fn multisig_set_time_lock(ctx: Context<Self>, args: MultisigSetTimeLockArgs) -> Result<()> {
168 let multisig = &mut ctx.accounts.multisig;
169
170 multisig.time_lock = args.time_lock;
171
172 multisig.invalidate_prior_transactions();
173
174 multisig.invariant()?;
175
176 Ok(())
177 }
178
179 #[access_control(ctx.accounts.validate())]
184 pub fn multisig_set_config_authority(
185 ctx: Context<Self>,
186 args: MultisigSetConfigAuthorityArgs,
187 ) -> Result<()> {
188 let multisig = &mut ctx.accounts.multisig;
189
190 multisig.config_authority = args.config_authority;
191
192 multisig.invalidate_prior_transactions();
193
194 multisig.invariant()?;
195
196 Ok(())
197 }
198
199 #[access_control(ctx.accounts.validate())]
204 pub fn multisig_set_rent_collector(
205 ctx: Context<Self>,
206 args: MultisigSetRentCollectorArgs,
207 ) -> Result<()> {
208 let multisig = &mut ctx.accounts.multisig;
209
210 multisig.rent_collector = args.rent_collector;
211
212 Multisig::realloc_if_needed(
214 multisig.to_account_info(),
215 multisig.members.len(),
216 ctx.accounts
217 .rent_payer
218 .as_ref()
219 .map(ToAccountInfo::to_account_info),
220 ctx.accounts
221 .system_program
222 .as_ref()
223 .map(ToAccountInfo::to_account_info),
224 )?;
225
226 multisig.invariant()?;
230
231 Ok(())
232 }
233}