Skip to content

Commit 554bd9b

Browse files
authored
Address feedback #2 (#419)
* close_bid_wall should return funds to authority always * set bid wall fee recipient to metadao multisig vault everywhere * add min_amount_out to bid wall sell instruction * disallow zero output amount after fees * prevent LP position hijack/freeze * prevent supplying wrong multisig when initializing proposal * prevent overcharging by 1 atom in provide_liquidity * apply min_liquidity slippage parameter to both first and subsequent lp provisioning * replace unreachable with proper errors * change comment to point to correct implementation reference * prevent launch front-running by merging instructions into single transaction * remove MAX_PREMINE from launchpad v7 * Disallow oracle changes while in Unlocking state to prevent TWAP corruption. * adjust liquidity provision logic when position is a new account * When a Proposal is Rejected by the Market The Squads Proposal Should Be Closed * prevent dao parameters being upadted during active futarchy markets * split_tokens and merge_tokens should verify question is unresolved * bid wall quote amount debits rounding * minor rename * slight rename for internal consistency * ensure conditional liquidities are always greater than zero * ensure max_base_amount is a positive nonzero integer when providing liquidity * short-circuit arbitrage when it doesn't yield results * refactor seeds and invariants into constants * explicitly prevent silent truncation in pass thresholds * ensure max twap change is nonzero * rename variable & comments to reflect actual situation * disallow empty spending limit members and duplicate spending limit members * box dao account where applicable
1 parent 5ee596f commit 554bd9b

23 files changed

+104
-51
lines changed

