Skip to main content

squads_multisig_program/
lib.rs

1#![allow(clippy::result_large_err)]
2#![deny(arithmetic_overflow)]
3#![deny(unused_must_use)]
4// #![deny(clippy::arithmetic_side_effects)]
5// #![deny(clippy::integer_arithmetic)]
6
7// Re-export anchor_lang for convenience.
8pub use anchor_lang;
9use anchor_lang::prelude::*;
10#[cfg(not(feature = "no-entrypoint"))]
11use solana_security_txt::security_txt;
12
13pub use instructions::ProgramConfig;
14pub use instructions::*;
15pub use state::*;
16pub use utils::SmallVec;
17
18pub mod allocator;
19pub mod errors;
20pub mod instructions;
21pub mod state;
22mod utils;
23
24#[cfg(not(feature = "no-entrypoint"))]
25security_txt! {
26    name: "Nova Shield Multisig Program (Fork of Squads V4)",
27    project_url: "https://github.com/ceobitch/nova-multisig",
28    contacts: "email:hi@nshield.org",
29    policy: "https://github.com/ceobitch/nova-multisig/blob/main/security.txt",
30    preferred_languages: "en",
31    source_code: "https://github.com/ceobitch/nova-multisig",
32    auditors: "Original Squads V4: OtterSec, Neodyme, Certora, Trail of Bits"
33}
34
35#[cfg(not(feature = "testing"))]
36declare_id!("novabpN56UHHXTFRnJrwuaJaQqCoBeXupf8fsiFA2r2");
37
38#[cfg(feature = "testing")]
39declare_id!("GyhGAqjokLwF9UXdQ2dR5Zwiup242j4mX4J1tSMKyAmD");
40
41#[program]
42pub mod squads_multisig_program {
43    use errors::MultisigError;
44
45    use super::*;
46
47    /// Initialize the program config.
48    pub fn program_config_init(
49        ctx: Context<ProgramConfigInit>,
50        args: ProgramConfigInitArgs,
51    ) -> Result<()> {
52        ProgramConfigInit::program_config_init(ctx, args)
53    }
54
55    /// Set the `authority` parameter of the program config.
56    pub fn program_config_set_authority(
57        ctx: Context<ProgramConfig>,
58        args: ProgramConfigSetAuthorityArgs,
59    ) -> Result<()> {
60        ProgramConfig::program_config_set_authority(ctx, args)
61    }
62
63    /// Set the `multisig_creation_fee` parameter of the program config.
64    pub fn program_config_set_multisig_creation_fee(
65        ctx: Context<ProgramConfig>,
66        args: ProgramConfigSetMultisigCreationFeeArgs,
67    ) -> Result<()> {
68        ProgramConfig::program_config_set_multisig_creation_fee(ctx, args)
69    }
70
71    /// Set the `treasury` parameter of the program config.
72    pub fn program_config_set_treasury(
73        ctx: Context<ProgramConfig>,
74        args: ProgramConfigSetTreasuryArgs,
75    ) -> Result<()> {
76        ProgramConfig::program_config_set_treasury(ctx, args)
77    }
78
79    /// Create a multisig.
80    pub fn multisig_create(_ctx: Context<Deprecated>) -> Result<()> {
81        msg!("multisig_create has been deprecated. Use multisig_create_v2 instead.");
82        Err(MultisigError::MultisigCreateDeprecated.into())
83    }
84
85    /// Create a multisig.
86    pub fn multisig_create_v2(
87        ctx: Context<MultisigCreateV2>,
88        args: MultisigCreateArgsV2,
89    ) -> Result<()> {
90        MultisigCreateV2::multisig_create(ctx, args)
91    }
92
93    /// Add a new member to the controlled multisig.
94    pub fn multisig_add_member(
95        ctx: Context<MultisigConfig>,
96        args: MultisigAddMemberArgs,
97    ) -> Result<()> {
98        MultisigConfig::multisig_add_member(ctx, args)
99    }
100
101    /// Remove a member/key from the controlled multisig.
102    pub fn multisig_remove_member(
103        ctx: Context<MultisigConfig>,
104        args: MultisigRemoveMemberArgs,
105    ) -> Result<()> {
106        MultisigConfig::multisig_remove_member(ctx, args)
107    }
108
109    /// Set the `time_lock` config parameter for the controlled multisig.
110    pub fn multisig_set_time_lock(
111        ctx: Context<MultisigConfig>,
112        args: MultisigSetTimeLockArgs,
113    ) -> Result<()> {
114        MultisigConfig::multisig_set_time_lock(ctx, args)
115    }
116
117    /// Set the `threshold` config parameter for the controlled multisig.
118    pub fn multisig_change_threshold(
119        ctx: Context<MultisigConfig>,
120        args: MultisigChangeThresholdArgs,
121    ) -> Result<()> {
122        MultisigConfig::multisig_change_threshold(ctx, args)
123    }
124
125    /// Set the multisig `config_authority`.
126    pub fn multisig_set_config_authority(
127        ctx: Context<MultisigConfig>,
128        args: MultisigSetConfigAuthorityArgs,
129    ) -> Result<()> {
130        MultisigConfig::multisig_set_config_authority(ctx, args)
131    }
132
133    /// Set the multisig `rent_collector`.
134    pub fn multisig_set_rent_collector(
135        ctx: Context<MultisigConfig>,
136        args: MultisigSetRentCollectorArgs,
137    ) -> Result<()> {
138        MultisigConfig::multisig_set_rent_collector(ctx, args)
139    }
140
141    /// Create a new spending limit for the controlled multisig.
142    pub fn multisig_add_spending_limit(
143        ctx: Context<MultisigAddSpendingLimit>,
144        args: MultisigAddSpendingLimitArgs,
145    ) -> Result<()> {
146        MultisigAddSpendingLimit::multisig_add_spending_limit(ctx, args)
147    }
148
149    /// Remove the spending limit from the controlled multisig.
150    pub fn multisig_remove_spending_limit(
151        ctx: Context<MultisigRemoveSpendingLimit>,
152        args: MultisigRemoveSpendingLimitArgs,
153    ) -> Result<()> {
154        MultisigRemoveSpendingLimit::multisig_remove_spending_limit(ctx, args)
155    }
156
157    /// Create a new config transaction.
158    pub fn config_transaction_create(
159        ctx: Context<ConfigTransactionCreate>,
160        args: ConfigTransactionCreateArgs,
161    ) -> Result<()> {
162        ConfigTransactionCreate::config_transaction_create(ctx, args)
163    }
164
165    /// Execute a config transaction.
166    /// The transaction must be `Approved`.
167    pub fn config_transaction_execute<'info>(
168        ctx: Context<'_, '_, 'info, 'info, ConfigTransactionExecute<'info>>,
169    ) -> Result<()> {
170        ConfigTransactionExecute::config_transaction_execute(ctx)
171    }
172
173    /// Create a new vault transaction.
174    pub fn vault_transaction_create(
175        ctx: Context<VaultTransactionCreate>,
176        args: VaultTransactionCreateArgs,
177    ) -> Result<()> {
178        VaultTransactionCreate::vault_transaction_create(ctx, args)
179    }
180
181    /// Create a transaction buffer account.
182    pub fn transaction_buffer_create(
183        ctx: Context<TransactionBufferCreate>,
184        args: TransactionBufferCreateArgs,
185    ) -> Result<()> {
186        TransactionBufferCreate::transaction_buffer_create(ctx, args)
187    }
188
189    /// Close a transaction buffer account.
190    pub fn transaction_buffer_close(ctx: Context<TransactionBufferClose>) -> Result<()> {
191        TransactionBufferClose::transaction_buffer_close(ctx)
192    }
193
194    /// Extend a transaction buffer account.
195    pub fn transaction_buffer_extend(
196        ctx: Context<TransactionBufferExtend>,
197        args: TransactionBufferExtendArgs,
198    ) -> Result<()> {
199        TransactionBufferExtend::transaction_buffer_extend(ctx, args)
200    }
201
202    /// Create a new vault transaction from a completed transaction buffer.
203    /// Finalized buffer hash must match `final_buffer_hash`
204    pub fn vault_transaction_create_from_buffer<'info>(
205        ctx: Context<'_, '_, 'info, 'info, VaultTransactionCreateFromBuffer<'info>>,
206        args: VaultTransactionCreateArgs,
207    ) -> Result<()> {
208        VaultTransactionCreateFromBuffer::vault_transaction_create_from_buffer(ctx, args)
209    }
210
211    /// Execute a vault transaction.
212    /// The transaction must be `Approved`.
213    pub fn vault_transaction_execute(ctx: Context<VaultTransactionExecute>) -> Result<()> {
214        VaultTransactionExecute::vault_transaction_execute(ctx)
215    }
216
217    /// Create a new batch.
218    pub fn batch_create(ctx: Context<BatchCreate>, args: BatchCreateArgs) -> Result<()> {
219        BatchCreate::batch_create(ctx, args)
220    }
221
222    /// Add a transaction to the batch.
223    pub fn batch_add_transaction(
224        ctx: Context<BatchAddTransaction>,
225        args: BatchAddTransactionArgs,
226    ) -> Result<()> {
227        BatchAddTransaction::batch_add_transaction(ctx, args)
228    }
229
230    /// Execute a transaction from the batch.
231    pub fn batch_execute_transaction(ctx: Context<BatchExecuteTransaction>) -> Result<()> {
232        BatchExecuteTransaction::batch_execute_transaction(ctx)
233    }
234
235    /// Create a new multisig proposal.
236    pub fn proposal_create(ctx: Context<ProposalCreate>, args: ProposalCreateArgs) -> Result<()> {
237        ProposalCreate::proposal_create(ctx, args)
238    }
239
240    /// Update status of a multisig proposal from `Draft` to `Active`.
241    pub fn proposal_activate(ctx: Context<ProposalActivate>) -> Result<()> {
242        ProposalActivate::proposal_activate(ctx)
243    }
244
245    /// Approve a multisig proposal on behalf of the `member`.
246    /// The proposal must be `Active`.
247    pub fn proposal_approve(ctx: Context<ProposalVote>, args: ProposalVoteArgs) -> Result<()> {
248        ProposalVote::proposal_approve(ctx, args)
249    }
250
251    /// Reject a multisig proposal on behalf of the `member`.
252    /// The proposal must be `Active`.
253    pub fn proposal_reject(ctx: Context<ProposalVote>, args: ProposalVoteArgs) -> Result<()> {
254        ProposalVote::proposal_reject(ctx, args)
255    }
256
257    /// Cancel a multisig proposal on behalf of the `member`.
258    /// The proposal must be `Approved`.
259    pub fn proposal_cancel(ctx: Context<ProposalVote>, args: ProposalVoteArgs) -> Result<()> {
260        ProposalVote::proposal_cancel(ctx, args)
261    }
262
263    /// Cancel a multisig proposal on behalf of the `member`.
264    /// The proposal must be `Approved`.
265    /// This was introduced to incorporate proper state update, as old multisig members
266    /// may have lingering votes, and the proposal size may need to be reallocated to
267    /// accommodate the new amount of cancel votes.
268    /// The previous implemenation still works if the proposal size is in line with the
269    /// threshold size.
270    pub fn proposal_cancel_v2<'info>(
271        ctx: Context<'_, '_, 'info, 'info, ProposalCancelV2<'info>>,
272        args: ProposalVoteArgs,
273    ) -> Result<()> {
274        ProposalCancelV2::proposal_cancel_v2(ctx, args)
275    }
276
277    /// Use a spending limit to transfer tokens from a multisig vault to a destination account.
278    pub fn spending_limit_use(
279        ctx: Context<SpendingLimitUse>,
280        args: SpendingLimitUseArgs,
281    ) -> Result<()> {
282        SpendingLimitUse::spending_limit_use(ctx, args)
283    }
284
285    /// Closes a `ConfigTransaction` and the corresponding `Proposal`.
286    /// `transaction` can be closed if either:
287    /// - the `proposal` is in a terminal state: `Executed`, `Rejected`, or `Cancelled`.
288    /// - the `proposal` is stale.
289    pub fn config_transaction_accounts_close(
290        ctx: Context<ConfigTransactionAccountsClose>,
291    ) -> Result<()> {
292        ConfigTransactionAccountsClose::config_transaction_accounts_close(ctx)
293    }
294
295    /// Closes a `VaultTransaction` and the corresponding `Proposal`.
296    /// `transaction` can be closed if either:
297    /// - the `proposal` is in a terminal state: `Executed`, `Rejected`, or `Cancelled`.
298    /// - the `proposal` is stale and not `Approved`.
299    pub fn vault_transaction_accounts_close(
300        ctx: Context<VaultTransactionAccountsClose>,
301    ) -> Result<()> {
302        VaultTransactionAccountsClose::vault_transaction_accounts_close(ctx)
303    }
304
305    /// Closes a `VaultBatchTransaction` belonging to the `batch` and `proposal`.
306    /// `transaction` can be closed if either:
307    /// - it's marked as executed within the `batch`;
308    /// - the `proposal` is in a terminal state: `Executed`, `Rejected`, or `Cancelled`.
309    /// - the `proposal` is stale and not `Approved`.
310    pub fn vault_batch_transaction_account_close(
311        ctx: Context<VaultBatchTransactionAccountClose>,
312    ) -> Result<()> {
313        VaultBatchTransactionAccountClose::vault_batch_transaction_account_close(ctx)
314    }
315
316    /// Closes Batch and the corresponding Proposal accounts for proposals in terminal states:
317    /// `Executed`, `Rejected`, or `Cancelled` or stale proposals that aren't `Approved`.
318    ///
319    /// This instruction is only allowed to be executed when all `VaultBatchTransaction` accounts
320    /// in the `batch` are already closed: `batch.size == 0`.
321    pub fn batch_accounts_close(ctx: Context<BatchAccountsClose>) -> Result<()> {
322        BatchAccountsClose::batch_accounts_close(ctx)
323    }
324}