From 056723186df366ba2c157cf2ad690ec8bc5812c8 Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Wed, 25 Dec 2024 08:44:17 +0800 Subject: [PATCH 01/12] imporve orderbook with split purchase and distribution --- apps/orderbook/sources/market.move | 205 ++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index bb4edbe58f..9700e6656c 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 module orderbook::market_v2 { use std::option; - use std::option::{Option, is_some, destroy_none}; + use std::option::{Option, is_some, destroy_none, none, some}; use std::string; use std::string::String; use std::vector; @@ -52,6 +52,7 @@ module orderbook::market_v2 { const ErrorUnauthorizedCancel: u64 = 8; const ErrorOrderLength: u64 = 9; const ErrorDeprecated: u64 = 10; + const ErrorInvalidAmount: u64 = 11; /// listing info in the market @@ -352,6 +353,97 @@ module orderbook::market_v2 { } + public entry fun buy_with_amount( + signer: &signer, + market_obj: &mut Object>, + order_id: u64, + amount: u256, + order_owner: address, + assert_order_exist: bool, + receiver: address + ){ + let option_coin = do_buy_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, none()); + if (is_some(&option_coin)) { + account_coin_store::deposit(receiver, option::extract(&mut option_coin)) + }; + destroy_none(option_coin) + } + + public entry fun buy_from_distributor( + signer: &signer, + market_obj: &mut Object>, + order_id: u64, + amount: u256, + order_owner: address, + assert_order_exist: bool, + receiver: address, + distributor: address + ){ + let option_coin = do_buy_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, some(distributor)); + if (is_some(&option_coin)) { + account_coin_store::deposit(receiver, option::extract(&mut option_coin)) + }; + destroy_none(option_coin) + } + + + public fun do_buy_internal( + signer: &signer, + market_obj: &mut Object>, + order_id: u64, + amount: u256, + order_owner: address, + assert_order_exist: bool, + distributor: Option
+ ): Option> { + let market = object::borrow_mut(market_obj); + assert!(market.is_paused == false, ErrorWrongPaused); + assert!(market.version == VERSION, ErrorWrongVersion); + let usr_open_orders = table::borrow_mut(&mut market.user_order_info, order_owner); + let tick_price = *linked_table::borrow(usr_open_orders, order_id); + let (tick_exists, tick_index) = find_leaf(&market.asks, tick_price); + // Return non-existent orders to none instead of panic during bulk buying + if (!assert_order_exist && !tick_exists) { + return option::none() + }; + assert!(tick_exists, ErrorInvalidOrderId); + let order = borrow_mut_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); + assert!(amount <= order.quantity, ErrorInvalidAmount); + // TODO here maybe wrap to u512? + let total_price = amount * (order.unit_price as u256); + let trade_coin = account_coin_store::withdraw(signer, total_price); + let trade_info = &mut market.trade_info; + trade_info.total_volume = trade_info.total_volume + total_price; + trade_info.txs = trade_info.txs + 1; + if (now_milliseconds() - trade_info.timestamp > 86400000) { + trade_info.yesterday_volume = trade_info.today_volume; + trade_info.today_volume = total_price; + trade_info.timestamp = now_milliseconds(); + }else { + trade_info.today_volume = trade_info.today_volume + total_price; + }; + + // TODO here maybe wrap to u512? + // Here is trade fee is BaseAsset + let trade_fee = total_price * market.fee / TRADE_FEE_BASE_RATIO; + if (option::is_some(&distributor)){ + let distributor_address = option::extract(&mut distributor); + let trade_fee_coin = coin::extract(&mut trade_coin, trade_fee); + let distributor_fee = trade_fee / 2; + account_coin_store::deposit(distributor_address, coin::extract(&mut trade_fee_coin, distributor_fee)); + coin_store::deposit(&mut market.base_asset_trading_fees, trade_fee_coin); + }else{ + coin_store::deposit(&mut market.base_asset_trading_fees, coin::extract(&mut trade_coin, trade_fee)); + }; + account_coin_store::deposit(order.owner, trade_coin); + order.quantity = order.quantity - amount; + if (order.quantity == 0 ) { + let _ = remove_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); + }; + option::some(coin_store::withdraw(&mut market.quote_asset, amount)) + } + + public entry fun batch_accept_bid( signer: &signer, market_obj: &mut Object>, @@ -427,6 +519,97 @@ module orderbook::market_v2 { } + public entry fun accept_bid_with_amount( + signer: &signer, + market_obj: &mut Object>, + order_id: u64, + amount: u256, + order_owner: address, + assert_order_exist: bool, + receiver: address + ){ + let option_coin = do_accept_bid_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, none()); + if (is_some(&option_coin)) { + account_coin_store::deposit(receiver, option::extract(&mut option_coin)) + }; + destroy_none(option_coin) + } + + public entry fun accept_bid_from_distributor( + signer: &signer, + market_obj: &mut Object>, + order_id: u64, + amount: u256, + order_owner: address, + assert_order_exist: bool, + receiver: address, + distributor: address + ){ + let option_coin = do_accept_bid_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, some(distributor)); + if (is_some(&option_coin)) { + account_coin_store::deposit(receiver, option::extract(&mut option_coin)) + }; + destroy_none(option_coin) + } + + public fun do_accept_bid_internal( + signer: &signer, + market_obj: &mut Object>, + order_id: u64, + amount: u256, + order_owner: address, + assert_order_exist: bool, + distributor: Option
+ ): Option> + { + let market = object::borrow_mut(market_obj); + assert!(market.is_paused == false, ErrorWrongPaused); + assert!(market.version == VERSION, ErrorWrongVersion); + let usr_open_orders = table::borrow_mut(&mut market.user_order_info, order_owner); + let tick_price = *linked_table::borrow(usr_open_orders, order_id); + let (tick_exists, tick_index) = find_leaf(&market.bids, tick_price); + // Return non-existent orders to none instead of panic during bulk buying + if (!assert_order_exist && !tick_exists) { + return option::none() + }; + assert!(tick_exists, ErrorInvalidOrderId); + + let order = borrow_mut_order(&mut market.bids, usr_open_orders, tick_index, order_id, order_owner); + assert!(order.quantity >= amount, ErrorInvalidAmount); + let trade_coin = account_coin_store::withdraw(signer, amount); + // TODO here maybe wrap to u512? + let total_price = (order.unit_price as u256) * amount; + let trade_info = &mut market.trade_info; + + trade_info.total_volume = trade_info.total_volume + total_price; + if (now_milliseconds() - trade_info.timestamp > 86400000) { + trade_info.yesterday_volume = trade_info.today_volume; + trade_info.today_volume = total_price; + trade_info.timestamp = now_milliseconds(); + }else { + trade_info.today_volume = trade_info.today_volume + total_price; + }; + + // Here trade fee is QuoteAsset + let trade_fee = amount * market.fee / TRADE_FEE_BASE_RATIO; + if (option::is_some(&distributor)){ + let distributor_address = option::extract(&mut distributor); + let trade_fee_coin = coin::extract(&mut trade_coin, trade_fee); + let distributor_fee = trade_fee / 2; + account_coin_store::deposit(distributor_address, coin::extract(&mut trade_fee_coin, distributor_fee)); + coin_store::deposit(&mut market.quote_asset_trading_fees, trade_fee_coin); + }else{ + coin_store::deposit(&mut market.quote_asset_trading_fees, coin::extract(&mut trade_coin, trade_fee)); + }; + account_coin_store::deposit(order.owner, trade_coin); + order.quantity = order.quantity - amount; + if (order.quantity == 0) { + let _ = remove_order(&mut market.bids, usr_open_orders, tick_index, order_id, order_owner); + }; + option::some(coin_store::withdraw(&mut market.base_asset, total_price)) + } + + public entry fun withdraw_profits( _admin: &mut Object, @@ -490,6 +673,26 @@ module orderbook::market_v2 { order } + + fun borrow_mut_order( + open_orders: &mut CritbitTree, + user_order_info: &mut LinkedTable, + tick_index: u64, + order_id: u64, + user: address, + ): &mut Order { + linked_table::remove(user_order_info, order_id); + let tick_level = borrow_leaf_by_index(open_orders, tick_index); + assert!(linked_table::contains(&tick_level.open_orders, order_id), ErrorInvalidOrderId); + let mut_tick_level = borrow_mut_leaf_by_index(open_orders, tick_index); + let order = linked_table::borrow_mut(&mut mut_tick_level.open_orders, order_id); + assert!(order.owner == user, ErrorUnauthorizedCancel); + // if (linked_table::is_empty(&mut_tick_level.open_orders)) { + // destroy_empty_level(remove_leaf_by_index(open_orders, tick_index)); + // }; + order + } + fun destroy_empty_level(level: TickLevel) { let TickLevel { price: _, From 5037dc3cc35c6f4e962405e9be1b4f5e2772242c Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Thu, 26 Dec 2024 10:57:55 +0800 Subject: [PATCH 02/12] update function name --- apps/orderbook/sources/market.move | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 9700e6656c..9f1fdc9ebd 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -179,7 +179,7 @@ module orderbook::market_v2 { ) { let coin= account_coin_store::withdraw(signer, quantity); let market = object::borrow_mut(market_obj); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); assert!(market.is_paused == false, ErrorWrongPaused); let order_id = market.next_ask_order_id; market.next_ask_order_id = market.next_ask_order_id + 1; @@ -218,7 +218,7 @@ module orderbook::market_v2 { quantity: u256, ) { let market = object::borrow_mut(market_obj); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); assert!(market.is_paused == false, ErrorWrongPaused); assert!(quantity > 0, ErrorWrongCreateBid); assert!(unit_price > 0, ErrorWrongCreateBid); @@ -258,7 +258,7 @@ module orderbook::market_v2 { ) { //Get the list from the collection let market = object::borrow_mut(market_obj); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); let usr_open_orders = table::borrow_mut(&mut market.user_order_info, sender()); let tick_price = *linked_table::borrow(usr_open_orders, order_id); @@ -320,7 +320,7 @@ module orderbook::market_v2 { ): Option> { let market = object::borrow_mut(market_obj); assert!(market.is_paused == false, ErrorWrongPaused); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); let usr_open_orders = table::borrow_mut(&mut market.user_order_info, order_owner); let tick_price = *linked_table::borrow(usr_open_orders, order_id); let (tick_exists, tick_index) = find_leaf(&market.asks, tick_price); @@ -353,7 +353,7 @@ module orderbook::market_v2 { } - public entry fun buy_with_amount( + public entry fun buy_from_origin( signer: &signer, market_obj: &mut Object>, order_id: u64, @@ -362,7 +362,7 @@ module orderbook::market_v2 { assert_order_exist: bool, receiver: address ){ - let option_coin = do_buy_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, none()); + let option_coin = do_buy_external(signer, market_obj, order_id, amount, order_owner, assert_order_exist, none()); if (is_some(&option_coin)) { account_coin_store::deposit(receiver, option::extract(&mut option_coin)) }; @@ -379,7 +379,7 @@ module orderbook::market_v2 { receiver: address, distributor: address ){ - let option_coin = do_buy_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, some(distributor)); + let option_coin = do_buy_external(signer, market_obj, order_id, amount, order_owner, assert_order_exist, some(distributor)); if (is_some(&option_coin)) { account_coin_store::deposit(receiver, option::extract(&mut option_coin)) }; @@ -387,7 +387,7 @@ module orderbook::market_v2 { } - public fun do_buy_internal( + public fun do_buy_external( signer: &signer, market_obj: &mut Object>, order_id: u64, @@ -398,7 +398,7 @@ module orderbook::market_v2 { ): Option> { let market = object::borrow_mut(market_obj); assert!(market.is_paused == false, ErrorWrongPaused); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); let usr_open_orders = table::borrow_mut(&mut market.user_order_info, order_owner); let tick_price = *linked_table::borrow(usr_open_orders, order_id); let (tick_exists, tick_index) = find_leaf(&market.asks, tick_price); @@ -484,7 +484,7 @@ module orderbook::market_v2 { { let market = object::borrow_mut(market_obj); assert!(market.is_paused == false, ErrorWrongPaused); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); let usr_open_orders = table::borrow_mut(&mut market.user_order_info, order_owner); let tick_price = *linked_table::borrow(usr_open_orders, order_id); let (tick_exists, tick_index) = find_leaf(&market.bids, tick_price); @@ -519,7 +519,7 @@ module orderbook::market_v2 { } - public entry fun accept_bid_with_amount( + public entry fun accept_bid_from_origin( signer: &signer, market_obj: &mut Object>, order_id: u64, @@ -528,7 +528,7 @@ module orderbook::market_v2 { assert_order_exist: bool, receiver: address ){ - let option_coin = do_accept_bid_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, none()); + let option_coin = do_accept_bid_external(signer, market_obj, order_id, amount, order_owner, assert_order_exist, none()); if (is_some(&option_coin)) { account_coin_store::deposit(receiver, option::extract(&mut option_coin)) }; @@ -545,14 +545,14 @@ module orderbook::market_v2 { receiver: address, distributor: address ){ - let option_coin = do_accept_bid_internal(signer, market_obj, order_id, amount, order_owner, assert_order_exist, some(distributor)); + let option_coin = do_accept_bid_external(signer, market_obj, order_id, amount, order_owner, assert_order_exist, some(distributor)); if (is_some(&option_coin)) { account_coin_store::deposit(receiver, option::extract(&mut option_coin)) }; destroy_none(option_coin) } - public fun do_accept_bid_internal( + public fun do_accept_bid_external( signer: &signer, market_obj: &mut Object>, order_id: u64, @@ -564,7 +564,7 @@ module orderbook::market_v2 { { let market = object::borrow_mut(market_obj); assert!(market.is_paused == false, ErrorWrongPaused); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); let usr_open_orders = table::borrow_mut(&mut market.user_order_info, order_owner); let tick_price = *linked_table::borrow(usr_open_orders, order_id); let (tick_exists, tick_index) = find_leaf(&market.bids, tick_price); @@ -617,7 +617,7 @@ module orderbook::market_v2 { receiver: address, ) { let market = object::borrow_mut(market_obj); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); let quote_amount = coin_store::balance(&market.quote_asset_trading_fees); account_coin_store::deposit(receiver, coin_store::withdraw(&mut market.quote_asset_trading_fees, quote_amount)); let base_amount = coin_store::balance(&market.base_asset_trading_fees); @@ -631,7 +631,7 @@ module orderbook::market_v2 { fee: u256, ) { let market = object::borrow_mut(market_obj); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); assert!(fee < TRADE_FEE_BASE_RATIO, ErrorFeeTooHigh); market.fee = fee } @@ -642,7 +642,7 @@ module orderbook::market_v2 { status: bool, ) { let market = object::borrow_mut(market_obj); - assert!(market.version == VERSION, ErrorWrongVersion); + // assert!(market.version == VERSION, ErrorWrongVersion); market.is_paused = status } From 8d02c4fbb2a12c13e3c56ce8c218f20234dbd3e2 Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Fri, 27 Dec 2024 00:20:42 +0800 Subject: [PATCH 03/12] fix: market unit price and amount --- apps/orderbook/sources/market.move | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 9f1fdc9ebd..5fe52f4ef0 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -5,6 +5,7 @@ module orderbook::market_v2 { use std::option::{Option, is_some, destroy_none, none, some}; use std::string; use std::string::String; + use std::u64; use std::vector; use std::vector::{length, zip}; @@ -19,7 +20,7 @@ module orderbook::market_v2 { use moveos_std::table::Table; use rooch_framework::coin_store::{CoinStore, create_coin_store}; - use rooch_framework::coin::{Self, Coin}; + use rooch_framework::coin::{Self, Coin, coin_info, decimals}; use rooch_framework::coin_store; use rooch_framework::account_coin_store; @@ -223,7 +224,7 @@ module orderbook::market_v2 { assert!(quantity > 0, ErrorWrongCreateBid); assert!(unit_price > 0, ErrorWrongCreateBid); // TODO here maybe wrap to u512? - let price = (unit_price as u256) * quantity; + let price = (unit_price as u256) * quantity / (u64::pow(10,decimals(coin_info())) as u256); let paid = account_coin_store::withdraw(signer, price); let order_id = market.next_bid_order_id; market.next_bid_order_id = market.next_bid_order_id + 1; @@ -331,7 +332,8 @@ module orderbook::market_v2 { assert!(tick_exists, ErrorInvalidOrderId); let order = remove_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); // TODO here maybe wrap to u512? - let total_price = order.quantity * (order.unit_price as u256); + let order_price = order.unit_price * u64::pow(10, decimals(coin_info())); + let total_price = order.quantity * (order_price as u256); let trade_coin = account_coin_store::withdraw(signer, total_price); let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; @@ -410,7 +412,8 @@ module orderbook::market_v2 { let order = borrow_mut_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); assert!(amount <= order.quantity, ErrorInvalidAmount); // TODO here maybe wrap to u512? - let total_price = amount * (order.unit_price as u256); + let order_price = order.unit_price * u64::pow(10, decimals(coin_info())); + let total_price = amount * (order_price as u256); let trade_coin = account_coin_store::withdraw(signer, total_price); let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; @@ -499,7 +502,8 @@ module orderbook::market_v2 { // assert!(coin::value(paid) >= order.quantity, ErrorInputCoin); // let trade_coin = coin::extract(paid, order.quantity); // TODO here maybe wrap to u512? - let total_price = (order.unit_price as u256) * order.quantity; + let total_price = (order.unit_price as u256) * order.quantity / (u64::pow(10,decimals(coin_info())) as u256); + // let total_price = (order.unit_price as u256) * order.quantity; let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; @@ -578,7 +582,8 @@ module orderbook::market_v2 { assert!(order.quantity >= amount, ErrorInvalidAmount); let trade_coin = account_coin_store::withdraw(signer, amount); // TODO here maybe wrap to u512? - let total_price = (order.unit_price as u256) * amount; + let total_price = (order.unit_price as u256) * amount / (u64::pow(10,decimals(coin_info())) as u256); + // let total_price = (order.unit_price as u256) * amount; let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; From 8c7f295481c18825cabed5902d202df80e16163f Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Fri, 27 Dec 2024 00:30:46 +0800 Subject: [PATCH 04/12] fix: buy price --- apps/orderbook/sources/market.move | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 5fe52f4ef0..28bfa6ec9e 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -332,8 +332,7 @@ module orderbook::market_v2 { assert!(tick_exists, ErrorInvalidOrderId); let order = remove_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); // TODO here maybe wrap to u512? - let order_price = order.unit_price * u64::pow(10, decimals(coin_info())); - let total_price = order.quantity * (order_price as u256); + let total_price = order.quantity * (order.unit_price as u256) / (u64::pow(10, decimals(coin_info())) as u256); let trade_coin = account_coin_store::withdraw(signer, total_price); let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; @@ -412,8 +411,7 @@ module orderbook::market_v2 { let order = borrow_mut_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); assert!(amount <= order.quantity, ErrorInvalidAmount); // TODO here maybe wrap to u512? - let order_price = order.unit_price * u64::pow(10, decimals(coin_info())); - let total_price = amount * (order_price as u256); + let total_price = amount * (order.unit_price as u256) / (u64::pow(10, decimals(coin_info())) as u256); let trade_coin = account_coin_store::withdraw(signer, total_price); let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; From 91018d305a6be97af4e093799a53538f11f8387b Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Fri, 27 Dec 2024 01:03:03 +0800 Subject: [PATCH 05/12] fix: unit_price scale --- apps/orderbook/sources/market.move | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 28bfa6ec9e..6edc0ac6cd 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -41,6 +41,8 @@ module orderbook::market_v2 { const MIN_BID_ORDER_ID: u64 = 1; const MIN_ASK_ORDER_ID: u64 = 1 << 63; + // 1e18 + const UNIT_PRICE_SCALE: u256 = 1000000000000000000; const ErrorWrongVersion: u64 = 0; const ErrorWrongPaused: u64 = 1; @@ -224,7 +226,7 @@ module orderbook::market_v2 { assert!(quantity > 0, ErrorWrongCreateBid); assert!(unit_price > 0, ErrorWrongCreateBid); // TODO here maybe wrap to u512? - let price = (unit_price as u256) * quantity / (u64::pow(10,decimals(coin_info())) as u256); + let price = (unit_price as u256) * quantity / UNIT_PRICE_SCALE; let paid = account_coin_store::withdraw(signer, price); let order_id = market.next_bid_order_id; market.next_bid_order_id = market.next_bid_order_id + 1; @@ -275,7 +277,7 @@ module orderbook::market_v2 { ); if (is_bid) { // TODO here maybe wrap to u512? - let total_balance = (order.unit_price as u256) * order.quantity; + let total_balance = (order.unit_price as u256) * order.quantity / UNIT_PRICE_SCALE; account_coin_store::deposit(sender(), coin_store::withdraw(&mut market.base_asset, total_balance)) }else { account_coin_store::deposit(sender(), coin_store::withdraw(&mut market.quote_asset, order.quantity)) @@ -332,7 +334,7 @@ module orderbook::market_v2 { assert!(tick_exists, ErrorInvalidOrderId); let order = remove_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); // TODO here maybe wrap to u512? - let total_price = order.quantity * (order.unit_price as u256) / (u64::pow(10, decimals(coin_info())) as u256); + let total_price = order.quantity * (order.unit_price as u256) / UNIT_PRICE_SCALE; let trade_coin = account_coin_store::withdraw(signer, total_price); let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; @@ -411,7 +413,7 @@ module orderbook::market_v2 { let order = borrow_mut_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); assert!(amount <= order.quantity, ErrorInvalidAmount); // TODO here maybe wrap to u512? - let total_price = amount * (order.unit_price as u256) / (u64::pow(10, decimals(coin_info())) as u256); + let total_price = amount * (order.unit_price as u256) / UNIT_PRICE_SCALE; let trade_coin = account_coin_store::withdraw(signer, total_price); let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; @@ -500,7 +502,7 @@ module orderbook::market_v2 { // assert!(coin::value(paid) >= order.quantity, ErrorInputCoin); // let trade_coin = coin::extract(paid, order.quantity); // TODO here maybe wrap to u512? - let total_price = (order.unit_price as u256) * order.quantity / (u64::pow(10,decimals(coin_info())) as u256); + let total_price = (order.unit_price as u256) * order.quantity / UNIT_PRICE_SCALE; // let total_price = (order.unit_price as u256) * order.quantity; let trade_info = &mut market.trade_info; @@ -580,7 +582,7 @@ module orderbook::market_v2 { assert!(order.quantity >= amount, ErrorInvalidAmount); let trade_coin = account_coin_store::withdraw(signer, amount); // TODO here maybe wrap to u512? - let total_price = (order.unit_price as u256) * amount / (u64::pow(10,decimals(coin_info())) as u256); + let total_price = (order.unit_price as u256) * amount / UNIT_PRICE_SCALE; // let total_price = (order.unit_price as u256) * amount; let trade_info = &mut market.trade_info; From 0c12f6fd7ca8bb3d6fca4b8dd167acdf1eefb583 Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Sat, 28 Dec 2024 00:18:54 +0800 Subject: [PATCH 06/12] update unit price scale --- apps/orderbook/sources/market.move | 183 +++++++++++++++++++++++++++-- 1 file changed, 172 insertions(+), 11 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 6edc0ac6cd..d4c1d766ac 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -3,6 +3,7 @@ module orderbook::market_v2 { use std::option; use std::option::{Option, is_some, destroy_none, none, some}; + use std::signer::address_of; use std::string; use std::string::String; use std::u64; @@ -20,7 +21,7 @@ module orderbook::market_v2 { use moveos_std::table::Table; use rooch_framework::coin_store::{CoinStore, create_coin_store}; - use rooch_framework::coin::{Self, Coin, coin_info, decimals}; + use rooch_framework::coin::{Self, Coin}; use rooch_framework::coin_store; use rooch_framework::account_coin_store; @@ -30,6 +31,9 @@ module orderbook::market_v2 { use orderbook::critbit; use app_admin::admin::AdminCap; + #[test_only] + use rooch_framework::account::create_account_for_testing; + const DEPLOYER: address = @orderbook; @@ -41,8 +45,8 @@ module orderbook::market_v2 { const MIN_BID_ORDER_ID: u64 = 1; const MIN_ASK_ORDER_ID: u64 = 1 << 63; - // 1e18 - const UNIT_PRICE_SCALE: u256 = 1000000000000000000; + + const UNIT_PRICE_SCALE: u256 = 100000; const ErrorWrongVersion: u64 = 0; const ErrorWrongPaused: u64 = 1; @@ -193,7 +197,7 @@ module orderbook::market_v2 { order_id, unit_price, quantity, - owner: sender(), + owner: address_of(signer), is_bid: false, }; coin_store::deposit(&mut market.quote_asset, coin); @@ -207,10 +211,10 @@ module orderbook::market_v2 { let tick_level = critbit::borrow_mut_leaf_by_index(&mut market.asks, index); linked_table::push_back(&mut tick_level.open_orders, order_id, asks); // - if (!table::contains(&market.user_order_info, sender())) { - table::add(&mut market.user_order_info, sender(), linked_table::new()); + if (!table::contains(&market.user_order_info, address_of(signer))) { + table::add(&mut market.user_order_info, address_of(signer), linked_table::new()); }; - linked_table::push_back(table::borrow_mut(&mut market.user_order_info, sender()), order_id, unit_price); + linked_table::push_back(table::borrow_mut(&mut market.user_order_info, address_of(signer)), order_id, unit_price); } @@ -234,7 +238,7 @@ module orderbook::market_v2 { order_id, unit_price, quantity, - owner: sender(), + owner: address_of(signer), is_bid: true, }; coin_store::deposit(&mut market.base_asset, paid); @@ -248,10 +252,10 @@ module orderbook::market_v2 { }; let tick_level = critbit::borrow_mut_leaf_by_index(&mut market.bids, index); linked_table::push_back(&mut tick_level.open_orders, order_id, bid); - if (!table::contains(&market.user_order_info, sender())) { - table::add(&mut market.user_order_info, sender(), linked_table::new()); + if (!table::contains(&market.user_order_info, address_of(signer))) { + table::add(&mut market.user_order_info, address_of(signer), linked_table::new()); }; - linked_table::push_back(table::borrow_mut(&mut market.user_order_info, sender()), order_id, unit_price); + linked_table::push_back(table::borrow_mut(&mut market.user_order_info, address_of(signer)), order_id, unit_price); } ///Cancel the listing of inscription @@ -878,4 +882,161 @@ module orderbook::market_v2 { fun order_is_bid(order_id: u64): bool { return order_id < MIN_ASK_ORDER_ID } + + #[test_only] + struct TestBaseCoin has key, store{} + #[test_only] + struct TestQuoteCoin has key, store{} + + #[test_only] + fun init_for_test(base_decimal: u8, quote_decimal: u8):(Object>, Coin, Coin) { + let base_coin_info = coin::register_extend( + string::utf8(b"Test Base Coin"), + string::utf8(b"TBC"), + option::none(), + base_decimal, + ); + let quote_coin_info = coin::register_extend( + string::utf8(b"Test Quote Coin"), + string::utf8(b"TQC"), + option::none(), + quote_decimal, + ); + let base_coin = coin::mint_extend(&mut base_coin_info, (1000 * u64::pow(10, base_decimal) as u256)); + let quote_coin = coin::mint_extend(&mut quote_coin_info, (1000 * u64::pow(10, quote_decimal) as u256)); + to_shared(base_coin_info); + to_shared(quote_coin_info); + let market_obj = new_named_object(Marketplace { + is_paused: false, + version: VERSION, + bids: critbit::new(), + asks: critbit::new(), + // Order id of the next bid order, starting from 0. + next_bid_order_id: MIN_BID_ORDER_ID, + // Order id of the next ask order, starting from 1<<63. + next_ask_order_id: MIN_ASK_ORDER_ID, + fee: 0, + user_order_info: table::new(), + base_asset: create_coin_store(), + quote_asset: create_coin_store(), + base_asset_trading_fees: create_coin_store(), + quote_asset_trading_fees: create_coin_store(), + trade_info: TradeInfo{ + timestamp: now_milliseconds(), + yesterday_volume: 0, + today_volume: 0, + total_volume: 0, + txs: 0 + } + }); + (market_obj, base_coin, quote_coin) + } + + #[test] + public fun test_buy_1() { + rooch_framework::genesis::init_for_test(); + let base_decimal = 0; + let quote_decimal = 0; + let account_list = create_account_for_testing(@0x43); + let address_list = address_of(&account_list); + let account_buy = create_account_for_testing(@0x44); + let address_buy = address_of(&account_buy); + let (market_obj, base_coin, quote_coin )= init_for_test(base_decimal, quote_decimal); + account_coin_store::deposit(address_list, quote_coin); + account_coin_store::deposit(address_buy, base_coin); + // Here we list it at price 10 base/quote, and list 10 quote coin + list(&account_list, &mut market_obj, (10 * u64::pow(10, quote_decimal) as u256), (10 * UNIT_PRICE_SCALE as u64) / u64::pow(10, quote_decimal)); + buy(&account_buy, &mut market_obj, MIN_ASK_ORDER_ID, address_list, true, address_buy); + to_shared(market_obj); + // list account will recieve 10 * 10 = 100 base coin + assert!(account_coin_store::balance(address_list) == 100, 0); + // buy account will recieve 10 quote coin + assert!(account_coin_store::balance(address_buy) == 10, 1); + // list account will pay 10 quote coin + assert!(account_coin_store::balance(address_list) == 990, 2); + // buy account will pay 10 * 10 = 100 base coin + assert!(account_coin_store::balance(address_buy) == 900, 3); + } + + #[test] + public fun test_buy_2() { + rooch_framework::genesis::init_for_test(); + let base_decimal = 8; + let quote_decimal = 0; + let account_list = create_account_for_testing(@0x43); + let address_list = address_of(&account_list); + let account_buy = create_account_for_testing(@0x44); + let address_buy = address_of(&account_buy); + let (market_obj, base_coin, quote_coin )= init_for_test(base_decimal, quote_decimal); + account_coin_store::deposit(address_list, quote_coin); + account_coin_store::deposit(address_buy, base_coin); + // Here we list it at price 10 base/quote, and list 10.0 quote coin + list(&account_list, &mut market_obj, (10 * u64::pow(10, quote_decimal) as u256), ((UNIT_PRICE_SCALE as u64) / u64::pow(10, quote_decimal)) * (10 * u64::pow(10, base_decimal))); + buy(&account_buy, &mut market_obj, MIN_ASK_ORDER_ID, address_list, true, address_buy); + to_shared(market_obj); + // list account will recieve 10 * 10 = 100.0000000000 base coin + assert!(account_coin_store::balance(address_list) == 100_00000000, 0); + // buy account will recieve 10 quote coin + assert!(account_coin_store::balance(address_buy) == 10, 1); + // list account will pay 10 quote coin + assert!(account_coin_store::balance(address_list) == 990, 2); + // buy account will pay 10 * 10 = 100.0000000000 base coin + assert!(account_coin_store::balance(address_buy) == 900_00000000, 3); + } + + + #[test] + public fun test_buy_3() { + rooch_framework::genesis::init_for_test(); + let base_decimal = 10; + let quote_decimal = 3; + let account_list = create_account_for_testing(@0x43); + let address_list = address_of(&account_list); + let account_buy = create_account_for_testing(@0x44); + let address_buy = address_of(&account_buy); + let (market_obj, base_coin, quote_coin )= init_for_test(base_decimal, quote_decimal); + account_coin_store::deposit(address_list, quote_coin); + account_coin_store::deposit(address_buy, base_coin); + // Here we list it at price 10 base/quote, and list 10.000 quote coin + list(&account_list, &mut market_obj, (10 * u64::pow(10, quote_decimal) as u256), ((UNIT_PRICE_SCALE as u64) / u64::pow(10, quote_decimal) * 10 * u64::pow(10, base_decimal))); + buy(&account_buy, &mut market_obj, MIN_ASK_ORDER_ID, address_list, true, address_buy); + to_shared(market_obj); + // list account will recieve 10 * 10 = 100.0000000000 base coin + assert!(account_coin_store::balance(address_list) == 100_0000000000, 0); + // buy account will recieve 10.000 quote coin + assert!(account_coin_store::balance(address_buy) == 10000, 1); + // list account will pay 10.000 quote coin + assert!(account_coin_store::balance(address_list) == 990_000, 2); + // buy account will pay 10 * 10 = 100.0000000000 base coin + assert!(account_coin_store::balance(address_buy) == 900_0000000000, 3); + } + + + // u64 max >= 1 * base_decimal * price * UNIT_PRICE_SCALE > quote_decimal + + #[test] + public fun test_buy_4() { + rooch_framework::genesis::init_for_test(); + let base_decimal = 8; + let quote_decimal = 10; + let account_list = create_account_for_testing(@0x43); + let address_list = address_of(&account_list); + let account_buy = create_account_for_testing(@0x44); + let address_buy = address_of(&account_buy); + let (market_obj, base_coin, quote_coin )= init_for_test(base_decimal, quote_decimal); + account_coin_store::deposit(address_list, quote_coin); + account_coin_store::deposit(address_buy, base_coin); + // Here we list it at price 10 base/quote, and list 10.000 quote coin + list(&account_list, &mut market_obj, (10 * u64::pow(10, quote_decimal) as u256), ((UNIT_PRICE_SCALE as u64) * 10 * u64::pow(10, base_decimal) / u64::pow(10, quote_decimal) )); + buy(&account_buy, &mut market_obj, MIN_ASK_ORDER_ID, address_list, true, address_buy); + to_shared(market_obj); + // list account will recieve 10 * 10 = 100.00000000 base coin + assert!(account_coin_store::balance(address_list) == 100_00000000, 0); + // buy account will recieve 10.0000000000 quote coin + assert!(account_coin_store::balance(address_buy) == 10_0000000000, 1); + // list account will pay 10.0000000000 quote coin + assert!(account_coin_store::balance(address_list) == 990_0000000000, 2); + // buy account will pay 10 * 10 = 100.00000000 base coin + assert!(account_coin_store::balance(address_buy) == 900_00000000, 3); + } } From 81e2cae04f9ed9bddeffbbd2da4b20c76125efc6 Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Sat, 28 Dec 2024 00:34:46 +0800 Subject: [PATCH 07/12] fix: borrow mut order and add test --- apps/orderbook/sources/market.move | 35 ++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index d4c1d766ac..c01aec1f2a 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -511,6 +511,7 @@ module orderbook::market_v2 { let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; + trade_info.txs = trade_info.txs + 1; if (now_milliseconds() - trade_info.timestamp > 86400000) { trade_info.yesterday_volume = trade_info.today_volume; trade_info.today_volume = total_price; @@ -591,6 +592,7 @@ module orderbook::market_v2 { let trade_info = &mut market.trade_info; trade_info.total_volume = trade_info.total_volume + total_price; + trade_info.txs = trade_info.txs + 1; if (now_milliseconds() - trade_info.timestamp > 86400000) { trade_info.yesterday_volume = trade_info.today_volume; trade_info.today_volume = total_price; @@ -685,12 +687,12 @@ module orderbook::market_v2 { fun borrow_mut_order( open_orders: &mut CritbitTree, - user_order_info: &mut LinkedTable, + _user_order_info: &mut LinkedTable, tick_index: u64, order_id: u64, user: address, ): &mut Order { - linked_table::remove(user_order_info, order_id); + // linked_table::remove(user_order_info, order_id); let tick_level = borrow_leaf_by_index(open_orders, tick_index); assert!(linked_table::contains(&tick_level.open_orders, order_id), ErrorInvalidOrderId); let mut_tick_level = borrow_mut_leaf_by_index(open_orders, tick_index); @@ -1039,4 +1041,33 @@ module orderbook::market_v2 { // buy account will pay 10 * 10 = 100.00000000 base coin assert!(account_coin_store::balance(address_buy) == 900_00000000, 3); } + + #[test] + public fun test_buy_5() { + rooch_framework::genesis::init_for_test(); + let base_decimal = 8; + let quote_decimal = 10; + let account_list = create_account_for_testing(@0x43); + let address_list = address_of(&account_list); + let account_buy = create_account_for_testing(@0x44); + let address_buy = address_of(&account_buy); + let (market_obj, base_coin, quote_coin )= init_for_test(base_decimal, quote_decimal); + account_coin_store::deposit(address_list, quote_coin); + account_coin_store::deposit(address_buy, base_coin); + // Here we list it at price 10 base/quote, and list 10.000 quote coin + list(&account_list, &mut market_obj, (10 * u64::pow(10, quote_decimal) as u256), ((UNIT_PRICE_SCALE as u64) * 10 * u64::pow(10, base_decimal) / u64::pow(10, quote_decimal) )); + buy_from_origin(&account_buy, &mut market_obj, MIN_ASK_ORDER_ID, + (5 * u64::pow(10, quote_decimal) as u256), address_list, true, address_buy); + // list account will recieve 10 * 5 = 50.00000000 base coin + assert!(account_coin_store::balance(address_list) == 50_00000000, 0); + // buy account will recieve 5.0000000000 quote coin + assert!(account_coin_store::balance(address_buy) == 5_0000000000, 1); + // list account will pay 5.0000000000 quote coin + assert!(account_coin_store::balance(address_list) == 990_0000000000, 2); + // buy account will pay 10 * 5 = 50.00000000 base coin + assert!(account_coin_store::balance(address_buy) == 950_00000000, 3); + buy_from_origin(&account_buy, &mut market_obj, MIN_ASK_ORDER_ID, + (5 * u64::pow(10, quote_decimal) as u256), address_list, true, address_buy); + to_shared(market_obj); + } } From d6453df3123b750492f0913863d9a9abb255bae8 Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Sat, 28 Dec 2024 00:55:19 +0800 Subject: [PATCH 08/12] add test case for bid --- apps/orderbook/sources/market.move | 38 +++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index c01aec1f2a..d6b2cd70c8 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -30,6 +30,8 @@ module orderbook::market_v2 { }; use orderbook::critbit; use app_admin::admin::AdminCap; + #[test_only] + use std::debug::print; #[test_only] use rooch_framework::account::create_account_for_testing; @@ -151,7 +153,7 @@ module orderbook::market_v2 { version: VERSION, bids: critbit::new(), asks: critbit::new(), - // Order id of the next bid order, starting from 0. + // Order id of the next bid order, starting from 1. next_bid_order_id: MIN_BID_ORDER_ID, // Order id of the next ask order, starting from 1<<63. next_ask_order_id: MIN_ASK_ORDER_ID, @@ -1042,7 +1044,7 @@ module orderbook::market_v2 { assert!(account_coin_store::balance(address_buy) == 900_00000000, 3); } - #[test] + #[test] public fun test_buy_5() { rooch_framework::genesis::init_for_test(); let base_decimal = 8; @@ -1062,7 +1064,7 @@ module orderbook::market_v2 { assert!(account_coin_store::balance(address_list) == 50_00000000, 0); // buy account will recieve 5.0000000000 quote coin assert!(account_coin_store::balance(address_buy) == 5_0000000000, 1); - // list account will pay 5.0000000000 quote coin + // list account will pay 10.0000000000 quote coin assert!(account_coin_store::balance(address_list) == 990_0000000000, 2); // buy account will pay 10 * 5 = 50.00000000 base coin assert!(account_coin_store::balance(address_buy) == 950_00000000, 3); @@ -1070,4 +1072,34 @@ module orderbook::market_v2 { (5 * u64::pow(10, quote_decimal) as u256), address_list, true, address_buy); to_shared(market_obj); } + + #[test] + public fun test_accept_bid() { + rooch_framework::genesis::init_for_test(); + let base_decimal = 8; + let quote_decimal = 10; + let account_create_bid = create_account_for_testing(@0x43); + let address_create_bid = address_of(&account_create_bid); + let account_accept_bid = create_account_for_testing(@0x44); + let address_accept_bid = address_of(&account_accept_bid); + let (market_obj, base_coin, quote_coin )= init_for_test(base_decimal, quote_decimal); + account_coin_store::deposit(address_accept_bid, quote_coin); + account_coin_store::deposit(address_create_bid, base_coin); + // Here we list it at price 10 base/quote, and list 10.000 quote coin + create_bid(&account_create_bid, &mut market_obj,((UNIT_PRICE_SCALE as u64) * 10 * u64::pow(10, base_decimal) / u64::pow(10, quote_decimal) ), (10 * u64::pow(10, quote_decimal) as u256), ); + accept_bid_from_origin(&account_accept_bid, &mut market_obj, MIN_BID_ORDER_ID, + (5 * u64::pow(10, quote_decimal) as u256), address_create_bid, true, address_accept_bid); + // accept bid account will recieve 10 * 5 = 50.00000000 base coin + assert!(account_coin_store::balance(address_accept_bid) == 50_00000000, 0); + // create bid account will recieve 5.0000000000 quote coin + assert!(account_coin_store::balance(address_create_bid) == 5_0000000000, 1); + // accept bid account will pay 5.0000000000 quote coin + assert!(account_coin_store::balance(address_accept_bid) == 995_0000000000, 2); + // create bid account will pay 10 * 10 = 100.00000000 base coin + assert!(account_coin_store::balance(address_create_bid) == 900_00000000, 3); + accept_bid_from_origin(&account_accept_bid, &mut market_obj, MIN_BID_ORDER_ID, + (5 * u64::pow(10, quote_decimal) as u256), address_create_bid, true, address_accept_bid); + to_shared(market_obj); + } } + From 1de0881b0dba6b3ed622aaa12a61032c2c9f834c Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Sat, 28 Dec 2024 01:22:07 +0800 Subject: [PATCH 09/12] add order event --- apps/orderbook/sources/market.move | 87 ++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index d6b2cd70c8..02f32c78da 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -30,8 +30,7 @@ module orderbook::market_v2 { }; use orderbook::critbit; use app_admin::admin::AdminCap; - #[test_only] - use std::debug::print; + use moveos_std::event::emit; #[test_only] use rooch_framework::account::create_account_for_testing; @@ -135,6 +134,19 @@ module orderbook::market_v2 { market_info: LinkedTable, } + + struct OrderEvent has copy, drop { + order_id: u64, + unit_price: u64, + quantity: u256, + owner: address, + timestamp: u64, + // 0 is list, 1 is create bid, 2 is cancel bid, 3 is cancel list, 4 is buy, 5 is accept bid + order_type: u8 + } + + + fun init() { let market_house = MarketplaceHouse { market_info: linked_table::new(), @@ -217,7 +229,14 @@ module orderbook::market_v2 { table::add(&mut market.user_order_info, address_of(signer), linked_table::new()); }; linked_table::push_back(table::borrow_mut(&mut market.user_order_info, address_of(signer)), order_id, unit_price); - + emit(OrderEvent { + order_id, + unit_price, + quantity, + owner: address_of(signer), + timestamp: now_milliseconds(), + order_type: 0 + }) } public entry fun create_bid( @@ -258,6 +277,14 @@ module orderbook::market_v2 { table::add(&mut market.user_order_info, address_of(signer), linked_table::new()); }; linked_table::push_back(table::borrow_mut(&mut market.user_order_info, address_of(signer)), order_id, unit_price); + emit(OrderEvent { + order_id, + unit_price, + quantity, + owner: address_of(signer), + timestamp: now_milliseconds(), + order_type: 1 + }) } ///Cancel the listing of inscription @@ -284,9 +311,25 @@ module orderbook::market_v2 { if (is_bid) { // TODO here maybe wrap to u512? let total_balance = (order.unit_price as u256) * order.quantity / UNIT_PRICE_SCALE; - account_coin_store::deposit(sender(), coin_store::withdraw(&mut market.base_asset, total_balance)) + account_coin_store::deposit(sender(), coin_store::withdraw(&mut market.base_asset, total_balance)); + emit(OrderEvent { + order_id, + unit_price: order.unit_price, + quantity: order.quantity, + owner: sender(), + timestamp: now_milliseconds(), + order_type: 2 + }) }else { - account_coin_store::deposit(sender(), coin_store::withdraw(&mut market.quote_asset, order.quantity)) + account_coin_store::deposit(sender(), coin_store::withdraw(&mut market.quote_asset, order.quantity)); + emit(OrderEvent { + order_id, + unit_price: order.unit_price, + quantity: order.quantity, + owner: sender(), + timestamp: now_milliseconds(), + order_type: 3 + }) } } @@ -358,7 +401,16 @@ module orderbook::market_v2 { let trade_fee = total_price * market.fee / TRADE_FEE_BASE_RATIO; coin_store::deposit(&mut market.base_asset_trading_fees, coin::extract(&mut trade_coin, trade_fee)); account_coin_store::deposit(order.owner, trade_coin); + emit(OrderEvent { + order_id, + unit_price: order.unit_price, + quantity: order.quantity, + owner: sender(), + timestamp: now_milliseconds(), + order_type: 4 + }); option::some(coin_store::withdraw(&mut market.quote_asset, order.quantity)) + } @@ -445,6 +497,14 @@ module orderbook::market_v2 { coin_store::deposit(&mut market.base_asset_trading_fees, coin::extract(&mut trade_coin, trade_fee)); }; account_coin_store::deposit(order.owner, trade_coin); + emit(OrderEvent { + order_id, + unit_price: order.unit_price, + quantity: order.quantity, + owner: sender(), + timestamp: now_milliseconds(), + order_type: 4 + }); order.quantity = order.quantity - amount; if (order.quantity == 0 ) { let _ = remove_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); @@ -526,6 +586,14 @@ module orderbook::market_v2 { let trade_fee = order.quantity * market.fee / TRADE_FEE_BASE_RATIO; coin_store::deposit(&mut market.quote_asset_trading_fees, coin::extract(&mut trade_coin, trade_fee)); account_coin_store::deposit(order.owner, trade_coin); + emit(OrderEvent { + order_id, + unit_price: order.unit_price, + quantity: order.quantity, + owner: sender(), + timestamp: now_milliseconds(), + order_type: 5 + }); option::some(coin_store::withdraw(&mut market.base_asset, total_price)) } @@ -615,10 +683,19 @@ module orderbook::market_v2 { coin_store::deposit(&mut market.quote_asset_trading_fees, coin::extract(&mut trade_coin, trade_fee)); }; account_coin_store::deposit(order.owner, trade_coin); + emit(OrderEvent { + order_id, + unit_price: order.unit_price, + quantity: order.quantity, + owner: sender(), + timestamp: now_milliseconds(), + order_type: 5 + }); order.quantity = order.quantity - amount; if (order.quantity == 0) { let _ = remove_order(&mut market.bids, usr_open_orders, tick_index, order_id, order_owner); }; + option::some(coin_store::withdraw(&mut market.base_asset, total_price)) } From b9c9d5076fb43a183e3dc8db916d91f6f0c16323 Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Sat, 28 Dec 2024 02:17:42 +0800 Subject: [PATCH 10/12] fix: query order --- apps/orderbook/sources/market.move | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 02f32c78da..42a249c7b2 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -802,7 +802,11 @@ module orderbook::market_v2 { let market = object::borrow(market_obj); let order_infos = vector::empty(); + if (query_bid) { + if (critbit::is_empty(&market.bids)) { + return order_infos + }; let i = 0; let from = if (from_price_is_none) { let (key, _) = critbit::max_leaf(&market.bids); @@ -845,6 +849,9 @@ module orderbook::market_v2 { } }; }else { + if (critbit::is_empty(&market.asks)) { + return order_infos + }; let i = 0; let from = if (from_price_is_none) { let (key, _) = critbit::min_leaf(&market.asks); From 2312298c59e60a87972151e9b13e48849547d865 Mon Sep 17 00:00:00 2001 From: jolestar Date: Mon, 30 Dec 2024 11:40:21 +0800 Subject: [PATCH 11/12] [release] Release package --- apps/orderbook/released/4/package.rpd | Bin 0 -> 12181 bytes apps/orderbook/sources/market.move | 1 - 2 files changed, 1 deletion(-) create mode 100644 apps/orderbook/released/4/package.rpd diff --git a/apps/orderbook/released/4/package.rpd b/apps/orderbook/released/4/package.rpd new file mode 100644 index 0000000000000000000000000000000000000000..25806949737b5cd2ea843ea6ca9e1eb68fd426f7 GIT binary patch literal 12181 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 literal 0 HcmV?d00001 diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index 42a249c7b2..bf437cd4ac 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -6,7 +6,6 @@ module orderbook::market_v2 { use std::signer::address_of; use std::string; use std::string::String; - use std::u64; use std::vector; use std::vector::{length, zip}; From d278bd21fb1acd0d8d0c79f78c36d7a61d4da68b Mon Sep 17 00:00:00 2001 From: mx819812523 Date: Mon, 30 Dec 2024 15:17:45 +0800 Subject: [PATCH 12/12] fix: assert quantity not zero --- apps/orderbook/sources/market.move | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/orderbook/sources/market.move b/apps/orderbook/sources/market.move index bf437cd4ac..e9c9b8136a 100644 --- a/apps/orderbook/sources/market.move +++ b/apps/orderbook/sources/market.move @@ -30,6 +30,8 @@ module orderbook::market_v2 { use orderbook::critbit; use app_admin::admin::AdminCap; use moveos_std::event::emit; + #[test_only] + use std::u64; #[test_only] use rooch_framework::account::create_account_for_testing; @@ -60,6 +62,7 @@ module orderbook::market_v2 { const ErrorOrderLength: u64 = 9; const ErrorDeprecated: u64 = 10; const ErrorInvalidAmount: u64 = 11; + const ErrorQuantityTooLow: u64 = 12; /// listing info in the market @@ -206,6 +209,7 @@ module orderbook::market_v2 { // TODO here maybe wrap to u512? // let price = (unit_price as u256) * quantity; assert!(unit_price > 0, ErrorPriceTooLow); + assert!(quantity > 0, ErrorQuantityTooLow); let asks = Order { order_id, unit_price, @@ -247,7 +251,7 @@ module orderbook::market_v2 { let market = object::borrow_mut(market_obj); // assert!(market.version == VERSION, ErrorWrongVersion); assert!(market.is_paused == false, ErrorWrongPaused); - assert!(quantity > 0, ErrorWrongCreateBid); + assert!(quantity > 0, ErrorQuantityTooLow); assert!(unit_price > 0, ErrorWrongCreateBid); // TODO here maybe wrap to u512? let price = (unit_price as u256) * quantity / UNIT_PRICE_SCALE; @@ -467,6 +471,7 @@ module orderbook::market_v2 { return option::none() }; assert!(tick_exists, ErrorInvalidOrderId); + assert!(amount > 0, ErrorQuantityTooLow); let order = borrow_mut_order(&mut market.asks, usr_open_orders, tick_index, order_id, order_owner); assert!(amount <= order.quantity, ErrorInvalidAmount); // TODO here maybe wrap to u512? @@ -651,7 +656,7 @@ module orderbook::market_v2 { return option::none() }; assert!(tick_exists, ErrorInvalidOrderId); - + assert!(amount > 0, ErrorQuantityTooLow); let order = borrow_mut_order(&mut market.bids, usr_open_orders, tick_index, order_id, order_owner); assert!(order.quantity >= amount, ErrorInvalidAmount); let trade_coin = account_coin_store::withdraw(signer, amount);