add create pair test

This commit is contained in:
David Rusu 2025-03-10 11:44:39 +04:00
parent 85b506c7ae
commit 9972df5f23
2 changed files with 157 additions and 0 deletions

View File

@ -109,6 +109,33 @@ pub struct AddLiquidity {
pub nonce: Nonce,
}
impl AddLiquidity {
pub fn new(
t0: Unit,
mut t0_in: u64,
t1: Unit,
mut t1_in: u64,
pk_out: NullifierCommitment,
nonce: Nonce,
) -> Self {
let pair = Pair::new(t0, t1);
(t0_in, t1_in) = if t0 == pair.t0 {
(t0_in, t1_in)
} else {
(t1_in, t0_in)
};
Self {
pair,
t0_in,
t1_in,
pk_out,
nonce,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SharesToMint {
pub amount: u64,
@ -165,6 +192,15 @@ pub struct Pair {
pub t1: Unit,
}
impl Pair {
pub fn new(t_a: Unit, t_b: Unit) -> Self {
Self {
t0: std::cmp::min(t_a, t_b),
t1: std::cmp::max(t_a, t_b),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Pool {
pub balance_0: u64,
@ -173,6 +209,12 @@ pub struct Pool {
pub total_shares: u64,
}
impl Pool {
pub fn price(&self) -> f64 {
self.balance_1 as f64 / self.balance_0 as f64
}
}
/// Prove the data was part of the tx output
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OutputDataProof;
@ -204,6 +246,27 @@ pub struct StateUpdate {
// Txs are of the following form:
impl ZoneData {
pub fn new() -> Self {
Self {
nfs: Default::default(),
pools: Default::default(),
zone_id: ZONE_ID,
shares_to_mint: Default::default(),
shares_to_redeem: Default::default(),
}
}
pub fn pair_price(&self, t_in: Unit, t_out: Unit) -> Option<f64> {
let pair = Pair::new(t_in, t_out);
self.pools.get(&pair).map(|pool| pool.price()).map(|price| {
if t_in == pair.t0 {
price
} else {
1.0 / price
}
})
}
/// A swap does not need to directly modify the pool balances, but the executor
/// should make sure that required funds are provided.
pub fn swap(&mut self, swap: &Swap) {
@ -398,3 +461,9 @@ impl ZoneData {
hasher.finalize().into()
}
}
impl Default for ZoneData {
fn default() -> Self {
Self::new()
}
}

View File

@ -0,0 +1,88 @@
use app::{AddLiquidity, SwapArgs, SwapOutput, ZoneData, ZONE_ID};
use cl::{
crust::{InputWitness, Nonce, NullifierSecret, OutputWitness, TxWitness, UnitWitness},
mantle::ledger::LedgerState,
};
fn nmo() -> UnitWitness {
UnitWitness::nop(b"NMO")
}
fn mem() -> UnitWitness {
UnitWitness::nop(b"MEM")
}
#[test]
fn pair_price() {
let mut rng = rand::thread_rng();
let mut swapvm_state = ZoneData::new();
// initially there is no NMO/MEM pair
assert_eq!(swapvm_state.pair_price(nmo().unit(), mem().unit()), None);
let lp_sk = NullifierSecret::random(&mut rng);
swapvm_state.add_liquidity(&AddLiquidity::new(
nmo().unit(),
10,
mem().unit(),
100,
lp_sk.commit(),
Nonce::random(&mut rng),
));
// given that there is 1nmo:10mem in the pool, the price should show that we get 10 NEM for 1 NMO
assert_eq!(
swapvm_state.pair_price(nmo().unit(), mem().unit()),
Some(10.0)
);
// switching the trade direction should flip the price as well
assert_eq!(
swapvm_state.pair_price(mem().unit(), nmo().unit()),
Some(0.1)
);
}
#[test]
fn simple_swap() {
let mut rng = rand::thread_rng();
let alice_sk = NullifierSecret::random(&mut rng);
let alice_in = InputWitness {
state: [0u8; 32],
value: 10,
unit_witness: nmo(),
nonce: Nonce::random(&mut rng),
zone_id: ZONE_ID,
nf_sk: alice_sk,
};
let alice_out = OutputWitness {
state: [0u8; 32],
value: 100,
unit: mem().unit(),
nonce: Nonce::random(&mut rng),
zone_id: ZONE_ID,
nf_pk: alice_sk.commit(),
};
let mut ledger = LedgerState::default();
// alice's input note is already in the ledger
let alice_in_proof = ledger.add_commitment(&alice_in.note_commitment());
let swap_tx = TxWitness::default()
.add_input(alice_in, alice_in_proof)
.add_output(alice_out, b"")
.add_output(
app::swap_goal_note(&mut rng),
SwapArgs {
output: SwapOutput::basic(mem().unit(), ZONE_ID, alice_sk.commit(), &mut rng),
limit: 90,
},
);
panic!()
// alice ---- swap_tx ---> executor
}