refactor(amm)!: derive pool active state from LP supply instead of explicit flag

Remove the `active: bool` field from `PoolDefinition` and replace it with an
implicit invariant: a pool is considered active when
`liquidity_pool_supply >= MINIMUM_LIQUIDITY`.

BREAKING CHANGE: `PoolDefinition` Borsh serialization format has changed.
Existing on-chain pool accounts encoded with the `active` field are
incompatible with this version.

Closes #25
This commit is contained in:
Ricardo Guilherme Schmidt 2026-04-10 15:43:13 -03:00 committed by r4bbit
parent 94f14ae305
commit 4a9a441ccd
8 changed files with 96 additions and 137 deletions

View File

@ -15,7 +15,7 @@ const LP_LOCK_HOLDING_PDA_SEED: [u8; 32] = [1; 32];
/// AMM Program Instruction.
#[derive(Serialize, Deserialize)]
pub enum Instruction {
/// Initializes a new Pool (or re-initializes an inactive Pool).
/// Initializes a new Pool (or re-initializes an existing zero-supply Pool).
///
/// On initialization, `MINIMUM_LIQUIDITY` LP tokens are permanently locked
/// in the LP-lock holding PDA; the caller receives `initial_lp - MINIMUM_LIQUIDITY`.
@ -104,7 +104,7 @@ pub enum Instruction {
/// Sync pool reserves with current vault balances.
///
/// Required accounts:
/// - AMM Pool (initialized, active)
/// - AMM Pool (initialized, with LP supply at or above minimum liquidity)
/// - Vault Holding Account for Token A (initialized)
/// - Vault Holding Account for Token B (initialized)
SyncReserves,
@ -119,19 +119,13 @@ pub struct PoolDefinition {
pub vault_a_id: AccountId,
pub vault_b_id: AccountId,
pub liquidity_pool_id: AccountId,
/// Total LP supply tracked by the pool. After initialization it includes the permanently
/// locked `MINIMUM_LIQUIDITY`; a zero supply means the pool is uninitialized
pub liquidity_pool_supply: u128,
pub reserve_a: u128,
pub reserve_b: u128,
/// Fee tier in basis points.
pub fees: u128,
/// Indicates whether the pool is initialized for use.
/// `MINIMUM_LIQUIDITY` LP tokens are permanently locked at initialization
/// and cannot be removed, so `liquidity_pool_supply` will never drop below
/// `MINIMUM_LIQUIDITY` for pools created after the minimum-liquidity lock
/// was introduced. Reaching that floor does not by itself imply
/// `active = false`; pools may remain active with only the permanently
/// locked minimum liquidity remaining.
pub active: bool,
}
pub const FEE_BPS_DENOMINATOR: u128 = 10_000;

View File

@ -15,7 +15,7 @@ mod amm {
#[allow(unused_imports)]
use super::*;
/// Initializes a new Pool (or re-initializes an inactive Pool).
/// Initializes a new Pool (or re-initializes an existing zero-supply Pool).
#[instruction]
pub fn new_definition(
pool: AccountWithMetadata,

View File

@ -73,7 +73,7 @@ pub fn new_definition(
assert_supported_fee_tier(fees);
// TODO: return here
// Verify that Pool Account is not active
// A pool can only be initialized from a fresh account state.
let is_new_pool = pool.account == Account::default();
let pool_account_data = if is_new_pool {
PoolDefinition::default()
@ -82,16 +82,10 @@ pub fn new_definition(
.expect("AMM program expects a valid Pool account")
};
assert!(
!pool_account_data.active,
"Cannot initialize an active Pool Definition"
assert_eq!(
pool_account_data.liquidity_pool_supply, 0,
"Cannot initialize a Pool Definition with nonzero LP supply"
);
if !is_new_pool {
assert_eq!(
pool_account_data.liquidity_pool_supply, 0,
"New definition: inactive Pool Definition must have zero LP supply before reinitialization"
);
}
// LP Token minting calculation
let initial_lp = token_a_amount
@ -117,11 +111,10 @@ pub fn new_definition(
reserve_a: token_a_amount.into(),
reserve_b: token_b_amount.into(),
fees,
active: true,
};
pool_post.data = Data::from(&pool_post_definition);
let pool_post: AccountPostState = if pool.account == Account::default() {
let pool_post: AccountPostState = if is_new_pool {
AccountPostState::new_claimed(pool_post.clone())
} else {
AccountPostState::new(pool_post.clone())

View File

@ -29,7 +29,10 @@ pub fn remove_liquidity(
.expect("Remove liquidity: AMM Program expects a valid Pool Definition Account");
assert_supported_fee_tier(pool_def_data.fees);
assert!(pool_def_data.active, "Pool is inactive");
assert!(
pool_def_data.liquidity_pool_supply >= MINIMUM_LIQUIDITY,
"Pool liquidity supply is below minimum liquidity"
);
assert_eq!(
pool_def_data.liquidity_pool_id, pool_definition_lp.account_id,
"LP definition mismatch"
@ -135,7 +138,6 @@ pub fn remove_liquidity(
.reserve_b
.checked_sub(withdraw_amount_b)
.expect("reserve_b - withdraw_amount_b underflows"),
active: true,
..pool_def_data.clone()
};

View File

@ -1,11 +1,11 @@
use amm_core::assert_supported_fee_tier;
use amm_core::{assert_supported_fee_tier, MINIMUM_LIQUIDITY};
pub use amm_core::{compute_liquidity_token_pda_seed, compute_vault_pda_seed, PoolDefinition};
use nssa_core::{
account::{AccountId, AccountWithMetadata, Data},
program::{AccountPostState, ChainedCall},
};
/// Validates swap setup: checks pool is active, vaults match, and reserves are sufficient.
/// Validates swap setup: checks pool liquidity is ready, vaults match, and reserves are sufficient.
fn validate_swap_setup(
pool: &AccountWithMetadata,
vault_a: &AccountWithMetadata,
@ -15,7 +15,10 @@ fn validate_swap_setup(
.expect("AMM Program expects a valid Pool Definition Account");
assert_supported_fee_tier(pool_def_data.fees);
assert!(pool_def_data.active, "Pool is inactive");
assert!(
pool_def_data.liquidity_pool_supply >= MINIMUM_LIQUIDITY,
"Pool liquidity supply is below minimum liquidity"
);
assert_eq!(
vault_a.account_id, pool_def_data.vault_a_id,
"Vault A was not provided"

View File

@ -1,4 +1,4 @@
use amm_core::{read_vault_fungible_balances, PoolDefinition};
use amm_core::{read_vault_fungible_balances, PoolDefinition, MINIMUM_LIQUIDITY};
use nssa_core::{
account::{AccountWithMetadata, Data},
program::{AccountPostState, ChainedCall},
@ -12,7 +12,10 @@ pub fn sync_reserves(
let pool_def_data = PoolDefinition::try_from(&pool.account.data)
.expect("Sync reserves: AMM Program expects a valid Pool Definition Account");
assert!(pool_def_data.active, "Pool is inactive");
assert!(
pool_def_data.liquidity_pool_supply >= MINIMUM_LIQUIDITY,
"Pool liquidity supply is below minimum liquidity"
);
assert_eq!(
vault_a.account_id, pool_def_data.vault_a_id,
"Vault A was not provided"

View File

@ -875,7 +875,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -903,7 +902,6 @@ impl AccountWithMetadataForTests {
reserve_a: 1_000,
reserve_b: 500,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -927,7 +925,6 @@ impl AccountWithMetadataForTests {
reserve_a: 0,
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -951,7 +948,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: 0,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -975,7 +971,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_low(),
reserve_b: BalanceForTests::vault_b_reserve_high(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -999,7 +994,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_high(),
reserve_b: BalanceForTests::vault_b_reserve_low(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1023,7 +1017,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_swap_test_1(),
reserve_b: BalanceForTests::vault_b_swap_test_1(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1047,7 +1040,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_swap_test_2(),
reserve_b: BalanceForTests::vault_b_swap_test_2(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1071,7 +1063,6 @@ impl AccountWithMetadataForTests {
reserve_a: 1498_u128,
reserve_b: 334_u128,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1095,7 +1086,6 @@ impl AccountWithMetadataForTests {
reserve_a: 715_u128,
reserve_b: 700_u128,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1119,7 +1109,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1143,7 +1132,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_add_successful(),
reserve_b: BalanceForTests::vault_b_add_successful(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1167,7 +1155,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_remove_successful(),
reserve_b: BalanceForTests::vault_b_remove_successful(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1176,7 +1163,7 @@ impl AccountWithMetadataForTests {
}
}
fn pool_definition_inactive() -> AccountWithMetadata {
fn pool_definition_below_minimum_liquidity() -> AccountWithMetadata {
AccountWithMetadata {
account: Account {
program_owner: ProgramId::default(),
@ -1187,11 +1174,10 @@ impl AccountWithMetadataForTests {
vault_a_id: IdForTests::vault_a_id(),
vault_b_id: IdForTests::vault_b_id(),
liquidity_pool_id: IdForTests::token_lp_definition_id(),
liquidity_pool_supply: BalanceForTests::lp_supply_init(),
liquidity_pool_supply: MINIMUM_LIQUIDITY - 1,
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: false,
}),
nonce: Nonce(0),
},
@ -1200,7 +1186,7 @@ impl AccountWithMetadataForTests {
}
}
fn pool_definition_reinitializable() -> AccountWithMetadata {
fn pool_definition_zero_supply_reinitializable() -> AccountWithMetadata {
AccountWithMetadata {
account: Account {
program_owner: ProgramId::default(),
@ -1215,7 +1201,6 @@ impl AccountWithMetadataForTests {
reserve_a: 0,
reserve_b: 0,
fees: 0u128,
active: false,
}),
nonce: Nonce(0),
},
@ -1239,7 +1224,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: false,
}),
nonce: Nonce(0),
},
@ -1280,30 +1264,6 @@ impl AccountWithMetadataForTests {
}
}
fn pool_definition_active() -> AccountWithMetadata {
AccountWithMetadata {
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: Data::from(&PoolDefinition {
definition_token_a_id: IdForTests::token_a_definition_id(),
definition_token_b_id: IdForTests::token_b_definition_id(),
vault_a_id: IdForTests::vault_a_id(),
vault_b_id: IdForTests::vault_b_id(),
liquidity_pool_id: IdForTests::token_lp_definition_id(),
liquidity_pool_supply: BalanceForTests::lp_supply_init(),
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
is_authorized: true,
account_id: IdForTests::pool_definition_id(),
}
}
/// Legacy/corrupted pool state whose reported supply has already been drained down to the
/// permanent lock (liquidity_pool_supply == MINIMUM_LIQUIDITY).
fn pool_definition_at_minimum_liquidity() -> AccountWithMetadata {
@ -1321,7 +1281,6 @@ impl AccountWithMetadataForTests {
reserve_a: BalanceForTests::vault_a_reserve_init(),
reserve_b: BalanceForTests::vault_b_reserve_init(),
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -1944,11 +1903,11 @@ fn test_call_new_definition_wrong_vault_id_2() {
);
}
#[should_panic(expected = "Cannot initialize an active Pool Definition")]
#[should_panic(expected = "Cannot initialize a Pool Definition with nonzero LP supply")]
#[test]
fn test_call_new_definition_cannot_initialize_active_pool() {
fn test_call_new_definition_cannot_initialize_nonzero_supply_pool() {
let _post_states = new_definition(
AccountWithMetadataForTests::pool_definition_active(),
AccountWithMetadataForTests::pool_definition_init(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_init(),
@ -1968,7 +1927,7 @@ fn test_call_new_definition_cannot_initialize_active_pool() {
fn test_call_new_definition_initial_lp_too_small() {
// isqrt(1000 * 1000) = 1000 == MINIMUM_LIQUIDITY, so the assertion fires.
let _post_states = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -1986,7 +1945,7 @@ fn test_call_new_definition_initial_lp_too_small() {
#[test]
fn test_call_new_definition_chained_call_successful() {
let (post_states, chained_calls) = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -2090,11 +2049,11 @@ fn test_call_swap_reserves_vault_mismatch_2() {
);
}
#[should_panic(expected = "Pool is inactive")]
#[should_panic(expected = "Pool liquidity supply is below minimum liquidity")]
#[test]
fn test_call_swap_ianctive() {
fn test_call_swap_below_minimum_liquidity() {
let _post_states = swap_exact_input(
AccountWithMetadataForTests::pool_definition_inactive(),
AccountWithMetadataForTests::pool_definition_below_minimum_liquidity(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::user_holding_a(),
@ -2279,11 +2238,11 @@ fn call_swap_exact_output_reserves_vault_mismatch_2() {
);
}
#[should_panic(expected = "Pool is inactive")]
#[should_panic(expected = "Pool liquidity supply is below minimum liquidity")]
#[test]
fn call_swap_exact_output_inactive() {
fn call_swap_exact_output_below_minimum_liquidity() {
let _post_states = swap_exact_output(
AccountWithMetadataForTests::pool_definition_inactive(),
AccountWithMetadataForTests::pool_definition_below_minimum_liquidity(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::user_holding_a(),
@ -2426,11 +2385,10 @@ fn swap_exact_output_overflow_protection() {
vault_a_id: IdForTests::vault_a_id(),
vault_b_id: IdForTests::vault_b_id(),
liquidity_pool_id: IdForTests::token_lp_definition_id(),
liquidity_pool_supply: 1,
liquidity_pool_supply: MINIMUM_LIQUIDITY,
reserve_a: large_reserve,
reserve_b,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -2482,7 +2440,7 @@ fn swap_exact_output_overflow_protection() {
#[test]
fn test_new_definition_lp_asymmetric_amounts() {
let (post_states, chained_calls) = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -2519,7 +2477,7 @@ fn test_new_definition_lp_symmetric_amounts() {
assert_eq!(expected_lp, 2_000);
let (post_states, chained_calls) = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -2574,13 +2532,11 @@ fn test_new_definition_lp_symmetric_amounts() {
assert_eq!(chained_call_lp_user, expected_lp_user_call);
}
#[should_panic(
expected = "New definition: inactive Pool Definition must have zero LP supply before reinitialization"
)]
#[should_panic(expected = "Cannot initialize a Pool Definition with nonzero LP supply")]
#[test]
fn test_call_new_definition_reinitialization_requires_zero_pool_supply() {
let _post_states = new_definition(
AccountWithMetadataForTests::pool_definition_inactive(),
AccountWithMetadataForTests::pool_definition_init(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -2601,7 +2557,7 @@ fn test_call_new_definition_reinitialization_requires_zero_pool_supply() {
#[test]
fn test_call_new_definition_reinitialization_requires_zero_lp_definition_supply() {
let _post_states = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_init(),
@ -2702,7 +2658,6 @@ fn test_minimum_liquidity_lock_and_remove_all_user_lp() {
assert_eq!(pool_after_remove.liquidity_pool_supply, MINIMUM_LIQUIDITY);
assert!(pool_after_remove.reserve_a > 0);
assert!(pool_after_remove.reserve_b > 0);
assert!(pool_after_remove.active);
}
#[test]
@ -2754,6 +2709,16 @@ fn test_sync_reserves_panics_when_vault_b_under_collateralized() {
);
}
#[should_panic(expected = "Pool liquidity supply is below minimum liquidity")]
#[test]
fn test_sync_reserves_rejects_pool_below_minimum_liquidity() {
let _ = sync_reserves(
AccountWithMetadataForTests::pool_definition_below_minimum_liquidity(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
);
}
#[test]
fn test_donation_then_add_liquidity_sync_mitigates_mispricing() {
let donation_a = 100u128;
@ -2822,7 +2787,7 @@ fn new_definition_overflow_protection() {
let large_amount = u128::MAX / 2 + 1;
let _result = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -2853,11 +2818,10 @@ fn add_liquidity_overflow_protection() {
vault_a_id: IdForTests::vault_a_id(),
vault_b_id: IdForTests::vault_b_id(),
liquidity_pool_id: IdForTests::token_lp_definition_id(),
liquidity_pool_supply: 1_000,
liquidity_pool_supply: MINIMUM_LIQUIDITY,
reserve_a: large_reserve,
reserve_b,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -2928,7 +2892,6 @@ fn remove_liquidity_overflow_protection() {
reserve_a: large_reserve,
reserve_b,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -3008,11 +2971,10 @@ fn swap_exact_input_overflow_protection() {
vault_a_id: IdForTests::vault_a_id(),
vault_b_id: IdForTests::vault_b_id(),
liquidity_pool_id: IdForTests::token_lp_definition_id(),
liquidity_pool_supply: 1,
liquidity_pool_supply: MINIMUM_LIQUIDITY,
reserve_a: 1_000,
reserve_b: large_reserve,
fees: BalanceForTests::fee_tier(),
active: true,
}),
nonce: Nonce(0),
},
@ -3071,7 +3033,7 @@ fn test_new_definition_supports_all_fee_tiers() {
FEE_TIER_BPS_100,
] {
let (post_states, _) = new_definition(
AccountWithMetadataForTests::pool_definition_reinitializable(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
@ -3095,10 +3057,10 @@ fn test_new_definition_supports_all_fee_tiers() {
#[test]
fn test_new_definition_rejects_unsupported_fee_tier() {
let _ = new_definition(
AccountWithMetadataForTests::pool_definition_inactive(),
AccountWithMetadataForTests::pool_definition_zero_supply_reinitializable(),
AccountWithMetadataForTests::vault_a_init(),
AccountWithMetadataForTests::vault_b_init(),
AccountWithMetadataForTests::pool_lp_init(),
AccountWithMetadataForTests::pool_lp_reinitializable(),
AccountWithMetadataForTests::lp_lock_holding_uninit(),
AccountWithMetadataForTests::user_holding_a(),
AccountWithMetadataForTests::user_holding_b(),

View File

@ -300,7 +300,6 @@ impl Accounts {
reserve_a: Balances::vault_a_init(),
reserve_b: Balances::vault_b_init(),
fees: Balances::fee_tier(),
active: true,
}),
nonce: Nonce(0),
}
@ -409,7 +408,6 @@ impl Accounts {
reserve_a: Balances::vault_a_swap_1(),
reserve_b: Balances::vault_b_swap_1(),
fees: Balances::fee_tier(),
active: true,
}),
nonce: Nonce(0),
}
@ -477,7 +475,6 @@ impl Accounts {
reserve_a: Balances::vault_a_swap_2(),
reserve_b: Balances::vault_b_swap_2(),
fees: Balances::fee_tier(),
active: true,
}),
nonce: Nonce(0),
}
@ -545,7 +542,6 @@ impl Accounts {
reserve_a: Balances::vault_a_add(),
reserve_b: Balances::vault_b_add(),
fees: Balances::fee_tier(),
active: true,
}),
nonce: Nonce(0),
}
@ -638,7 +634,6 @@ impl Accounts {
reserve_a: Balances::vault_a_remove(),
reserve_b: Balances::vault_b_remove(),
fees: Balances::fee_tier(),
active: true,
}),
nonce: Nonce(0),
}
@ -717,7 +712,7 @@ impl Accounts {
}
}
fn token_lp_definition_init_inactive() -> Account {
fn token_lp_definition_reinitializable() -> Account {
Account {
program_owner: Ids::token_program(),
balance: 0_u128,
@ -730,7 +725,7 @@ impl Accounts {
}
}
fn vault_a_init_inactive() -> Account {
fn vault_a_reinitializable() -> Account {
Account {
program_owner: Ids::token_program(),
balance: 0_u128,
@ -742,7 +737,7 @@ impl Accounts {
}
}
fn vault_b_init_inactive() -> Account {
fn vault_b_reinitializable() -> Account {
Account {
program_owner: Ids::token_program(),
balance: 0_u128,
@ -754,7 +749,7 @@ impl Accounts {
}
}
fn pool_definition_inactive() -> Account {
fn pool_definition_zero_supply_reinitializable() -> Account {
Account {
program_owner: Ids::amm_program(),
balance: 0_u128,
@ -768,7 +763,6 @@ impl Accounts {
reserve_a: 0,
reserve_b: 0,
fees: Balances::fee_tier(),
active: false,
}),
nonce: Nonce(0),
}
@ -849,7 +843,6 @@ impl Accounts {
reserve_a: Balances::vault_a_init(),
reserve_b: Balances::vault_b_init(),
fees: Balances::fee_tier(),
active: true,
}),
nonce: Nonce(0),
}
@ -1056,14 +1049,17 @@ fn amm_remove_liquidity_insufficient_user_lp_fails() {
}
#[test]
fn amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() {
fn amm_new_definition_zero_supply_initialized_pool_and_uninit_user_lp() {
let mut state = state_for_amm_tests_with_new_def();
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_init_inactive());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_init_inactive());
state.force_insert_account(Ids::pool_definition(), Accounts::pool_definition_inactive());
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
state.force_insert_account(
Ids::pool_definition(),
Accounts::pool_definition_zero_supply_reinitializable(),
);
state.force_insert_account(
Ids::token_lp_definition(),
Accounts::token_lp_definition_init_inactive(),
Accounts::token_lp_definition_reinitializable(),
);
execute_new_definition(&mut state, Balances::fee_tier());
@ -1103,14 +1099,17 @@ fn amm_new_definition_inactive_initialized_pool_and_uninit_user_lp() {
}
#[test]
fn amm_new_definition_inactive_initialized_pool_init_user_lp() {
fn amm_new_definition_zero_supply_initialized_pool_init_user_lp() {
let mut state = state_for_amm_tests_with_new_def();
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_init_inactive());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_init_inactive());
state.force_insert_account(Ids::pool_definition(), Accounts::pool_definition_inactive());
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
state.force_insert_account(
Ids::pool_definition(),
Accounts::pool_definition_zero_supply_reinitializable(),
);
state.force_insert_account(
Ids::token_lp_definition(),
Accounts::token_lp_definition_init_inactive(),
Accounts::token_lp_definition_reinitializable(),
);
state.force_insert_account(Ids::user_lp(), Accounts::user_lp_holding_init_zero());
@ -1153,8 +1152,8 @@ fn amm_new_definition_inactive_initialized_pool_init_user_lp() {
#[test]
fn amm_new_definition_uninitialized_pool() {
let mut state = state_for_amm_tests_with_new_def();
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_init_inactive());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_init_inactive());
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
execute_new_definition(&mut state, Balances::fee_tier());
@ -1201,8 +1200,8 @@ fn amm_new_definition_supports_all_fee_tiers() {
FEE_TIER_BPS_100,
] {
let mut state = state_for_amm_tests_with_new_def();
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_init_inactive());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_init_inactive());
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
execute_new_definition(&mut state, fees);
@ -1216,12 +1215,15 @@ fn amm_new_definition_supports_all_fee_tiers() {
#[test]
fn amm_new_definition_rejects_unsupported_fee_tier_transaction() {
let mut state = state_for_amm_tests_with_new_def();
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_init_inactive());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_init_inactive());
state.force_insert_account(Ids::pool_definition(), Accounts::pool_definition_inactive());
state.force_insert_account(Ids::vault_a(), Accounts::vault_a_reinitializable());
state.force_insert_account(Ids::vault_b(), Accounts::vault_b_reinitializable());
state.force_insert_account(
Ids::pool_definition(),
Accounts::pool_definition_zero_supply_reinitializable(),
);
state.force_insert_account(
Ids::token_lp_definition(),
Accounts::token_lp_definition_init_inactive(),
Accounts::token_lp_definition_reinitializable(),
);
state.force_insert_account(Ids::user_lp(), Accounts::user_lp_holding_init_zero());
@ -1230,19 +1232,19 @@ fn amm_new_definition_rejects_unsupported_fee_tier_transaction() {
assert!(matches!(result, Err(NssaError::ProgramExecutionFailed(_))));
assert_eq!(
state.get_account_by_id(Ids::pool_definition()),
Accounts::pool_definition_inactive()
Accounts::pool_definition_zero_supply_reinitializable()
);
assert_eq!(
state.get_account_by_id(Ids::vault_a()),
Accounts::vault_a_init_inactive()
Accounts::vault_a_reinitializable()
);
assert_eq!(
state.get_account_by_id(Ids::vault_b()),
Accounts::vault_b_init_inactive()
Accounts::vault_b_reinitializable()
);
assert_eq!(
state.get_account_by_id(Ids::token_lp_definition()),
Accounts::token_lp_definition_init_inactive()
Accounts::token_lp_definition_reinitializable()
);
assert_eq!(
state.get_account_by_id(Ids::user_a()),