432 lines
17 KiB
Rust
Raw Normal View History

2026-01-23 16:30:54 -05:00
use amm_core::{compute_liquidity_token_pda, compute_pool_pda, compute_vault_pda};
2026-05-17 12:32:43 -04:00
use common::HashType;
use nssa::{AccountId, program::Program};
use token_core::TokenHolding;
2025-12-17 14:21:36 +02:00
use crate::{AccountIdentity, ExecutionFailureKind, WalletCore, cli::CliAccountMention};
2026-03-04 18:42:33 +03:00
pub struct Amm<'wallet>(pub &'wallet WalletCore);
2025-12-22 04:42:32 +02:00
impl Amm<'_> {
2026-05-15 18:15:54 -04:00
#[expect(clippy::too_many_arguments, reason = "each parameter is distinct")]
2025-12-22 04:42:32 +02:00
pub async fn send_new_definition(
2025-12-16 14:05:34 +02:00
&self,
2025-12-18 11:44:38 +02:00
user_holding_a: AccountId,
user_holding_b: AccountId,
user_holding_lp: AccountId,
2025-12-17 11:44:52 +02:00
balance_a: u128,
balance_b: u128,
user_holding_a_mention: &CliAccountMention,
user_holding_b_mention: &CliAccountMention,
user_holding_lp_mention: &CliAccountMention,
) -> Result<HashType, ExecutionFailureKind> {
let user_holding_a_identity = user_holding_a_mention.key_path().map_or(
AccountIdentity::Public(user_holding_a),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_a,
key_path: key_path.to_owned(),
},
);
let user_holding_b_identity = user_holding_b_mention.key_path().map_or(
AccountIdentity::Public(user_holding_b),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_b,
key_path: key_path.to_owned(),
},
);
let user_holding_lp_identity = user_holding_lp_mention.key_path().map_or(
AccountIdentity::Public(user_holding_lp),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_lp,
key_path: key_path.to_owned(),
},
);
2026-01-23 16:30:54 -05:00
let program = Program::amm();
2025-12-18 11:44:38 +02:00
let amm_program_id = Program::amm().id();
2025-12-22 04:42:32 +02:00
let user_a_acc = self
.0
.get_account_public(user_holding_a)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-22 04:42:32 +02:00
let user_b_acc = self
.0
.get_account_public(user_holding_b)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-18 11:44:38 +02:00
let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id();
let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_b))?
.definition_id();
2025-12-18 11:44:38 +02:00
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let instruction = amm_core::Instruction::NewDefinition {
token_a_amount: balance_a,
token_b_amount: balance_b,
amm_program_id,
};
let instruction_data =
Program::serialize_instruction(instruction).expect("Instruction should serialize");
2025-12-18 11:44:38 +02:00
2026-05-17 12:32:43 -04:00
self.0
.send_pub_tx(
vec![
AccountIdentity::PublicNoSign(amm_pool),
AccountIdentity::PublicNoSign(vault_holding_a),
AccountIdentity::PublicNoSign(vault_holding_b),
AccountIdentity::PublicNoSign(pool_lp),
user_holding_a_identity,
user_holding_b_identity,
user_holding_lp_identity,
],
instruction_data,
&program.into(),
)
2026-05-17 12:32:43 -04:00
.await
2025-12-16 14:05:34 +02:00
}
2026-05-15 18:15:54 -04:00
#[expect(clippy::too_many_arguments, reason = "each parameter is distinct")]
pub async fn send_swap_exact_input(
2025-12-16 14:05:34 +02:00
&self,
2025-12-18 11:44:38 +02:00
user_holding_a: AccountId,
user_holding_b: AccountId,
2026-01-23 16:30:54 -05:00
swap_amount_in: u128,
2025-12-16 14:05:34 +02:00
min_amount_out: u128,
2026-01-23 16:30:54 -05:00
token_definition_id_in: AccountId,
user_holding_a_mention: &CliAccountMention,
user_holding_b_mention: &CliAccountMention,
) -> Result<HashType, ExecutionFailureKind> {
2026-01-23 16:30:54 -05:00
let program = Program::amm();
2025-12-18 11:44:38 +02:00
let amm_program_id = Program::amm().id();
2025-12-22 04:42:32 +02:00
let user_a_acc = self
.0
.get_account_public(user_holding_a)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-22 04:42:32 +02:00
let user_b_acc = self
.0
.get_account_public(user_holding_b)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-18 11:44:38 +02:00
let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id();
let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_b))?
.definition_id();
2025-12-18 11:44:38 +02:00
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let instruction = amm_core::Instruction::SwapExactInput {
swap_amount_in,
min_amount_out,
token_definition_id_in,
};
let instruction_data =
Program::serialize_instruction(instruction).expect("Instruction should serialize");
2025-12-18 11:44:38 +02:00
if (token_definition_id_in != definition_token_a_id)
&& (token_definition_id_in != definition_token_b_id)
{
2026-05-17 12:32:43 -04:00
return Err(ExecutionFailureKind::AccountDataError(
token_definition_id_in,
));
}
let user_a_signing_identity = if token_definition_id_in == definition_token_a_id {
user_holding_a_mention.key_path().map_or(
AccountIdentity::Public(user_holding_a),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_a,
key_path: key_path.to_owned(),
},
)
} else {
AccountIdentity::PublicNoSign(user_holding_a)
};
let user_b_signing_identity = if token_definition_id_in == definition_token_b_id {
user_holding_b_mention.key_path().map_or(
AccountIdentity::Public(user_holding_b),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_b,
key_path: key_path.to_owned(),
},
)
} else {
AccountIdentity::PublicNoSign(user_holding_b)
};
2026-05-17 12:32:43 -04:00
self.0
.send_pub_tx(
vec![
AccountIdentity::PublicNoSign(amm_pool),
AccountIdentity::PublicNoSign(vault_holding_a),
AccountIdentity::PublicNoSign(vault_holding_b),
user_a_signing_identity,
user_b_signing_identity,
],
instruction_data,
&program.into(),
)
2026-05-17 12:32:43 -04:00
.await
}
2026-05-15 18:15:54 -04:00
#[expect(clippy::too_many_arguments, reason = "each parameter is distinct")]
pub async fn send_swap_exact_output(
&self,
user_holding_a: AccountId,
user_holding_b: AccountId,
exact_amount_out: u128,
max_amount_in: u128,
token_definition_id_in: AccountId,
user_holding_a_mention: &CliAccountMention,
user_holding_b_mention: &CliAccountMention,
) -> Result<HashType, ExecutionFailureKind> {
let program = Program::amm();
let amm_program_id = Program::amm().id();
let user_a_acc = self
2025-12-18 11:44:38 +02:00
.0
.get_account_public(user_holding_a)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
let user_b_acc = self
2025-12-18 11:44:38 +02:00
.0
.get_account_public(user_holding_b)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-18 11:44:38 +02:00
let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data)
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id();
let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data)
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_b))?
.definition_id();
2025-12-18 11:44:38 +02:00
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let instruction = amm_core::Instruction::SwapExactOutput {
exact_amount_out,
max_amount_in,
token_definition_id_in,
};
let instruction_data =
Program::serialize_instruction(instruction).expect("Instruction should serialize");
if (token_definition_id_in != definition_token_a_id)
&& (token_definition_id_in != definition_token_b_id)
{
2026-05-17 12:32:43 -04:00
return Err(ExecutionFailureKind::AccountDataError(
token_definition_id_in,
));
}
let user_a_signing_identity = if token_definition_id_in == definition_token_a_id {
user_holding_a_mention.key_path().map_or(
AccountIdentity::Public(user_holding_a),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_a,
key_path: key_path.to_owned(),
},
)
} else {
AccountIdentity::PublicNoSign(user_holding_a)
};
let user_b_signing_identity = if token_definition_id_in == definition_token_b_id {
user_holding_b_mention.key_path().map_or(
AccountIdentity::Public(user_holding_b),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_b,
key_path: key_path.to_owned(),
},
)
} else {
AccountIdentity::PublicNoSign(user_holding_b)
};
2025-12-16 14:05:34 +02:00
2026-05-17 12:32:43 -04:00
self.0
.send_pub_tx(
vec![
AccountIdentity::PublicNoSign(amm_pool),
AccountIdentity::PublicNoSign(vault_holding_a),
AccountIdentity::PublicNoSign(vault_holding_b),
user_a_signing_identity,
user_b_signing_identity,
],
instruction_data,
&program.into(),
)
2026-05-17 12:32:43 -04:00
.await
2025-12-16 14:05:34 +02:00
}
2026-05-15 18:15:54 -04:00
#[expect(clippy::too_many_arguments, reason = "each parameter is distinct")]
2025-12-22 04:42:32 +02:00
pub async fn send_add_liquidity(
2025-12-16 14:05:34 +02:00
&self,
2025-12-18 11:44:38 +02:00
user_holding_a: AccountId,
user_holding_b: AccountId,
user_holding_lp: AccountId,
2026-01-23 16:30:54 -05:00
min_amount_liquidity: u128,
max_amount_to_add_token_a: u128,
max_amount_to_add_token_b: u128,
user_holding_a_mention: &CliAccountMention,
user_holding_b_mention: &CliAccountMention,
user_holding_lp_mention: &CliAccountMention,
) -> Result<HashType, ExecutionFailureKind> {
let user_holding_a_identity = user_holding_a_mention.key_path().map_or(
AccountIdentity::Public(user_holding_a),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_a,
key_path: key_path.to_owned(),
},
);
let user_holding_b_identity = user_holding_b_mention.key_path().map_or(
AccountIdentity::Public(user_holding_b),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_b,
key_path: key_path.to_owned(),
},
);
let user_holding_lp_identity = user_holding_lp_mention.key_path().map_or(
AccountIdentity::Public(user_holding_lp),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_lp,
key_path: key_path.to_owned(),
},
);
2026-01-23 16:30:54 -05:00
let program = Program::amm();
2025-12-18 11:44:38 +02:00
let amm_program_id = Program::amm().id();
2025-12-22 04:42:32 +02:00
let user_a_acc = self
.0
.get_account_public(user_holding_a)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-22 04:42:32 +02:00
let user_b_acc = self
.0
.get_account_public(user_holding_b)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-18 11:44:38 +02:00
let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id();
let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_b))?
.definition_id();
2025-12-18 11:44:38 +02:00
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let instruction = amm_core::Instruction::AddLiquidity {
min_amount_liquidity,
max_amount_to_add_token_a,
max_amount_to_add_token_b,
};
let instruction_data =
Program::serialize_instruction(instruction).expect("Instruction should serialize");
2025-12-18 11:44:38 +02:00
2026-05-17 12:32:43 -04:00
self.0
.send_pub_tx(
vec![
AccountIdentity::PublicNoSign(amm_pool),
AccountIdentity::PublicNoSign(vault_holding_a),
AccountIdentity::PublicNoSign(vault_holding_b),
AccountIdentity::PublicNoSign(pool_lp),
user_holding_a_identity,
user_holding_b_identity,
user_holding_lp_identity,
],
instruction_data,
&program.into(),
)
2026-05-17 12:32:43 -04:00
.await
2025-12-16 14:05:34 +02:00
}
2026-05-15 18:15:54 -04:00
#[expect(clippy::too_many_arguments, reason = "each parameter is distinct")]
2025-12-22 04:42:32 +02:00
pub async fn send_remove_liquidity(
2025-12-16 14:05:34 +02:00
&self,
2025-12-18 11:44:38 +02:00
user_holding_a: AccountId,
user_holding_b: AccountId,
user_holding_lp: AccountId,
2026-01-23 16:30:54 -05:00
remove_liquidity_amount: u128,
min_amount_to_remove_token_a: u128,
min_amount_to_remove_token_b: u128,
user_holding_lp_mention: &CliAccountMention,
) -> Result<HashType, ExecutionFailureKind> {
let user_holding_lp_identity = user_holding_lp_mention.key_path().map_or(
AccountIdentity::Public(user_holding_lp),
|key_path| AccountIdentity::PublicKeycard {
account_id: user_holding_lp,
key_path: key_path.to_owned(),
},
);
2026-01-23 16:30:54 -05:00
let program = Program::amm();
2025-12-18 11:44:38 +02:00
let amm_program_id = Program::amm().id();
2025-12-22 04:42:32 +02:00
let user_a_acc = self
.0
.get_account_public(user_holding_a)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-22 04:42:32 +02:00
let user_b_acc = self
.0
.get_account_public(user_holding_b)
.await
2026-03-04 18:42:33 +03:00
.map_err(ExecutionFailureKind::SequencerError)?;
2025-12-18 11:44:38 +02:00
let definition_token_a_id = TokenHolding::try_from(&user_a_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_a))?
.definition_id();
let definition_token_b_id = TokenHolding::try_from(&user_b_acc.data)
2026-03-04 18:42:33 +03:00
.map_err(|_err| ExecutionFailureKind::AccountDataError(user_holding_b))?
.definition_id();
2025-12-18 11:44:38 +02:00
let amm_pool =
compute_pool_pda(amm_program_id, definition_token_a_id, definition_token_b_id);
let vault_holding_a = compute_vault_pda(amm_program_id, amm_pool, definition_token_a_id);
let vault_holding_b = compute_vault_pda(amm_program_id, amm_pool, definition_token_b_id);
let pool_lp = compute_liquidity_token_pda(amm_program_id, amm_pool);
let instruction = amm_core::Instruction::RemoveLiquidity {
remove_liquidity_amount,
min_amount_to_remove_token_a,
min_amount_to_remove_token_b,
};
let instruction_data =
Program::serialize_instruction(instruction).expect("Instruction should serialize");
2025-12-18 11:44:38 +02:00
2026-05-17 12:32:43 -04:00
self.0
.send_pub_tx(
vec![
AccountIdentity::PublicNoSign(amm_pool),
AccountIdentity::PublicNoSign(vault_holding_a),
AccountIdentity::PublicNoSign(vault_holding_b),
AccountIdentity::PublicNoSign(pool_lp),
AccountIdentity::PublicNoSign(user_holding_a),
AccountIdentity::PublicNoSign(user_holding_b),
user_holding_lp_identity,
],
instruction_data,
&program.into(),
)
2026-05-17 12:32:43 -04:00
.await
2025-12-16 14:05:34 +02:00
}
}