programs/futarchy/src/instructions/admin_approve_execute_multisig_proposal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ impl<'info, 'c: 'info> AdminApproveExecuteMultisigProposal<'info> {
7777

7878
let dao_nonce = &dao.nonce.to_le_bytes();
7979
let dao_creator_key = &dao.dao_creator.as_ref();
80-
let dao_seeds = &[b"dao".as_ref(), dao_creator_key, dao_nonce, &[dao.pda_bump]];
80+
let dao_seeds = &[SEED_DAO, dao_creator_key, dao_nonce, &[dao.pda_bump]];
8181
let dao_signer = &[&dao_seeds[..]];
8282

8383
// Approve the proposal

programs/futarchy/src/instructions/collect_fees.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub mod metadao_admin {
1717
#[event_cpi]
1818
pub struct CollectFees<'info> {
1919
#[account(mut)]
20-
pub dao: Account<'info, Dao>,
20+
pub dao: Box<Account<'info, Dao>>,
2121
pub admin: Signer<'info>,
2222
#[account(mut, associated_token::mint = dao.base_mint, associated_token::authority = metadao_multisig_vault::ID)]
2323
pub base_token_account: Account<'info, TokenAccount>,
@@ -68,7 +68,7 @@ impl CollectFees<'_> {
6868
let dao_creator = dao.dao_creator;
6969
let nonce = dao.nonce.to_le_bytes();
7070
let signer_seeds = &[
71-
b"dao".as_ref(),
71+
SEED_DAO,
7272
dao_creator.as_ref(),
7373
nonce.as_ref(),
7474
&[dao.pda_bump],

programs/futarchy/src/instructions/collect_meteora_damm_fees.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ impl CollectMeteoraDammFees<'_> {
238238
let dao_nonce = &ctx.accounts.dao.nonce.to_le_bytes();
239239
let dao_creator_key = ctx.accounts.dao.dao_creator.as_ref();
240240
let dao_seeds = &[
241-
b"dao".as_ref(),
241+
SEED_DAO,
242242
dao_creator_key,
243243
dao_nonce,
244244
&[ctx.accounts.dao.pda_bump],

programs/futarchy/src/instructions/conditional_swap.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl ConditionalSwap<'_> {
166166
let dao_creator = dao.dao_creator;
167167
let nonce = dao.nonce.to_le_bytes();
168168
let signer_seeds = &[
169-
b"dao".as_ref(),
169+
SEED_DAO,
170170
dao_creator.as_ref(),
171171
nonce.as_ref(),
172172
&[dao.pda_bump],

programs/futarchy/src/instructions/execute_spending_limit_change.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl<'info, 'c: 'info> ExecuteSpendingLimitChange<'info> {
7373

7474
let dao_nonce = &dao.nonce.to_le_bytes();
7575
let dao_creator_key = &dao.dao_creator.as_ref();
76-
let dao_seeds = &[b"dao".as_ref(), dao_creator_key, dao_nonce, &[dao.pda_bump]];
76+
let dao_seeds = &[SEED_DAO, dao_creator_key, dao_nonce, &[dao.pda_bump]];
7777
let dao_signer = &[&dao_seeds[..]];
7878

7979
squads_multisig_program::cpi::vault_transaction_execute(

programs/futarchy/src/instructions/finalize_proposal.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl FinalizeProposal<'_> {
109109

110110
let squads_proposal_key = squads_proposal.key();
111111
let proposal_seeds = &[
112-
b"proposal",
112+
SEED_PROPOSAL,
113113
squads_proposal_key.as_ref(),
114114
&[proposal.pda_bump],
115115
];
@@ -142,7 +142,8 @@ impl FinalizeProposal<'_> {
142142
let threshold_bps = if proposal.is_team_sponsored {
143143
dao.team_sponsored_pass_threshold_bps
144144
} else {
145-
dao.pass_threshold_bps as i16
145+
// Thanks to invariants this will never error - still it's better to be safe here.
146+
i16::try_from(dao.pass_threshold_bps).map_err(|_| FutarchyError::CastingOverflow)?
146147
};
147148

148149
// this can't overflow because each twap can only be MAX_PRICE (~1e31),
@@ -175,7 +176,7 @@ impl FinalizeProposal<'_> {
175176

176177
let dao_nonce = &dao.nonce.to_le_bytes();
177178
let dao_creator_key = &dao.dao_creator.as_ref();
178-
let dao_seeds = &[b"dao".as_ref(), dao_creator_key, dao_nonce, &[dao.pda_bump]];
179+
let dao_seeds = &[SEED_DAO, dao_creator_key, dao_nonce, &[dao.pda_bump]];
179180
let dao_signer = &[&dao_seeds[..]];
180181

181182
if new_proposal_state == ProposalState::Passed {

programs/futarchy/src/instructions/initialize_dao.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub struct InitializeDao<'info> {
2727
#[account(
2828
init,
2929
payer = payer,
30-
seeds = [b"dao", dao_creator.key().as_ref(), params.nonce.to_le_bytes().as_ref()],
30+
seeds = [SEED_DAO, dao_creator.key().as_ref(), params.nonce.to_le_bytes().as_ref()],
3131
bump,
3232
space = 8 + Dao::INIT_SPACE,
3333
)]
@@ -90,7 +90,7 @@ impl InitializeDao<'_> {
9090

9191
let creator_key = ctx.accounts.dao_creator.key();
9292
let dao_seeds = &[
93-
b"dao".as_ref(),
93+
SEED_DAO,
9494
creator_key.as_ref(),
9595
&nonce.to_le_bytes(),
9696
&[ctx.bumps.dao],

programs/futarchy/src/instructions/initialize_proposal.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ pub struct InitializeProposal<'info> {
77
init,
88
payer = payer,
99
space = 8 + Proposal::INIT_SPACE,
10-
seeds = [b"proposal", squads_proposal.key().as_ref()],
10+
seeds = [SEED_PROPOSAL, squads_proposal.key().as_ref()],
1111
bump
1212
)]
1313
pub proposal: Box<Account<'info, Proposal>>,

programs/futarchy/src/instructions/launch_proposal.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ impl LaunchProposal<'_> {
105105
let base_to_lp = spot.base_reserves / 2;
106106
let quote_to_lp = spot.quote_reserves / 2;
107107

108+
// Prevent launching proposals with zero reserves, which would permanently
109+
// freeze the DAO (no swaps possible, finalize_proposal fails, no recovery path)
110+
require_gt!(base_to_lp, 0, FutarchyError::InsufficientLiquidity);
111+
require_gt!(quote_to_lp, 0, FutarchyError::InsufficientLiquidity);
112+
108113
spot.base_reserves -= base_to_lp;
109114
spot.quote_reserves -= quote_to_lp;
110115

programs/futarchy/src/instructions/provide_liquidity.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ pub struct ProvideLiquidity<'info> {
5050
#[account(
5151
init_if_needed,
5252
payer = payer,
53-
seeds = [b"amm_position", dao.key().as_ref(), params.position_authority.key().as_ref()],
53+
seeds = [SEED_AMM_POSITION, dao.key().as_ref(), params.position_authority.key().as_ref()],
5454
bump,
5555
space = 8 + AmmPosition::INIT_SPACE,
5656
)]
@@ -119,6 +119,7 @@ impl ProvideLiquidity<'_> {
119119
} else {
120120
// equivalent to $0.1 if the quote is USDC, here for rounding
121121
require_gte!(quote_amount, MIN_QUOTE_LIQUIDITY);
122+
require_gt!(max_base_amount, 0);
122123

123124
let base_amount = max_base_amount;
124125

0 commit comments

Comments
 (0)