mirror of
https://github.com/logos-blockchain/logos-blockchain-pocs.git
synced 2026-02-05 05:33:29 +00:00
swap scenario
This commit is contained in:
parent
104ad9bbff
commit
bde46cefe7
@ -1,10 +1,98 @@
|
||||
use app::{StateUpdate, ZoneOp};
|
||||
use cl::crust::BundleWitness;
|
||||
use cl::mantle::{ledger::Ledger, zone::ZoneData};
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use app::{swap_goal_unit, StateUpdate, ZoneData, ZoneOp};
|
||||
use cl::crust::{BundleWitness, InputWitness, NoteCommitment, Nullifier, Unit};
|
||||
use cl::ds::mmr::{MMRProof, MMR};
|
||||
use cl::mantle::ledger::Ledger;
|
||||
use cl::mantle::ledger::LedgerState;
|
||||
use ledger_proof_statements::ledger::SyncLog;
|
||||
use methods::{STF_ELF, STF_ID};
|
||||
use risc0_zkvm::{ExecutorEnv, Prover, Receipt, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FundNote {
|
||||
note: InputWitness,
|
||||
mmr: MMR,
|
||||
path: MMRProof,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ExecutorState {
|
||||
pub ledger: LedgerState,
|
||||
pub swapvm: ZoneData,
|
||||
pub fund_notes: BTreeMap<Unit, FundNote>,
|
||||
}
|
||||
|
||||
impl ExecutorState {
|
||||
pub fn observe_cms(&mut self, cms: impl IntoIterator<Item = NoteCommitment>) {
|
||||
for cm in cms {
|
||||
self.ledger.add_commitment(&cm);
|
||||
|
||||
// update merkle proofs for each fund note.
|
||||
for (_, fund_note) in self.fund_notes.iter_mut() {
|
||||
let folds = fund_note.mmr.folds(&cm.0);
|
||||
fund_note
|
||||
.path
|
||||
.update(&fund_note.note.note_commitment().0, folds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn observe_nfs(&mut self, nfs: Vec<Nullifier>) {
|
||||
self.ledger.add_nullifiers(nfs);
|
||||
}
|
||||
|
||||
// pub fn bundle_tx(&mut self, proved_tx: ProvedTx) -> StfPrivate {
|
||||
// let tx = proved_tx.public();
|
||||
|
||||
// if tx.balance.unit_balance(swap_goal_unit()).is_neg() {
|
||||
// // this is a SWAP
|
||||
// let (swap_cm, swap_args_bytes) = &tx.outputs[0];
|
||||
// let swap_args: SwapArgs = cl::deserialize(&swap_args_bytes);
|
||||
|
||||
// // verify the user proved the correct swap goal note
|
||||
// assert_eq!(
|
||||
// swap_cm,
|
||||
// &app::swap_goal_note(swap_args.nonce).note_commitment()
|
||||
// );
|
||||
|
||||
// // assume there are only the goal unit and tokenIn units at play
|
||||
// assert_eq!(tx.balance.balances.len(), 2);
|
||||
|
||||
// let balance_in = tx
|
||||
// .balance
|
||||
// .balances
|
||||
// .iter()
|
||||
// .find(|bal| bal.unit != swap_goal_unit())
|
||||
// .unwrap();
|
||||
|
||||
// let token_in = balance_in.unit;
|
||||
// assert_eq!(balance_in.neg, 0);
|
||||
// assert!(balance_in.pos > 0);
|
||||
|
||||
// let amount_in = balance_in.pos;
|
||||
// let amount_out = self
|
||||
// .swapvm
|
||||
// .amount_out(token_in, swap_args.output.unit, amount_in)
|
||||
// .unwrap();
|
||||
|
||||
// // ensure we can satisfy the limit order
|
||||
// assert!(amount_out > swap_args.limit);
|
||||
|
||||
// // now build the balancing tx
|
||||
|
||||
// let balancing_tx = TxWitness::default()
|
||||
// .add_input(self.fund_notes[token_in], self.fund_notes[token_in].1)
|
||||
// .add_input(self.fund_notes[token_out]);
|
||||
// }
|
||||
// }
|
||||
|
||||
pub fn set_fund_note(&mut self, note: InputWitness, mmr: MMR, path: MMRProof) {
|
||||
self.fund_notes
|
||||
.insert(note.unit_witness.unit(), FundNote { note, mmr, path });
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StfPrivate {
|
||||
pub zone_data: ZoneData,
|
||||
pub old_ledger: Ledger,
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use app::{AddLiquidity, ZoneData, ZONE_ID};
|
||||
use cl::{
|
||||
crust::{InputWitness, Nonce, NullifierSecret, TxWitness, UnitWitness},
|
||||
mantle::ledger::LedgerState,
|
||||
};
|
||||
use app::{AddLiquidity, ZONE_ID};
|
||||
use cl::crust::{InputWitness, Nonce, NullifierSecret, TxWitness, UnitWitness};
|
||||
use host::ExecutorState;
|
||||
use ledger::tx::ProvedTx;
|
||||
use rand::RngCore;
|
||||
|
||||
fn nmo() -> UnitWitness {
|
||||
UnitWitness::nop(b"NMO")
|
||||
@ -11,10 +11,59 @@ fn mem() -> UnitWitness {
|
||||
UnitWitness::nop(b"MEM")
|
||||
}
|
||||
|
||||
fn setup_executor(mut rng: impl RngCore) -> ExecutorState {
|
||||
let mut exec_state = ExecutorState::default();
|
||||
|
||||
let nmo_fund = InputWitness {
|
||||
state: [0u8; 32],
|
||||
value: 1348,
|
||||
unit_witness: nmo(),
|
||||
nonce: Nonce::random(&mut rng),
|
||||
zone_id: ZONE_ID,
|
||||
nf_sk: NullifierSecret::zero(),
|
||||
};
|
||||
|
||||
let (mmr, mmr_proof) = exec_state
|
||||
.ledger
|
||||
.add_commitment(&nmo_fund.note_commitment());
|
||||
exec_state.set_fund_note(nmo_fund, mmr, mmr_proof);
|
||||
|
||||
let mem_fund = InputWitness {
|
||||
state: [0u8; 32],
|
||||
value: 14102,
|
||||
unit_witness: mem(),
|
||||
nonce: Nonce::random(&mut rng),
|
||||
zone_id: ZONE_ID,
|
||||
nf_sk: NullifierSecret::zero(),
|
||||
};
|
||||
let (mmr, mmr_proof) = exec_state
|
||||
.ledger
|
||||
.add_commitment(&mem_fund.note_commitment());
|
||||
exec_state.set_fund_note(mem_fund, mmr, mmr_proof);
|
||||
|
||||
// HACK: we don't currently support liquidity notes, we directly hard code the corresponding liquidity
|
||||
// in the swapvm instead of minting pool LP tokens
|
||||
exec_state.swapvm.add_liquidity(&AddLiquidity::new(
|
||||
nmo().unit(),
|
||||
nmo_fund.value,
|
||||
mem().unit(),
|
||||
mem_fund.value,
|
||||
NullifierSecret::random(&mut rng).commit(),
|
||||
Nonce::random(&mut rng),
|
||||
));
|
||||
|
||||
exec_state
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_swap() {
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
// ---- setup scenario ----
|
||||
let mut exec_state = setup_executor(&mut rng);
|
||||
|
||||
// setup fund notes
|
||||
|
||||
let alice_sk = NullifierSecret::random(&mut rng);
|
||||
|
||||
let alice_in = InputWitness {
|
||||
@ -26,13 +75,18 @@ fn simple_swap() {
|
||||
nf_sk: alice_sk,
|
||||
};
|
||||
|
||||
let mut ledger = LedgerState::default();
|
||||
// alice's note lands in the ledger through some other executor
|
||||
let mut other_exec_ledger = exec_state.ledger.clone();
|
||||
let alice_in_proof = other_exec_ledger.add_commitment(&alice_in.note_commitment());
|
||||
|
||||
// alice's input note is already in the ledger
|
||||
let alice_in_proof = ledger.add_commitment(&alice_in.note_commitment());
|
||||
// executor becomes aware of the commitment through observing a zone update
|
||||
exec_state.observe_cms([alice_in.note_commitment()]);
|
||||
|
||||
// ----- end setup ----
|
||||
// Alice now has a valid 10 NMO note, she wants to swap it for 90 MEM
|
||||
// ---- begin swap ----
|
||||
|
||||
let swap_goal_nonce = Nonce::random(&mut rng);
|
||||
|
||||
let swap_tx = TxWitness::default()
|
||||
.add_input(alice_in, alice_in_proof)
|
||||
.add_output(
|
||||
@ -44,30 +98,26 @@ fn simple_swap() {
|
||||
},
|
||||
);
|
||||
|
||||
let swap_tx_proof = ledger::tx::ProvedTx::prove(swap_tx, vec![], vec![]).unwrap();
|
||||
let swap_tx_proof = ProvedTx::prove(swap_tx, vec![], vec![]).unwrap();
|
||||
|
||||
//
|
||||
// alice ---- (swap_tx, swap_tx_proof) ---> executor
|
||||
|
||||
let mut swapvm_state = ZoneData::new();
|
||||
|
||||
swapvm_state.add_liquidity(&AddLiquidity::new(
|
||||
nmo().unit(),
|
||||
1348,
|
||||
mem().unit(),
|
||||
14102,
|
||||
NullifierSecret::random(&mut rng).commit(),
|
||||
Nonce::random(&mut rng),
|
||||
));
|
||||
//
|
||||
// alice sends the tx to an executor
|
||||
|
||||
// ensure the pair price is above the minimum realized price (90 out / 10 in = 9.0)
|
||||
assert_eq!(
|
||||
swapvm_state.pair_price(nmo().unit(), mem().unit()).unwrap(),
|
||||
exec_state
|
||||
.swapvm
|
||||
.pair_price(nmo().unit(), mem().unit())
|
||||
.unwrap(),
|
||||
9.0
|
||||
);
|
||||
|
||||
// ensure that the realized output is above the limit order
|
||||
assert!(
|
||||
swapvm_state
|
||||
exec_state
|
||||
.swapvm
|
||||
.amount_out(nmo().unit(), mem().unit(), 10)
|
||||
.unwrap()
|
||||
>= 90
|
||||
|
||||
@ -41,21 +41,28 @@ fn main() {
|
||||
continue
|
||||
};
|
||||
|
||||
zone_data.validate_no_pools(zone_update);
|
||||
if zone_data.validate_no_pools(zone_update) {
|
||||
// This tx does not touch pool notes, we can allow zone ops.
|
||||
|
||||
if tx.balance.unit_balance(app::swap_goal_unit().unit()).is_neg() {
|
||||
// This TX encodes a SWAP request.
|
||||
// as a simplifying assumption, we will assume that the SWAP goal note is the only output
|
||||
assert_eq!(zone_update.outputs.len(), 1);
|
||||
let (swap_goal_cm, swap_args_bytes) = &zone_update.outputs[0];
|
||||
let swap_args: SwapArgs = cl::deserialize(&swap_args_bytes);
|
||||
// is it a SWAP?
|
||||
if tx.balance.unit_balance(app::swap_goal_unit().unit()).is_neg() {
|
||||
// This TX encodes a SWAP request.
|
||||
// as a simplifying assumption, we will assume that the SWAP goal note is the only output
|
||||
assert_eq!(zone_update.outputs.len(), 1);
|
||||
let (swap_goal_cm, swap_args_bytes) = &zone_update.outputs[0];
|
||||
let swap_args: SwapArgs = cl::deserialize(&swap_args_bytes);
|
||||
|
||||
// ensure the witness corresponds to the swap goal cm
|
||||
assert_eq!(
|
||||
swap_goal_cm,
|
||||
&app::swap_goal_note(swap_args.nonce).note_commitment()
|
||||
);
|
||||
panic!("zone_data.swap()");
|
||||
// ensure the witness corresponds to the swap goal cm
|
||||
assert_eq!(
|
||||
swap_goal_cm,
|
||||
&app::swap_goal_note(swap_args.nonce).note_commitment()
|
||||
);
|
||||
panic!("zone_data.swap()");
|
||||
}
|
||||
// otherwise it's a normal ledger Tx
|
||||
} else {
|
||||
// This tx does touch pool notes. therefore we must ensure the changes reflect the zone balances
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user