mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-02 13:23:10 +00:00
feat: swaps, add/rem liq
This commit is contained in:
parent
c5cca4376e
commit
d4a471e948
@ -16,7 +16,7 @@ use crate::{Commitment, account::Account};
|
||||
|
||||
pub type Scalar = [u8; 32];
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||
pub struct SharedSecretKey(pub [u8; 32]);
|
||||
|
||||
pub struct EncryptionScheme;
|
||||
|
||||
@ -55,6 +55,7 @@ use nssa_core::{
|
||||
// * 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
|
||||
//
|
||||
|
||||
const POOL_DEFINITION_DATA_SIZE: usize = 225;
|
||||
|
||||
|
||||
@ -216,7 +216,7 @@ mod tests {
|
||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||
&[0, 2],
|
||||
&[0xdeadbeef],
|
||||
&[(recipient_keys.npk(), shared_secret.clone())],
|
||||
&[(recipient_keys.npk(), shared_secret)],
|
||||
&[],
|
||||
&Program::authenticated_transfer_program().into(),
|
||||
)
|
||||
@ -312,8 +312,8 @@ mod tests {
|
||||
&[1, 2],
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
(sender_keys.npk(), shared_secret_1.clone()),
|
||||
(recipient_keys.npk(), shared_secret_2.clone()),
|
||||
(sender_keys.npk(), shared_secret_1),
|
||||
(recipient_keys.npk(), shared_secret_2),
|
||||
],
|
||||
&[(
|
||||
sender_keys.nsk,
|
||||
|
||||
@ -2094,7 +2094,7 @@ pub mod tests {
|
||||
&visibility_mask,
|
||||
&[0xdeadbeef1, 0xdeadbeef2],
|
||||
&[
|
||||
(sender_keys.npk(), shared_secret.clone()),
|
||||
(sender_keys.npk(), shared_secret),
|
||||
(sender_keys.npk(), shared_secret),
|
||||
],
|
||||
&private_account_auth,
|
||||
@ -2288,12 +2288,12 @@ pub mod tests {
|
||||
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();
|
||||
let token_1 = definition_token_a_id;
|
||||
let token_2 = definition_token_b_id;
|
||||
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();
|
||||
let token_1 = definition_token_b_id;
|
||||
let token_2 = definition_token_a_id;
|
||||
break (token_1, token_2);
|
||||
}
|
||||
|
||||
@ -2396,6 +2396,7 @@ pub mod tests {
|
||||
.expect("225 bytes should fit into Data")
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn parse(data: &[u8]) -> Option<Self> {
|
||||
if data.len() != POOL_DEFINITION_DATA_SIZE {
|
||||
None
|
||||
@ -2531,6 +2532,7 @@ pub mod tests {
|
||||
UserTokenBHoldingNewDef,
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum IdEnum {
|
||||
PoolDefinitionId,
|
||||
TokenLPDefinitionId,
|
||||
@ -2543,6 +2545,7 @@ pub mod tests {
|
||||
VaultBId,
|
||||
}
|
||||
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
enum PrivateKeysEnum {
|
||||
UserTokenAKey,
|
||||
UserTokenBKey,
|
||||
@ -2680,9 +2683,7 @@ pub mod tests {
|
||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit),
|
||||
fees: 0u128,
|
||||
active: true,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::TokenADefinitionAcc => Account {
|
||||
@ -2692,9 +2693,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: helper_balances_constructor(BalancesEnum::TokenASupply),
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::TokenBDefinitionAcc => Account {
|
||||
@ -2704,9 +2703,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: helper_balances_constructor(BalancesEnum::TokenBSupply),
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::TokenLPDefinitionAcc => Account {
|
||||
@ -2716,9 +2713,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupply),
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::VaultAInit => Account {
|
||||
@ -2787,9 +2782,7 @@ pub mod tests {
|
||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap1),
|
||||
fees: 0u128,
|
||||
active: true,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::UserTokenAHoldingSwap1 => Account {
|
||||
@ -2848,9 +2841,7 @@ pub mod tests {
|
||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap2),
|
||||
fees: 0u128,
|
||||
active: true,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::UserTokenAHoldingSwap2 => Account {
|
||||
@ -2909,9 +2900,7 @@ pub mod tests {
|
||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceAdd),
|
||||
fees: 0u128,
|
||||
active: true,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::UserTokenAHoldingAdd => Account {
|
||||
@ -2951,9 +2940,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyAdd),
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::VaultARemove => Account {
|
||||
@ -2992,9 +2979,7 @@ pub mod tests {
|
||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceRemove),
|
||||
fees: 0u128,
|
||||
active: true,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::UserTokenAHoldingRemove => Account {
|
||||
@ -3034,9 +3019,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyRemove),
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::TokenLPDefinitionInitInactive => Account {
|
||||
@ -3046,9 +3029,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: 0,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::VaultAInitInactive => Account {
|
||||
@ -3085,9 +3066,7 @@ pub mod tests {
|
||||
reserve_b: 0,
|
||||
fees: 0u128,
|
||||
active: false,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::UserTokenAHoldingNewInit => Account {
|
||||
@ -3127,9 +3106,7 @@ pub mod tests {
|
||||
account_type: 0u8,
|
||||
name: [1u8; 6],
|
||||
total_supply: helper_balances_constructor(BalancesEnum::VaultABalanceInit),
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::PoolDefinitionNewInit => Account {
|
||||
@ -3148,9 +3125,7 @@ pub mod tests {
|
||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit),
|
||||
fees: 0u128,
|
||||
active: true,
|
||||
})
|
||||
.try_into()
|
||||
.expect("Data too big"),
|
||||
}),
|
||||
nonce: 0,
|
||||
},
|
||||
AccountsEnum::UserTokenLPHoldingInitZero => Account {
|
||||
|
||||
@ -11,8 +11,8 @@ use crate::{
|
||||
chain::ChainSubcommand,
|
||||
config::ConfigSubcommand,
|
||||
programs::{
|
||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
||||
token::TokenProgramAgnosticSubcommand,
|
||||
amm::AmmProgramAgnosticSubcommand, native_token_transfer::AuthTransferSubcommand,
|
||||
pinata::PinataProgramAgnosticSubcommand, token::TokenProgramAgnosticSubcommand,
|
||||
},
|
||||
},
|
||||
helperfunctions::{fetch_config, fetch_persistent_storage, merge_auth_config},
|
||||
@ -47,6 +47,9 @@ pub enum Command {
|
||||
/// Token program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
Token(TokenProgramAgnosticSubcommand),
|
||||
/// AMM program interaction subcommand
|
||||
#[command(subcommand)]
|
||||
AMM(AmmProgramAgnosticSubcommand),
|
||||
/// Check the wallet can connect to the node and builtin local programs
|
||||
/// match the remote versions
|
||||
CheckHealth {},
|
||||
@ -165,6 +168,7 @@ pub async fn execute_subcommand_with_auth(
|
||||
Command::Token(token_subcommand) => {
|
||||
token_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||
}
|
||||
Command::AMM(amm_subcommand) => amm_subcommand.handle_subcommand(&mut wallet_core).await?,
|
||||
Command::Config(config_subcommand) => {
|
||||
config_subcommand
|
||||
.handle_subcommand(&mut wallet_core)
|
||||
|
||||
452
wallet/src/cli/programs/amm.rs
Normal file
452
wallet/src/cli/programs/amm.rs
Normal file
@ -0,0 +1,452 @@
|
||||
use anyhow::Result;
|
||||
use clap::Subcommand;
|
||||
|
||||
use crate::{
|
||||
PrivacyPreservingAccount, WalletCore,
|
||||
cli::{SubcommandReturnValue, WalletSubcommand},
|
||||
helperfunctions::parse_addr_with_privacy_prefix,
|
||||
program_facades::amm::AMM,
|
||||
};
|
||||
|
||||
/// Represents generic CLI subcommand for a wallet working with amm program
|
||||
#[derive(Subcommand, Debug, Clone)]
|
||||
pub enum AmmProgramAgnosticSubcommand {
|
||||
/// Produce a new token
|
||||
///
|
||||
/// user_holding_a and user_holding_b must be owned.
|
||||
New {
|
||||
/// amm_pool - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
amm_pool: String,
|
||||
/// vault_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_a: String,
|
||||
/// vault_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_b: String,
|
||||
/// pool_lp - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pool_lp: String,
|
||||
/// user_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_a: String,
|
||||
/// user_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_b: String,
|
||||
/// user_holding_lp - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_lp: String,
|
||||
#[arg(long)]
|
||||
balance_a: u128,
|
||||
#[arg(long)]
|
||||
balance_b: u128,
|
||||
},
|
||||
/// Swap with variable privacy
|
||||
///
|
||||
/// The account associated with swapping token must be owned
|
||||
Swap {
|
||||
/// amm_pool - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
amm_pool: String,
|
||||
/// vault_holding_1 - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_1: String,
|
||||
/// vault_holding_2 - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_2: String,
|
||||
/// user_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_a: String,
|
||||
/// user_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_b: String,
|
||||
#[arg(long)]
|
||||
amount_in: u128,
|
||||
#[arg(long)]
|
||||
min_amount_out: u128,
|
||||
/// token_definition - valid 32 byte base58 string WITHOUT privacy prefix
|
||||
#[arg(long)]
|
||||
token_definition: String,
|
||||
},
|
||||
/// Add liquidity with variable privacy
|
||||
///
|
||||
/// user_holding_a and user_holding_b must be owned.
|
||||
AddLiquidity {
|
||||
/// amm_pool - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
amm_pool: String,
|
||||
/// vault_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_a: String,
|
||||
/// vault_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_b: String,
|
||||
/// pool_lp - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pool_lp: String,
|
||||
/// user_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_a: String,
|
||||
/// user_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_b: String,
|
||||
/// user_holding_lp - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_lp: String,
|
||||
#[arg(long)]
|
||||
min_amount_lp: u128,
|
||||
#[arg(long)]
|
||||
max_amount_a: u128,
|
||||
#[arg(long)]
|
||||
max_amount_b: u128,
|
||||
},
|
||||
/// Remove liquidity with variable privacy
|
||||
///
|
||||
/// user_holding_lp must be owned.
|
||||
RemoveLiquidity {
|
||||
/// amm_pool - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
amm_pool: String,
|
||||
/// vault_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_a: String,
|
||||
/// vault_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
vault_holding_b: String,
|
||||
/// pool_lp - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
pool_lp: String,
|
||||
/// user_holding_a - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_a: String,
|
||||
/// user_holding_b - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_b: String,
|
||||
/// user_holding_lp - valid 32 byte base58 string with privacy prefix
|
||||
#[arg(long)]
|
||||
user_holding_lp: String,
|
||||
#[arg(long)]
|
||||
balance_lp: u128,
|
||||
#[arg(long)]
|
||||
max_amount_a: u128,
|
||||
#[arg(long)]
|
||||
max_amount_b: u128,
|
||||
},
|
||||
}
|
||||
|
||||
impl WalletSubcommand for AmmProgramAgnosticSubcommand {
|
||||
async fn handle_subcommand(
|
||||
self,
|
||||
wallet_core: &mut WalletCore,
|
||||
) -> Result<SubcommandReturnValue> {
|
||||
match self {
|
||||
AmmProgramAgnosticSubcommand::New {
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
balance_a,
|
||||
balance_b,
|
||||
} => {
|
||||
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&amm_pool)?,
|
||||
)?;
|
||||
let vault_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_a)?,
|
||||
)?;
|
||||
let vault_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_b)?,
|
||||
)?;
|
||||
let pool_lp = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&pool_lp)?,
|
||||
)?;
|
||||
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_a)?,
|
||||
)?;
|
||||
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_b)?,
|
||||
)?;
|
||||
let user_holding_lp = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_lp)?,
|
||||
)?;
|
||||
|
||||
let is_public_tx = [
|
||||
&amm_pool,
|
||||
&vault_holding_a,
|
||||
&vault_holding_b,
|
||||
&pool_lp,
|
||||
&user_holding_a,
|
||||
&user_holding_b,
|
||||
&user_holding_lp,
|
||||
]
|
||||
.into_iter()
|
||||
.all(|acc| acc.is_public());
|
||||
|
||||
if is_public_tx {
|
||||
AMM(wallet_core)
|
||||
.send_new_amm_definition(
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
balance_a,
|
||||
balance_b,
|
||||
)
|
||||
.await?;
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
} else {
|
||||
AMM(wallet_core)
|
||||
.send_new_amm_definition_privacy_preserving(
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
balance_a,
|
||||
balance_b,
|
||||
)
|
||||
.await?;
|
||||
// ToDo: change into correct return value
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
AmmProgramAgnosticSubcommand::Swap {
|
||||
amm_pool,
|
||||
vault_holding_1,
|
||||
vault_holding_2,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
amount_in,
|
||||
min_amount_out,
|
||||
token_definition,
|
||||
} => {
|
||||
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&amm_pool)?,
|
||||
)?;
|
||||
let vault_holding_1 = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_1)?,
|
||||
)?;
|
||||
let vault_holding_2 = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_2)?,
|
||||
)?;
|
||||
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_a)?,
|
||||
)?;
|
||||
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_b)?,
|
||||
)?;
|
||||
|
||||
let is_public_tx = [
|
||||
&amm_pool,
|
||||
&vault_holding_1,
|
||||
&vault_holding_2,
|
||||
&user_holding_a,
|
||||
&user_holding_b,
|
||||
]
|
||||
.into_iter()
|
||||
.all(|acc| acc.is_public());
|
||||
|
||||
if is_public_tx {
|
||||
AMM(wallet_core)
|
||||
.send_swap(
|
||||
amm_pool,
|
||||
vault_holding_1,
|
||||
vault_holding_2,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
amount_in,
|
||||
min_amount_out,
|
||||
token_definition.parse()?,
|
||||
)
|
||||
.await?;
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
} else {
|
||||
AMM(wallet_core)
|
||||
.send_swap_privacy_preserving(
|
||||
amm_pool,
|
||||
vault_holding_1,
|
||||
vault_holding_2,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
amount_in,
|
||||
min_amount_out,
|
||||
token_definition.parse()?,
|
||||
)
|
||||
.await?;
|
||||
// ToDo: change into correct return value
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
AmmProgramAgnosticSubcommand::AddLiquidity {
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
min_amount_lp,
|
||||
max_amount_a,
|
||||
max_amount_b,
|
||||
} => {
|
||||
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&amm_pool)?,
|
||||
)?;
|
||||
let vault_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_a)?,
|
||||
)?;
|
||||
let vault_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_b)?,
|
||||
)?;
|
||||
let pool_lp = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&pool_lp)?,
|
||||
)?;
|
||||
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_a)?,
|
||||
)?;
|
||||
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_b)?,
|
||||
)?;
|
||||
let user_holding_lp = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_lp)?,
|
||||
)?;
|
||||
|
||||
let is_public_tx = [
|
||||
&amm_pool,
|
||||
&vault_holding_a,
|
||||
&vault_holding_b,
|
||||
&pool_lp,
|
||||
&user_holding_a,
|
||||
&user_holding_b,
|
||||
&user_holding_lp,
|
||||
]
|
||||
.into_iter()
|
||||
.all(|acc| acc.is_public());
|
||||
|
||||
if is_public_tx {
|
||||
AMM(wallet_core)
|
||||
.send_add_liq(
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
min_amount_lp,
|
||||
max_amount_a,
|
||||
max_amount_b,
|
||||
)
|
||||
.await?;
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
} else {
|
||||
AMM(wallet_core)
|
||||
.send_add_liq_privacy_preserving(
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
min_amount_lp,
|
||||
max_amount_a,
|
||||
max_amount_b,
|
||||
)
|
||||
.await?;
|
||||
// ToDo: change into correct return value
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
AmmProgramAgnosticSubcommand::RemoveLiquidity {
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
balance_lp,
|
||||
max_amount_a,
|
||||
max_amount_b,
|
||||
} => {
|
||||
let amm_pool = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&amm_pool)?,
|
||||
)?;
|
||||
let vault_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_a)?,
|
||||
)?;
|
||||
let vault_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&vault_holding_b)?,
|
||||
)?;
|
||||
let pool_lp = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&pool_lp)?,
|
||||
)?;
|
||||
let user_holding_a = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_a)?,
|
||||
)?;
|
||||
let user_holding_b = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_b)?,
|
||||
)?;
|
||||
let user_holding_lp = PrivacyPreservingAccount::parse_with_privacy(
|
||||
parse_addr_with_privacy_prefix(&user_holding_lp)?,
|
||||
)?;
|
||||
|
||||
let is_public_tx = [
|
||||
&amm_pool,
|
||||
&vault_holding_a,
|
||||
&vault_holding_b,
|
||||
&pool_lp,
|
||||
&user_holding_a,
|
||||
&user_holding_b,
|
||||
&user_holding_lp,
|
||||
]
|
||||
.into_iter()
|
||||
.all(|acc| acc.is_public());
|
||||
|
||||
if is_public_tx {
|
||||
AMM(wallet_core)
|
||||
.send_remove_liq(
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
balance_lp,
|
||||
max_amount_a,
|
||||
max_amount_b,
|
||||
)
|
||||
.await?;
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
} else {
|
||||
AMM(wallet_core)
|
||||
.send_remove_liq_privacy_preserving(
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
balance_lp,
|
||||
max_amount_a,
|
||||
max_amount_b,
|
||||
)
|
||||
.await?;
|
||||
// ToDo: change into correct return value
|
||||
Ok(SubcommandReturnValue::Empty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
pub mod amm;
|
||||
pub mod native_token_transfer;
|
||||
pub mod pinata;
|
||||
pub mod token;
|
||||
|
||||
@ -280,7 +280,7 @@ impl WalletCore {
|
||||
&produce_random_nonces(private_account_keys.len()),
|
||||
&private_account_keys
|
||||
.iter()
|
||||
.map(|keys| (keys.npk.clone(), keys.ssk.clone()))
|
||||
.map(|keys| (keys.npk.clone(), keys.ssk))
|
||||
.collect::<Vec<_>>(),
|
||||
&acc_manager.private_account_auth(),
|
||||
&program.to_owned().into(),
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
use anyhow::Result;
|
||||
use common::error::ExecutionFailureKind;
|
||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||
use nssa::{AccountId, PrivateKey};
|
||||
@ -7,8 +8,9 @@ use nssa_core::{
|
||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
||||
};
|
||||
|
||||
use crate::WalletCore;
|
||||
use crate::{WalletCore, helperfunctions::AccountPrivacyKind};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum PrivacyPreservingAccount {
|
||||
Public(AccountId),
|
||||
PrivateOwned(AccountId),
|
||||
@ -18,6 +20,28 @@ pub enum PrivacyPreservingAccount {
|
||||
},
|
||||
}
|
||||
|
||||
impl PrivacyPreservingAccount {
|
||||
pub fn parse_with_privacy(input: (String, AccountPrivacyKind)) -> Result<Self> {
|
||||
let acc_id: AccountId = input.0.parse()?;
|
||||
|
||||
match input.1 {
|
||||
AccountPrivacyKind::Public => Ok(Self::Public(acc_id)),
|
||||
AccountPrivacyKind::Private => Ok(Self::PrivateOwned(acc_id)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_public(&self) -> bool {
|
||||
matches!(&self, Self::Public(_))
|
||||
}
|
||||
|
||||
pub fn is_private(&self) -> bool {
|
||||
matches!(
|
||||
&self,
|
||||
Self::PrivateOwned(_) | Self::PrivateForeign { npk: _, ipk: _ }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PrivateAccountKeys {
|
||||
pub npk: NullifierPublicKey,
|
||||
pub ssk: SharedSecretKey,
|
||||
|
||||
522
wallet/src/program_facades/amm.rs
Normal file
522
wallet/src/program_facades/amm.rs
Normal file
@ -0,0 +1,522 @@
|
||||
use common::{error::ExecutionFailureKind, rpc_primitives::requests::SendTxResponse};
|
||||
use nssa::{AccountId, program::Program};
|
||||
use nssa_core::{SharedSecretKey, program::InstructionData};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{PrivacyPreservingAccount, WalletCore};
|
||||
|
||||
struct OrphanHack65BytesInput([u8; 65]);
|
||||
|
||||
impl Serialize for OrphanHack65BytesInput {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_bytes(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct OrphanHack49BytesInput([u8; 49]);
|
||||
|
||||
impl Serialize for OrphanHack49BytesInput {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
serializer.serialize_bytes(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AMM<'w>(pub &'w WalletCore);
|
||||
|
||||
impl AMM<'_> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_new_amm_definition(
|
||||
&self,
|
||||
_amm_pool: PrivacyPreservingAccount,
|
||||
_vault_holding_a: PrivacyPreservingAccount,
|
||||
_vault_holding_b: PrivacyPreservingAccount,
|
||||
_pool_lp: PrivacyPreservingAccount,
|
||||
_user_holding_a: PrivacyPreservingAccount,
|
||||
_user_holding_b: PrivacyPreservingAccount,
|
||||
_user_holding_lp: PrivacyPreservingAccount,
|
||||
_balance_a: u128,
|
||||
_balance_b: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_new_amm_definition_privacy_preserving(
|
||||
&self,
|
||||
_amm_pool: PrivacyPreservingAccount,
|
||||
_vault_holding_a: PrivacyPreservingAccount,
|
||||
_vault_holding_b: PrivacyPreservingAccount,
|
||||
_pool_lp: PrivacyPreservingAccount,
|
||||
_user_holding_a: PrivacyPreservingAccount,
|
||||
_user_holding_b: PrivacyPreservingAccount,
|
||||
_user_holding_lp: PrivacyPreservingAccount,
|
||||
_balance_a: u128,
|
||||
_balance_b: u128,
|
||||
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 7]), ExecutionFailureKind> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_swap(
|
||||
&self,
|
||||
amm_pool: PrivacyPreservingAccount,
|
||||
vault_holding_1: PrivacyPreservingAccount,
|
||||
vault_holding_2: PrivacyPreservingAccount,
|
||||
user_holding_a: PrivacyPreservingAccount,
|
||||
user_holding_b: PrivacyPreservingAccount,
|
||||
amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_definition_id: AccountId,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let (instruction, program) =
|
||||
amm_program_preparation_swap(amount_in, min_amount_out, token_definition_id);
|
||||
|
||||
match (
|
||||
amm_pool,
|
||||
vault_holding_1,
|
||||
vault_holding_2,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
) {
|
||||
(
|
||||
PrivacyPreservingAccount::Public(amm_pool),
|
||||
PrivacyPreservingAccount::Public(vault_holding_1),
|
||||
PrivacyPreservingAccount::Public(vault_holding_2),
|
||||
PrivacyPreservingAccount::Public(user_holding_a),
|
||||
PrivacyPreservingAccount::Public(user_holding_b),
|
||||
) => {
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_1,
|
||||
vault_holding_2,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
];
|
||||
|
||||
// ToDo: Correct authorization
|
||||
// ToDo: Also correct instruction serialization
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_swap_privacy_preserving(
|
||||
&self,
|
||||
amm_pool: PrivacyPreservingAccount,
|
||||
vault_holding_1: PrivacyPreservingAccount,
|
||||
vault_holding_2: PrivacyPreservingAccount,
|
||||
user_holding_a: PrivacyPreservingAccount,
|
||||
user_holding_b: PrivacyPreservingAccount,
|
||||
amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_definition_id: AccountId,
|
||||
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 5]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) =
|
||||
amm_program_preparation_swap(amount_in, min_amount_out, token_definition_id);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
amm_pool.clone(),
|
||||
vault_holding_1.clone(),
|
||||
vault_holding_2.clone(),
|
||||
user_holding_a.clone(),
|
||||
user_holding_b.clone(),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets = secrets.into_iter();
|
||||
let mut secrets_res = [None; 5];
|
||||
|
||||
for acc_id in [
|
||||
amm_pool,
|
||||
vault_holding_1,
|
||||
vault_holding_2,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if acc_id.1.is_private() {
|
||||
let secret = secrets.next().expect("expected next secret");
|
||||
|
||||
secrets_res[acc_id.0] = Some(secret);
|
||||
}
|
||||
}
|
||||
|
||||
(resp, secrets_res)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_add_liq(
|
||||
&self,
|
||||
amm_pool: PrivacyPreservingAccount,
|
||||
vault_holding_a: PrivacyPreservingAccount,
|
||||
vault_holding_b: PrivacyPreservingAccount,
|
||||
pool_lp: PrivacyPreservingAccount,
|
||||
user_holding_a: PrivacyPreservingAccount,
|
||||
user_holding_b: PrivacyPreservingAccount,
|
||||
user_holding_lp: PrivacyPreservingAccount,
|
||||
min_amount_lp: u128,
|
||||
max_amount_a: u128,
|
||||
max_amount_b: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let (instruction, program) =
|
||||
amm_program_preparation_add_liq(min_amount_lp, max_amount_a, max_amount_b);
|
||||
|
||||
match (
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
) {
|
||||
(
|
||||
PrivacyPreservingAccount::Public(amm_pool),
|
||||
PrivacyPreservingAccount::Public(vault_holding_a),
|
||||
PrivacyPreservingAccount::Public(vault_holding_b),
|
||||
PrivacyPreservingAccount::Public(pool_lp),
|
||||
PrivacyPreservingAccount::Public(user_holding_a),
|
||||
PrivacyPreservingAccount::Public(user_holding_b),
|
||||
PrivacyPreservingAccount::Public(user_holding_lp),
|
||||
) => {
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
];
|
||||
|
||||
// ToDo: Correct authorization
|
||||
// ToDo: Also correct instruction serialization
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_add_liq_privacy_preserving(
|
||||
&self,
|
||||
amm_pool: PrivacyPreservingAccount,
|
||||
vault_holding_a: PrivacyPreservingAccount,
|
||||
vault_holding_b: PrivacyPreservingAccount,
|
||||
pool_lp: PrivacyPreservingAccount,
|
||||
user_holding_a: PrivacyPreservingAccount,
|
||||
user_holding_b: PrivacyPreservingAccount,
|
||||
user_holding_lp: PrivacyPreservingAccount,
|
||||
min_amount_lp: u128,
|
||||
max_amount_a: u128,
|
||||
max_amount_b: u128,
|
||||
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 7]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) =
|
||||
amm_program_preparation_add_liq(min_amount_lp, max_amount_a, max_amount_b);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
amm_pool.clone(),
|
||||
vault_holding_a.clone(),
|
||||
vault_holding_b.clone(),
|
||||
pool_lp.clone(),
|
||||
user_holding_a.clone(),
|
||||
user_holding_b.clone(),
|
||||
user_holding_lp.clone(),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets = secrets.into_iter();
|
||||
let mut secrets_res = [None; 7];
|
||||
|
||||
for acc_id in [
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if acc_id.1.is_private() {
|
||||
let secret = secrets.next().expect("expected next secret");
|
||||
|
||||
secrets_res[acc_id.0] = Some(secret);
|
||||
}
|
||||
}
|
||||
|
||||
(resp, secrets_res)
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_remove_liq(
|
||||
&self,
|
||||
amm_pool: PrivacyPreservingAccount,
|
||||
vault_holding_a: PrivacyPreservingAccount,
|
||||
vault_holding_b: PrivacyPreservingAccount,
|
||||
pool_lp: PrivacyPreservingAccount,
|
||||
user_holding_a: PrivacyPreservingAccount,
|
||||
user_holding_b: PrivacyPreservingAccount,
|
||||
user_holding_lp: PrivacyPreservingAccount,
|
||||
balance_lp: u128,
|
||||
max_amount_a: u128,
|
||||
max_amount_b: u128,
|
||||
) -> Result<SendTxResponse, ExecutionFailureKind> {
|
||||
let (instruction, program) =
|
||||
amm_program_preparation_remove_liq(balance_lp, max_amount_a, max_amount_b);
|
||||
|
||||
match (
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
) {
|
||||
(
|
||||
PrivacyPreservingAccount::Public(amm_pool),
|
||||
PrivacyPreservingAccount::Public(vault_holding_a),
|
||||
PrivacyPreservingAccount::Public(vault_holding_b),
|
||||
PrivacyPreservingAccount::Public(pool_lp),
|
||||
PrivacyPreservingAccount::Public(user_holding_a),
|
||||
PrivacyPreservingAccount::Public(user_holding_b),
|
||||
PrivacyPreservingAccount::Public(user_holding_lp),
|
||||
) => {
|
||||
let account_ids = vec![
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
];
|
||||
|
||||
// ToDo: Correct authorization
|
||||
// ToDo: Also correct instruction serialization
|
||||
|
||||
let message = nssa::public_transaction::Message::try_new(
|
||||
program.id(),
|
||||
account_ids,
|
||||
vec![],
|
||||
instruction,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let witness_set = nssa::public_transaction::WitnessSet::for_message(&message, &[]);
|
||||
|
||||
let tx = nssa::PublicTransaction::new(message, witness_set);
|
||||
|
||||
Ok(self.0.sequencer_client.send_tx_public(tx).await?)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn send_remove_liq_privacy_preserving(
|
||||
&self,
|
||||
amm_pool: PrivacyPreservingAccount,
|
||||
vault_holding_a: PrivacyPreservingAccount,
|
||||
vault_holding_b: PrivacyPreservingAccount,
|
||||
pool_lp: PrivacyPreservingAccount,
|
||||
user_holding_a: PrivacyPreservingAccount,
|
||||
user_holding_b: PrivacyPreservingAccount,
|
||||
user_holding_lp: PrivacyPreservingAccount,
|
||||
balance_lp: u128,
|
||||
max_amount_a: u128,
|
||||
max_amount_b: u128,
|
||||
) -> Result<(SendTxResponse, [Option<SharedSecretKey>; 7]), ExecutionFailureKind> {
|
||||
let (instruction_data, program) =
|
||||
amm_program_preparation_remove_liq(balance_lp, max_amount_a, max_amount_b);
|
||||
|
||||
self.0
|
||||
.send_privacy_preserving_tx(
|
||||
vec![
|
||||
amm_pool.clone(),
|
||||
vault_holding_a.clone(),
|
||||
vault_holding_b.clone(),
|
||||
pool_lp.clone(),
|
||||
user_holding_a.clone(),
|
||||
user_holding_b.clone(),
|
||||
user_holding_lp.clone(),
|
||||
],
|
||||
&instruction_data,
|
||||
&program,
|
||||
)
|
||||
.await
|
||||
.map(|(resp, secrets)| {
|
||||
let mut secrets = secrets.into_iter();
|
||||
let mut secrets_res = [None; 7];
|
||||
|
||||
for acc_id in [
|
||||
amm_pool,
|
||||
vault_holding_a,
|
||||
vault_holding_b,
|
||||
pool_lp,
|
||||
user_holding_a,
|
||||
user_holding_b,
|
||||
user_holding_lp,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
if acc_id.1.is_private() {
|
||||
let secret = secrets.next().expect("expected next secret");
|
||||
|
||||
secrets_res[acc_id.0] = Some(secret);
|
||||
}
|
||||
}
|
||||
|
||||
(resp, secrets_res)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
fn amm_program_preparation_definition(
|
||||
balance_a: u128,
|
||||
balance_b: u128,
|
||||
) -> (InstructionData, Program) {
|
||||
// An instruction data of 65-bytes, indicating the initial amm reserves' balances and
|
||||
// token_program_id with the following layout:
|
||||
// [0x00 || array of balances (little-endian 16 bytes) || AMM_PROGRAM_ID)]
|
||||
let amm_program_id = Program::token().id();
|
||||
|
||||
let mut instruction = [0; 65];
|
||||
instruction[1..17].copy_from_slice(&balance_a.to_le_bytes());
|
||||
instruction[17..33].copy_from_slice(&balance_b.to_le_bytes());
|
||||
|
||||
// This can be done less verbose, but it is better to use same way, as in amm program
|
||||
instruction[33..37].copy_from_slice(&amm_program_id[0].to_le_bytes());
|
||||
instruction[37..41].copy_from_slice(&amm_program_id[1].to_le_bytes());
|
||||
instruction[41..45].copy_from_slice(&amm_program_id[2].to_le_bytes());
|
||||
instruction[45..49].copy_from_slice(&amm_program_id[3].to_le_bytes());
|
||||
instruction[49..53].copy_from_slice(&amm_program_id[4].to_le_bytes());
|
||||
instruction[53..57].copy_from_slice(&amm_program_id[5].to_le_bytes());
|
||||
instruction[57..61].copy_from_slice(&amm_program_id[6].to_le_bytes());
|
||||
instruction[61..].copy_from_slice(&amm_program_id[7].to_le_bytes());
|
||||
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(OrphanHack65BytesInput(instruction)).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
}
|
||||
|
||||
fn amm_program_preparation_swap(
|
||||
amount_in: u128,
|
||||
min_amount_out: u128,
|
||||
token_definition_id: AccountId,
|
||||
) -> (InstructionData, Program) {
|
||||
// An instruction data byte string of length 65, indicating which token type to swap, quantity
|
||||
// of tokens put into the swap (of type TOKEN_DEFINITION_ID) and min_amount_out.
|
||||
// [0x01 || amount (little-endian 16 bytes) || TOKEN_DEFINITION_ID].
|
||||
let mut instruction = [0; 65];
|
||||
instruction[1..17].copy_from_slice(&amount_in.to_le_bytes());
|
||||
instruction[17..33].copy_from_slice(&min_amount_out.to_le_bytes());
|
||||
|
||||
// This can be done less verbose, but it is better to use same way, as in amm program
|
||||
instruction[33..].copy_from_slice(&token_definition_id.to_bytes());
|
||||
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(OrphanHack65BytesInput(instruction)).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
}
|
||||
|
||||
fn amm_program_preparation_add_liq(
|
||||
min_amount_lp: u128,
|
||||
max_amount_a: u128,
|
||||
max_amount_b: u128,
|
||||
) -> (InstructionData, Program) {
|
||||
// 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)].
|
||||
let mut instruction = [0; 49];
|
||||
instruction[0] = 0x02;
|
||||
|
||||
instruction[1..17].copy_from_slice(&min_amount_lp.to_le_bytes());
|
||||
instruction[17..33].copy_from_slice(&max_amount_a.to_le_bytes());
|
||||
instruction[33..49].copy_from_slice(&max_amount_b.to_le_bytes());
|
||||
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(OrphanHack49BytesInput(instruction)).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
}
|
||||
|
||||
fn amm_program_preparation_remove_liq(
|
||||
balance_lp: u128,
|
||||
max_amount_a: u128,
|
||||
max_amount_b: u128,
|
||||
) -> (InstructionData, Program) {
|
||||
// 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)].
|
||||
let mut instruction = [0; 49];
|
||||
instruction[0] = 0x03;
|
||||
|
||||
instruction[1..17].copy_from_slice(&balance_lp.to_le_bytes());
|
||||
instruction[17..33].copy_from_slice(&max_amount_a.to_le_bytes());
|
||||
instruction[33..49].copy_from_slice(&max_amount_b.to_le_bytes());
|
||||
|
||||
let instruction_data =
|
||||
Program::serialize_instruction(OrphanHack49BytesInput(instruction)).unwrap();
|
||||
let program = Program::token();
|
||||
|
||||
(instruction_data, program)
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
//! This module contains [`WalletCore`](crate::WalletCore) facades for interacting with various
|
||||
//! on-chain programs.
|
||||
|
||||
pub mod amm;
|
||||
pub mod native_token_transfer;
|
||||
pub mod pinata;
|
||||
pub mod token;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user