3356 lines
160 KiB
Rust
Raw Normal View History

2025-11-14 20:59:42 -05:00
use nssa_core::{
account::{Account, AccountId, AccountWithMetadata, Data},
2025-12-07 20:34:26 -05:00
program::{ProgramId, ProgramInput, ChainedCall, AccountPostState, PdaSeed, read_nssa_inputs, write_nssa_outputs_with_chained_call},
2025-11-14 20:59:42 -05:00
};
// The AMM program has five functions (four directly accessible via instructions):
2025-11-20 21:02:18 -05:00
// 1. New AMM definition.
2025-11-14 20:59:42 -05:00
// Arguments to this function are:
2025-12-09 14:42:58 -05:00
// * Seven **default** accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, user_holding_a, user_holding_b, user_holding_lp].
2025-11-20 21:02:18 -05:00
// amm_pool is a default account that will initiate the amm definition account values
// vault_holding_a is a token holding account for token a
// vault_holding_b is a token holding account for token b
// pool_lp is a token holding account for the pool's lp token
2025-12-09 14:42:58 -05:00
// user_holding_a is a token holding account for token a
// user_holding_b is a token holding account for token b
2025-11-20 21:02:18 -05:00
// user_holding_lp is a token holding account for lp token
2025-12-09 14:42:58 -05:00
// * Requires authorization: user_holding_a, user_holding_b
// * An instruction data of 65-bytes, indicating the initial amm reserves' balances and token_program_id with
2025-11-14 20:59:42 -05:00
// the following layout:
2025-12-09 14:42:58 -05:00
// [0x00 || array of balances (little-endian 16 bytes) || AMM_PROGRAM_ID)]
2025-11-20 21:02:18 -05:00
// 2. Swap assets
2025-11-14 20:59:42 -05:00
// Arguments to this function are:
2025-12-09 14:42:58 -05:00
// * Five accounts: [amm_pool, vault_holding_1, vault_holding_2, user_holding_a, user_holding_b].
// * Requires authorization: user holding account associated to TOKEN_DEFINITION_ID (either user_holding_a or user_holding_b)
// * An instruction data byte string of length 49, indicating which token type to swap, quantity of tokens put into the swap
// (of type TOKEN_DEFINITION_ID) and min_amount_out.
2025-11-20 21:02:18 -05:00
// [0x01 || amount (little-endian 16 bytes) || TOKEN_DEFINITION_ID].
// 3. Add liquidity
// Arguments to this function are:
2025-12-09 14:42:58 -05:00
// * Seven accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, user_holding_a, UserHouser_holding_a, user_holding_lp].
// * Requires authorization: user_holding_a, user_holding_b
// * An instruction data byte string of length 49, amounts for minimum amount of liquidity from add (min_amount_lp),
// * max amount added for each token (max_amount_a and max_amount_b); indicate
// [0x02 || array of of balances (little-endian 16 bytes)].
2025-11-20 21:02:18 -05:00
// 4. Remove liquidity
2025-12-09 14:42:58 -05:00
// * Seven accounts: [amm_pool, vault_holding_a, vault_holding_b, pool_lp, user_holding_a, UserHouser_holding_a, user_holding_lp].
// * Requires authorization: user_holding_lp
// * An instruction data byte string of length 49, amounts for minimum amount of liquidity to redeem (balance_lp),
// * minimum balance of each token to remove (min_amount_a and min_amount_b); indicate
// [0x03 || array of balances (little-endian 16 bytes)].
// - Internal functions:
// - Swap logic
// Arguments of this function are:
// * Four accounts: [user_deposit_tx, vault_deposit_tx, vault_withdraw_tx, user_withdraw_tx].
// user_deposit_tx and vault_deposit_tx define deposit transaction.
// vault_withdraw_tx and user_withdraw_tx define withdraw transaction.
// * deposit_amount is the amount for user_deposit_tx -> vault_deposit_tx transfer.
// * reserve_amounts is the pool's reserves; used to compute the withdraw amount.
// * Outputs the token transfers as a Vec<ChainedCall> and the withdraw amount.
2025-12-09 14:42:58 -05:00
// - PDA computations:
// * compute_pool_pda: AMM_PROGRAM_ID, token definitions for the pool pair
// * compute_vault_pda: AMM_PROGRAM_ID, pool definition id, definition token id
// * compute_liquidity_token_pda: AMM_PROGRAM, pool definition id, pool definition id
// - PDA seed computations:
// * compute_pool_pda_seed: token definitions for the pool pair
// * compute_vault_pda_seed: pool definition id, definition token id,
// * compute_liquidity_token_pda_seed: pool definition id
2025-11-14 20:59:42 -05:00
2025-12-06 14:52:18 -05:00
const POOL_DEFINITION_DATA_SIZE: usize = 225;
2025-12-07 20:34:26 -05:00
#[derive(Default)]
2025-11-14 20:59:42 -05:00
struct PoolDefinition{
2025-12-02 15:20:16 -05:00
definition_token_a_id: AccountId,
definition_token_b_id: AccountId,
2025-12-08 22:05:51 -05:00
vault_a_id: AccountId,
vault_b_id: AccountId,
2025-11-14 20:59:42 -05:00
liquidity_pool_id: AccountId,
liquidity_pool_supply: u128,
2025-11-14 20:59:42 -05:00
reserve_a: u128,
reserve_b: u128,
2025-12-06 14:52:18 -05:00
fees: u128,
active: bool
2025-11-14 20:59:42 -05:00
}
impl PoolDefinition {
2025-12-15 18:55:38 -05:00
fn into_data(self) -> Data {
2025-11-14 20:59:42 -05:00
let mut bytes = [0; POOL_DEFINITION_DATA_SIZE];
bytes[0..32].copy_from_slice(&self.definition_token_a_id.to_bytes());
bytes[32..64].copy_from_slice(&self.definition_token_b_id.to_bytes());
2025-12-08 22:05:51 -05:00
bytes[64..96].copy_from_slice(&self.vault_a_id.to_bytes());
bytes[96..128].copy_from_slice(&self.vault_b_id.to_bytes());
2025-11-14 20:59:42 -05:00
bytes[128..160].copy_from_slice(&self.liquidity_pool_id.to_bytes());
bytes[160..176].copy_from_slice(&self.liquidity_pool_supply.to_le_bytes());
2025-11-14 20:59:42 -05:00
bytes[176..192].copy_from_slice(&self.reserve_a.to_le_bytes());
bytes[192..208].copy_from_slice(&self.reserve_b.to_le_bytes());
2025-12-06 14:52:18 -05:00
bytes[208..224].copy_from_slice(&self.fees.to_le_bytes());
bytes[224] = self.active as u8;
2025-12-15 18:55:38 -05:00
bytes
.to_vec()
.try_into()
.expect("225 bytes should fit into Data")
2025-11-14 20:59:42 -05:00
}
fn parse(data: &[u8]) -> Option<Self> {
if data.len() != POOL_DEFINITION_DATA_SIZE {
None
} else {
let definition_token_a_id = AccountId::new(data[0..32].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Token A definition"));
let definition_token_b_id = AccountId::new(data[32..64].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Vault B definition"));
2025-12-08 22:05:51 -05:00
let vault_a_id = AccountId::new(data[64..96].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Vault A"));
let vault_b_id = AccountId::new(data[96..128].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Vault B"));
let liquidity_pool_id = AccountId::new(data[128..160].try_into().expect("Parse data: The AMM program must be provided a valid AccountId for Token liquidity pool definition"));
let liquidity_pool_supply = u128::from_le_bytes(data[160..176].try_into().expect("Parse data: The AMM program must be provided a valid u128 for liquidity cap"));
let reserve_a = u128::from_le_bytes(data[176..192].try_into().expect("Parse data: The AMM program must be provided a valid u128 for reserve A balance"));
let reserve_b = u128::from_le_bytes(data[192..208].try_into().expect("Parse data: The AMM program must be provided a valid u128 for reserve B balance"));
2025-12-06 14:52:18 -05:00
let fees = u128::from_le_bytes(data[208..224].try_into().expect("Parse data: The AMM program must be provided a valid u128 for fees"));
let active = match data[224] {
0 => false,
1 => true,
_ => panic!("Parse data: The AMM program must be provided a valid bool for active"),
};
2025-11-14 20:59:42 -05:00
Some(Self {
definition_token_a_id,
definition_token_b_id,
2025-12-08 22:05:51 -05:00
vault_a_id,
vault_b_id,
2025-11-14 20:59:42 -05:00
liquidity_pool_id,
liquidity_pool_supply,
2025-11-14 20:59:42 -05:00
reserve_a,
reserve_b,
2025-12-06 14:52:18 -05:00
fees,
active,
2025-11-14 20:59:42 -05:00
})
}
}
}
//TODO: remove repeated code for Token_Definition and TokenHoldling
const TOKEN_DEFINITION_TYPE: u8 = 0;
const TOKEN_DEFINITION_DATA_SIZE: usize = 23;
2025-11-14 20:59:42 -05:00
const TOKEN_HOLDING_TYPE: u8 = 1;
const TOKEN_HOLDING_DATA_SIZE: usize = 49;
struct TokenDefinition {
account_type: u8,
name: [u8; 6],
total_supply: u128,
}
2025-11-14 20:59:42 -05:00
struct TokenHolding {
account_type: u8,
definition_id: AccountId,
balance: u128,
}
impl TokenDefinition {
2025-12-15 18:55:38 -05:00
fn into_data(self) -> Data {
let mut bytes = [0; TOKEN_DEFINITION_DATA_SIZE];
bytes[0] = self.account_type;
bytes[1..7].copy_from_slice(&self.name);
bytes[7..].copy_from_slice(&self.total_supply.to_le_bytes());
2025-12-15 18:55:38 -05:00
bytes
.to_vec()
.try_into()
.expect("23 bytes should fit into Data")
}
2025-12-15 18:55:38 -05:00
fn parse(data: &[u8]) -> Option<Self> {
if data.len() != TOKEN_DEFINITION_DATA_SIZE || data[0] != TOKEN_DEFINITION_TYPE {
None
} else {
let account_type = data[0];
let name = data[1..7].try_into().unwrap();
let total_supply = u128::from_le_bytes(
data[7..]
.try_into()
.expect("Total supply must be 16 bytes little-endian"),
);
Some(Self {
account_type,
name,
total_supply,
})
}
}
}
2025-11-14 20:59:42 -05:00
impl TokenHolding {
fn new(definition_id: &AccountId) -> Self {
Self {
account_type: TOKEN_HOLDING_TYPE,
definition_id: definition_id.clone(),
balance: 0,
}
}
2025-11-14 20:59:42 -05:00
fn parse(data: &[u8]) -> Option<Self> {
if data.len() != TOKEN_HOLDING_DATA_SIZE || data[0] != TOKEN_HOLDING_TYPE {
None
} else {
let account_type = data[0];
let definition_id = AccountId::new(
data[1..33]
.try_into()
.expect("Defintion ID must be 32 bytes long"),
);
let balance = u128::from_le_bytes(
data[33..]
.try_into()
.expect("balance must be 16 bytes little-endian"),
);
2025-11-14 20:59:42 -05:00
Some(Self {
definition_id,
balance,
account_type,
})
}
}
fn into_data(self) -> Data {
let mut bytes = [0; TOKEN_HOLDING_DATA_SIZE];
bytes[0] = self.account_type;
bytes[1..33].copy_from_slice(&self.definition_id.to_bytes());
bytes[33..].copy_from_slice(&self.balance.to_le_bytes());
2025-12-15 18:55:38 -05:00
bytes
.to_vec()
.try_into()
.expect("49 bytes should fit into Data")
2025-11-14 20:59:42 -05:00
}
}
2025-11-24 19:44:08 -05:00
2025-11-25 23:06:47 -05:00
type Instruction = Vec<u8>;
fn main() {
2025-12-15 18:55:38 -05:00
let (ProgramInput {
2025-11-25 23:06:47 -05:00
pre_states,
instruction,
2025-12-15 18:55:38 -05:00
}, instruction_words) = read_nssa_inputs::<Instruction>();
2025-11-25 23:06:47 -05:00
2025-12-07 20:34:26 -05:00
let (post_states, chained_calls) = match instruction[0] {
2025-11-25 23:06:47 -05:00
0 => {
let balance_a: u128 = u128::from_le_bytes(instruction[1..17].try_into().expect("New definition: AMM Program expects u128 for balance a"));
let balance_b: u128 = u128::from_le_bytes(instruction[17..33].try_into().expect("New definition: AMM Program expects u128 for balance b"));
2025-12-07 20:34:26 -05:00
2025-12-08 22:05:51 -05:00
// Convert Vec<u8> to ProgramId ([u32;8])
let mut amm_program_id: [u32;8] = [0;8];
amm_program_id[0] = u32::from_le_bytes(instruction[33..37].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[1] = u32::from_le_bytes(instruction[37..41].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[2] = u32::from_le_bytes(instruction[41..45].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[3] = u32::from_le_bytes(instruction[45..49].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[4] = u32::from_le_bytes(instruction[49..53].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[5] = u32::from_le_bytes(instruction[53..57].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[6] = u32::from_le_bytes(instruction[57..61].try_into().expect("New definition: AMM Program expects valid u32"));
amm_program_id[7] = u32::from_le_bytes(instruction[61..65].try_into().expect("New definition: AMM Program expects valid u32"));
new_definition(&pre_states, &[balance_a, balance_b], amm_program_id)
2025-11-25 23:06:47 -05:00
}
1 => {
2025-12-08 22:05:51 -05:00
let mut token_in_id: [u8;32] = [0;32];
token_in_id[0..].copy_from_slice(&instruction[33..65]);
let token_in_id = AccountId::new(token_in_id);
2025-11-25 23:06:47 -05:00
2025-12-06 14:52:18 -05:00
let amount_in = u128::from_le_bytes(instruction[1..17].try_into().expect("Swap: AMM Program expects valid u128 for balance to move"));
let min_amount_out = u128::from_le_bytes(instruction[17..33].try_into().expect("Swap: AMM Program expects valid u128 for balance to move"));
2025-11-25 23:06:47 -05:00
2025-12-08 22:05:51 -05:00
swap(&pre_states, &[amount_in, min_amount_out], token_in_id)
2025-11-25 23:06:47 -05:00
}
2 => {
2025-12-08 13:19:30 -05:00
let min_amount_lp = u128::from_le_bytes(instruction[1..17].try_into().expect("Add liquidity: AMM Program expects valid u128 for min amount liquidity"));
2025-12-06 14:52:18 -05:00
let max_amount_a = u128::from_le_bytes(instruction[17..33].try_into().expect("Add liquidity: AMM Program expects valid u128 for max amount a"));
let max_amount_b = u128::from_le_bytes(instruction[33..49].try_into().expect("Add liquidity: AMM Program expects valid u128 for max amount b"));
2025-12-07 20:34:26 -05:00
add_liquidity(&pre_states, &[min_amount_lp, max_amount_a, max_amount_b])
2025-11-25 23:06:47 -05:00
}
3 => {
let balance_lp = u128::from_le_bytes(instruction[1..17].try_into().expect("Remove liquidity: AMM Program expects valid u128 for balance liquidity"));
2025-12-08 13:19:30 -05:00
let min_amount_a = u128::from_le_bytes(instruction[17..33].try_into().expect("Remove liquidity: AMM Program expects valid u128 for balance a"));
let min_amount_b = u128::from_le_bytes(instruction[33..49].try_into().expect("Remove liquidity: AMM Program expects valid u128 for balance b"));
2025-12-08 13:19:30 -05:00
remove_liquidity(&pre_states, &[balance_lp, min_amount_a, min_amount_b])
2025-11-25 23:06:47 -05:00
}
_ => panic!("Invalid instruction"),
};
2025-11-14 20:59:42 -05:00
2025-12-15 18:55:38 -05:00
write_nssa_outputs_with_chained_call(instruction_words, pre_states, post_states, chained_calls);
2025-12-07 20:34:26 -05:00
}
2025-12-06 14:52:18 -05:00
2025-12-08 22:05:51 -05:00
fn compute_pool_pda(amm_program_id: ProgramId, definition_token_a_id: AccountId, definition_token_b_id: AccountId) -> AccountId {
AccountId::from((&amm_program_id,
&compute_pool_pda_seed(definition_token_a_id, definition_token_b_id)))
}
fn compute_pool_pda_seed(definition_token_a_id: AccountId, definition_token_b_id: AccountId) -> PdaSeed {
2025-12-07 20:34:26 -05:00
use risc0_zkvm::sha::{Impl, Sha256};
2025-12-08 22:05:51 -05:00
let mut i: usize = 0;
let (token_1, token_2) = loop {
if definition_token_a_id.value()[i] > definition_token_b_id.value()[i] {
let token_1 = definition_token_a_id.clone();
let token_2 = definition_token_b_id.clone();
break (token_1, token_2)
} else if definition_token_a_id.value()[i] < definition_token_b_id.value()[i] {
let token_1 = definition_token_b_id.clone();
let token_2 = definition_token_a_id.clone();
break (token_1, token_2)
}
if i == 32 {
panic!("Definitions match");
} else {
i += 1;
}
};
2025-12-08 13:19:30 -05:00
let mut bytes = [0; 64];
2025-12-08 22:05:51 -05:00
bytes[0..32].copy_from_slice(&token_1.to_bytes());
bytes[32..].copy_from_slice(&token_2.to_bytes());
PdaSeed::new(Impl::hash_bytes(&bytes).as_bytes().try_into().expect("Hash output must be exactly 32 bytes long"))
}
fn compute_vault_pda(amm_program_id: ProgramId,
pool_id: AccountId,
definition_token_id: AccountId
) -> AccountId {
AccountId::from((&amm_program_id,
&compute_vault_pda_seed(pool_id, definition_token_id)))
2025-12-07 20:34:26 -05:00
}
2025-12-06 14:52:18 -05:00
2025-12-08 22:05:51 -05:00
fn compute_vault_pda_seed(pool_id: AccountId,
definition_token_id: AccountId
) -> PdaSeed {
2025-12-07 20:34:26 -05:00
use risc0_zkvm::sha::{Impl, Sha256};
2025-12-08 13:19:30 -05:00
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&pool_id.to_bytes());
bytes[32..].copy_from_slice(&definition_token_id.to_bytes());
2025-12-06 14:52:18 -05:00
2025-12-08 13:19:30 -05:00
PdaSeed::new(Impl::hash_bytes(&bytes).as_bytes().try_into().expect("Hash output must be exactly 32 bytes long"))
2025-12-06 14:52:18 -05:00
}
2025-12-08 22:05:51 -05:00
fn compute_liquidity_token_pda(amm_program_id: ProgramId, pool_id: AccountId) -> AccountId {
AccountId::from((&amm_program_id,
&compute_liquidity_token_pda_seed(pool_id)))
}
fn compute_liquidity_token_pda_seed(pool_id: AccountId) -> PdaSeed {
use risc0_zkvm::sha::{Impl, Sha256};
let mut bytes = [0; 64];
bytes[0..32].copy_from_slice(&pool_id.to_bytes());
bytes[32..].copy_from_slice(&[0;32]);
PdaSeed::new(Impl::hash_bytes(&bytes).as_bytes().try_into().expect("Hash output must be exactly 32 bytes long"))
}
2025-12-07 20:34:26 -05:00
fn new_definition (
2025-11-14 20:59:42 -05:00
pre_states: &[AccountWithMetadata],
balance_in: &[u128],
2025-12-08 22:05:51 -05:00
amm_program_id: ProgramId,
2025-12-07 20:34:26 -05:00
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
2025-12-06 14:52:18 -05:00
2025-11-14 20:59:42 -05:00
//Pool accounts: pool itself, and its 2 vaults and LP token
//2 accounts for funding tokens
//initial funder's LP account
2025-12-07 20:34:26 -05:00
if pre_states.len() != 7 {
2025-11-18 14:43:40 -05:00
panic!("Invalid number of input accounts")
2025-11-14 20:59:42 -05:00
}
if balance_in.len() != 2 {
2025-12-07 20:34:26 -05:00
panic!("Invalid number of input balances")
2025-11-14 20:59:42 -05:00
}
2025-12-07 20:34:26 -05:00
let pool = &pre_states[0];
let vault_a = &pre_states[1];
let vault_b = &pre_states[2];
let pool_lp = &pre_states[3];
let user_holding_a = &pre_states[4];
let user_holding_b = &pre_states[5];
let user_holding_lp = &pre_states[6];
2025-11-14 20:59:42 -05:00
let amount_a = balance_in[0];
let amount_b = balance_in[1];
// Prevents pool constant coefficient (k) from being 0.
2025-11-18 14:43:40 -05:00
if amount_a == 0 || amount_b == 0 {
panic!("Balances must be nonzero")
}
2025-11-14 20:59:42 -05:00
// Verify token_a and token_b are different
2025-12-08 22:05:51 -05:00
let definition_token_a_id = TokenHolding::parse(&user_holding_a.account.data)
.expect("New definition: AMM Program expects valid Token Holding account for Token A").definition_id;
let definition_token_b_id = TokenHolding::parse(&user_holding_b.account.data)
.expect("New definition: AMM Program expects valid Token Holding account for Token B").definition_id;
// both instances of the same token program
2025-12-07 20:34:26 -05:00
let token_program = user_holding_a.account.program_owner;
2025-11-17 18:48:17 -05:00
if definition_token_a_id == definition_token_b_id {
2025-12-09 14:42:58 -05:00
panic!("Cannot set up a swap for a token with itself")
2025-11-17 18:48:17 -05:00
}
2025-12-08 22:05:51 -05:00
if pool.account_id != compute_pool_pda(amm_program_id.clone(),
definition_token_a_id.clone(),
definition_token_b_id.clone()) {
2025-12-07 20:34:26 -05:00
panic!("Pool Definition Account ID does not match PDA");
}
2025-12-08 22:05:51 -05:00
if vault_a.account_id != compute_vault_pda(amm_program_id.clone(),
pool.account_id.clone(),
definition_token_a_id.clone()) ||
vault_b.account_id != compute_vault_pda(amm_program_id.clone(),
pool.account_id.clone(),
definition_token_b_id.clone()) {
2025-12-07 20:34:26 -05:00
panic!("Vault ID does not match PDA");
}
2025-12-08 22:05:51 -05:00
if pool_lp.account_id != compute_liquidity_token_pda(amm_program_id.clone(),
pool.account_id.clone()) {
panic!("Liquidity pool Token Definition Account ID does not match PDA");
}
2025-12-07 20:34:26 -05:00
// Verify that Pool Account is not active
let pool_account_data = if pool.account == Account::default() {
PoolDefinition::default()
} else {
PoolDefinition::parse(&pool.account.data).expect("AMM program expects a valid Pool account")
};
2025-12-08 22:05:51 -05:00
if pool_account_data.active {
2025-12-07 20:34:26 -05:00
panic!("Cannot initialize an active Pool Definition")
2025-12-06 14:52:18 -05:00
}
2025-12-07 20:34:26 -05:00
//3. LP Token minting calculation
// We assume LP is based on the initial deposit amount for Token_A.
2025-12-06 14:52:18 -05:00
2025-11-14 20:59:42 -05:00
// 5. Update pool account
2025-12-09 14:42:58 -05:00
let mut pool_post = pool.account.clone();
2025-11-14 20:59:42 -05:00
let pool_post_definition = PoolDefinition {
definition_token_a_id,
definition_token_b_id,
2025-12-08 22:05:51 -05:00
vault_a_id: vault_a.account_id.clone(),
vault_b_id: vault_b.account_id.clone(),
liquidity_pool_id: pool_lp.account_id.clone(),
2025-12-09 14:42:58 -05:00
liquidity_pool_supply: amount_a.clone(),
reserve_a: amount_a.clone(),
reserve_b: amount_b.clone(),
2025-12-06 14:52:18 -05:00
fees: 0u128, //TODO: we assume all fees are 0 for now.
active: true,
2025-11-14 20:59:42 -05:00
};
pool_post.data = pool_post_definition.into_data();
2025-12-09 14:42:58 -05:00
let pool_post: AccountPostState =
if pool.account == Account::default() { AccountPostState::new_claimed(pool_post.clone()) }
else { AccountPostState::new(pool_post.clone()) };
2025-11-14 20:59:42 -05:00
2025-12-09 14:42:58 -05:00
let mut chained_calls = Vec::<ChainedCall>::new();
2025-12-07 20:34:26 -05:00
//Chain call for Token A (user_holding_a -> Vault_A)
2025-12-09 14:42:58 -05:00
let mut instruction_data = [0; 23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(&amount_a.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("New definition: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_a = ChainedCall{
2025-12-09 14:42:58 -05:00
program_id: user_holding_a.account.program_owner,
instruction_data,
2025-12-07 20:34:26 -05:00
pre_states: vec![user_holding_a.clone(), vault_a.clone()],
pda_seeds: Vec::<PdaSeed>::new(),
2025-11-14 20:59:42 -05:00
};
2025-12-09 14:42:58 -05:00
//Chain call for Token B (user_holding_b -> Vault_B)
2025-12-09 14:42:58 -05:00
let mut instruction_data = [0; 23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(&amount_b.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("New definition: AMM Program expects valid instruction_data");
2025-11-25 23:06:47 -05:00
2025-11-14 20:59:42 -05:00
let call_token_b = ChainedCall{
2025-12-09 14:42:58 -05:00
program_id: user_holding_b.account.program_owner,
instruction_data,
2025-12-07 20:34:26 -05:00
pre_states: vec![user_holding_b.clone(), vault_b.clone()],
pda_seeds: Vec::<PdaSeed>::new(),
2025-11-14 20:59:42 -05:00
};
2025-12-09 14:42:58 -05:00
//Chain call for liquidity token (TokenLP definition -> User LP Holding)
let mut instruction_data = [0; 23];
instruction_data[0] = if pool.account == Account::default() { 0 } else { 4 }; //new or mint
let nme = if pool.account == Account::default() { [1u8;6] } else { [0u8; 6] };
2025-12-08 22:05:51 -05:00
2025-12-09 14:42:58 -05:00
instruction_data[1..17].copy_from_slice(&amount_a.to_le_bytes());
instruction_data[17..].copy_from_slice(&nme);
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("New definition: AMM Program expects valid instruction_data");
2025-11-25 23:06:47 -05:00
2025-12-08 22:05:51 -05:00
let mut pool_lp_auth = pool_lp.clone();
pool_lp_auth.is_authorized = true;
2025-12-09 14:42:58 -05:00
let token_program_id = user_holding_a.account.program_owner;
2025-11-14 20:59:42 -05:00
let call_token_lp = ChainedCall{
2025-12-09 14:42:58 -05:00
program_id: token_program_id,
instruction_data,
2025-12-08 22:05:51 -05:00
pre_states: vec![pool_lp_auth.clone(), user_holding_lp.clone()],
pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id.clone())],
2025-11-14 20:59:42 -05:00
};
2025-12-07 20:34:26 -05:00
chained_calls.push(call_token_lp);
chained_calls.push(call_token_b);
chained_calls.push(call_token_a);
2025-11-14 20:59:42 -05:00
2025-12-09 14:42:58 -05:00
2025-11-25 23:06:47 -05:00
let post_states = vec![
2025-12-09 14:42:58 -05:00
pool_post.clone(),
2025-12-07 20:34:26 -05:00
AccountPostState::new(pre_states[1].account.clone()),
AccountPostState::new(pre_states[2].account.clone()),
AccountPostState::new(pre_states[3].account.clone()),
AccountPostState::new(pre_states[4].account.clone()),
AccountPostState::new(pre_states[5].account.clone()),
AccountPostState::new(pre_states[6].account.clone())];
(post_states.clone(), chained_calls)
2025-11-14 20:59:42 -05:00
}
fn swap(
pre_states: &[AccountWithMetadata],
2025-12-06 14:52:18 -05:00
amounts: &[u128],
2025-12-08 22:05:51 -05:00
token_in_id: AccountId,
2025-12-07 20:34:26 -05:00
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
2025-11-14 20:59:42 -05:00
if pre_states.len() != 5 {
panic!("Invalid number of input accounts");
}
2025-12-06 14:52:18 -05:00
if amounts.len() != 2 {
panic!("Invalid number of amounts provided");
}
let amount_in = amounts[0];
let min_amount_out = amounts[1];
2025-11-14 20:59:42 -05:00
let pool = &pre_states[0];
let vault_a = &pre_states[1];
let vault_b = &pre_states[2];
let user_holding_a = &pre_states[3];
let user_holding_b = &pre_states[4];
2025-11-14 20:59:42 -05:00
// Verify vaults are in fact vaults
let pool_def_data = PoolDefinition::parse(&pool.account.data).expect("Swap: AMM Program expects a valid Pool Definition Account");
if !pool_def_data.active {
panic!("Pool is inactive");
}
2025-11-20 21:02:18 -05:00
2025-12-08 22:05:51 -05:00
if vault_a.account_id != pool_def_data.vault_a_id {
panic!("Vault A was not provided");
}
2025-11-14 20:59:42 -05:00
2025-12-08 22:05:51 -05:00
if vault_b.account_id != pool_def_data.vault_b_id {
2025-11-18 14:43:40 -05:00
panic!("Vault B was not provided");
}
2025-11-14 20:59:42 -05:00
// fetch pool reserves
2025-12-06 14:52:18 -05:00
// validates reserves is at least the vaults' balances
if TokenHolding::parse(&vault_a.account.data).expect("Swap: AMM Program expects a valid Token Holding Account for Vault A").balance < pool_def_data.reserve_a {
panic!("Reserve for Token A exceeds vault balance");
}
if TokenHolding::parse(&vault_b.account.data).expect("Swap: AMM Program expects a valid Token Holding Account for Vault B").balance < pool_def_data.reserve_b {
panic!("Reserve for Token B exceeds vault balance");
}
2025-11-14 20:59:42 -05:00
2025-12-07 20:34:26 -05:00
let (chained_calls, [deposit_a, withdraw_a], [deposit_b, withdraw_b])
2025-12-08 22:05:51 -05:00
= if token_in_id == pool_def_data.definition_token_a_id {
let (chained_calls, withdraw_b) = swap_logic(&[user_holding_a.clone(),
vault_a.clone(),
vault_b.clone(),
user_holding_b.clone()],
&[amount_in, min_amount_out],
&[pool_def_data.reserve_a, pool_def_data.reserve_b],
pool.account_id.clone());
2025-12-07 20:34:26 -05:00
(chained_calls, [amount_in, 0], [0, withdraw_b])
2025-12-08 22:05:51 -05:00
} else if token_in_id == pool_def_data.definition_token_b_id {
let (chained_calls, withdraw_a) = swap_logic(&[user_holding_b.clone(),
vault_b.clone(),
vault_a.clone(),
user_holding_a.clone()],
&[amount_in, min_amount_out],
&[pool_def_data.reserve_b, pool_def_data.reserve_a],
pool.account_id.clone());
2025-12-07 20:34:26 -05:00
(chained_calls, [0, withdraw_a], [amount_in, 0])
} else {
panic!("AccountId is not a token type for the pool");
};
2025-11-14 20:59:42 -05:00
// Update pool account
2025-11-14 20:59:42 -05:00
let mut pool_post = pool.account.clone();
let pool_post_definition = PoolDefinition {
definition_token_a_id: pool_def_data.definition_token_a_id.clone(),
definition_token_b_id: pool_def_data.definition_token_b_id.clone(),
2025-12-08 22:05:51 -05:00
vault_a_id: pool_def_data.vault_a_id.clone(),
vault_b_id: pool_def_data.vault_b_id.clone(),
2025-11-14 20:59:42 -05:00
liquidity_pool_id: pool_def_data.liquidity_pool_id.clone(),
liquidity_pool_supply: pool_def_data.liquidity_pool_supply.clone(),
2025-11-14 20:59:42 -05:00
reserve_a: pool_def_data.reserve_a + deposit_a - withdraw_a,
reserve_b: pool_def_data.reserve_b + deposit_b - withdraw_b,
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
2025-11-14 20:59:42 -05:00
};
pool_post.data = pool_post_definition.into_data();
2025-11-25 23:06:47 -05:00
let post_states = vec![
2025-12-07 20:34:26 -05:00
AccountPostState::new(pool_post.clone()),
AccountPostState::new(pre_states[1].account.clone()),
AccountPostState::new(pre_states[2].account.clone()),
AccountPostState::new(pre_states[3].account.clone()),
AccountPostState::new(pre_states[4].account.clone())];
2025-11-25 23:06:47 -05:00
2025-12-07 20:34:26 -05:00
(post_states, chained_calls)
}
2025-11-25 23:06:47 -05:00
fn swap_logic(
pre_states: &[AccountWithMetadata],
2025-12-08 22:05:51 -05:00
balances: &[u128],
reserve_amounts: &[u128],
2025-12-08 22:05:51 -05:00
pool_id: AccountId,
) -> (Vec<ChainedCall>, u128)
{
let user_deposit_tx = pre_states[0].clone();
let vault_deposit_tx = pre_states[1].clone();
let vault_withdraw_tx = pre_states[2].clone();
let user_withdraw_tx = pre_states[3].clone();
let reserve_deposit_vault_amount = reserve_amounts[0];
let reserve_withdraw_vault_amount = reserve_amounts[1];
2025-12-08 22:05:51 -05:00
let deposit_amount = balances[0];
let min_amount_out = balances[1];
// Compute withdraw amount
// Compute pool's exchange constant
// let k = pool_def_data.reserve_a * pool_def_data.reserve_b;
let withdraw_amount = (reserve_withdraw_vault_amount * deposit_amount)/(reserve_deposit_vault_amount + deposit_amount);
//Slippage check
2025-12-06 14:52:18 -05:00
if min_amount_out > withdraw_amount {
panic!("Withdraw amount is less than minimal amount out");
}
if withdraw_amount == 0 {
panic!("Withdraw amount should be nonzero");
}
2025-12-07 20:34:26 -05:00
let mut chained_calls = Vec::new();
let mut instruction_data = [0;23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(&deposit_amount.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("Swap Logic: AMM Program expects valid transaction instruction data");
2025-12-07 20:34:26 -05:00
chained_calls.push(
ChainedCall{
program_id: vault_deposit_tx.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-07 20:34:26 -05:00
pre_states: vec![user_deposit_tx.clone(), vault_deposit_tx.clone()],
pda_seeds: Vec::<PdaSeed>::new(),
}
);
2025-11-14 20:59:42 -05:00
2025-12-08 22:05:51 -05:00
let mut vault_withdraw_tx = vault_withdraw_tx.clone();
vault_withdraw_tx.is_authorized = true;
let mut instruction_data = [0;23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(&withdraw_amount.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("Swap Logic: AMM Program expects valid transaction instruction data");
2025-12-07 20:34:26 -05:00
chained_calls.push(
ChainedCall{
program_id: vault_deposit_tx.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-07 20:34:26 -05:00
pre_states: vec![vault_withdraw_tx.clone(), user_withdraw_tx.clone()],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![compute_vault_pda_seed(pool_id,
TokenHolding::parse(&vault_withdraw_tx.account.data)
.expect("Swap Logic: AMM Program expects valid token data")
.definition_id)],
}
);
2025-12-07 20:34:26 -05:00
(chained_calls, withdraw_amount)
2025-11-14 20:59:42 -05:00
}
fn add_liquidity(pre_states: &[AccountWithMetadata],
2025-12-07 20:34:26 -05:00
balances: &[u128]) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
2025-11-14 20:59:42 -05:00
if pre_states.len() != 7 {
panic!("Invalid number of input accounts");
}
let pool = &pre_states[0];
let vault_a = &pre_states[1];
let vault_b = &pre_states[2];
2025-12-06 14:52:18 -05:00
let pool_definition_lp = &pre_states[3];
let user_holding_a = &pre_states[4];
let user_holding_b = &pre_states[5];
let user_holding_lp = &pre_states[6];
2025-11-14 20:59:42 -05:00
// Verify vaults are in fact vaults
let pool_def_data = PoolDefinition::parse(&pool.account.data).expect("Add liquidity: AMM Program expects valid Pool Definition Account");
2025-12-08 22:05:51 -05:00
if vault_a.account_id != pool_def_data.vault_a_id {
panic!("Vault A was not provided");
}
2025-12-06 14:52:18 -05:00
if pool_def_data.liquidity_pool_id != pool_definition_lp.account_id {
panic!("LP definition mismatch");
}
2025-12-08 22:05:51 -05:00
if vault_b.account_id != pool_def_data.vault_b_id {
2025-11-18 14:43:40 -05:00
panic!("Vault B was not provided");
}
2025-12-06 14:52:18 -05:00
if balances.len() != 3 {
2025-11-20 21:02:18 -05:00
panic!("Invalid number of input balances");
}
2025-12-06 14:52:18 -05:00
let min_amount_lp = balances[0];
let max_amount_a = balances[1];
let max_amount_b = balances[2];
2025-11-14 20:59:42 -05:00
2025-11-20 21:02:18 -05:00
if max_amount_a == 0 || max_amount_b == 0 {
panic!("Both max-balances must be nonzero");
}
2025-12-06 14:52:18 -05:00
if min_amount_lp == 0 {
panic!("Min-lp must be nonzero");
}
2025-11-20 21:02:18 -05:00
// 2. Determine deposit amount
let vault_b_balance = TokenHolding::parse(&vault_b.account.data).expect("Add liquidity: AMM Program expects valid Token Holding Account for Vault B").balance;
let vault_a_balance = TokenHolding::parse(&vault_a.account.data).expect("Add liquidity: AMM Program expects valid Token Holding Account for Vault A").balance;
2025-12-06 14:52:18 -05:00
2025-11-20 21:02:18 -05:00
if pool_def_data.reserve_a == 0 || pool_def_data.reserve_b == 0 {
panic!("Reserves must be nonzero");
}
2025-12-06 14:52:18 -05:00
if vault_a_balance < pool_def_data.reserve_a || vault_b_balance < pool_def_data.reserve_b {
panic!("Vaults' balances must be at least the reserve amounts");
}
2025-12-06 14:52:18 -05:00
// Calculate actual_amounts
let ideal_a: u128 = (pool_def_data.reserve_a*max_amount_b)/pool_def_data.reserve_b;
let ideal_b: u128 = (pool_def_data.reserve_b*max_amount_a)/pool_def_data.reserve_a;
2025-11-14 20:59:42 -05:00
2025-12-06 14:52:18 -05:00
let actual_amount_a = if ideal_a > max_amount_a { max_amount_a } else { ideal_a };
let actual_amount_b = if ideal_b > max_amount_b { max_amount_b } else { ideal_b };
2025-11-20 21:02:18 -05:00
2025-12-06 14:52:18 -05:00
// 3. Validate amounts
if max_amount_a < actual_amount_a || max_amount_b < actual_amount_b {
panic!("Actual trade amounts cannot exceed max_amounts");
2025-11-20 21:02:18 -05:00
}
if actual_amount_a == 0 || actual_amount_b == 0 {
panic!("A trade amount is 0");
}
2025-11-14 20:59:42 -05:00
// 4. Calculate LP to mint
2025-12-06 14:52:18 -05:00
let delta_lp = std::cmp::min(pool_def_data.liquidity_pool_supply * actual_amount_a/pool_def_data.reserve_a,
pool_def_data.liquidity_pool_supply * actual_amount_b/pool_def_data.reserve_b);
if delta_lp == 0 {
panic!("Payable LP must be nonzero");
}
2025-11-14 20:59:42 -05:00
2025-12-06 14:52:18 -05:00
if delta_lp < min_amount_lp {
panic!("Payable LP is less than provided minimum LP amount");
}
2025-11-14 20:59:42 -05:00
// 5. Update pool account
let mut pool_post = pool.account.clone();
let pool_post_definition = PoolDefinition {
definition_token_a_id: pool_def_data.definition_token_a_id.clone(),
definition_token_b_id: pool_def_data.definition_token_b_id.clone(),
2025-12-08 22:05:51 -05:00
vault_a_id: pool_def_data.vault_a_id.clone(),
vault_b_id: pool_def_data.vault_b_id.clone(),
2025-11-14 20:59:42 -05:00
liquidity_pool_id: pool_def_data.liquidity_pool_id.clone(),
liquidity_pool_supply: pool_def_data.liquidity_pool_supply + delta_lp,
2025-11-14 20:59:42 -05:00
reserve_a: pool_def_data.reserve_a + actual_amount_a,
reserve_b: pool_def_data.reserve_b + actual_amount_b,
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
2025-11-14 20:59:42 -05:00
};
2025-11-25 23:06:47 -05:00
2025-11-14 20:59:42 -05:00
pool_post.data = pool_post_definition.into_data();
let mut chained_call = Vec::new();
2025-12-07 20:34:26 -05:00
// Chain call for Token A (UserHoldingA -> Vault_A)
2025-11-14 20:59:42 -05:00
let mut instruction_data = [0; 23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(&actual_amount_a.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("Add liquidity: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_a = ChainedCall{
program_id: vault_a.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-07 20:34:26 -05:00
pre_states: vec![user_holding_a.clone(), vault_a.clone()],
pda_seeds: Vec::<PdaSeed>::new(),
2025-11-14 20:59:42 -05:00
};
2025-12-07 20:34:26 -05:00
// Chain call for Token B (UserHoldingB -> Vault_B)
2025-11-25 23:06:47 -05:00
let mut instruction_data = [0; 23];
instruction_data[0] = 1;
2025-11-14 20:59:42 -05:00
instruction_data[1..17].copy_from_slice(&actual_amount_b.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("Add liquidity: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_b = ChainedCall{
program_id: vault_b.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-07 20:34:26 -05:00
pre_states: vec![user_holding_b.clone(), vault_b.clone()],
pda_seeds: Vec::<PdaSeed>::new(),
2025-11-14 20:59:42 -05:00
};
2025-12-08 22:05:51 -05:00
// Chain call for LP (mint new tokens for user_holding_lp)
let mut pool_definition_lp_auth = pool_definition_lp.clone();
pool_definition_lp_auth.is_authorized = true;
2025-11-25 23:06:47 -05:00
let mut instruction_data = [0; 23];
2025-12-06 14:52:18 -05:00
instruction_data[0] = 4;
2025-11-14 20:59:42 -05:00
instruction_data[1..17].copy_from_slice(&delta_lp.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("Add liquidity: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_lp = ChainedCall{
2025-12-06 14:52:18 -05:00
program_id: pool_definition_lp.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-08 22:05:51 -05:00
pre_states: vec![pool_definition_lp_auth.clone(), user_holding_lp.clone()],
pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id.clone())]
2025-11-14 20:59:42 -05:00
};
chained_call.push(call_token_lp);
chained_call.push(call_token_b);
chained_call.push(call_token_a);
2025-11-25 09:02:43 -05:00
let post_states = vec![
2025-12-07 20:34:26 -05:00
AccountPostState::new(pool_post),
AccountPostState::new(pre_states[1].account.clone()),
AccountPostState::new(pre_states[2].account.clone()),
AccountPostState::new(pre_states[3].account.clone()),
AccountPostState::new(pre_states[4].account.clone()),
AccountPostState::new(pre_states[5].account.clone()),
AccountPostState::new(pre_states[6].account.clone()),];
2025-11-14 20:59:42 -05:00
2025-12-07 20:34:26 -05:00
(post_states, chained_call)
2025-11-14 20:59:42 -05:00
}
fn remove_liquidity(pre_states: &[AccountWithMetadata],
amounts: &[u128]
2025-12-07 20:34:26 -05:00
) -> (Vec<AccountPostState>, Vec<ChainedCall>)
{
2025-11-14 20:59:42 -05:00
if pre_states.len() != 7 {
panic!("Invalid number of input accounts");
}
let pool = &pre_states[0];
let vault_a = &pre_states[1];
let vault_b = &pre_states[2];
2025-12-06 14:52:18 -05:00
let pool_definition_lp = &pre_states[3];
let user_holding_a = &pre_states[4];
let user_holding_b = &pre_states[5];
let user_holding_lp = &pre_states[6];
if amounts.len() != 3 {
panic!("Invalid number of balances");
}
let amount_lp = amounts[0];
let amount_min_a = amounts[1];
let amount_min_b = amounts[2];
// Verify vaults are in fact vaults
let pool_def_data = PoolDefinition::parse(&pool.account.data).expect("Remove liquidity: AMM Program expects a valid Pool Definition Account");
2025-11-14 20:59:42 -05:00
if !pool_def_data.active {
panic!("Pool is inactive");
}
2025-12-06 14:52:18 -05:00
if pool_def_data.liquidity_pool_id != pool_definition_lp.account_id {
panic!("LP definition mismatch");
}
2025-12-08 22:05:51 -05:00
if vault_a.account_id != pool_def_data.vault_a_id {
panic!("Vault A was not provided");
}
2025-12-08 22:05:51 -05:00
if vault_b.account_id != pool_def_data.vault_b_id {
2025-11-18 14:43:40 -05:00
panic!("Vault B was not provided");
}
2025-12-08 13:19:30 -05:00
// Vault addresses do not need to be checked with PDA
// calculation for setting authorization since stored
// in the Pool Definition.
let mut running_vault_a = vault_a.clone();
let mut running_vault_b = vault_b.clone();
running_vault_a.is_authorized = true;
running_vault_b.is_authorized = true;
2025-12-06 14:52:18 -05:00
if amount_min_a == 0 || amount_min_b == 0 {
panic!("Minimum withdraw amount must be nonzero");
}
if amount_lp == 0 {
panic!("Liquidity amount must be nonzero");
}
// 2. Compute withdrawal amounts
let user_holding_lp_data = TokenHolding::parse(&user_holding_lp.account.data).expect("Remove liquidity: AMM Program expects a valid Token Account for liquidity token");
if user_holding_lp_data.balance > pool_def_data.liquidity_pool_supply || user_holding_lp_data.definition_id != pool_def_data.liquidity_pool_id {
panic!("Invalid liquidity account provided");
}
2025-12-06 14:52:18 -05:00
let withdraw_amount_a = (pool_def_data.reserve_a * amount_lp)/pool_def_data.liquidity_pool_supply;
let withdraw_amount_b = (pool_def_data.reserve_b * amount_lp)/pool_def_data.liquidity_pool_supply;
2025-11-14 20:59:42 -05:00
// 3. Validate and slippage check
if withdraw_amount_a < amount_min_a {
panic!("Insufficient minimal withdraw amount (Token A) provided for liquidity amount");
}
if withdraw_amount_b < amount_min_b {
panic!("Insufficient minimal withdraw amount (Token B) provided for liquidity amount");
}
2025-11-14 20:59:42 -05:00
// 4. Calculate LP to reduce cap by
let delta_lp : u128 = (pool_def_data.liquidity_pool_supply*amount_lp)/pool_def_data.liquidity_pool_supply;
2025-11-14 20:59:42 -05:00
2025-12-06 14:52:18 -05:00
let active: bool = if pool_def_data.liquidity_pool_supply - delta_lp == 0 { false } else { true };
2025-11-14 20:59:42 -05:00
// 5. Update pool account
let mut pool_post = pool.account.clone();
let pool_post_definition = PoolDefinition {
definition_token_a_id: pool_def_data.definition_token_a_id.clone(),
definition_token_b_id: pool_def_data.definition_token_b_id.clone(),
2025-12-08 22:05:51 -05:00
vault_a_id: pool_def_data.vault_a_id.clone(),
vault_b_id: pool_def_data.vault_b_id.clone(),
2025-11-14 20:59:42 -05:00
liquidity_pool_id: pool_def_data.liquidity_pool_id.clone(),
liquidity_pool_supply: pool_def_data.liquidity_pool_supply - delta_lp,
2025-11-14 20:59:42 -05:00
reserve_a: pool_def_data.reserve_a - withdraw_amount_a,
reserve_b: pool_def_data.reserve_b - withdraw_amount_b,
2025-12-06 14:52:18 -05:00
fees: 0u128,
active,
2025-11-14 20:59:42 -05:00
};
pool_post.data = pool_post_definition.into_data();
2025-12-07 20:34:26 -05:00
let mut chained_calls = Vec::new();
2025-11-14 20:59:42 -05:00
//Chaincall for Token A withdraw
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
2025-12-08 13:19:30 -05:00
instruction[0] = 1; // token transfer
2025-11-25 23:06:47 -05:00
instruction[1..17].copy_from_slice(&withdraw_amount_a.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Remove liquidity: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_a = ChainedCall{
program_id: vault_a.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-08 13:19:30 -05:00
pre_states: vec![running_vault_a, user_holding_a.clone()],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![compute_vault_pda_seed(pool.account_id.clone(), pool_def_data.definition_token_a_id.clone())],
2025-11-14 20:59:42 -05:00
};
//Chaincall for Token B withdraw
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
2025-12-08 13:19:30 -05:00
instruction[0] = 1; // token transfer
2025-11-25 23:06:47 -05:00
instruction[1..17].copy_from_slice(&withdraw_amount_b.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Remove liquidity: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_b = ChainedCall{
program_id: vault_b.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-08 13:19:30 -05:00
pre_states: vec![running_vault_b, user_holding_b.clone()],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![compute_vault_pda_seed(pool.account_id.clone(), pool_def_data.definition_token_b_id.clone())],
2025-11-14 20:59:42 -05:00
};
2025-12-08 22:05:51 -05:00
//Chaincall for LP adjustment
let mut pool_definition_lp_auth = pool_definition_lp.clone();
pool_definition_lp_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
2025-12-08 13:19:30 -05:00
instruction[0] = 3; // token burn
2025-11-25 23:06:47 -05:00
instruction[1..17].copy_from_slice(&delta_lp.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Remove liquidity: AMM Program expects valid token transfer instruction data");
2025-11-14 20:59:42 -05:00
let call_token_lp = ChainedCall{
2025-12-06 14:52:18 -05:00
program_id: pool_definition_lp.account.program_owner,
2025-12-09 14:42:58 -05:00
instruction_data,
2025-12-08 22:05:51 -05:00
pre_states: vec![pool_definition_lp_auth.clone(), user_holding_lp.clone()],
pda_seeds: vec![compute_liquidity_token_pda_seed(pool.account_id.clone())]
2025-11-14 20:59:42 -05:00
};
2025-12-07 20:34:26 -05:00
chained_calls.push(call_token_lp);
chained_calls.push(call_token_b);
chained_calls.push(call_token_a);
2025-12-06 14:52:18 -05:00
2025-11-25 09:02:43 -05:00
let post_states = vec!
2025-12-06 14:52:18 -05:00
[
2025-12-07 20:34:26 -05:00
AccountPostState::new(pool_post.clone()),
AccountPostState::new(pre_states[1].account.clone()),
AccountPostState::new(pre_states[2].account.clone()),
AccountPostState::new(pre_states[3].account.clone()),
AccountPostState::new(pre_states[4].account.clone()),
AccountPostState::new(pre_states[5].account.clone()),
AccountPostState::new(pre_states[6].account.clone())];
(post_states, chained_calls)
2025-11-17 18:48:17 -05:00
}
2025-11-18 14:43:40 -05:00
#[cfg(test)]
mod tests {
2025-12-07 20:34:26 -05:00
use nssa_core::{{account::{Account, AccountId, AccountWithMetadata}, program::ChainedCall, program::PdaSeed}, program::ProgramId};
2025-11-18 14:43:40 -05:00
2025-12-08 22:05:51 -05:00
use crate::{PoolDefinition, TokenDefinition, TokenHolding, add_liquidity, new_definition, remove_liquidity, swap,
compute_liquidity_token_pda, compute_liquidity_token_pda_seed, compute_pool_pda, compute_pool_pda_seed,
compute_vault_pda, compute_vault_pda_seed};
const TOKEN_PROGRAM_ID: ProgramId = [15;8];
2025-12-08 22:05:51 -05:00
const AMM_PROGRAM_ID: ProgramId = [42;8];
enum AccountEnum {
2025-12-07 20:34:26 -05:00
UserHoldingB,
UserHoldingA,
VaultAUninit,
VaultBUninit,
VaultAInit,
VaultBInit,
VaultAInitHigh,
VaultBInitHigh,
VaultAInitLow,
VaultBInitLow,
VaultAInitZero,
VaultBInitZero,
VaultAWrongAccId,
VaultBWrongAccId,
PoolLPUninit,
PoolLPInit,
PoolLPWrongAccId,
UserHoldingLPUninit,
UserHoldingLPInit,
PoolDefinitionUninit,
PoolDefinitionInit,
PoolDefinitionInitReserveAZero,
PoolDefinitionInitReserveBZero,
PoolDefinitionInitReserveALow,
PoolDefinitionInitReserveBLow,
PoolDefinitionUnauth,
PoolDefinitionSwapTest1,
PoolDefinitionSwapTest2,
PoolDefinitionAddZeroLP,
PoolDefinitionAddSuccessful,
PoolDefinitionRemoveSuccessful,
2025-12-08 22:05:51 -05:00
PoolDefinitionInactive,
PoolDefinitionWrongId,
VaultAWrongId,
VaultBWrongId,
PoolLPWrongId,
PoolDefinitionActive,
}
enum BalanceEnum {
2025-12-07 20:34:26 -05:00
VaultAReserveInit,
VaultBReserveInit,
VaultAReserveLow,
VaultBReserveLow,
VaultAReserveHigh,
VaultBReserveHigh,
UserTokenABal,
UserTokenBBal,
UserTokenLPBal,
RemoveMinAmountA,
RemoveMinAmountB,
RemoveActualASuccessful,
RemoveMinAmountBLow,
RemoveMinAmountBAow,
RemoveAmountLP,
RemoveAmountLP1,
AddMaxAmountALow,
AddMaxAmountBLow,
AddMaxAmountBHigh,
AddMaxAmountA,
AddMaxAmountb,
AddMinAmountLP,
VaultASwapTest1,
VaultASwapTest2,
VaultBSwapTest1,
VaultBSwapTest2,
MinAmountOut,
VaultAAddSuccessful,
VaultBAddSuccessful,
AddSuccessfulAmountA,
AddSuccessfulAmountB,
VaultARemoveSuccessful,
VaultBRemoveSuccessful,
}
fn helper_balance_constructor(selection: BalanceEnum) -> u128 {
match selection {
2025-12-07 20:34:26 -05:00
BalanceEnum::VaultAReserveInit => 1_000,
BalanceEnum::VaultBReserveInit => 500,
BalanceEnum::VaultAReserveLow => 10,
BalanceEnum::VaultBReserveLow => 10,
BalanceEnum::VaultAReserveHigh => 500_000,
BalanceEnum::VaultBReserveHigh => 500_000,
BalanceEnum::UserTokenABal => 1_000,
BalanceEnum::UserTokenBBal => 500,
BalanceEnum::UserTokenLPBal => 100,
BalanceEnum::RemoveMinAmountA => 50,
BalanceEnum::RemoveMinAmountB => 100,
BalanceEnum::RemoveActualASuccessful => 100,
BalanceEnum::RemoveMinAmountBLow => 50,
BalanceEnum::RemoveMinAmountBAow => 10,
BalanceEnum::RemoveAmountLP => 100,
BalanceEnum::RemoveAmountLP1 => 30,
BalanceEnum::AddMaxAmountA => 500,
BalanceEnum::AddMaxAmountb => 200,
BalanceEnum::AddMaxAmountBHigh => 20_000,
BalanceEnum::AddMaxAmountALow => 10,
BalanceEnum::AddMaxAmountBLow => 10,
BalanceEnum::AddMinAmountLP => 20,
BalanceEnum::VaultASwapTest1 => 1_500,
BalanceEnum::VaultASwapTest2 => 715,
BalanceEnum::VaultBSwapTest1 => 334,
BalanceEnum::VaultBSwapTest2 => 700,
BalanceEnum::MinAmountOut => 200,
BalanceEnum::VaultAAddSuccessful => 1_400,
BalanceEnum::VaultBAddSuccessful => 700,
BalanceEnum::AddSuccessfulAmountA => 400,
BalanceEnum::AddSuccessfulAmountB => 200,
BalanceEnum::VaultARemoveSuccessful => 900,
BalanceEnum::VaultBRemoveSuccessful => 450,
_ => panic!("Invalid selection")
}
}
enum IdEnum {
2025-12-07 20:34:26 -05:00
TokenADefinitionId,
TokenBDefinitionId,
TokenLPDefinitionId,
UserTokenAId,
UserTokenBId,
UserTokenLPId,
PoolDefinitionId,
VaultAId,
VaultBId,
}
2025-12-06 14:52:18 -05:00
enum ChainedCallsEnum {
2025-12-07 20:34:26 -05:00
CcTokenAInitialization,
CcTokenBInitialization,
CcPoolLPInitiailization,
CcSwapTokenATest1,
CcSwapTokenBTest1,
CcSwapTokenATest2,
CcSwapTokenBTest2,
CcAddTokenA,
CcAddTokenB,
CcAddPoolLP,
CcRemoveTokenA,
CcRemoveTokenB,
CcRemovePoolLP,
2025-12-08 22:05:51 -05:00
CcNewDefinitionTokenA,
CcNewDefinitionTokenB,
CcNewDefinitionLP,
2025-12-06 14:52:18 -05:00
}
fn helper_chained_call_constructor(selection: ChainedCallsEnum) -> ChainedCall {
match selection {
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcTokenAInitialization => {
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::UserTokenABal)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::VaultAUninit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcTokenBInitialization => {
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::UserTokenBBal)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::VaultBUninit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcPoolLPInitiailization => {
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::UserTokenABal)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolLPUninit),
helper_account_constructor(AccountEnum::UserHoldingLPUninit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcSwapTokenATest1 => {
2025-12-06 14:52:18 -05:00
let mut instruction_data: [u8;23] = [0; 23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::AddMaxAmountA)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::VaultAInit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcSwapTokenBTest1 => {
2025-12-06 14:52:18 -05:00
let swap_amount: u128 = 166;
2025-12-08 22:05:51 -05:00
let mut vault_b_auth = helper_account_constructor(AccountEnum::VaultBInit);
vault_b_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
&swap_amount
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-08 22:05:51 -05:00
vault_b_auth,
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingB)],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![
compute_vault_pda_seed(helper_id_constructor(IdEnum::PoolDefinitionId),
helper_id_constructor(IdEnum::TokenBDefinitionId)),
],
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcSwapTokenATest2 => {
2025-12-06 14:52:18 -05:00
let swap_amount: u128 = 285;
2025-12-08 22:05:51 -05:00
let mut vault_a_auth = helper_account_constructor(AccountEnum::VaultAInit);
vault_a_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction_data: [u8;23] = [0; 23];
instruction_data[0] = 1;
instruction_data[1..17].copy_from_slice(
&swap_amount
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction_data).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-08 22:05:51 -05:00
vault_a_auth,
helper_account_constructor(AccountEnum::UserHoldingA),
],
pda_seeds: vec![
compute_vault_pda_seed(helper_id_constructor(IdEnum::PoolDefinitionId),
helper_id_constructor(IdEnum::TokenADefinitionId)),
],
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcSwapTokenBTest2 => {
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::AddMaxAmountb)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::VaultBInit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcAddTokenA => {
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::VaultAInit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcAddTokenB => {
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::AddSuccessfulAmountB)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Swap Logic: AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::VaultBInit)],
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcAddPoolLP => {
2025-12-08 22:05:51 -05:00
let mut pool_lp_auth = helper_account_constructor(AccountEnum::PoolLPInit);
pool_lp_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 4;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Swap Logic: AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-08 22:05:51 -05:00
pool_lp_auth,
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingLPInit)],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![compute_liquidity_token_pda_seed(
helper_id_constructor(IdEnum::PoolDefinitionId))],
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcRemoveTokenA => {
2025-12-08 22:05:51 -05:00
let mut vault_a_auth = helper_account_constructor(AccountEnum::VaultAInit);
vault_a_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::RemoveActualASuccessful)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-08 22:05:51 -05:00
vault_a_auth,
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingA),],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![
compute_vault_pda_seed(helper_id_constructor(IdEnum::PoolDefinitionId),
helper_id_constructor(IdEnum::TokenADefinitionId)),
],
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcRemoveTokenB => {
2025-12-08 22:05:51 -05:00
let mut vault_b_auth = helper_account_constructor(AccountEnum::VaultBInit);
vault_b_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::RemoveMinAmountBLow)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-08 22:05:51 -05:00
vault_b_auth,
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingB),],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![
compute_vault_pda_seed(helper_id_constructor(IdEnum::PoolDefinitionId),
helper_id_constructor(IdEnum::TokenBDefinitionId)),
],
2025-12-06 14:52:18 -05:00
}
}
2025-12-07 20:34:26 -05:00
ChainedCallsEnum::CcRemovePoolLP => {
2025-12-08 22:05:51 -05:00
let mut pool_lp_auth = helper_account_constructor(AccountEnum::PoolLPInit);
pool_lp_auth.is_authorized = true;
2025-12-06 14:52:18 -05:00
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 3;
instruction[1..17].copy_from_slice(
2025-12-07 20:34:26 -05:00
&helper_balance_constructor(BalanceEnum::RemoveActualASuccessful)
2025-12-06 14:52:18 -05:00
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::UserHoldingLPInit),
helper_account_constructor(AccountEnum::PoolLPInit),],
2025-12-08 22:05:51 -05:00
pda_seeds: vec![compute_liquidity_token_pda_seed(
helper_id_constructor(IdEnum::PoolDefinitionId))],
}
}
ChainedCallsEnum::CcNewDefinitionTokenA => {
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
&helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA)
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::VaultAInit)],
pda_seeds: Vec::<PdaSeed>::new(),
}
}
ChainedCallsEnum::CcNewDefinitionTokenB => {
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 1;
instruction[1..17].copy_from_slice(
&helper_balance_constructor(BalanceEnum::AddSuccessfulAmountB)
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Swap Logic: AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::VaultBInit)],
2025-12-07 20:34:26 -05:00
pda_seeds: Vec::<PdaSeed>::new(),
2025-12-06 14:52:18 -05:00
}
}
2025-12-08 22:05:51 -05:00
ChainedCallsEnum::CcAddPoolLP => {
let mut pool_lp_auth = helper_account_constructor(AccountEnum::PoolLPInit);
pool_lp_auth.is_authorized = true;
let mut instruction: [u8;23] = [0; 23];
instruction[0] = 0;
instruction[1..17].copy_from_slice(
&helper_balance_constructor(BalanceEnum::AddSuccessfulAmountA)
.to_le_bytes());
let instruction_data = risc0_zkvm::serde::to_vec(&instruction).expect("Swap Logic: AMM Program expects valid transaction instruction data");
ChainedCall{
program_id: TOKEN_PROGRAM_ID,
instruction_data,
pre_states: vec![
pool_lp_auth,
helper_account_constructor(AccountEnum::UserHoldingLPInit)],
pda_seeds: vec![compute_liquidity_token_pda_seed(
helper_id_constructor(IdEnum::PoolDefinitionId))],
}
}
_ => panic!("Invalid selection")
2025-12-06 14:52:18 -05:00
}
}
fn helper_id_constructor(selection: IdEnum) -> AccountId {
match selection {
2025-12-07 20:34:26 -05:00
IdEnum::TokenADefinitionId => AccountId::new([42;32]),
IdEnum::TokenBDefinitionId => AccountId::new([43;32]),
2025-12-08 22:05:51 -05:00
IdEnum::TokenLPDefinitionId => compute_liquidity_token_pda(AMM_PROGRAM_ID,
helper_id_constructor(IdEnum::PoolDefinitionId),),
2025-12-07 20:34:26 -05:00
IdEnum::UserTokenAId => AccountId::new([45;32]),
IdEnum::UserTokenBId => AccountId::new([46;32]),
IdEnum::UserTokenLPId => AccountId::new([47;32]),
2025-12-08 22:05:51 -05:00
IdEnum::PoolDefinitionId => compute_pool_pda(AMM_PROGRAM_ID,
helper_id_constructor(IdEnum::TokenADefinitionId),
helper_id_constructor(IdEnum::TokenBDefinitionId)),
IdEnum::VaultAId => compute_vault_pda(AMM_PROGRAM_ID,
helper_id_constructor(IdEnum::PoolDefinitionId),
helper_id_constructor(IdEnum::TokenADefinitionId)),
IdEnum::VaultBId => compute_vault_pda(AMM_PROGRAM_ID,
helper_id_constructor(IdEnum::PoolDefinitionId),
helper_id_constructor(IdEnum::TokenBDefinitionId)),
_ => panic!("Invalid selection")
}
}
fn helper_account_constructor(selection: AccountEnum) -> AccountWithMetadata {
match selection {
2025-12-07 20:34:26 -05:00
AccountEnum::UserHoldingA => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: helper_balance_constructor(BalanceEnum::UserTokenABal),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::UserTokenAId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::UserHoldingB => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: helper_balance_constructor(BalanceEnum::UserTokenBBal),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::UserTokenBId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultAUninit => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: 0,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultBUninit => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: 0,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultBId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultAInit => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultBInit => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultBId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultAInitHigh => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultAReserveHigh),
2025-12-06 14:52:18 -05:00
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultBInitHigh => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultBReserveHigh),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultBId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultAInitLow => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultAReserveLow),
2025-12-06 14:52:18 -05:00
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultBInitLow => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultBReserveLow),
2025-12-06 14:52:18 -05:00
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultAInitZero => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
balance: 0,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultBInitZero => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: 0,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultBId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultAWrongAccId => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultBId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::VaultBWrongAccId => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
2025-12-06 14:52:18 -05:00
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolLPUninit => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenDefinition::into_data(
TokenDefinition{
account_type: 0u8,
name: [1;6],
total_supply: 0u128,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolLPInit => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenDefinition::into_data(
TokenDefinition{
account_type: 0u8,
name: [1;6],
2025-12-07 20:34:26 -05:00
total_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
2025-12-06 14:52:18 -05:00
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolLPWrongAccId => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenDefinition::into_data(
TokenDefinition{
account_type: 0u8,
name: [1;6],
2025-12-07 20:34:26 -05:00
total_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::VaultAId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::UserHoldingLPUninit => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
balance: 0,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::UserTokenLPId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::UserHoldingLPInit => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
2025-12-07 20:34:26 -05:00
definition_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
balance: helper_balance_constructor(BalanceEnum::UserTokenLPBal),
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::UserTokenLPId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionUninit => AccountWithMetadata {
account: Account::default(),
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionInit => AccountWithMetadata {
account: Account {
2025-12-06 14:52:18 -05:00
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionInitReserveAZero => AccountWithMetadata {
account: Account {
2025-12-06 14:52:18 -05:00
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
2025-12-06 14:52:18 -05:00
reserve_a: 0,
2025-12-07 20:34:26 -05:00
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
2025-12-06 14:52:18 -05:00
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionInitReserveBZero => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
2025-12-06 14:52:18 -05:00
reserve_b: 0,
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionInitReserveALow => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveLow),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveLow),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveHigh),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionInitReserveBLow => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveHigh),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveHigh),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveLow),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionUnauth => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: false,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionSwapTest1 => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultASwapTest1),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBSwapTest1),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionSwapTest2 => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultASwapTest2),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBSwapTest2),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionAddZeroLP => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveLow),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionAddSuccessful => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAAddSuccessful),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAAddSuccessful),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBAddSuccessful),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-07 20:34:26 -05:00
AccountEnum::PoolDefinitionRemoveSuccessful => AccountWithMetadata {
2025-12-06 14:52:18 -05:00
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
2025-12-07 20:34:26 -05:00
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-08 22:05:51 -05:00
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
2025-12-07 20:34:26 -05:00
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultARemoveSuccessful),
reserve_a: helper_balance_constructor(BalanceEnum::VaultARemoveSuccessful),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBRemoveSuccessful),
2025-12-06 14:52:18 -05:00
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
2025-12-07 20:34:26 -05:00
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
2025-12-06 14:52:18 -05:00
},
2025-12-08 22:05:51 -05:00
AccountEnum::PoolDefinitionInactive => AccountWithMetadata {
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
fees: 0u128,
active: false,
}),
nonce: 0,
},
is_authorized: true,
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
},
AccountEnum::PoolDefinitionWrongId => AccountWithMetadata {
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
fees: 0u128,
active: false,
}),
nonce: 0,
},
is_authorized: true,
account_id: AccountId::new([4;32]),
},
AccountEnum::VaultAWrongId => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
definition_id: helper_id_constructor(IdEnum::TokenADefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
}),
nonce: 0,
},
is_authorized: true,
account_id: AccountId::new([4;32]),
},
AccountEnum::VaultBWrongId => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenHolding::into_data(
TokenHolding{
account_type: 1u8,
definition_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
balance: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
}),
nonce: 0,
},
is_authorized: true,
account_id: AccountId::new([4;32]),
},
AccountEnum::PoolLPWrongId => AccountWithMetadata {
account: Account {
program_owner: TOKEN_PROGRAM_ID,
balance: 0u128,
data: TokenDefinition::into_data(
TokenDefinition{
account_type: 0u8,
name: [1;6],
total_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
}),
nonce: 0,
},
is_authorized: true,
account_id: AccountId::new([4;32]),
},
AccountEnum::PoolDefinitionActive => AccountWithMetadata {
account: Account {
program_owner: ProgramId::default(),
balance: 0u128,
data: PoolDefinition::into_data(
PoolDefinition {
definition_token_a_id: helper_id_constructor(IdEnum::TokenADefinitionId),
definition_token_b_id: helper_id_constructor(IdEnum::TokenBDefinitionId),
vault_a_id: helper_id_constructor(IdEnum::VaultAId),
vault_b_id: helper_id_constructor(IdEnum::VaultBId),
liquidity_pool_id: helper_id_constructor(IdEnum::TokenLPDefinitionId),
liquidity_pool_supply: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_a: helper_balance_constructor(BalanceEnum::VaultAReserveInit),
reserve_b: helper_balance_constructor(BalanceEnum::VaultBReserveInit),
fees: 0u128,
active: true,
}),
nonce: 0,
},
is_authorized: true,
account_id: helper_id_constructor(IdEnum::PoolDefinitionId),
},
2025-12-06 14:52:18 -05:00
_ => panic!("Invalid selection"),
}
}
2025-12-08 13:19:30 -05:00
2025-12-08 22:05:51 -05:00
#[test]
fn test_pool_pda_produces_unique_id_for_token_pair() {
//compute_pool_pda(amm_program_id: ProgramId, definition_token_a_id: AccountId, definition_token_b_id: AccountId)
assert!(compute_pool_pda(AMM_PROGRAM_ID,
helper_id_constructor(IdEnum::TokenADefinitionId),
helper_id_constructor(IdEnum::TokenBDefinitionId)) ==
compute_pool_pda(AMM_PROGRAM_ID,
helper_id_constructor(IdEnum::TokenBDefinitionId),
helper_id_constructor(IdEnum::TokenADefinitionId)));
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_with_invalid_number_of_accounts_1() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionUninit),
2025-12-06 14:52:18 -05:00
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
2025-12-08 22:05:51 -05:00
helper_balance_constructor(BalanceEnum::VaultBReserveInit)],
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
2025-11-18 14:43:40 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_with_invalid_number_of_accounts_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
2025-12-08 22:05:51 -05:00
helper_balance_constructor(BalanceEnum::VaultBReserveInit)],
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition__with_invalid_number_of_accounts_3() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
2025-12-08 22:05:51 -05:00
helper_balance_constructor(BalanceEnum::VaultBReserveInit)],
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
2025-11-18 14:43:40 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition__with_invalid_number_of_accounts_4() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit)],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
2025-11-18 14:43:40 -05:00
}
2025-12-07 20:34:26 -05:00
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition__with_invalid_number_of_accounts_5() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit)],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
2025-11-18 14:43:40 -05:00
}
2025-12-07 20:34:26 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
2025-11-18 14:43:40 -05:00
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_with_invalid_number_of_accounts_6() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit)],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
2025-11-18 14:43:40 -05:00
}
2025-12-07 20:34:26 -05:00
#[should_panic(expected = "Invalid number of input balances")]
2025-11-18 14:43:40 -05:00
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_with_invalid_number_of_balances() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Balances must be nonzero")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_with_zero_balance_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[0,
2025-12-07 20:34:26 -05:00
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Balances must be nonzero")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_with_zero_balance_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
0],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
2025-12-07 20:34:26 -05:00
);
}
2025-12-07 20:34:26 -05:00
#[should_panic(expected = "Cannot set up a swap for a token with itself")]
#[test]
2025-12-07 20:34:26 -05:00
fn test_call_new_definition_same_token_definition() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
2025-12-07 20:34:26 -05:00
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
2025-12-08 22:05:51 -05:00
AMM_PROGRAM_ID,
);
}
#[should_panic(expected = "Liquidity pool Token Definition Account ID does not match PDA")]
#[test]
fn test_call_new_definition_wrong_liquidity_id() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPWrongId),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
AMM_PROGRAM_ID,
);
2025-12-07 20:34:26 -05:00
}
2025-12-08 22:05:51 -05:00
#[should_panic(expected = "Pool Definition Account ID does not match PDA")]
#[test]
fn test_call_new_definition_wrong_pool_id() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionWrongId),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
AMM_PROGRAM_ID,
);
}
#[should_panic(expected = "Vault ID does not match PDA")]
#[test]
fn test_call_new_definition_wrong_vault_id_1() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAWrongId),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
AMM_PROGRAM_ID,
);
}
#[should_panic(expected = "Vault ID does not match PDA")]
#[test]
fn test_call_new_definition_wrong_vault_id_2() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBWrongId),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
AMM_PROGRAM_ID,
);
}
#[should_panic(expected = "Cannot initialize an active Pool Definition")]
#[test]
fn test_call_new_definition_cannot_initialize_active_pool() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionActive),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
let _post_states = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
AMM_PROGRAM_ID,
);
}
#[should_panic(expected = "Cannot initialize an active Pool Definition")]
#[test]
fn test_call_new_definition_chain_call_successful() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionActive),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPUninit),
];
let (post_states, chained_calls) = new_definition(&pre_states,
&[helper_balance_constructor(BalanceEnum::VaultAReserveInit),
helper_balance_constructor(BalanceEnum::VaultBReserveInit),],
AMM_PROGRAM_ID,
);
let pool_post = post_states[0].clone();
assert!(helper_account_constructor(AccountEnum::PoolDefinitionAddSuccessful).account ==
*pool_post.account());
let chained_call_lp = chained_calls[0].clone();
let chained_call_b = chained_calls[1].clone();
let chained_call_a = chained_calls[2].clone();
assert!(chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcNewDefinitionTokenA));
assert!(chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcNewDefinitionTokenB));
assert!(chained_call_lp == helper_chained_call_constructor(ChainedCallsEnum::CcNewDefinitionLP));
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_remove_liquidity_with_invalid_number_of_accounts_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
2025-11-18 14:43:40 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_remove_liquidity_with_invalid_number_of_accounts_3() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
2025-11-18 14:43:40 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_remove_liquidity_with_invalid_number_of_accounts_4() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_remove_liquidity_with_invalid_number_of_accounts_5() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
2025-11-18 14:43:40 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
2025-11-18 14:43:40 -05:00
#[test]
fn test_call_remove_liquidity_with_invalid_number_of_accounts_6() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
#[should_panic(expected = "Vault A was not provided")]
#[test]
fn test_call_remove_liquidity_vault_a_omitted() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAWrongAccId),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
#[should_panic(expected = "Vault B was not provided")]
#[test]
fn test_call_remove_liquidity_vault_b_omitted() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBWrongAccId),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
2025-12-06 20:03:05 -05:00
#[should_panic(expected = "LP definition mismatch")]
#[test]
fn test_call_remove_liquidity_lp_def_mismatch() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPWrongAccId),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 20:03:05 -05:00
];
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
2025-12-06 20:03:05 -05:00
);
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Invalid liquidity account provided")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_remove_liquidity_insufficient_liquidity_amount() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingA), //different token account than lp to create desired error
];
2025-12-06 14:52:18 -05:00
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Insufficient minimal withdraw amount (Token A) provided for liquidity amount")]
2025-11-18 14:43:40 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_remove_liquidity_insufficient_balance_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
2025-12-06 14:52:18 -05:00
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP1),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
2025-11-18 14:43:40 -05:00
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Insufficient minimal withdraw amount (Token B) provided for liquidity amount")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_remove_liquidity_insufficient_balance_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
2025-12-06 14:52:18 -05:00
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
2025-11-20 21:02:18 -05:00
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Minimum withdraw amount must be nonzero")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_remove_liquidity_min_bal_zero_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
2025-12-06 14:52:18 -05:00
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
2025-12-06 14:52:18 -05:00
0,
2025-12-07 20:34:26 -05:00
helper_balance_constructor(BalanceEnum::RemoveMinAmountB)],
);
}
2025-11-20 21:02:18 -05:00
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Minimum withdraw amount must be nonzero")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_remove_liquidity_min_bal_zero_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
2025-12-06 14:52:18 -05:00
let _post_states = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
2025-12-06 14:52:18 -05:00
0],
);
}
2025-11-20 21:02:18 -05:00
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Liquidity amount must be nonzero")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_remove_liquidity_lp_bal_zero() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
2025-12-06 14:52:18 -05:00
let _post_states = remove_liquidity(&pre_states,
&[0,
2025-12-07 20:34:26 -05:00
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountB),],
2025-12-06 14:52:18 -05:00
);
}
#[test]
fn test_call_remove_liquidity_chained_call_successful() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let (post_states, chained_calls) = remove_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::RemoveAmountLP),
helper_balance_constructor(BalanceEnum::RemoveMinAmountA),
helper_balance_constructor(BalanceEnum::RemoveMinAmountBLow),],
2025-12-06 14:52:18 -05:00
);
let pool_post = post_states[0].clone();
2025-12-07 20:34:26 -05:00
assert!(helper_account_constructor(AccountEnum::PoolDefinitionRemoveSuccessful).account ==
*pool_post.account());
2025-12-06 14:52:18 -05:00
let chained_call_lp = chained_calls[0].clone();
let chained_call_b = chained_calls[1].clone();
let chained_call_a = chained_calls[2].clone();
2025-12-07 20:34:26 -05:00
assert!(chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcRemoveTokenA));
assert!(chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcRemoveTokenB));
assert!(chained_call_lp.instruction_data == helper_chained_call_constructor(ChainedCallsEnum::CcRemovePoolLP).instruction_data);
2025-12-06 14:52:18 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_add_liquidity_with_invalid_number_of_accounts_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
);
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_add_liquidity_with_invalid_number_of_accounts_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_add_liquidity_with_invalid_number_of_accounts_3() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_add_liquidity_with_invalid_number_of_accounts_4() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_add_liquidity_with_invalid_number_of_accounts_5() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
2025-11-20 21:02:18 -05:00
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_add_liquidity_with_invalid_number_of_accounts_6() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of input balances")]
#[test]
fn test_call_add_liquidity_invalid_number_of_balances_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),],
);
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Vault A was not provided")]
#[test]
fn test_call_add_liquidity_vault_a_omitted() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAWrongAccId),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
);
}
2025-11-18 14:43:40 -05:00
#[should_panic(expected = "Vault B was not provided")]
#[test]
fn test_call_add_liquidity_vault_b_omitted() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBWrongAccId),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
);
}
2025-11-18 14:43:40 -05:00
2025-12-06 20:03:05 -05:00
#[should_panic(expected = "LP definition mismatch")]
#[test]
fn test_call_add_liquidity_lp_def_mismatch() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPWrongAccId),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 20:03:05 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 20:03:05 -05:00
);
}
#[should_panic(expected = "Both max-balances must be nonzero")]
#[test]
fn test_call_add_liquidity_zero_balance_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMinAmountLP),
2025-12-06 20:03:05 -05:00
0,
2025-12-07 20:34:26 -05:00
helper_balance_constructor(BalanceEnum::AddMaxAmountb),],
);
2025-11-18 14:43:40 -05:00
}
#[should_panic(expected = "Both max-balances must be nonzero")]
#[test]
fn test_call_add_liquidity_zero_balance_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
2025-12-06 14:52:18 -05:00
0,
2025-12-07 20:34:26 -05:00
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
);
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Min-lp must be nonzero")]
2025-11-18 14:43:40 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_zero_min_lp() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-06 20:03:05 -05:00
&[0,
2025-12-07 20:34:26 -05:00
helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),],);
2025-12-06 14:52:18 -05:00
}
2025-11-20 21:02:18 -05:00
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Vaults' balances must be at least the reserve amounts")]
2025-11-20 21:02:18 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_vault_insufficient_balance_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInitZero),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Vaults' balances must be at least the reserve amounts")]
2025-11-20 21:02:18 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_vault_insufficient_balance_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInitZero),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "A trade amount is 0")]
2025-11-20 21:02:18 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_actual_amount_zero_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInitReserveALow),
helper_account_constructor(AccountEnum::VaultAInitLow),
helper_account_constructor(AccountEnum::VaultBInitHigh),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "A trade amount is 0")]
2025-11-20 21:02:18 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_actual_amount_zero_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInitReserveBLow),
helper_account_constructor(AccountEnum::VaultAInitHigh),
helper_account_constructor(AccountEnum::VaultBInitLow),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountALow),
helper_balance_constructor(BalanceEnum::AddMaxAmountBLow),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
2025-11-20 21:02:18 -05:00
}
#[should_panic(expected = "Reserves must be nonzero")]
#[test]
2025-11-25 23:06:47 -05:00
fn test_call_add_liquidity_reserves_zero_1() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInitReserveAZero),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
2025-11-25 23:06:47 -05:00
}
2025-11-25 23:06:47 -05:00
#[should_panic(expected = "Reserves must be nonzero")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_reserves_zero_2() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInitReserveBZero),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
2025-11-20 21:02:18 -05:00
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Payable LP must be nonzero")]
2025-11-25 23:06:47 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_payable_lp_zero() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionAddZeroLP),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountALow),
helper_balance_constructor(BalanceEnum::AddMaxAmountBLow),
helper_balance_constructor(BalanceEnum::AddMinAmountLP),],
2025-12-06 14:52:18 -05:00
);
}
2025-12-06 14:52:18 -05:00
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_add_liquidity_successful_chain_call() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::PoolLPInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
helper_account_constructor(AccountEnum::UserHoldingLPInit),
2025-12-06 14:52:18 -05:00
];
let (post_states, chained_calls) = add_liquidity(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMinAmountLP),
helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountb),],
2025-12-06 14:52:18 -05:00
);
2025-12-06 14:52:18 -05:00
let pool_post = post_states[0].clone();
2025-12-07 20:34:26 -05:00
assert!(helper_account_constructor(AccountEnum::PoolDefinitionAddSuccessful).account ==
*pool_post.account());
let chained_call_lp = chained_calls[0].clone();
let chained_call_b = chained_calls[1].clone();
let chained_call_a = chained_calls[2].clone();
2025-12-07 20:34:26 -05:00
assert!(chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcAddTokenA));
assert!(chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcAddTokenB));
assert!(chained_call_lp == helper_chained_call_constructor(ChainedCallsEnum::CcAddPoolLP));
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_swap_with_invalid_number_of_accounts_1() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_swap_with_invalid_number_of_accounts_2() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_swap_with_invalid_number_of_accounts_3() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
2025-11-25 23:06:47 -05:00
}
#[should_panic(expected = "Invalid number of input accounts")]
#[test]
fn test_call_swap_with_invalid_number_of_accounts_4() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
}
#[should_panic(expected = "Invalid number of amounts provided")]
#[test]
fn test_call_swap_with_invalid_number_of_amounts() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA)],
helper_id_constructor(IdEnum::TokenLPDefinitionId),
2025-12-06 14:52:18 -05:00
);
2025-11-25 23:06:47 -05:00
}
2025-12-02 15:20:16 -05:00
#[should_panic(expected = "AccountId is not a token type for the pool")]
2025-11-20 21:02:18 -05:00
#[test]
fn test_call_swap_incorrect_token_type() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenLPDefinitionId),
2025-12-06 14:52:18 -05:00
);
2025-11-20 21:02:18 -05:00
}
#[should_panic(expected = "Vault A was not provided")]
#[test]
fn test_call_swap_vault_a_omitted() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAWrongAccId),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
2025-11-20 21:02:18 -05:00
}
#[should_panic(expected = "Vault B was not provided")]
#[test]
fn test_call_swap_vault_b_omitted() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBWrongAccId),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
2025-11-18 14:43:40 -05:00
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Reserve for Token A exceeds vault balance")]
#[test]
2025-12-06 14:52:18 -05:00
fn test_call_swap_reserves_vault_mismatch_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInitLow),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Reserve for Token B exceeds vault balance")]
#[test]
2025-12-08 22:05:51 -05:00
fn test_call_swap_reserves_vault_mismatch_2() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInitLow),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
}
2025-12-08 22:05:51 -05:00
#[should_panic(expected = "Pool is inactive")]
#[test]
fn test_call_swap_ianctive() {
let pre_states = vec![
helper_account_constructor(AccountEnum::PoolDefinitionInactive),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
];
let _post_states = swap(&pre_states,
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
);
}
2025-12-06 14:52:18 -05:00
#[should_panic(expected = "Withdraw amount is less than minimal amount out")]
#[test]
fn test_call_swap_below_min_out() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let _post_states = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
}
2025-12-06 14:52:18 -05:00
#[test]
fn test_call_swap_successful_chain_call_1() {
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let (post_states, chained_calls) = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountA),
helper_balance_constructor(BalanceEnum::AddMaxAmountALow)],
helper_id_constructor(IdEnum::TokenADefinitionId),
2025-12-06 14:52:18 -05:00
);
let pool_post = post_states[0].clone();
2025-12-07 20:34:26 -05:00
assert!(helper_account_constructor(AccountEnum::PoolDefinitionSwapTest1).account ==
*pool_post.account());
2025-12-06 14:52:18 -05:00
let chained_call_a = chained_calls[0].clone();
let chained_call_b = chained_calls[1].clone();
2025-12-07 20:34:26 -05:00
assert!(chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenATest1));
assert!(chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenBTest1));
}
#[test]
fn test_call_swap_successful_chain_call_2() {
2025-12-06 14:52:18 -05:00
let pre_states = vec![
2025-12-07 20:34:26 -05:00
helper_account_constructor(AccountEnum::PoolDefinitionInit),
helper_account_constructor(AccountEnum::VaultAInit),
helper_account_constructor(AccountEnum::VaultBInit),
helper_account_constructor(AccountEnum::UserHoldingA),
helper_account_constructor(AccountEnum::UserHoldingB),
2025-12-06 14:52:18 -05:00
];
let (post_states, chained_calls) = swap(&pre_states,
2025-12-07 20:34:26 -05:00
&[helper_balance_constructor(BalanceEnum::AddMaxAmountb),
helper_balance_constructor(BalanceEnum::MinAmountOut)],
helper_id_constructor(IdEnum::TokenBDefinitionId),
2025-12-06 14:52:18 -05:00
);
let pool_post = post_states[0].clone();
2025-12-07 20:34:26 -05:00
assert!(helper_account_constructor(AccountEnum::PoolDefinitionSwapTest2).account ==
*pool_post.account());
2025-12-06 14:52:18 -05:00
let chained_call_a = chained_calls[1].clone();
let chained_call_b = chained_calls[0].clone();
2025-12-07 20:34:26 -05:00
assert!(chained_call_a == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenATest2));
assert!(chained_call_b == helper_chained_call_constructor(ChainedCallsEnum::CcSwapTokenBTest2));
2025-12-06 14:52:18 -05:00
}
2025-12-07 20:34:26 -05:00
}