diff --git a/apps/rooch_dex/sources/route.move b/apps/rooch_dex/sources/router.move similarity index 97% rename from apps/rooch_dex/sources/route.move rename to apps/rooch_dex/sources/router.move index 5818c4a811..568b208132 100644 --- a/apps/rooch_dex/sources/route.move +++ b/apps/rooch_dex/sources/router.move @@ -2,8 +2,8 @@ module rooch_dex::router { use rooch_dex::swap; use std::signer; use std::signer::address_of; + use rooch_dex::swap::LPToken; use rooch_framework::account_coin_store; - use moveos_std::object::ObjectID; use rooch_framework::coin; use rooch_dex::swap_utils; @@ -26,11 +26,11 @@ module rooch_dex::router { ) { assert!(!(swap::is_pair_created() || swap::is_pair_created()), ErrorTokenPairAlreadyExist); if (swap_utils::sort_token_type()) { - let coin_info_id = swap::create_pair(sender); - add_liquidity(sender, amount_x_desired, amount_y_desired, amount_x_min, amount_y_min, coin_info_id); + swap::create_pair(sender); + add_liquidity(sender, amount_x_desired, amount_y_desired, amount_x_min, amount_y_min); } else { - let coin_info_id = swap::create_pair(sender); - add_liquidity(sender, amount_x_desired, amount_y_desired, amount_x_min, amount_y_min, coin_info_id); + swap::create_pair(sender); + add_liquidity(sender, amount_x_desired, amount_y_desired, amount_x_min, amount_y_min); }; } @@ -42,23 +42,30 @@ module rooch_dex::router { amount_y_desired: u64, amount_x_min: u64, amount_y_min: u64, - coin_info: ObjectID, ) { let amount_x; let amount_y; let _lp_amount; if (swap_utils::sort_token_type()) { - (amount_x, amount_y, _lp_amount) = swap::add_liquidity(sender, amount_x_desired, amount_y_desired, coin_info); + (amount_x, amount_y, _lp_amount) = swap::add_liquidity(sender, amount_x_desired, amount_y_desired); assert!(amount_x >= amount_x_min, ErrorInsufficientXAmount); assert!(amount_y >= amount_y_min, ErrorInsufficientYAmount); } else { - (amount_y, amount_x, _lp_amount) = swap::add_liquidity(sender, amount_y_desired, amount_x_desired, coin_info); + (amount_y, amount_x, _lp_amount) = swap::add_liquidity(sender, amount_y_desired, amount_x_desired); assert!(amount_x >= amount_x_min, ErrorInsufficientXAmount); assert!(amount_y >= amount_y_min, ErrorInsufficientYAmount); }; } + public fun lp_balance(addr: address): u256 { + if (swap_utils::sort_token_type()) { + account_coin_store::balance>(addr) + } else { + account_coin_store::balance>(addr) + } + } + fun assert_token_pair_created(){ assert!(swap::is_pair_created() || swap::is_pair_created(), ErrorTokenPairNotExist); } @@ -69,17 +76,16 @@ module rooch_dex::router { liquidity: u64, amount_x_min: u64, amount_y_min: u64, - coin_info: ObjectID ) { assert_token_pair_created(); let amount_x; let amount_y; if (swap_utils::sort_token_type()) { - (amount_x, amount_y) = swap::remove_liquidity(sender, liquidity, coin_info); + (amount_x, amount_y) = swap::remove_liquidity(sender, liquidity); assert!(amount_x >= amount_x_min, ErrorInsufficientXAmount); assert!(amount_y >= amount_y_min, ErrorInsufficientYAmount); } else { - (amount_y, amount_x) = swap::remove_liquidity(sender, liquidity, coin_info); + (amount_y, amount_x) = swap::remove_liquidity(sender, liquidity); assert!(amount_x >= amount_x_min, ErrorInsufficientXAmount); assert!(amount_y >= amount_y_min, ErrorInsufficientYAmount); } diff --git a/apps/rooch_dex/sources/swap.move b/apps/rooch_dex/sources/swap.move index 63f90d5122..22d674786b 100644 --- a/apps/rooch_dex/sources/swap.move +++ b/apps/rooch_dex/sources/swap.move @@ -16,7 +16,7 @@ module rooch_dex::swap { use moveos_std::object; use moveos_std::account; use rooch_framework::coin::{CoinInfo, symbol_by_type, supply_by_type}; - use moveos_std::object::{Object, ObjectID}; + use moveos_std::object::{Object, ObjectID, named_object_id}; use rooch_framework::coin_store::{CoinStore, balance, deposit, withdraw}; use rooch_framework::coin_store; #[test_only] @@ -47,16 +47,20 @@ module rooch_dex::swap { const PRECISION: u64 = 10000; + const DEFAULT_FEE_RATE: u64 = 9975; + const MAX_U128: u128 = 340282366920938463463374607431768211455; struct LPToken has key, store {} - struct TokenPair has key { + struct TokenPair has key, store { creator: address, fee: Object>>, + fee_rate: u64, k_last: u128, balance_x: Object>, balance_y: Object>, + coin_info: Object>>, is_open: bool } @@ -68,6 +72,7 @@ module rooch_dex::swap { struct PairCreatedEvent has drop, store, copy { user: address, + token_pair_id: ObjectID, token_x: string::String, token_y: string::String } @@ -116,7 +121,7 @@ module rooch_dex::swap { /// Create the specified coin pair public(friend) fun create_pair( sender: &signer, - ): ObjectID { + ){ assert!(!is_pair_created(), ErrorAlreadyExists); let sender_addr = signer::address_of(sender); @@ -140,7 +145,6 @@ module rooch_dex::swap { 8, ); - let coin_info_id = object::id(&coin_info); account::move_resource_to>( &resource_signer, TokenPairReserve { @@ -150,18 +154,17 @@ module rooch_dex::swap { } ); - account::move_resource_to>( - &resource_signer, - TokenPair { - creator: sender_addr, - fee: coin_store::create_coin_store(), - k_last: 0, - balance_x: coin_store::create_coin_store(), - balance_y: coin_store::create_coin_store(), - is_open: true - } - ); - + let token_pair = object::new_named_object(TokenPair { + creator: sender_addr, + fee: coin_store::create_coin_store(), + k_last: 0, + fee_rate: DEFAULT_FEE_RATE, + balance_x: coin_store::create_coin_store(), + balance_y: coin_store::create_coin_store(), + coin_info, + is_open: true + }); + let token_pair_id = object::id(&token_pair); // pair created event let token_x = type_info::type_name(); let token_y = type_info::type_name(); @@ -169,24 +172,18 @@ module rooch_dex::swap { event::emit( PairCreatedEvent { user: sender_addr, + token_pair_id, token_x, token_y } ); - object::to_shared(coin_info); - return coin_info_id + object::to_shared(token_pair) } public fun is_pair_created(): bool { - account::exists_resource>(RESOURCE_ACCOUNT) - } - - /// Obtain the LP token balance of `addr`. - /// This method can only be used to check other users' balance. - public fun lp_balance(addr: address): u256 { - account_coin_store::balance>(addr) + object::exists_object_with_type>(object::named_object_id>()) } /// Get the total supply of LP Tokens @@ -205,9 +202,7 @@ module rooch_dex::swap { } /// The amount of balance currently in pools of the liquidity pair - public fun token_balances(): (u64, u64) { - let token_pair = - account::borrow_resource>(RESOURCE_ACCOUNT); + public fun token_balances(token_pair: &TokenPair): (u64, u64) { ( (balance(&token_pair.balance_x) as u64), (balance(&token_pair.balance_y) as u64) @@ -222,12 +217,10 @@ module rooch_dex::swap { sender: &signer, amount_x: u64, amount_y: u64, - coin_info_id: ObjectID ): (u64, u64, u64) { - let coin_info = object::borrow_mut_object_shared(coin_info_id); let (a_x, a_y, coin_lp, fee, coin_left_x, coin_left_y) = add_liquidity_direct(account_coin_store::withdraw(sender, (amount_x as u256) - ), account_coin_store::withdraw(sender, (amount_y as u256)), coin_info); + ), account_coin_store::withdraw(sender, (amount_y as u256))); let sender_addr = signer::address_of(sender); let lp_amount = (coin::value(&coin_lp) as u64); assert!(lp_amount > 0, ErrorInsufficientLiquidity); @@ -290,7 +283,6 @@ module rooch_dex::swap { fun add_liquidity_direct( x: coin::Coin, y: coin::Coin, - coin_info: &mut Object>> ): (u64, u64, coin::Coin>, u64, coin::Coin, coin::Coin){ let amount_x = (coin::value(&x) as u64); let amount_y = (coin::value(&y) as u64); @@ -315,7 +307,7 @@ module rooch_dex::swap { let left_y = coin::extract(&mut y, (amount_y - a_y as u256)); deposit_x(x); deposit_y(y); - let (lp, fee) = mint(coin_info); + let (lp, fee) = mint(); (a_x, a_y, lp, fee, left_x, left_y) } @@ -323,11 +315,9 @@ module rooch_dex::swap { public(friend) fun remove_liquidity( sender: &signer, liquidity: u64, - coin_info_id: ObjectID ): (u64, u64) { - let coin_info = object::borrow_mut_object_shared(coin_info_id); let coins = account_coin_store::withdraw>(sender, (liquidity as u256)); - let (coins_x, coins_y, fee) = remove_liquidity_direct(coins, coin_info); + let (coins_x, coins_y, fee) = remove_liquidity_direct(coins); let amount_x = (coin::value(&coins_x) as u64); let amount_y = (coin::value(&coins_y) as u64); let sender_addr = signer::address_of(sender); @@ -347,11 +337,8 @@ module rooch_dex::swap { } /// Remove liquidity to token types. - fun remove_liquidity_direct( - liquidity: coin::Coin>, - coin_info: &mut Object>> - ): (coin::Coin, coin::Coin, u64){ - burn(liquidity, coin_info) + fun remove_liquidity_direct(liquidity: coin::Coin>): (coin::Coin, coin::Coin, u64){ + burn(liquidity) } /// Swap X to Y, X is in and Y is out. This method assumes amount_out_min is 0 @@ -460,14 +447,14 @@ module rooch_dex::swap { let reserves = account::borrow_mut_resource>(RESOURCE_ACCOUNT); assert!(amount_x_out < reserves.reserve_x && amount_y_out < reserves.reserve_y, ErrorInsufficientLiquidity); - - let token_pair = account::borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); assert!(token_pair.is_open, ErrorTokenPairNotOpen); let coins_x_out = coin::zero(); let coins_y_out = coin::zero(); if (amount_x_out > 0) coin::merge(&mut coins_x_out, withdraw_x((amount_x_out as u256), token_pair)); if (amount_y_out > 0) coin::merge(&mut coins_y_out, withdraw_y((amount_y_out as u256), token_pair)); - let (balance_x, balance_y) = token_balances(); + let (balance_x, balance_y) = token_balances(token_pair); let amount_x_in = if (balance_x > reserves.reserve_x - amount_x_out) { balance_x - (reserves.reserve_x - amount_x_out) @@ -500,17 +487,16 @@ module rooch_dex::swap { /// Mint LP Token. /// This low-level function should be called from a contract which performs important safety checks - fun mint( - coin_info: &mut Object>> - ): (coin::Coin>, u64) { - let token_pair = borrow_mut_resource>(RESOURCE_ACCOUNT); + fun mint(): (coin::Coin>, u64) { + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); assert!(token_pair.is_open, ErrorTokenPairNotOpen); let (balance_x, balance_y) = (balance(&token_pair.balance_x), balance(&token_pair.balance_y)); let reserves = borrow_mut_resource>(RESOURCE_ACCOUNT); let amount_x = (balance_x as u128) - (reserves.reserve_x as u128); let amount_y = (balance_y as u128) - (reserves.reserve_y as u128); - let fee = mint_fee(reserves.reserve_x, reserves.reserve_y, token_pair, coin_info); + let fee = mint_fee(reserves.reserve_x, reserves.reserve_y, token_pair); //Need to add fee amount which have not been mint. let total_supply = total_lp_supply(); @@ -519,7 +505,7 @@ module rooch_dex::swap { assert!(sqrt > MINIMUM_LIQUIDITY, ErrorInsufficientLiquidityAmount); let l = sqrt - MINIMUM_LIQUIDITY; // permanently lock the first MINIMUM_LIQUIDITY tokens - mint_lp_to(RESOURCE_ACCOUNT, (MINIMUM_LIQUIDITY as u64), coin_info); + mint_lp_to(RESOURCE_ACCOUNT, (MINIMUM_LIQUIDITY as u64), &mut token_pair.coin_info); l } else { let liquidity = u128::min(amount_x * total_supply / (reserves.reserve_x as u128), amount_y * total_supply / (reserves.reserve_y as u128)); @@ -528,7 +514,7 @@ module rooch_dex::swap { }; - let lp = mint_lp((liquidity as u64), coin_info); + let lp = mint_lp((liquidity as u64), &mut token_pair.coin_info); update((balance_x as u64), (balance_y as u64), reserves); @@ -537,20 +523,21 @@ module rooch_dex::swap { (lp, fee) } - fun burn(lp_tokens: coin::Coin>, coin_info: &mut Object>>): (coin::Coin, coin::Coin, u64){ - let token_pair = account::borrow_mut_resource>(RESOURCE_ACCOUNT); + fun burn(lp_tokens: coin::Coin>): (coin::Coin, coin::Coin, u64){ + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); assert!(token_pair.is_open, ErrorTokenPairNotOpen); let reserves = account::borrow_mut_resource>(RESOURCE_ACCOUNT); let liquidity = coin::value(&lp_tokens); - let fee = mint_fee(reserves.reserve_x, reserves.reserve_y, token_pair, coin_info); + let fee = mint_fee(reserves.reserve_x, reserves.reserve_y, token_pair); //Need to add fee amount which have not been mint. let total_lp_supply = total_lp_supply(); let amount_x = ((coin_store::balance(&token_pair.balance_x) as u128) * (liquidity as u128) / total_lp_supply as u256); let amount_y = ((coin_store::balance(&token_pair.balance_x) as u128) * (liquidity as u128) / total_lp_supply as u256); assert!(amount_x > 0 && amount_y > 0, ErrorLiquidityBurned); - coin::burn>(coin_info, lp_tokens); + coin::burn>(&mut token_pair.coin_info, lp_tokens); let w_x = withdraw_x(amount_x, token_pair); let w_y = withdraw_y(amount_y, token_pair); @@ -586,14 +573,14 @@ module rooch_dex::swap { } fun deposit_x(amount: coin::Coin){ - let token_pair = - borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); deposit(&mut token_pair.balance_x, amount); } fun deposit_y(amount: coin::Coin) { - let token_pair = - borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); deposit(&mut token_pair.balance_y, amount); } @@ -607,7 +594,7 @@ module rooch_dex::swap { withdraw(&mut token_pair.balance_y, amount) } - fun mint_fee(reserve_x: u64, reserve_y: u64, token_pair: &mut TokenPair, coin_info: &mut Object>>): u64 { + fun mint_fee(reserve_x: u64, reserve_y: u64, token_pair: &mut TokenPair): u64 { let fee = 0u64; if (token_pair.k_last != 0) { let root_k = u128::sqrt((reserve_x as u128) * (reserve_y as u128)); @@ -618,7 +605,7 @@ module rooch_dex::swap { let liquidity = numerator / denominator; fee = (liquidity as u64); if (fee > 0) { - let coin = mint_lp(fee, coin_info); + let coin = mint_lp(fee, &mut token_pair.coin_info); deposit(&mut token_pair.fee, coin); } }; @@ -629,13 +616,15 @@ module rooch_dex::swap { public entry fun withdraw_fee(admin_cap: &mut Object){ if (swap_utils::sort_token_type()) { - let token_pair = account::borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); assert!(balance(&token_pair.fee) > 0, ErrorWithdrawFee); let fee = balance(&token_pair.fee); let coin = withdraw(&mut token_pair.fee, fee); account_coin_store::deposit(object::owner(admin_cap), coin); } else { - let token_pair = account::borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); assert!(balance(&token_pair.fee) > 0, ErrorWithdrawFee); let fee = balance(&token_pair.fee); let coin = withdraw(&mut token_pair.fee, fee); @@ -645,10 +634,12 @@ module rooch_dex::swap { public entry fun update_token_pair_status(_admin_cap: &mut Object, status: bool){ if (swap_utils::sort_token_type()) { - let token_pair = account::borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); token_pair.is_open = status } else { - let token_pair = account::borrow_mut_resource>(RESOURCE_ACCOUNT); + let token_pair_obj = object::borrow_mut_object_shared>(named_object_id>()); + let token_pair = object::borrow_mut>(token_pair_obj); token_pair.is_open = status }; }