Skip to content

Commit 3dfd69e

Browse files
authored
Splits adminApproveExecuteMultisigProposal into two instructions (#434)
1 parent f28e301 commit 3dfd69e

File tree

8 files changed

+558
-106
lines changed

8 files changed

+558
-106
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
use super::*;
2+
3+
mod admin {
4+
use anchor_lang::prelude::declare_id;
5+
6+
// MetaDAO-controlled admin - cannot be a Squads signer because of reentrancy
7+
declare_id!("CWGawadYU8CzRVBecnJymNw97H7E3ndDinV5sMzesgY2");
8+
}
9+
10+
#[derive(Accounts)]
11+
pub struct AdminApproveMultisigProposal<'info> {
12+
#[account(mut, has_one = squads_multisig)]
13+
pub dao: Account<'info, Dao>,
14+
#[account(mut)]
15+
pub admin: Signer<'info>,
16+
17+
#[account(
18+
mut,
19+
seeds = [
20+
squads_multisig_program::SEED_PREFIX,
21+
squads_multisig_program::SEED_MULTISIG,
22+
dao.key().as_ref(),
23+
],
24+
bump,
25+
seeds::program = squads_multisig_program
26+
)]
27+
pub squads_multisig: Account<'info, squads_multisig_program::Multisig>,
28+
29+
#[account(
30+
mut,
31+
seeds = [
32+
squads_multisig_program::SEED_PREFIX,
33+
squads_multisig.key().as_ref(),
34+
squads_multisig_program::SEED_TRANSACTION,
35+
squads_multisig_vault_transaction.index.to_le_bytes().as_ref(),
36+
squads_multisig_program::SEED_PROPOSAL,
37+
],
38+
bump,
39+
seeds::program = squads_multisig_program
40+
)]
41+
pub squads_multisig_proposal: Account<'info, squads_multisig_program::Proposal>,
42+
43+
#[account(
44+
seeds = [
45+
squads_multisig_program::SEED_PREFIX,
46+
squads_multisig.key().as_ref(),
47+
squads_multisig_program::SEED_TRANSACTION,
48+
squads_multisig_vault_transaction.index.to_le_bytes().as_ref(),
49+
],
50+
bump,
51+
seeds::program = squads_multisig_program
52+
)]
53+
pub squads_multisig_vault_transaction:
54+
Account<'info, squads_multisig_program::VaultTransaction>,
55+
56+
pub squads_multisig_program:
57+
Program<'info, squads_multisig_program::program::SquadsMultisigProgram>,
58+
}
59+
60+
impl AdminApproveMultisigProposal<'_> {
61+
pub fn validate(&self) -> Result<()> {
62+
#[cfg(feature = "production")]
63+
require_keys_eq!(self.admin.key(), admin::ID, FutarchyError::InvalidAdmin);
64+
65+
if !matches!(self.dao.amm.state, PoolState::Spot { .. }) {
66+
return Err(FutarchyError::PoolNotInSpotState.into());
67+
}
68+
69+
Ok(())
70+
}
71+
72+
pub fn handle(ctx: Context<Self>) -> Result<()> {
73+
let Self {
74+
dao,
75+
admin: _,
76+
squads_multisig,
77+
squads_multisig_proposal,
78+
squads_multisig_vault_transaction: _,
79+
squads_multisig_program,
80+
} = ctx.accounts;
81+
82+
let dao_nonce = &dao.nonce.to_le_bytes();
83+
let dao_creator_key = &dao.dao_creator.as_ref();
84+
let dao_seeds = &[SEED_DAO, dao_creator_key, dao_nonce, &[dao.pda_bump]];
85+
let dao_signer = &[&dao_seeds[..]];
86+
87+
// Approve the proposal
88+
squads_multisig_program::cpi::proposal_approve(
89+
CpiContext::new_with_signer(
90+
squads_multisig_program.to_account_info(),
91+
squads_multisig_program::cpi::accounts::ProposalVote {
92+
proposal: squads_multisig_proposal.to_account_info(),
93+
multisig: squads_multisig.to_account_info(),
94+
member: dao.to_account_info(),
95+
},
96+
dao_signer,
97+
),
98+
squads_multisig_program::ProposalVoteArgs { memo: None },
99+
)?;
100+
101+
Ok(())
102+
}
103+
}

programs/futarchy/src/instructions/admin_approve_execute_multisig_proposal.rs renamed to programs/futarchy/src/instructions/admin_execute_multisig_proposal.rs

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
11
use super::*;
22

