diff --git a/emmarin/apps/swapvm/app/src/lib.rs b/emmarin/apps/swapvm/app/src/lib.rs index 00bb85c..efbf4e3 100644 --- a/emmarin/apps/swapvm/app/src/lib.rs +++ b/emmarin/apps/swapvm/app/src/lib.rs @@ -267,6 +267,24 @@ impl ZoneData { }) } + pub fn amount_out(&self, t_in: Unit, t_out: Unit, amount_in: u64) -> Option { + let pair = Pair::new(t_in, t_out); + let pool = self.pools.get(&pair)?; + + let (balance_in, balance_out) = if pair.t0 == t_in { + (pool.balance_0, pool.balance_1) + } else { + (pool.balance_1, pool.balance_0) + }; + + let amount_in_after_fee = amount_in * 1000 - amount_in * 3; + + let amount_out = + (balance_out * 1000 * amount_in_after_fee) / (balance_in * 1000 + amount_in_after_fee); + + Some(amount_out / 1000) + } + /// 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) { diff --git a/emmarin/apps/swapvm/app/tests/swap.rs b/emmarin/apps/swapvm/app/tests/swap.rs index 2d791c7..33774b9 100644 --- a/emmarin/apps/swapvm/app/tests/swap.rs +++ b/emmarin/apps/swapvm/app/tests/swap.rs @@ -41,6 +41,20 @@ fn pair_price() { swapvm_state.pair_price(mem().unit(), nmo().unit()), Some(0.1) ); + + // Due to slippage, the amount we get out is less than what the price would imply + assert_eq!( + swapvm_state.amount_out(nmo().unit(), mem().unit(), 1), + Some(9) // 1 MEM slippage + ); + assert_eq!( + swapvm_state.amount_out(nmo().unit(), mem().unit(), 2), + Some(18) // 2 MEM slippage + ); + assert_eq!( + swapvm_state.amount_out(nmo().unit(), mem().unit(), 5), + Some(39) // 11 MEM slippage + ); } #[test]