mirror of
https://github.com/logos-blockchain/lez-programs.git
synced 2026-06-10 02:09:49 +00:00
feat(amm): route user deposits and LP burns through ATA program
Add `owner` and `ata_program_id` parameters to `add_liquidity`, `remove_liquidity`, `swap_exact_input`, and `swap_exact_output`. User deposit-side transfers now emit `ATA::Transfer` chained calls instead of `Token::Transfer` directly, and LP burns emit `ATA::Burn` instead of `Token::Burn`. Vault withdrawal chained calls are unchanged. - Add `ata_program_id` field to `AddLiquidity`, `RemoveLiquidity`, `SwapExactInput`, and `SwapExactOutput` instruction variants in `amm_core` - Add `ata_core` dependency to `amm_program` and guest crates - Update guest binary, unit tests, and integration tests to supply the new `owner` account and `ata_program_id` at every call site - Regenerate `artifacts/amm-idl.json` Closes #11
This commit is contained in:
parent
471abef719
commit
9444d72c60
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -54,6 +54,7 @@ name = "amm_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"amm_core",
|
||||
"ata_core",
|
||||
"nssa_core",
|
||||
"token_core",
|
||||
]
|
||||
|
||||
@ -6,4 +6,5 @@ edition = "2021"
|
||||
[dependencies]
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1", features = ["host"] }
|
||||
amm_core = { path = "core" }
|
||||
ata_core = { path = "../ata/core" }
|
||||
token_core = { path = "../token/core" }
|
||||
|
||||
@ -44,13 +44,15 @@ pub enum Instruction {
|
||||
/// - Vault Holding Account for Token A (initialized)
|
||||
/// - Vault Holding Account for Token B (initialized)
|
||||
/// - Pool Liquidity Token Definition (initialized)
|
||||
/// - User Holding Account for Token A (authorized)
|
||||
/// - User Holding Account for Token B (authorized)
|
||||
/// - User Holding Account for Pool Liquidity
|
||||
/// - Owner account (authorized)
|
||||
/// - User ATA for Token A
|
||||
/// - User ATA for Token B
|
||||
/// - User ATA for Pool Liquidity
|
||||
AddLiquidity {
|
||||
min_amount_liquidity: u128,
|
||||
max_amount_to_add_token_a: u128,
|
||||
max_amount_to_add_token_b: u128,
|
||||
ata_program_id: ProgramId,
|
||||
},
|
||||
|
||||
/// Removes liquidity from the Pool
|
||||
@ -60,13 +62,15 @@ pub enum Instruction {
|
||||
/// - Vault Holding Account for Token A (initialized)
|
||||
/// - Vault Holding Account for Token B (initialized)
|
||||
/// - Pool Liquidity Token Definition (initialized)
|
||||
/// - User Holding Account for Token A (initialized)
|
||||
/// - User Holding Account for Token B (initialized)
|
||||
/// - User Holding Account for Pool Liquidity (authorized)
|
||||
/// - Owner account (authorized)
|
||||
/// - User ATA for Token A (initialized)
|
||||
/// - User ATA for Token B (initialized)
|
||||
/// - User ATA for Pool Liquidity
|
||||
RemoveLiquidity {
|
||||
remove_liquidity_amount: u128,
|
||||
min_amount_to_remove_token_a: u128,
|
||||
min_amount_to_remove_token_b: u128,
|
||||
ata_program_id: ProgramId,
|
||||
},
|
||||
|
||||
/// Swap some quantity of Tokens (either Token A or Token B)
|
||||
@ -76,13 +80,14 @@ pub enum Instruction {
|
||||
/// - AMM Pool (initialized)
|
||||
/// - Vault Holding Account for Token A (initialized)
|
||||
/// - Vault Holding Account for Token B (initialized)
|
||||
/// - User Holding Account for Token A
|
||||
/// - User Holding Account for Token B Either User Holding Account for Token A or Token B is
|
||||
/// authorized.
|
||||
/// - Owner account (authorized)
|
||||
/// - User ATA for Token A
|
||||
/// - User ATA for Token B
|
||||
SwapExactInput {
|
||||
swap_amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
},
|
||||
|
||||
/// Swap tokens specifying the exact desired output amount,
|
||||
@ -92,13 +97,14 @@ pub enum Instruction {
|
||||
/// - AMM Pool (initialized)
|
||||
/// - Vault Holding Account for Token A (initialized)
|
||||
/// - Vault Holding Account for Token B (initialized)
|
||||
/// - User Holding Account for Token A
|
||||
/// - User Holding Account for Token B Either User Holding Account for Token A or Token B is
|
||||
/// authorized.
|
||||
/// - Owner account (authorized)
|
||||
/// - User ATA for Token A
|
||||
/// - User ATA for Token B
|
||||
SwapExactOutput {
|
||||
exact_amount_out: u128,
|
||||
max_amount_in: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
},
|
||||
|
||||
/// Sync pool reserves with current vault balances.
|
||||
|
||||
12
amm/methods/guest/Cargo.lock
generated
12
amm/methods/guest/Cargo.lock
generated
@ -35,6 +35,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"amm_core",
|
||||
"amm_program",
|
||||
"ata_core",
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
"risc0-zkvm",
|
||||
@ -59,6 +60,7 @@ name = "amm_program"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"amm_core",
|
||||
"ata_core",
|
||||
"nssa_core",
|
||||
"token_core",
|
||||
]
|
||||
@ -304,6 +306,16 @@ version = "0.7.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
|
||||
|
||||
[[package]]
|
||||
name = "ata_core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"borsh",
|
||||
"nssa_core",
|
||||
"risc0-zkvm",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
|
||||
@ -14,6 +14,7 @@ spel-framework = { git = "https://github.com/logos-co/spel.git", tag = "v0.2.0-r
|
||||
nssa_core = { git = "https://github.com/logos-blockchain/logos-execution-zone.git", tag = "v0.2.0-rc1" }
|
||||
risc0-zkvm = { version = "=3.0.5", default-features = false }
|
||||
amm_core = { path = "../../core" }
|
||||
ata_core = { path = "../../../ata/core" }
|
||||
amm_program = { path = "../..", package = "amm_program" }
|
||||
token_core = { path = "../../../token/core" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@ -56,24 +56,28 @@ mod amm {
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
pool_definition_lp: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
user_holding_lp: AccountWithMetadata,
|
||||
min_amount_liquidity: u128,
|
||||
max_amount_to_add_token_a: u128,
|
||||
max_amount_to_add_token_b: u128,
|
||||
ata_program_id: ProgramId,
|
||||
) -> SpelResult {
|
||||
let (post_states, chained_calls) = amm_program::add::add_liquidity(
|
||||
pool,
|
||||
vault_a,
|
||||
vault_b,
|
||||
pool_definition_lp,
|
||||
owner,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
NonZeroU128::new(min_amount_liquidity).expect("min_amount_liquidity must be nonzero"),
|
||||
max_amount_to_add_token_a,
|
||||
max_amount_to_add_token_b,
|
||||
ata_program_id,
|
||||
);
|
||||
Ok(SpelOutput::with_chained_calls(post_states, chained_calls))
|
||||
}
|
||||
@ -85,18 +89,21 @@ mod amm {
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
pool_definition_lp: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
user_holding_lp: AccountWithMetadata,
|
||||
remove_liquidity_amount: u128,
|
||||
min_amount_to_remove_token_a: u128,
|
||||
min_amount_to_remove_token_b: u128,
|
||||
ata_program_id: ProgramId,
|
||||
) -> SpelResult {
|
||||
let (post_states, chained_calls) = amm_program::remove::remove_liquidity(
|
||||
pool,
|
||||
vault_a,
|
||||
vault_b,
|
||||
pool_definition_lp,
|
||||
owner,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
@ -104,6 +111,7 @@ mod amm {
|
||||
.expect("remove_liquidity_amount must be nonzero"),
|
||||
min_amount_to_remove_token_a,
|
||||
min_amount_to_remove_token_b,
|
||||
ata_program_id,
|
||||
);
|
||||
Ok(SpelOutput::with_chained_calls(post_states, chained_calls))
|
||||
}
|
||||
@ -114,21 +122,25 @@ mod amm {
|
||||
pool: AccountWithMetadata,
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
swap_amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
) -> SpelResult {
|
||||
let (post_states, chained_calls) = amm_program::swap::swap_exact_input(
|
||||
pool,
|
||||
vault_a,
|
||||
vault_b,
|
||||
owner,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
swap_amount_in,
|
||||
min_amount_out,
|
||||
token_definition_id_in,
|
||||
ata_program_id,
|
||||
);
|
||||
Ok(SpelOutput::with_chained_calls(post_states, chained_calls))
|
||||
}
|
||||
@ -139,21 +151,25 @@ mod amm {
|
||||
pool: AccountWithMetadata,
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
exact_amount_out: u128,
|
||||
max_amount_in: u128,
|
||||
token_definition_id_in: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
) -> SpelResult {
|
||||
let (post_states, chained_calls) = amm_program::swap::swap_exact_output(
|
||||
pool,
|
||||
vault_a,
|
||||
vault_b,
|
||||
owner,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
exact_amount_out,
|
||||
max_amount_in,
|
||||
token_definition_id_in,
|
||||
ata_program_id,
|
||||
);
|
||||
Ok(SpelOutput::with_chained_calls(post_states, chained_calls))
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ use amm_core::{
|
||||
};
|
||||
use nssa_core::{
|
||||
account::{AccountWithMetadata, Data},
|
||||
program::{AccountPostState, ChainedCall},
|
||||
program::{AccountPostState, ChainedCall, ProgramId},
|
||||
};
|
||||
|
||||
#[expect(clippy::too_many_arguments, reason = "TODO: Fix later")]
|
||||
@ -15,12 +15,14 @@ pub fn add_liquidity(
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
pool_definition_lp: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
user_holding_lp: AccountWithMetadata,
|
||||
min_amount_liquidity: NonZeroU128,
|
||||
max_amount_to_add_token_a: u128,
|
||||
max_amount_to_add_token_b: u128,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
|
||||
// 1. Fetch Pool state
|
||||
let pool_def_data = PoolDefinition::try_from(&pool.account.data)
|
||||
@ -138,25 +140,27 @@ pub fn add_liquidity(
|
||||
};
|
||||
|
||||
pool_post.data = Data::from(&pool_post_definition);
|
||||
let token_program_id = user_holding_a.account.program_owner;
|
||||
let token_program_id = vault_a.account.program_owner;
|
||||
|
||||
// Chain call for Token A (UserHoldingA -> Vault_A)
|
||||
// Chain call for Token A (owner's ATA -> Vault_A via ATA program)
|
||||
let call_token_a = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![user_holding_a.clone(), vault_a.clone()],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: actual_amount_a,
|
||||
ata_program_id,
|
||||
vec![owner.clone(), user_holding_a.clone(), vault_a.clone()],
|
||||
&ata_core::Instruction::Transfer {
|
||||
ata_program_id,
|
||||
amount: actual_amount_a,
|
||||
},
|
||||
);
|
||||
// Chain call for Token B (UserHoldingB -> Vault_B)
|
||||
// Chain call for Token B (owner's ATA -> Vault_B via ATA program)
|
||||
let call_token_b = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![user_holding_b.clone(), vault_b.clone()],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: actual_amount_b,
|
||||
ata_program_id,
|
||||
vec![owner.clone(), user_holding_b.clone(), vault_b.clone()],
|
||||
&ata_core::Instruction::Transfer {
|
||||
ata_program_id,
|
||||
amount: actual_amount_b,
|
||||
},
|
||||
);
|
||||
// Chain call for LP (mint new tokens for user_holding_lp)
|
||||
// Chain call for LP (mint new tokens for user's LP ATA)
|
||||
let mut pool_definition_lp_auth = pool_definition_lp.clone();
|
||||
pool_definition_lp_auth.is_authorized = true;
|
||||
let call_token_lp = ChainedCall::new(
|
||||
@ -175,6 +179,7 @@ pub fn add_liquidity(
|
||||
AccountPostState::new(vault_a.account.clone()),
|
||||
AccountPostState::new(vault_b.account.clone()),
|
||||
AccountPostState::new(pool_definition_lp.account.clone()),
|
||||
AccountPostState::new(owner.account.clone()),
|
||||
AccountPostState::new(user_holding_a.account.clone()),
|
||||
AccountPostState::new(user_holding_b.account.clone()),
|
||||
AccountPostState::new(user_holding_lp.account.clone()),
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
use std::num::NonZeroU128;
|
||||
|
||||
use amm_core::{
|
||||
assert_supported_fee_tier, compute_liquidity_token_pda_seed, compute_vault_pda_seed,
|
||||
PoolDefinition, MINIMUM_LIQUIDITY,
|
||||
assert_supported_fee_tier, compute_vault_pda_seed, PoolDefinition, MINIMUM_LIQUIDITY,
|
||||
};
|
||||
use nssa_core::{
|
||||
account::{AccountWithMetadata, Data},
|
||||
program::{AccountPostState, ChainedCall},
|
||||
program::{AccountPostState, ChainedCall, ProgramId},
|
||||
};
|
||||
|
||||
#[expect(clippy::too_many_arguments, reason = "TODO: Fix later")]
|
||||
@ -15,12 +14,14 @@ pub fn remove_liquidity(
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
pool_definition_lp: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
user_holding_lp: AccountWithMetadata,
|
||||
remove_liquidity_amount: NonZeroU128,
|
||||
min_amount_to_remove_token_a: u128,
|
||||
min_amount_to_remove_token_b: u128,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
|
||||
let remove_liquidity_amount: u128 = remove_liquidity_amount.into();
|
||||
|
||||
@ -143,9 +144,9 @@ pub fn remove_liquidity(
|
||||
|
||||
pool_post.data = Data::from(&pool_post_definition);
|
||||
|
||||
let token_program_id = user_holding_a.account.program_owner;
|
||||
let token_program_id = vault_a.account.program_owner;
|
||||
|
||||
// Chaincall for Token A withdraw
|
||||
// Chaincall for Token A withdraw (vault PDA -> user's ATA)
|
||||
let call_token_a = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![running_vault_a, user_holding_a.clone()],
|
||||
@ -157,7 +158,7 @@ pub fn remove_liquidity(
|
||||
pool.account_id,
|
||||
pool_def_data.definition_token_a_id,
|
||||
)]);
|
||||
// Chaincall for Token B withdraw
|
||||
// Chaincall for Token B withdraw (vault PDA -> user's ATA)
|
||||
let call_token_b = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![running_vault_b, user_holding_b.clone()],
|
||||
@ -169,17 +170,19 @@ pub fn remove_liquidity(
|
||||
pool.account_id,
|
||||
pool_def_data.definition_token_b_id,
|
||||
)]);
|
||||
// Chaincall for LP adjustment
|
||||
let mut pool_definition_lp_auth = pool_definition_lp.clone();
|
||||
pool_definition_lp_auth.is_authorized = true;
|
||||
// Chaincall for LP burn (owner's LP ATA -> burn via ATA program)
|
||||
let call_token_lp = ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![pool_definition_lp_auth, user_holding_lp.clone()],
|
||||
&token_core::Instruction::Burn {
|
||||
amount_to_burn: delta_lp,
|
||||
ata_program_id,
|
||||
vec![
|
||||
owner.clone(),
|
||||
user_holding_lp.clone(),
|
||||
pool_definition_lp.clone(),
|
||||
],
|
||||
&ata_core::Instruction::Burn {
|
||||
ata_program_id,
|
||||
amount: delta_lp,
|
||||
},
|
||||
)
|
||||
.with_pda_seeds(vec![compute_liquidity_token_pda_seed(pool.account_id)]);
|
||||
);
|
||||
|
||||
let chained_calls = vec![call_token_lp, call_token_b, call_token_a];
|
||||
|
||||
@ -188,6 +191,7 @@ pub fn remove_liquidity(
|
||||
AccountPostState::new(vault_a.account.clone()),
|
||||
AccountPostState::new(vault_b.account.clone()),
|
||||
AccountPostState::new(pool_definition_lp.account.clone()),
|
||||
AccountPostState::new(owner.account.clone()),
|
||||
AccountPostState::new(user_holding_a.account.clone()),
|
||||
AccountPostState::new(user_holding_b.account.clone()),
|
||||
AccountPostState::new(user_holding_lp.account.clone()),
|
||||
|
||||
@ -4,7 +4,7 @@ use amm_core::{
|
||||
pub use amm_core::{compute_liquidity_token_pda_seed, compute_vault_pda_seed, PoolDefinition};
|
||||
use nssa_core::{
|
||||
account::{AccountId, AccountWithMetadata, Data},
|
||||
program::{AccountPostState, ChainedCall},
|
||||
program::{AccountPostState, ChainedCall, ProgramId},
|
||||
};
|
||||
|
||||
/// Validates swap setup: checks pool liquidity is ready, vaults match, and reserves are sufficient.
|
||||
@ -56,6 +56,7 @@ fn create_swap_post_states(
|
||||
pool_def_data: PoolDefinition,
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
deposit_a: u128,
|
||||
@ -86,6 +87,7 @@ fn create_swap_post_states(
|
||||
AccountPostState::new(pool_post),
|
||||
AccountPostState::new(vault_a.account),
|
||||
AccountPostState::new(vault_b.account),
|
||||
AccountPostState::new(owner.account),
|
||||
AccountPostState::new(user_holding_a.account),
|
||||
AccountPostState::new(user_holding_b.account),
|
||||
]
|
||||
@ -97,17 +99,20 @@ pub fn swap_exact_input(
|
||||
pool: AccountWithMetadata,
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
swap_amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_in_id: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
|
||||
let pool_def_data = validate_swap_setup(&pool, &vault_a, &vault_b);
|
||||
|
||||
let (chained_calls, [deposit_a, withdraw_a], [deposit_b, withdraw_b]) =
|
||||
if token_in_id == pool_def_data.definition_token_a_id {
|
||||
let (chained_calls, deposit_a, withdraw_b) = swap_logic(
|
||||
owner.clone(),
|
||||
user_holding_a.clone(),
|
||||
vault_a.clone(),
|
||||
vault_b.clone(),
|
||||
@ -118,11 +123,13 @@ pub fn swap_exact_input(
|
||||
pool_def_data.reserve_a,
|
||||
pool_def_data.reserve_b,
|
||||
pool.account_id,
|
||||
ata_program_id,
|
||||
);
|
||||
|
||||
(chained_calls, [deposit_a, 0], [0, withdraw_b])
|
||||
} else if token_in_id == pool_def_data.definition_token_b_id {
|
||||
let (chained_calls, deposit_b, withdraw_a) = swap_logic(
|
||||
owner.clone(),
|
||||
user_holding_b.clone(),
|
||||
vault_b.clone(),
|
||||
vault_a.clone(),
|
||||
@ -133,6 +140,7 @@ pub fn swap_exact_input(
|
||||
pool_def_data.reserve_b,
|
||||
pool_def_data.reserve_a,
|
||||
pool.account_id,
|
||||
ata_program_id,
|
||||
);
|
||||
|
||||
(chained_calls, [0, withdraw_a], [deposit_b, 0])
|
||||
@ -145,6 +153,7 @@ pub fn swap_exact_input(
|
||||
pool_def_data,
|
||||
vault_a,
|
||||
vault_b,
|
||||
owner,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
deposit_a,
|
||||
@ -158,6 +167,7 @@ pub fn swap_exact_input(
|
||||
|
||||
#[expect(clippy::too_many_arguments, reason = "TODO: Fix later")]
|
||||
fn swap_logic(
|
||||
owner: AccountWithMetadata,
|
||||
user_deposit: AccountWithMetadata,
|
||||
vault_deposit: AccountWithMetadata,
|
||||
vault_withdraw: AccountWithMetadata,
|
||||
@ -168,6 +178,7 @@ fn swap_logic(
|
||||
reserve_deposit_vault_amount: u128,
|
||||
reserve_withdraw_vault_amount: u128,
|
||||
pool_id: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<ChainedCall>, u128, u128) {
|
||||
let effective_amount_in = swap_amount_in
|
||||
.checked_mul(FEE_BPS_DENOMINATOR - fee_bps)
|
||||
@ -195,14 +206,16 @@ fn swap_logic(
|
||||
);
|
||||
assert!(withdraw_amount != 0, "Withdraw amount should be nonzero");
|
||||
|
||||
let token_program_id = user_deposit.account.program_owner;
|
||||
let token_program_id = vault_withdraw.account.program_owner;
|
||||
|
||||
let mut chained_calls = Vec::new();
|
||||
// Deposit: owner's ATA -> vault via ATA program
|
||||
chained_calls.push(ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![user_deposit, vault_deposit],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: swap_amount_in,
|
||||
ata_program_id,
|
||||
vec![owner, user_deposit, vault_deposit],
|
||||
&ata_core::Instruction::Transfer {
|
||||
ata_program_id,
|
||||
amount: swap_amount_in,
|
||||
},
|
||||
));
|
||||
|
||||
@ -216,6 +229,7 @@ fn swap_logic(
|
||||
.definition_id(),
|
||||
);
|
||||
|
||||
// Withdrawal: vault PDA -> user's ATA (no ATA auth needed for recipient)
|
||||
chained_calls.push(
|
||||
ChainedCall::new(
|
||||
token_program_id,
|
||||
@ -236,17 +250,20 @@ pub fn swap_exact_output(
|
||||
pool: AccountWithMetadata,
|
||||
vault_a: AccountWithMetadata,
|
||||
vault_b: AccountWithMetadata,
|
||||
owner: AccountWithMetadata,
|
||||
user_holding_a: AccountWithMetadata,
|
||||
user_holding_b: AccountWithMetadata,
|
||||
exact_amount_out: u128,
|
||||
max_amount_in: u128,
|
||||
token_in_id: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<AccountPostState>, Vec<ChainedCall>) {
|
||||
let pool_def_data = validate_swap_setup(&pool, &vault_a, &vault_b);
|
||||
|
||||
let (chained_calls, [deposit_a, withdraw_a], [deposit_b, withdraw_b]) =
|
||||
if token_in_id == pool_def_data.definition_token_a_id {
|
||||
let (chained_calls, deposit_a, withdraw_b) = exact_output_swap_logic(
|
||||
owner.clone(),
|
||||
user_holding_a.clone(),
|
||||
vault_a.clone(),
|
||||
vault_b.clone(),
|
||||
@ -257,11 +274,13 @@ pub fn swap_exact_output(
|
||||
pool_def_data.reserve_b,
|
||||
pool_def_data.fees,
|
||||
pool.account_id,
|
||||
ata_program_id,
|
||||
);
|
||||
|
||||
(chained_calls, [deposit_a, 0], [0, withdraw_b])
|
||||
} else if token_in_id == pool_def_data.definition_token_b_id {
|
||||
let (chained_calls, deposit_b, withdraw_a) = exact_output_swap_logic(
|
||||
owner.clone(),
|
||||
user_holding_b.clone(),
|
||||
vault_b.clone(),
|
||||
vault_a.clone(),
|
||||
@ -272,6 +291,7 @@ pub fn swap_exact_output(
|
||||
pool_def_data.reserve_a,
|
||||
pool_def_data.fees,
|
||||
pool.account_id,
|
||||
ata_program_id,
|
||||
);
|
||||
|
||||
(chained_calls, [0, withdraw_a], [deposit_b, 0])
|
||||
@ -284,6 +304,7 @@ pub fn swap_exact_output(
|
||||
pool_def_data,
|
||||
vault_a,
|
||||
vault_b,
|
||||
owner,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
deposit_a,
|
||||
@ -297,6 +318,7 @@ pub fn swap_exact_output(
|
||||
|
||||
#[expect(clippy::too_many_arguments, reason = "TODO: Fix later")]
|
||||
fn exact_output_swap_logic(
|
||||
owner: AccountWithMetadata,
|
||||
user_deposit: AccountWithMetadata,
|
||||
vault_deposit: AccountWithMetadata,
|
||||
vault_withdraw: AccountWithMetadata,
|
||||
@ -307,6 +329,7 @@ fn exact_output_swap_logic(
|
||||
reserve_withdraw_vault_amount: u128,
|
||||
fee_bps: u128,
|
||||
pool_id: AccountId,
|
||||
ata_program_id: ProgramId,
|
||||
) -> (Vec<ChainedCall>, u128, u128) {
|
||||
// Guard: exact_amount_out must be nonzero
|
||||
assert_ne!(exact_amount_out, 0, "Exact amount out must be nonzero");
|
||||
@ -346,14 +369,16 @@ fn exact_output_swap_logic(
|
||||
"Required input exceeds maximum amount in"
|
||||
);
|
||||
|
||||
let token_program_id = user_deposit.account.program_owner;
|
||||
let token_program_id = vault_withdraw.account.program_owner;
|
||||
|
||||
let mut chained_calls = Vec::new();
|
||||
// Deposit: owner's ATA -> vault via ATA program
|
||||
chained_calls.push(ChainedCall::new(
|
||||
token_program_id,
|
||||
vec![user_deposit, vault_deposit],
|
||||
&token_core::Instruction::Transfer {
|
||||
amount_to_transfer: deposit_amount,
|
||||
ata_program_id,
|
||||
vec![owner, user_deposit, vault_deposit],
|
||||
&ata_core::Instruction::Transfer {
|
||||
ata_program_id,
|
||||
amount: deposit_amount,
|
||||
},
|
||||
));
|
||||
|
||||
@ -367,6 +392,7 @@ fn exact_output_swap_logic(
|
||||
.definition_id(),
|
||||
);
|
||||
|
||||
// Withdrawal: vault PDA -> user's ATA (no ATA auth needed for recipient)
|
||||
chained_calls.push(
|
||||
ChainedCall::new(
|
||||
token_program_id,
|
||||
|
||||
212
amm/src/tests.rs
212
amm/src/tests.rs
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
||||
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.53s
|
||||
Running `target/debug/idl-gen amm/methods/guest/src/bin/amm.rs`
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"name": "amm",
|
||||
@ -100,6 +102,12 @@
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"writable": false,
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "user_holding_a",
|
||||
"writable": false,
|
||||
@ -131,6 +139,10 @@
|
||||
{
|
||||
"name": "max_amount_to_add_token_b",
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "ata_program_id",
|
||||
"type": "program_id"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -161,6 +173,12 @@
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"writable": false,
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "user_holding_a",
|
||||
"writable": false,
|
||||
@ -192,6 +210,10 @@
|
||||
{
|
||||
"name": "min_amount_to_remove_token_b",
|
||||
"type": "u128"
|
||||
},
|
||||
{
|
||||
"name": "ata_program_id",
|
||||
"type": "program_id"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -216,6 +238,12 @@
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"writable": false,
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "user_holding_a",
|
||||
"writable": false,
|
||||
@ -241,6 +269,10 @@
|
||||
{
|
||||
"name": "token_definition_id_in",
|
||||
"type": "account_id"
|
||||
},
|
||||
{
|
||||
"name": "ata_program_id",
|
||||
"type": "program_id"
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -265,6 +297,12 @@
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "owner",
|
||||
"writable": false,
|
||||
"signer": false,
|
||||
"init": false
|
||||
},
|
||||
{
|
||||
"name": "user_holding_a",
|
||||
"writable": false,
|
||||
@ -290,6 +328,10 @@
|
||||
{
|
||||
"name": "token_definition_id_in",
|
||||
"type": "account_id"
|
||||
},
|
||||
{
|
||||
"name": "ata_program_id",
|
||||
"type": "program_id"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@ -38,6 +38,10 @@ impl Ids {
|
||||
amm_methods::AMM_ID
|
||||
}
|
||||
|
||||
fn ata_program() -> nssa_core::program::ProgramId {
|
||||
ata_methods::ATA_ID
|
||||
}
|
||||
|
||||
fn token_a_definition() -> AccountId {
|
||||
AccountId::new([3; 32])
|
||||
}
|
||||
@ -1018,6 +1022,7 @@ fn execute_swap_a_to_b(state: &mut V03State, swap_amount_in: u128, min_amount_ou
|
||||
swap_amount_in,
|
||||
min_amount_out,
|
||||
token_definition_id_in: Ids::token_a_definition(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1045,6 +1050,7 @@ fn execute_swap_b_to_a(state: &mut V03State, swap_amount_in: u128, min_amount_ou
|
||||
swap_amount_in,
|
||||
min_amount_out,
|
||||
token_definition_id_in: Ids::token_b_definition(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1077,6 +1083,7 @@ fn execute_add_liquidity(
|
||||
min_amount_liquidity,
|
||||
max_amount_to_add_token_a,
|
||||
max_amount_to_add_token_b,
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1115,6 +1122,7 @@ fn execute_remove_liquidity(
|
||||
remove_liquidity_amount,
|
||||
min_amount_to_remove_token_a,
|
||||
min_amount_to_remove_token_b,
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1178,6 +1186,7 @@ fn amm_remove_liquidity() {
|
||||
remove_liquidity_amount: Balances::remove_lp(),
|
||||
min_amount_to_remove_token_a: Balances::remove_min_a(),
|
||||
min_amount_to_remove_token_b: Balances::remove_min_b(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1240,6 +1249,7 @@ fn amm_remove_liquidity_insufficient_user_lp_fails() {
|
||||
remove_liquidity_amount: Balances::remove_lp(),
|
||||
min_amount_to_remove_token_a: Balances::remove_min_a(),
|
||||
min_amount_to_remove_token_b: Balances::remove_min_b(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1464,6 +1474,7 @@ fn amm_add_liquidity() {
|
||||
min_amount_liquidity: Balances::add_min_lp(),
|
||||
max_amount_to_add_token_a: Balances::add_max_a(),
|
||||
max_amount_to_add_token_b: Balances::add_max_b(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1526,6 +1537,7 @@ fn amm_swap_b_to_a() {
|
||||
swap_amount_in: Balances::swap_amount_in(),
|
||||
min_amount_out: Balances::swap_min_out(),
|
||||
token_definition_id_in: Ids::token_b_definition(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
@ -1577,6 +1589,7 @@ fn amm_swap_a_to_b() {
|
||||
swap_amount_in: Balances::swap_amount_in(),
|
||||
min_amount_out: Balances::swap_min_out(),
|
||||
token_definition_id_in: Ids::token_a_definition(),
|
||||
ata_program_id: Ids::ata_program(),
|
||||
};
|
||||
|
||||
let message = public_transaction::Message::try_new(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user