3-
pub mod admin {
3+
mod admin {
44
use anchor_lang::prelude::declare_id;
55

66
// MetaDAO-controlled admin - cannot be a Squads signer because of reentrancy
77
declare_id!("CWGawadYU8CzRVBecnJymNw97H7E3ndDinV5sMzesgY2");
88
}
99

1010
#[derive(Accounts)]
11-
#[event_cpi]
12-
pub struct AdminApproveExecuteMultisigProposal<'info> {
11+
pub struct AdminExecuteMultisigProposal<'info> {
1312
#[account(mut, has_one = squads_multisig)]
1413
pub dao: Account<'info, Dao>,
1514
#[account(mut)]
1615
pub admin: Signer<'info>,
1716

18-
/// CHECK: checked by futarchy program
19-
#[account(mut, seeds = [squads_multisig_program::SEED_PREFIX, squads_multisig_program::SEED_MULTISIG, dao.key().as_ref()], bump, seeds::program = squads_multisig_program)]
17+
#[account(
18+
mut,
19+
seeds = [
20+
squads_multisig_program::SEED_PREFIX,
21+
squads_multisig_program::SEED_MULTISIG,
22+
dao.key().as_ref(),
23+
],
24+
bump,
25+
seeds::program = squads_multisig_program
26+
)]
2027
pub squads_multisig: Account<'info, squads_multisig_program::Multisig>,
21-
/// CHECK: squads proposal, initialized by squads multisig program, checked by squads multisig program
28+
2229
#[account(
2330
mut,
2431
seeds = [
@@ -32,7 +39,7 @@ pub struct AdminApproveExecuteMultisigProposal<'info> {
3239
seeds::program = squads_multisig_program
3340
)]
3441
pub squads_multisig_proposal: Account<'info, squads_multisig_program::Proposal>,
35-
/// CHECK: squads vault transaction, initialized by squads multisig program, checked by squads multisig program
42+
3643
#[account(
3744
mut,
3845
seeds = [
@@ -51,7 +58,7 @@ pub struct AdminApproveExecuteMultisigProposal<'info> {
5158
Program<'info, squads_multisig_program::program::SquadsMultisigProgram>,
5259
}
5360

