mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-01-04 06:13: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];
|
pub type Scalar = [u8; 32];
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone, Copy)]
|
||||||
pub struct SharedSecretKey(pub [u8; 32]);
|
pub struct SharedSecretKey(pub [u8; 32]);
|
||||||
|
|
||||||
pub struct EncryptionScheme;
|
pub struct EncryptionScheme;
|
||||||
|
|||||||
@ -55,6 +55,7 @@ use nssa_core::{
|
|||||||
// * compute_pool_pda_seed: token definitions for the pool pair
|
// * compute_pool_pda_seed: token definitions for the pool pair
|
||||||
// * compute_vault_pda_seed: pool definition id, definition token id,
|
// * compute_vault_pda_seed: pool definition id, definition token id,
|
||||||
// * compute_liquidity_token_pda_seed: pool definition id
|
// * compute_liquidity_token_pda_seed: pool definition id
|
||||||
|
//
|
||||||
|
|
||||||
const POOL_DEFINITION_DATA_SIZE: usize = 225;
|
const POOL_DEFINITION_DATA_SIZE: usize = 225;
|
||||||
|
|
||||||
|
|||||||
@ -216,7 +216,7 @@ mod tests {
|
|||||||
&Program::serialize_instruction(balance_to_move).unwrap(),
|
&Program::serialize_instruction(balance_to_move).unwrap(),
|
||||||
&[0, 2],
|
&[0, 2],
|
||||||
&[0xdeadbeef],
|
&[0xdeadbeef],
|
||||||
&[(recipient_keys.npk(), shared_secret.clone())],
|
&[(recipient_keys.npk(), shared_secret)],
|
||||||
&[],
|
&[],
|
||||||
&Program::authenticated_transfer_program().into(),
|
&Program::authenticated_transfer_program().into(),
|
||||||
)
|
)
|
||||||
@ -312,8 +312,8 @@ mod tests {
|
|||||||
&[1, 2],
|
&[1, 2],
|
||||||
&[0xdeadbeef1, 0xdeadbeef2],
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
&[
|
&[
|
||||||
(sender_keys.npk(), shared_secret_1.clone()),
|
(sender_keys.npk(), shared_secret_1),
|
||||||
(recipient_keys.npk(), shared_secret_2.clone()),
|
(recipient_keys.npk(), shared_secret_2),
|
||||||
],
|
],
|
||||||
&[(
|
&[(
|
||||||
sender_keys.nsk,
|
sender_keys.nsk,
|
||||||
|
|||||||
@ -2094,7 +2094,7 @@ pub mod tests {
|
|||||||
&visibility_mask,
|
&visibility_mask,
|
||||||
&[0xdeadbeef1, 0xdeadbeef2],
|
&[0xdeadbeef1, 0xdeadbeef2],
|
||||||
&[
|
&[
|
||||||
(sender_keys.npk(), shared_secret.clone()),
|
(sender_keys.npk(), shared_secret),
|
||||||
(sender_keys.npk(), shared_secret),
|
(sender_keys.npk(), shared_secret),
|
||||||
],
|
],
|
||||||
&private_account_auth,
|
&private_account_auth,
|
||||||
@ -2288,12 +2288,12 @@ pub mod tests {
|
|||||||
let mut i: usize = 0;
|
let mut i: usize = 0;
|
||||||
let (token_1, token_2) = loop {
|
let (token_1, token_2) = loop {
|
||||||
if definition_token_a_id.value()[i] > definition_token_b_id.value()[i] {
|
if definition_token_a_id.value()[i] > definition_token_b_id.value()[i] {
|
||||||
let token_1 = definition_token_a_id.clone();
|
let token_1 = definition_token_a_id;
|
||||||
let token_2 = definition_token_b_id.clone();
|
let token_2 = definition_token_b_id;
|
||||||
break (token_1, token_2);
|
break (token_1, token_2);
|
||||||
} else if definition_token_a_id.value()[i] < definition_token_b_id.value()[i] {
|
} else if definition_token_a_id.value()[i] < definition_token_b_id.value()[i] {
|
||||||
let token_1 = definition_token_b_id.clone();
|
let token_1 = definition_token_b_id;
|
||||||
let token_2 = definition_token_a_id.clone();
|
let token_2 = definition_token_a_id;
|
||||||
break (token_1, token_2);
|
break (token_1, token_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2396,6 +2396,7 @@ pub mod tests {
|
|||||||
.expect("225 bytes should fit into Data")
|
.expect("225 bytes should fit into Data")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn parse(data: &[u8]) -> Option<Self> {
|
fn parse(data: &[u8]) -> Option<Self> {
|
||||||
if data.len() != POOL_DEFINITION_DATA_SIZE {
|
if data.len() != POOL_DEFINITION_DATA_SIZE {
|
||||||
None
|
None
|
||||||
@ -2531,6 +2532,7 @@ pub mod tests {
|
|||||||
UserTokenBHoldingNewDef,
|
UserTokenBHoldingNewDef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
enum IdEnum {
|
enum IdEnum {
|
||||||
PoolDefinitionId,
|
PoolDefinitionId,
|
||||||
TokenLPDefinitionId,
|
TokenLPDefinitionId,
|
||||||
@ -2543,6 +2545,7 @@ pub mod tests {
|
|||||||
VaultBId,
|
VaultBId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::enum_variant_names)]
|
||||||
enum PrivateKeysEnum {
|
enum PrivateKeysEnum {
|
||||||
UserTokenAKey,
|
UserTokenAKey,
|
||||||
UserTokenBKey,
|
UserTokenBKey,
|
||||||
@ -2680,9 +2683,7 @@ pub mod tests {
|
|||||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit),
|
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit),
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::TokenADefinitionAcc => Account {
|
AccountsEnum::TokenADefinitionAcc => Account {
|
||||||
@ -2692,9 +2693,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: helper_balances_constructor(BalancesEnum::TokenASupply),
|
total_supply: helper_balances_constructor(BalancesEnum::TokenASupply),
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::TokenBDefinitionAcc => Account {
|
AccountsEnum::TokenBDefinitionAcc => Account {
|
||||||
@ -2704,9 +2703,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: helper_balances_constructor(BalancesEnum::TokenBSupply),
|
total_supply: helper_balances_constructor(BalancesEnum::TokenBSupply),
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::TokenLPDefinitionAcc => Account {
|
AccountsEnum::TokenLPDefinitionAcc => Account {
|
||||||
@ -2716,9 +2713,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupply),
|
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupply),
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::VaultAInit => Account {
|
AccountsEnum::VaultAInit => Account {
|
||||||
@ -2787,9 +2782,7 @@ pub mod tests {
|
|||||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap1),
|
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap1),
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::UserTokenAHoldingSwap1 => Account {
|
AccountsEnum::UserTokenAHoldingSwap1 => Account {
|
||||||
@ -2848,9 +2841,7 @@ pub mod tests {
|
|||||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap2),
|
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceSwap2),
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::UserTokenAHoldingSwap2 => Account {
|
AccountsEnum::UserTokenAHoldingSwap2 => Account {
|
||||||
@ -2909,9 +2900,7 @@ pub mod tests {
|
|||||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceAdd),
|
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceAdd),
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::UserTokenAHoldingAdd => Account {
|
AccountsEnum::UserTokenAHoldingAdd => Account {
|
||||||
@ -2951,9 +2940,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyAdd),
|
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyAdd),
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::VaultARemove => Account {
|
AccountsEnum::VaultARemove => Account {
|
||||||
@ -2992,9 +2979,7 @@ pub mod tests {
|
|||||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceRemove),
|
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceRemove),
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::UserTokenAHoldingRemove => Account {
|
AccountsEnum::UserTokenAHoldingRemove => Account {
|
||||||
@ -3034,9 +3019,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyRemove),
|
total_supply: helper_balances_constructor(BalancesEnum::TokenLPSupplyRemove),
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::TokenLPDefinitionInitInactive => Account {
|
AccountsEnum::TokenLPDefinitionInitInactive => Account {
|
||||||
@ -3046,9 +3029,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: 0,
|
total_supply: 0,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::VaultAInitInactive => Account {
|
AccountsEnum::VaultAInitInactive => Account {
|
||||||
@ -3085,9 +3066,7 @@ pub mod tests {
|
|||||||
reserve_b: 0,
|
reserve_b: 0,
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: false,
|
active: false,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::UserTokenAHoldingNewInit => Account {
|
AccountsEnum::UserTokenAHoldingNewInit => Account {
|
||||||
@ -3127,9 +3106,7 @@ pub mod tests {
|
|||||||
account_type: 0u8,
|
account_type: 0u8,
|
||||||
name: [1u8; 6],
|
name: [1u8; 6],
|
||||||
total_supply: helper_balances_constructor(BalancesEnum::VaultABalanceInit),
|
total_supply: helper_balances_constructor(BalancesEnum::VaultABalanceInit),
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::PoolDefinitionNewInit => Account {
|
AccountsEnum::PoolDefinitionNewInit => Account {
|
||||||
@ -3148,9 +3125,7 @@ pub mod tests {
|
|||||||
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit),
|
reserve_b: helper_balances_constructor(BalancesEnum::VaultBBalanceInit),
|
||||||
fees: 0u128,
|
fees: 0u128,
|
||||||
active: true,
|
active: true,
|
||||||
})
|
}),
|
||||||
.try_into()
|
|
||||||
.expect("Data too big"),
|
|
||||||
nonce: 0,
|
nonce: 0,
|
||||||
},
|
},
|
||||||
AccountsEnum::UserTokenLPHoldingInitZero => Account {
|
AccountsEnum::UserTokenLPHoldingInitZero => Account {
|
||||||
|
|||||||
@ -11,8 +11,8 @@ use crate::{
|
|||||||
chain::ChainSubcommand,
|
chain::ChainSubcommand,
|
||||||
config::ConfigSubcommand,
|
config::ConfigSubcommand,
|
||||||
programs::{
|
programs::{
|
||||||
native_token_transfer::AuthTransferSubcommand, pinata::PinataProgramAgnosticSubcommand,
|
amm::AmmProgramAgnosticSubcommand, native_token_transfer::AuthTransferSubcommand,
|
||||||
token::TokenProgramAgnosticSubcommand,
|
pinata::PinataProgramAgnosticSubcommand, token::TokenProgramAgnosticSubcommand,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
helperfunctions::{fetch_config, fetch_persistent_storage, merge_auth_config},
|
helperfunctions::{fetch_config, fetch_persistent_storage, merge_auth_config},
|
||||||
@ -47,6 +47,9 @@ pub enum Command {
|
|||||||
/// Token program interaction subcommand
|
/// Token program interaction subcommand
|
||||||
#[command(subcommand)]
|
#[command(subcommand)]
|
||||||
Token(TokenProgramAgnosticSubcommand),
|
Token(TokenProgramAgnosticSubcommand),
|
||||||
|
/// AMM program interaction subcommand
|
||||||
|
#[command(subcommand)]
|
||||||
|
AMM(AmmProgramAgnosticSubcommand),
|
||||||
/// Check the wallet can connect to the node and builtin local programs
|
/// Check the wallet can connect to the node and builtin local programs
|
||||||
/// match the remote versions
|
/// match the remote versions
|
||||||
CheckHealth {},
|
CheckHealth {},
|
||||||
@ -165,6 +168,7 @@ pub async fn execute_subcommand_with_auth(
|
|||||||
Command::Token(token_subcommand) => {
|
Command::Token(token_subcommand) => {
|
||||||
token_subcommand.handle_subcommand(&mut wallet_core).await?
|
token_subcommand.handle_subcommand(&mut wallet_core).await?
|
||||||
}
|
}
|
||||||
|
Command::AMM(amm_subcommand) => amm_subcommand.handle_subcommand(&mut wallet_core).await?,
|
||||||
Command::Config(config_subcommand) => {
|
Command::Config(config_subcommand) => {
|
||||||
config_subcommand
|
config_subcommand
|
||||||
.handle_subcommand(&mut wallet_core)
|
.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 native_token_transfer;
|
||||||
pub mod pinata;
|
pub mod pinata;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
|||||||
@ -280,7 +280,7 @@ impl WalletCore {
|
|||||||
&produce_random_nonces(private_account_keys.len()),
|
&produce_random_nonces(private_account_keys.len()),
|
||||||
&private_account_keys
|
&private_account_keys
|
||||||
.iter()
|
.iter()
|
||||||
.map(|keys| (keys.npk.clone(), keys.ssk.clone()))
|
.map(|keys| (keys.npk.clone(), keys.ssk))
|
||||||
.collect::<Vec<_>>(),
|
.collect::<Vec<_>>(),
|
||||||
&acc_manager.private_account_auth(),
|
&acc_manager.private_account_auth(),
|
||||||
&program.to_owned().into(),
|
&program.to_owned().into(),
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use anyhow::Result;
|
||||||
use common::error::ExecutionFailureKind;
|
use common::error::ExecutionFailureKind;
|
||||||
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
use key_protocol::key_management::ephemeral_key_holder::EphemeralKeyHolder;
|
||||||
use nssa::{AccountId, PrivateKey};
|
use nssa::{AccountId, PrivateKey};
|
||||||
@ -7,8 +8,9 @@ use nssa_core::{
|
|||||||
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
encryption::{EphemeralPublicKey, IncomingViewingPublicKey},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::WalletCore;
|
use crate::{WalletCore, helperfunctions::AccountPrivacyKind};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub enum PrivacyPreservingAccount {
|
pub enum PrivacyPreservingAccount {
|
||||||
Public(AccountId),
|
Public(AccountId),
|
||||||
PrivateOwned(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 struct PrivateAccountKeys {
|
||||||
pub npk: NullifierPublicKey,
|
pub npk: NullifierPublicKey,
|
||||||
pub ssk: SharedSecretKey,
|
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
|
//! This module contains [`WalletCore`](crate::WalletCore) facades for interacting with various
|
||||||
//! on-chain programs.
|
//! on-chain programs.
|
||||||
|
|
||||||
|
pub mod amm;
|
||||||
pub mod native_token_transfer;
|
pub mod native_token_transfer;
|
||||||
pub mod pinata;
|
pub mod pinata;
|
||||||
pub mod token;
|
pub mod token;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user