54-
impl<'info, 'c: 'info> AdminApproveExecuteMultisigProposal<'info> {
61+
impl<'info, 'c: 'info> AdminExecuteMultisigProposal<'info> {
5562
pub fn validate(&self) -> Result<()> {
5663
#[cfg(feature = "production")]
5764
require_keys_eq!(self.admin.key(), admin::ID, FutarchyError::InvalidAdmin);
@@ -71,29 +78,13 @@ impl<'info, 'c: 'info> AdminApproveExecuteMultisigProposal<'info> {
7178
squads_multisig_proposal,
7279
squads_multisig_vault_transaction,
7380
squads_multisig_program,
74-
event_authority: _,
75-
program: _,
7681
} = ctx.accounts;
7782

7883
let dao_nonce = &dao.nonce.to_le_bytes();
7984
let dao_creator_key = &dao.dao_creator.as_ref();
8085
let dao_seeds = &[SEED_DAO, dao_creator_key, dao_nonce, &[dao.pda_bump]];
8186
let dao_signer = &[&dao_seeds[..]];
8287

83-
// Approve the proposal
84-
squads_multisig_program::cpi::proposal_approve(
85-
CpiContext::new_with_signer(
86-
squads_multisig_program.to_account_info(),
87-
squads_multisig_program::cpi::accounts::ProposalVote {
88-
proposal: squads_multisig_proposal.to_account_info(),
89-
multisig: squads_multisig.to_account_info(),
90-
member: dao.to_account_info(),
91-
},
92-
dao_signer,
93-
),
94-
squads_multisig_program::ProposalVoteArgs { memo: None },
95-
)?;
96-
9788
// Execute the vault transaction
9889
squads_multisig_program::cpi::vault_transaction_execute(
9990
CpiContext::new_with_signer(

programs/futarchy/src/instructions/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use super::*;
22

3-
pub mod admin_approve_execute_multisig_proposal;
3+
pub mod admin_approve_multisig_proposal;
44
pub mod admin_cancel_proposal;
5+
pub mod admin_execute_multisig_proposal;
56
pub mod admin_remove_proposal;
67
pub mod collect_fees;
78
pub mod collect_meteora_damm_fees;
@@ -19,8 +20,9 @@ pub mod unstake_from_proposal;
1920
pub mod update_dao;
2021
pub mod withdraw_liquidity;
2122

22-
pub use admin_approve_execute_multisig_proposal::*;
23+
pub use admin_approve_multisig_proposal::*;
2324
pub use admin_cancel_proposal::*;
25+
pub use admin_execute_multisig_proposal::*;
2426
pub use admin_remove_proposal::*;
2527
pub use collect_fees::*;
2628
pub use collect_meteora_damm_fees::*;

programs/futarchy/src/lib.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,17 @@ pub mod futarchy {
151151
}
152152

153153
#[access_control(ctx.accounts.validate())]
154-
pub fn admin_approve_execute_multisig_proposal<'c: 'info, 'info>(
155-
ctx: Context<'_, '_, 'c, 'info, AdminApproveExecuteMultisigProposal<'info>>,
154+
pub fn admin_approve_multisig_proposal(
155+
ctx: Context<AdminApproveMultisigProposal>,
156156
) -> Result<()> {
157-
AdminApproveExecuteMultisigProposal::handle(ctx)
157+
AdminApproveMultisigProposal::handle(ctx)
158+
}
159+
160+
#[access_control(ctx.accounts.validate())]
161+
pub fn admin_execute_multisig_proposal<'c: 'info, 'info>(
162+
ctx: Context<'_, '_, 'c, 'info, AdminExecuteMultisigProposal<'info>>,
163+
) -> Result<()> {
164+
AdminExecuteMultisigProposal::handle(ctx)
158165
}
159166

160167
#[access_control(ctx.accounts.validate())]

sdk/src/v0.7/types/futarchy.ts

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,7 +1186,7 @@ export type Futarchy = {
11861186
args: [];
11871187
},
11881188
{
1189-
name: "adminApproveExecuteMultisigProposal";
1189+
name: "adminApproveMultisigProposal";
11901190
accounts: [
11911191
{
11921192
name: "dao";
@@ -1210,21 +1210,47 @@ export type Futarchy = {
12101210
},
12111211
{
12121212
name: "squadsMultisigVaultTransaction";
1213-
isMut: true;
1213+
isMut: false;
12141214
isSigner: false;
12151215
},
12161216
{
12171217
name: "squadsMultisigProgram";
12181218
isMut: false;
12191219
isSigner: false;
12201220
},
1221+
];
1222+
args: [];
1223+
},
1224+
{
1225+
name: "adminExecuteMultisigProposal";
1226+
accounts: [
12211227
{
1222-
name: "eventAuthority";
1223-
isMut: false;
1228+
name: "dao";
1229+
isMut: true;
12241230
isSigner: false;
12251231
},
12261232
{
1227-
name: "program";
1233+
name: "admin";
1234+
isMut: true;
1235+
isSigner: true;
1236+
},
1237+
{
1238+
name: "squadsMultisig";
1239+
isMut: true;
1240+
isSigner: false;
1241+
},
1242+
{
1243+
name: "squadsMultisigProposal";
1244+
isMut: true;
1245+
isSigner: false;
1246+
},
1247+
{
1248+
name: "squadsMultisigVaultTransaction";
1249+
isMut: true;
1250+
isSigner: false;
1251+
},
1252+
{
1253+
name: "squadsMultisigProgram";
12281254
isMut: false;
12291255
isSigner: false;
12301256
},
@@ -4449,7 +4475,7 @@ export const IDL: Futarchy = {
44494475
args: [],
44504476
},
44514477
{
4452-
name: "adminApproveExecuteMultisigProposal",
4478+
name: "adminApproveMultisigProposal",
44534479
accounts: [
44544480
{
44554481
name: "dao",
@@ -4473,21 +4499,47 @@ export const IDL: Futarchy = {
44734499
},
44744500
{
44754501
name: "squadsMultisigVaultTransaction",
4476-
isMut: true,
4502+
isMut: false,
44774503
isSigner: false,
44784504
},
44794505
{
44804506
name: "squadsMultisigProgram",
44814507
isMut: false,
44824508
isSigner: false,
44834509
},
4510+
],
4511+
args: [],
4512+
},
4513+
{
4514+
name: "adminExecuteMultisigProposal",
4515+
accounts: [
44844516
{
4485-
name: "eventAuthority",
4486-
isMut: false,
4517+
name: "dao",
4518+
isMut: true,
44874519
isSigner: false,
44884520
},
44894521
{
4490-
name: "program",
4522+
name: "admin",
4523+
isMut: true,
4524+
isSigner: true,
4525+
},
4526+
{
4527+
name: "squadsMultisig",
4528+
isMut: true,
4529+
isSigner: false,
4530+
},
4531+
{
4532+
name: "squadsMultisigProposal",
4533+
isMut: true,
4534+
isSigner: false,
4535+
},
4536+
{
4537+
name: "squadsMultisigVaultTransaction",
4538+
isMut: true,
4539+
isSigner: false,
4540+
},
4541+
{
4542+
name: "squadsMultisigProgram",
44914543
isMut: false,
44924544
isSigner: false,
44934545
},

tests/futarchy/main.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import provideLiquidity from "./unit/provideLiquidity.test.js";
1313
import executeSpendingLimitChange from "./unit/executeSpendingLimitChange.test.js";
1414

1515
import collectMeteoraDammFees from "./unit/collectMeteoraDammFees.test.js";
16-
import adminApproveProposal from "./unit/adminApproveExecuteMultisigProposal.test.js";
16+
import adminApproveMultisigProposal from "./unit/adminApproveMultisigProposal.test.js";
17+
import adminExecuteMultisigProposal from "./unit/adminExecuteMultisigProposal.test.js";
1718
import adminCancelProposal from "./unit/adminCancelProposal.test.js";
1819
import adminRemoveProposal from "./unit/adminRemoveProposal.test.js";
1920

@@ -60,7 +61,8 @@ export default function suite() {
6061

6162
describe("#collect_meteora_damm_fees", collectMeteoraDammFees);
6263

63-
describe("#admin_approve_proposal", adminApproveProposal);
64+
describe("#admin_approve_multisig_proposal", adminApproveMultisigProposal);
65+
describe("#admin_execute_multisig_proposal", adminExecuteMultisigProposal);
6466
describe("#admin_cancel_proposal", adminCancelProposal);
6567
describe("#admin_remove_proposal", adminRemoveProposal);
6668
// describe("full proposal", fullProposal);

0 commit comments

Comments
 (0)