From 73dab3b669d75f1d94da14bc7f711bf4343c3717 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 29 Jun 2023 08:42:05 -0700 Subject: [PATCH 01/56] Add backwards-compatible taker ID support (draft) --- src/move/econia/sources/market.move | 41 ++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 8ef528628..140ec85c2 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -628,6 +628,17 @@ module econia::market { map: Tablist } + /// Stored in the Econia resource account. + struct TakerEventV2Handles has key { + /// Map from market ID to TakerEventV2 handle holder. + map: Table + } + + /// Stores handles for TakerEventV2 streams for each market. + struct TakerEventV2HandleHolder has store { + taker_events: EventHandle + } + /// User-friendly representation of an open order on the order book, /// combining fields from `Order` and the corresponding /// `MakerEvent` emitted when order was first placed. @@ -702,6 +713,18 @@ module econia::market { price: u64 } + struct TakerEventV2 has drop, store { + market_id: u64, + side: bool, + /// Market order ID of maker side of trade. + market_order_id_maker: u128, + /// Market order ID of taker side of trade. + market_order_id_taker: u128, + maker: address, + custodian_id: u64, + size: u64, + price: u64 + } // Structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Error codes >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -2652,6 +2675,11 @@ module econia::market { u64, bool ) { + /* + Borrow the TakerEventV2HandleHolder for the market ID. + */ + // Increment order counter. + order_book_ref_mut.counter = order_book_ref_mut.counter + 1; // Assert price is not too high. assert!(limit_price <= HI_PRICE, E_PRICE_TOO_HIGH); // Taker buy fills against asks, sell against bids. @@ -2772,6 +2800,12 @@ module econia::market { event::emit_event(taker_handle, TakerEvent{ market_id, side, market_order_id, maker, custodian_id: maker_custodian_id, size: fill_size, price}); + // Get market order ID for taker side of trade. + let market_order_id_taker = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + /* + Emit a Taker Event V2. + */ // If order on book completely filled: if (complete_fill) { let avlq_access_key = // Get AVL queue access key. @@ -3089,7 +3123,10 @@ module econia::market { size = if (still_crosses_spread || self_match_cancel) 0 else // Else update size to amount left to fill post-match. size - (base_traded / order_book_ref_mut.lot_size); - }; // Done with optional matching as a taker across the spread. + } else { // If spread not crossed (matching engine not called): + // Increment order counter. + order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + }; // Return without market order ID if immediate-or-cancel or if // remaining size to fill after matching does not meet minimum // size requirement for market. @@ -3115,8 +3152,6 @@ module econia::market { // Get market order ID from AVL queue access key, counter. let market_order_id = (avlq_access_key as u128) | ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); - // Increment maker counter. - order_book_ref_mut.counter = order_book_ref_mut.counter + 1; user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, market_order_id, order_access_key); From f01cf2f70359e1f59c8a1e3f89b40f3bfe678253 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 29 Jun 2023 17:13:50 -0700 Subject: [PATCH 02/56] Implement FillEvent support, update docs/changelog --- doc/doc-site/docs/move/changelog.md | 4 + .../econia/doc/img/market_forward_dep.svg | 916 +++++++++--------- src/move/econia/doc/market.md | 394 ++++++-- src/move/econia/sources/market.move | 872 ++++++++++++----- 4 files changed, 1404 insertions(+), 782 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 8b25527a3..61c62bcb3 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -7,16 +7,20 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] ### Added - Assorted view functions ([#287], [#301]). +- Fill events with order book counter ([#312]). ### Deprecated +- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#312]) - [`market::Orders`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3337) ([#301]) +- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#312]) - [`market::index_orders_sdk()`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3362) ([#287]) - [`move-to-ts`](https://github.com/hippospace/move-to-ts) attributes ([#292]) [#287]: https://github.com/econia-labs/econia/pull/287 [#292]: https://github.com/econia-labs/econia/pull/292 [#301]: https://github.com/econia-labs/econia/pull/301 +[#312]: https://github.com/econia-labs/econia/pull/312 [keep a changelog]: https://keepachangelog.com/en/1.0.0/ [semantic versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/econia-labs/econia/compare/v4.0.2-audited...HEAD diff --git a/src/move/econia/doc/img/market_forward_dep.svg b/src/move/econia/doc/img/market_forward_dep.svg index e2a723eda..7812d7298 100644 --- a/src/move/econia/doc/img/market_forward_dep.svg +++ b/src/move/econia/doc/img/market_forward_dep.svg @@ -4,922 +4,928 @@ - + G - + market - -market + +market option - -option + +option market->option - - + + string - -string + +string market->string - - + + signer - -signer + +signer market->signer - - + + type_info - -type_info + +type_info market->type_info - - + + - + +table + +table + + + +market->table + + + + + event - -event + +event - + market->event - - + + - + account - -account + +account - + market->account - - + + - + coin - -coin + +coin - + market->coin - - + + - + avl_queue - -avl_queue + +avl_queue - + market->avl_queue - - + + - + tablist - -tablist + +tablist - + market->tablist - - + + - + resource_account - -resource_account + +resource_account - + market->resource_account - - + + - + incentives - -incentives + +incentives - + market->incentives - - + + - + registry - -registry + +registry - + market->registry - - + + - + user - -user + +user - + market->user - - + + - + vector - -vector + +vector - + option->vector - - + + - + string->option - - + + - + string->vector - - + + - + type_info->string - - + + - + error - -error + +error - + type_info->error - - + + - + features - -features + +features - + type_info->features - - + + - + bcs - -bcs + +bcs - + type_info->bcs - - + + - + event->bcs - - + + - + guid - -guid + +guid - + event->guid - - + + - + account->option - - + + - + account->signer - - + + - + account->type_info - - + + + + + +account->table + + - + account->event - - + + - + account->vector - - + + - + account->error - - + + - + account->bcs - - + + - + account->guid - - - - - -table - -table - - - -account->table - - + + system_addresses - -system_addresses + +system_addresses - + account->system_addresses - - + + hash - -hash + +hash - + account->hash - - + + ed25519 - -ed25519 + +ed25519 - + account->ed25519 - - + + multi_ed25519 - -multi_ed25519 + +multi_ed25519 - + account->multi_ed25519 - - + + from_bcs - -from_bcs + +from_bcs - + account->from_bcs - - + + create_signer - -create_signer + +create_signer - + account->create_signer - - + + chain_id - -chain_id + +chain_id - + account->chain_id - - + + - + coin->option - - + + - + coin->string - - + + - + coin->signer - - + + - + coin->type_info - - + + - + coin->event - - + + - + coin->account - - + + - + coin->error - - + + - + coin->system_addresses - - + + aggregator - -aggregator + +aggregator - + coin->aggregator - - + + aggregator_factory - -aggregator_factory + +aggregator_factory - + coin->aggregator_factory - - + + optional_aggregator - -optional_aggregator + +optional_aggregator - + coin->optional_aggregator - - + + - + avl_queue->option - - + + - + avl_queue->table - - + + table_with_length - -table_with_length + +table_with_length - + avl_queue->table_with_length - - + + - + tablist->option - - + + - + tablist->table_with_length - - + + - + resource_account->account - - + + - + resource_account->bcs - - + + timestamp - -timestamp + +timestamp - + resource_account->timestamp - - + + - + incentives->signer - - + + - + incentives->type_info - - + + - + incentives->coin - - + + - + incentives->tablist - - + + - + incentives->resource_account - - + + - + incentives->vector - - + + aptos_coin - -aptos_coin + +aptos_coin - + incentives->aptos_coin - - + + - + registry->option - - + + - + registry->string - - + + - + registry->signer - - + + - + registry->type_info - - + + - + +registry->table + + + + + registry->event - - + + - + registry->account - - + + - + registry->coin - - + + - + registry->tablist - - + + - + registry->incentives - - - - - -registry->table - - + + - + user->option - - + + - + user->string - - + + - + user->signer - - + + - + user->type_info - - + + - + +user->table + + + + + user->coin - - + + - + user->tablist - - + + - + user->registry - - + + - + user->vector - - - - - -user->table - - + + - + features->signer - - + + - + features->error - - + + - + system_addresses->signer - - + + - + system_addresses->error - - + + - + ed25519->option - - + + - + ed25519->type_info - - + + - + ed25519->error - - + + - + ed25519->bcs - - + + - + ed25519->hash - - + + - + multi_ed25519->option - - + + - + multi_ed25519->error - - + + - + multi_ed25519->features - - + + - + multi_ed25519->bcs - - + + - + multi_ed25519->hash - - + + - + multi_ed25519->ed25519 - - + + - + from_bcs->string - - + + - -chain_id->system_addresses - - - - -aggregator_factory->error - - +chain_id->system_addresses + + - + aggregator_factory->table - - + + + + + +aggregator_factory->error + + - + aggregator_factory->system_addresses - - + + - + aggregator_factory->aggregator - - + + - + optional_aggregator->option - - + + - + optional_aggregator->error - - + + - + optional_aggregator->aggregator - - + + - -optional_aggregator->aggregator_factory - - - - -table_with_length->error - - +optional_aggregator->aggregator_factory + + - + table_with_length->table - - + + + + + +table_with_length->error + + - + timestamp->error - - + + - + timestamp->system_addresses - - + + - + aptos_coin->option - - + + - + aptos_coin->string - - + + - + aptos_coin->signer - - + + - + aptos_coin->coin - - + + - + aptos_coin->vector - - + + - + aptos_coin->error - - + + - + aptos_coin->system_addresses - - + + diff --git a/src/move/econia/doc/market.md b/src/move/econia/doc/market.md index 86898feb0..4cf1432ad 100644 --- a/src/move/econia/doc/market.md +++ b/src/move/econia/doc/market.md @@ -11,9 +11,10 @@ order book entry is added under the resource account at a new market ID. Once a market is registered, signing users and delegated custodians -can place limit orders on the book as makers, takers can place -market orders or swaps against the order book, and makers can cancel -or change the size of any outstanding orders they have on the book. +can place limit orders on the book as makers and/or as takers, +takers can place market orders or swaps against the order book, and +makers can cancel or change the size of any outstanding orders they +have on the book. Econia implements an atomic matching engine for processing taker fills against maker orders on the book, and emits events in response @@ -25,10 +26,11 @@ Multiple API variants are supported for market registration and order management function, to enable diagnostic function returns, public entry calls, etc. -When a maker places a limit order, they are issued a "market order -ID" that is unique to the given market. The maker order price is -encoded in the market order ID, as well as a counter for the number -of orders that have been placed on the corresponding order book. +When a maker places a limit order that posts against the book, they +are issued a "market order ID" that is unique to the given market. +The maker order price is encoded in the market order ID, as well as +a counter for the number of orders that have been placed for the +corresponding market. @@ -638,6 +640,8 @@ The below index is automatically generated from source code: - [Invocation proxies](#@Invocation_proxies_19) - [Branching functions](#@Branching_functions_20) - [Complete DocGen index](#@Complete_DocGen_index_21) +- [Struct `FillEvent`](#0xc0deb00c_market_FillEvent) +- [Resource `FillEventHandles`](#0xc0deb00c_market_FillEventHandles) - [Struct `MakerEvent`](#0xc0deb00c_market_MakerEvent) - [Struct `Order`](#0xc0deb00c_market_Order) - [Struct `OrderBook`](#0xc0deb00c_market_OrderBook) @@ -646,8 +650,8 @@ The below index is automatically generated from source code: - [Struct `OrdersView`](#0xc0deb00c_market_OrdersView) - [Struct `PriceLevel`](#0xc0deb00c_market_PriceLevel) - [Struct `PriceLevels`](#0xc0deb00c_market_PriceLevels) -- [Struct `TakerEvent`](#0xc0deb00c_market_TakerEvent) - [Resource `Orders`](#0xc0deb00c_market_Orders) +- [Struct `TakerEvent`](#0xc0deb00c_market_TakerEvent) - [Constants](#@Constants_22) - [Function `get_ABORT`](#0xc0deb00c_market_get_ABORT) - [Testing](#@Testing_23) @@ -850,6 +854,7 @@ The below index is automatically generated from source code: use 0x1::option; use 0x1::signer; use 0x1::string; +use 0x1::table; use 0x1::type_info; use 0xc0deb00c::avl_queue; use 0xc0deb00c::incentives; @@ -873,6 +878,109 @@ The below index is automatically generated from source code: ![](img/market_backward_dep.svg) + + +## Struct `FillEvent` + +Emitted each time an order fills as a taker. If an order results +in multiple fills, a separate event is emitted for each one. + + +
struct FillEvent has drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID of corresponding market. +
+
+order_book_counter: u64 +
+
+ Order book counter at time of fill, incremented for each + order placed on the book. If an order results in multiple + FillEvents, they will all have the same + FillEvent.order_book_counter. If a limit order crosses the + spread and fills first as a taker before posting to the book + as a maker, the FillEvent.order_book_counter field for + each fill is identical to the counter encoded in the + corresponding MakerEvent.market_order_id. +
+
+size: u64 +
+
+ The size filled, in lots. +
+
+price: u64 +
+
+ Fill price, in ticks per lot. +
+
+maker_side: bool +
+
+ ASK or BID, the side of the maker order filled against. +
+
+maker_market_order_id: u128 +
+
+ Maket order ID of maker order just filled against. +
+
+maker: address +
+
+ Address of user holding maker order. +
+
+maker_custodian_id: u64 +
+
+ For given maker, ID of custodian required to approve order + operations and withdrawals on given market account. +
+
+ + + + +## Resource `FillEventHandles` + +Map of FillEvent handles, implemented as a replacement for +OrderBook.taker_events through a backwards-compatible package +upgrade. + + +
struct FillEventHandles has key
+
+ + + +##### Fields + + +
+
+map: table::Table<u64, event::EventHandle<market::FillEvent>> +
+
+ Map from market ID to FillEvent event handle. +
+
+ + ## Struct `MakerEvent` @@ -1070,7 +1178,7 @@ item queries against the registry. counter: u64
- Cumulative number of maker orders placed on book. + Cumulative number of orders placed.
maker_events: event::EventHandle<market::MakerEvent> @@ -1082,7 +1190,7 @@ item queries against the registry. taker_events: event::EventHandle<market::TakerEvent>
- Event handle for taker events. + Deprecated field retained for backwards compatibility.
@@ -1281,13 +1389,42 @@ sorted by price-time priority. + + +## Resource `Orders` + +Deprecated struct retained for backwards compatibility. + + +
struct Orders has key
+
+ + + +##### Fields + + +
+
+asks: vector<market::Order> +
+
+ +
+
+bids: vector<market::Order> +
+
+ +
+
+ + ## Struct `TakerEvent` -Emitted when a taker order fills against a maker order. If a -taker order fills against multiple maker orders, a separate -event is emitted for each one. +Deprecated struct retained for backwards compatibility.
struct TakerEvent has drop, store
@@ -1303,73 +1440,40 @@ event is emitted for each one.
 market_id: u64
 
 
- Market ID of corresponding market. +
side: bool
- ASK or BID, the side of the maker order. +
market_order_id: u128
- Order ID, unique within given market, of maker order just - filled against. +
maker: address
- Address of user holding maker order. +
custodian_id: u64
- For given maker, ID of custodian required to approve order - operations and withdrawals on given market account. +
size: u64
-
- The size filled, in lots. -
-
-price: u64 -
-
- Fill price, in ticks per lot. -
- - - - - -## Resource `Orders` - -Deprecated struct retained for backwards compatibility. - - -
struct Orders has key
-
- - - -##### Fields - - -
-
-asks: vector<market::Order> -
-bids: vector<market::Order> +price: u64
@@ -1989,8 +2093,7 @@ Flag for post-or-abort order restriction. -Number of bits maker order counter is shifted in a market order -ID. +Number of bits order counter is shifted in a market order ID.
const SHIFT_COUNTER: u8 = 64;
@@ -2520,7 +2623,7 @@ Public constant getter for TIC
 
 ## Function `get_market_order_id_counter`
 
-Return maker order counter encoded in market order ID.
+Return order counter encoded in market order ID.
 
 
 
@@ -3137,7 +3240,10 @@ order under authority of delegated custodian.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_limit_order<
         BaseType,
         QuoteType
@@ -3195,7 +3301,10 @@ authority of delegated custodian.
     target_advance_amount: u64,
     custodian_capability_ref: &CustodianCapability
 ): u128
-acquires OrderBooks {
+acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_limit_order_passive_advance<
         BaseType,
         QuoteType
@@ -3257,7 +3366,10 @@ authority of signing user.
     advance_style: bool,
     target_advance_amount: u64
 ): u128
-acquires OrderBooks {
+acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_limit_order_passive_advance<
         BaseType,
         QuoteType
@@ -3323,7 +3435,10 @@ order under authority of signing user.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_limit_order<
         BaseType,
         QuoteType
@@ -3383,7 +3498,10 @@ order under authority of delegated custodian.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_market_order<BaseType, QuoteType>(
         user_address,
         market_id,
@@ -3436,7 +3554,10 @@ order under authority of signing user.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_market_order<BaseType, QuoteType>(
         address_of(user),
         market_id,
@@ -3516,7 +3637,10 @@ See inner function r
     min_size: u64,
     utility_coins: Coin<UtilityType>
 ): u64
-acquires OrderBooks {
+acquires
+    FillEventHandles,
+    OrderBooks
+{
     // Register market in global registry, storing market ID.
     let market_id = registry::register_market_base_coin_internal<
         BaseType, QuoteType, UtilityType>(lot_size, tick_size, min_size,
@@ -3604,7 +3728,10 @@ underwriter capability.
     utility_coins: Coin<UtilityType>,
     underwriter_capability_ref: &UnderwriterCapability
 ): u64
-acquires OrderBooks {
+acquires
+    FillEventHandles,
+    OrderBooks
+{
     // Register market in global registry, storing market ID.
     let market_id = registry::register_market_base_generic_internal<
         QuoteType, UtilityType>(base_name_generic, lot_size, tick_size,
@@ -3705,7 +3832,10 @@ for coin store.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     let user_address = address_of(user); // Get user address.
     // Register base coin store if user does not have one.
     if (!coin::is_account_registered<BaseType>(user_address))
@@ -3866,7 +3996,10 @@ the case of a buy, base coins in the case of a sell.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     let (base_value, quote_value) = // Get coin value amounts.
         (coin::value(&base_coins), coin::value("e_coins));
     // Get option wrapped base coins.
@@ -4002,7 +4135,10 @@ underwriter capability for given market.
     u64,
     u64,
     u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     let underwriter_id = // Get underwriter ID.
         registry::get_underwriter_id(underwriter_capability_ref);
     // Get quote coin value.
@@ -4204,7 +4340,10 @@ Public entry function wrapper for
     size: u64,
     advance_style: bool,
     target_advance_amount: u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_limit_order_passive_advance_user<
         BaseType,
         QuoteType
@@ -4256,7 +4395,10 @@ Public entry function wrapper for OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_limit_order_user<BaseType, QuoteType>(
         user, market_id, integrator, side, size, price, restriction,
         self_match_behavior);
@@ -4298,7 +4440,10 @@ Public entry function wrapper for OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     place_market_order_user<BaseType, QuoteType>(
         user, market_id, integrator, direction, size, self_match_behavior);
 }
@@ -4339,7 +4484,10 @@ coins from an aptos_framework::coin::CoinStore.
     lot_size: u64,
     tick_size: u64,
     min_size: u64
-) acquires OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     // Get market registration fee, denominated in utility coins.
     let fee = incentives::get_market_registration_fee();
     // Register market with base coin, paying fees from coin store.
@@ -4387,7 +4535,10 @@ Public entry function wrapper for OrderBooks {
+) acquires
+    FillEventHandles,
+    OrderBooks
+{
     swap_between_coinstores<BaseType, QuoteType>(
         user, market_id, integrator, direction, min_base, max_base,
         min_quote, max_quote, limit_price);
@@ -4954,6 +5105,8 @@ then proceeds according to specified self match behavior.
 
 
 * market_id: Market ID of market.
+* resource_address: Address of resource account where order
+books and fill event handles are stored.
 * order_book_ref_mut: Mutable reference to market order book.
 * taker: Address of taker whose order is matched. Passed as
 NO_MARKET_ACCOUNT when taker order originates from a swap.
@@ -5016,7 +5169,7 @@ net change in taker's quote coin holdings.
 ### Emits
 
 
-* TakerEvent: Information about a fill against a maker order,
+* FillEvent: Information about a fill against a maker order,
 emitted for each separate maker order that is filled against.
 
 
@@ -5071,7 +5224,7 @@ requirement not met.
 * test_match_self_match_invalid()
 
 
-
fun match<BaseType, QuoteType>(market_id: u64, order_book_ref_mut: &mut market::OrderBook, taker: address, custodian_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, self_match_behavior: u8, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, bool)
+
fun match<BaseType, QuoteType>(market_id: u64, resource_address: address, order_book_ref_mut: &mut market::OrderBook, taker: address, custodian_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, self_match_behavior: u8, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, bool)
 
@@ -5084,6 +5237,7 @@ requirement not met. QuoteType >( market_id: u64, + resource_address: address, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -5104,7 +5258,7 @@ requirement not met. u64, u64, bool -) { +) acquires FillEventHandles { // Assert price is not too high. assert!(limit_price <= HI_PRICE, E_PRICE_TOO_HIGH); // Taker buy fills against asks, sell against bids. @@ -5127,6 +5281,14 @@ requirement not met. // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; + // Mutably borrow fill event handles map. + let fill_event_handles_map_ref_mut = + &mut borrow_global_mut<FillEventHandles>(resource_address).map; + // Mutably borrow fill event handle for market. + let fill_event_handle_ref_mut = + table::borrow_mut(fill_event_handles_map_ref_mut, market_id); + // Increment order counter. + order_book_ref_mut.counter = order_book_ref_mut.counter + 1; // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -5219,13 +5381,12 @@ requirement not met. fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - // Get taker events handle. - let taker_handle = &mut order_book_ref_mut.taker_events; - // Emit corresponding taker event. - event::emit_event(taker_handle, TakerEvent{ - market_id, side, market_order_id, maker, custodian_id: - maker_custodian_id, size: fill_size, price}); - // If order on book completely filled: + // Emit corresponding fill event. + event::emit_event(fill_event_handle_ref_mut, FillEvent{ + market_id, order_book_counter: order_book_ref_mut.counter, + size: fill_size, price, maker_side: side, + maker_market_order_id: market_order_id, maker, + maker_custodian_id: custodian_id}); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -5465,7 +5626,10 @@ restriction, and u64, u64, u64 -) acquires OrderBooks { +) acquires + FillEventHandles, + OrderBooks +{ // Assert valid order restriction flag. assert!(restriction <= N_RESTRICTIONS, E_INVALID_RESTRICTION); assert!(price != 0, E_PRICE_0); // Assert nonzero price. @@ -5570,13 +5734,13 @@ restriction, and // Match against order book, storing optionally modified // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of - // the order. + // the order. (Increments order book counter). (optional_base_coins, quote_coins, base_traded, quote_traded, fees, self_match_cancel) = match( - market_id, order_book_ref_mut, user_address, custodian_id, - integrator, direction, min_base, max_base, min_quote, - max_quote, price, self_match_behavior, optional_base_coins, - quote_coins); + market_id, resource_address, order_book_ref_mut, user_address, + custodian_id, integrator, direction, min_base, max_base, + min_quote, max_quote, price, self_match_behavior, + optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -5599,7 +5763,10 @@ restriction, and size = if (still_crosses_spread || self_match_cancel) 0 else // Else update size to amount left to fill post-match. size - (base_traded / order_book_ref_mut.lot_size); - }; // Done with optional matching as a taker across the spread. + } else { // If spread not crossed (matching engine not called): + // Increment order counter. + order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + }; // Return without market order ID if immediate-or-cancel or if // remaining size to fill after matching does not meet minimum // size requirement for market. @@ -5625,8 +5792,6 @@ restriction, and // Get market order ID from AVL queue access key, counter. let market_order_id = (avlq_access_key as u128) | ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); - // Increment maker counter. - order_book_ref_mut.counter = order_book_ref_mut.counter + 1; user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, market_order_id, order_access_key); @@ -5796,7 +5961,10 @@ advance. advance_style: bool, target_advance_amount: u64 ): u128 -acquires OrderBooks { +acquires + FillEventHandles, + OrderBooks +{ // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); let order_books_map_ref = // Immutably borrow order books map. @@ -5990,7 +6158,10 @@ size for market. u64, u64, u64 -) acquires OrderBooks { +) acquires + FillEventHandles, + OrderBooks +{ // Get user's available and ceiling asset counts. let (_, base_available, base_ceiling, _, quote_available, quote_ceiling) = user::get_asset_counts_internal( @@ -6051,9 +6222,9 @@ size for market. // Match against order book, storing optionally modified asset // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match(market_id, order_book_ref_mut, user_address, - custodian_id, integrator, direction, min_base, - max_base, min_quote, max_quote, limit_price, + _) = match(market_id, resource_address, order_book_ref_mut, + user_address, custodian_id, integrator, direction, + min_base, max_base, min_quote, max_quote, limit_price, self_match_behavior, optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else @@ -6270,7 +6441,10 @@ for market. min_size: u64, underwriter_id: u64 ): u64 -acquires OrderBooks { +acquires + FillEventHandles, + OrderBooks +{ // Get Econia resource account signer. let resource_account = resource_account::get_signer(); // Get resource account address. @@ -6293,6 +6467,21 @@ for market. account::new_event_handle<MakerEvent>(&resource_account), taker_events: account::new_event_handle<TakerEvent>(&resource_account)}); + // If a fill event handles map has not yet been moved to the + // resource account: + if (!exists<FillEventHandles>(resource_address)) { + // Initialize fill event handles map under resource account. + // This is done here rather than in `init_module()` since + // the fill event handles map was implemented in a + // backwards-compatible package upgrade. + move_to(&resource_account, FillEventHandles{map: table::new()}); + }; + // Mutably borrow fill event handles map. + let fill_event_handles_map_ref_mut = + &mut borrow_global_mut<FillEventHandles>(resource_address).map; + table::add( // Add fill event handle to fill event handles map. + fill_event_handles_map_ref_mut, market_id, + account::new_event_handle<FillEvent>(&resource_account)); // Register an Econia fee store entry for market quote coin. incentives::register_econia_fee_store_entry<QuoteType>(market_id); market_id // Return market ID. @@ -6411,7 +6600,10 @@ same as for match() u64, u64, u64 -) acquires OrderBooks { +) acquires + FillEventHandles, + OrderBooks +{ // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); let order_books_map_ref_mut = // Mutably borrow order books map. @@ -6433,10 +6625,10 @@ same as for match() let (base_traded, quote_traded, fees); (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) = match<BaseType, QuoteType>( // Match against order book. - market_id, order_book_ref_mut, NO_MARKET_ACCOUNT, NO_CUSTODIAN, - integrator, direction, min_base, max_base, min_quote, - max_quote, limit_price, ABORT, optional_base_coins, - quote_coins); + market_id, resource_address, order_book_ref_mut, + NO_MARKET_ACCOUNT, NO_CUSTODIAN, integrator, direction, + min_base, max_base, min_quote, max_quote, limit_price, ABORT, + optional_base_coins, quote_coins); // Return optionally modified asset inputs, trade amounts, fees. (optional_base_coins, quote_coins, base_traded, quote_traded, fees) } diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 140ec85c2..67b629423 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -6,9 +6,10 @@ /// ID. /// /// Once a market is registered, signing users and delegated custodians -/// can place limit orders on the book as makers, takers can place -/// market orders or swaps against the order book, and makers can cancel -/// or change the size of any outstanding orders they have on the book. +/// can place limit orders on the book as makers and/or as takers, +/// takers can place market orders or swaps against the order book, and +/// makers can cancel or change the size of any outstanding orders they +/// have on the book. /// /// Econia implements an atomic matching engine for processing taker /// fills against maker orders on the book, and emits events in response @@ -20,10 +21,11 @@ /// order management function, to enable diagnostic function returns, /// public entry calls, etc. /// -/// When a maker places a limit order, they are issued a "market order -/// ID" that is unique to the given market. The maker order price is -/// encoded in the market order ID, as well as a counter for the number -/// of orders that have been placed on the corresponding order book. +/// When a maker places a limit order that posts against the book, they +/// are issued a "market order ID" that is unique to the given market. +/// The maker order price is encoded in the market order ID, as well as +/// a counter for the number of orders that have been placed for the +/// corresponding market. /// /// # General overview sections /// @@ -528,6 +530,7 @@ module econia::market { use aptos_framework::account; use aptos_framework::coin::{Self, Coin}; use aptos_framework::event::{Self, EventHandle}; + use aptos_framework::table::{Self, Table}; use aptos_framework::type_info::{Self, TypeInfo}; use econia::avl_queue::{Self, AVLqueue}; use econia::incentives; @@ -552,6 +555,43 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + /// Emitted each time an order fills as a taker. If an order results + /// in multiple fills, a separate event is emitted for each one. + struct FillEvent has drop, store { + /// Market ID of corresponding market. + market_id: u64, + /// Order book counter at time of fill, incremented for each + /// order placed on the book. If an order results in multiple + /// `FillEvent`s, they will all have the same + /// `FillEvent.order_book_counter`. If a limit order crosses the + /// spread and fills first as a taker before posting to the book + /// as a maker, the `FillEvent.order_book_counter` field for + /// each fill is identical to the counter encoded in the + /// corresponding `MakerEvent.market_order_id`. + order_book_counter: u64, + /// The size filled, in lots. + size: u64, + /// Fill price, in ticks per lot. + price: u64, + /// `ASK` or `BID`, the side of the maker order filled against. + maker_side: bool, + /// Maket order ID of maker order just filled against. + maker_market_order_id: u128, + /// Address of user holding maker order. + maker: address, + /// For given maker, ID of custodian required to approve order + /// operations and withdrawals on given market account. + maker_custodian_id: u64 + } + + /// Map of `FillEvent` handles, implemented as a replacement for + /// `OrderBook.taker_events` through a backwards-compatible package + /// upgrade. + struct FillEventHandles has key { + /// Map from market ID to `FillEvent` event handle. + map: Table> + } + /// Emitted when a maker order is placed, cancelled, evicted, or its /// size is manually changed. struct MakerEvent has drop, store { @@ -613,11 +653,11 @@ module econia::market { asks: AVLqueue, /// Bids AVL queue. bids: AVLqueue, - /// Cumulative number of maker orders placed on book. + /// Cumulative number of orders placed. counter: u64, /// Event handle for maker events. maker_events: EventHandle, - /// Event handle for taker events. + /// Deprecated field retained for backwards compatibility. taker_events: EventHandle } @@ -628,17 +668,6 @@ module econia::market { map: Tablist } - /// Stored in the Econia resource account. - struct TakerEventV2Handles has key { - /// Map from market ID to TakerEventV2 handle holder. - map: Table - } - - /// Stores handles for TakerEventV2 streams for each market. - struct TakerEventV2HandleHolder has store { - taker_events: EventHandle - } - /// User-friendly representation of an open order on the order book, /// combining fields from `Order` and the corresponding /// `MakerEvent` emitted when order was first placed. @@ -691,40 +720,6 @@ module econia::market { bids: vector } - /// Emitted when a taker order fills against a maker order. If a - /// taker order fills against multiple maker orders, a separate - /// event is emitted for each one. - struct TakerEvent has drop, store { - /// Market ID of corresponding market. - market_id: u64, - /// `ASK` or `BID`, the side of the maker order. - side: bool, - /// Order ID, unique within given market, of maker order just - /// filled against. - market_order_id: u128, - /// Address of user holding maker order. - maker: address, - /// For given maker, ID of custodian required to approve order - /// operations and withdrawals on given market account. - custodian_id: u64, - /// The size filled, in lots. - size: u64, - /// Fill price, in ticks per lot. - price: u64 - } - - struct TakerEventV2 has drop, store { - market_id: u64, - side: bool, - /// Market order ID of maker side of trade. - market_order_id_maker: u128, - /// Market order ID of taker side of trade. - market_order_id_taker: u128, - maker: address, - custodian_id: u64, - size: u64, - price: u64 - } // Structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Error codes >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -859,8 +854,7 @@ module econia::market { const POST_OR_ABORT: u8 = 3; /// Flag for sell direction. const SELL: bool = true; - /// Number of bits maker order counter is shifted in a market order - /// ID. + /// Number of bits order counter is shifted in a market order ID. const SHIFT_COUNTER: u8 = 64; /// Flag for passive order specified by advance in ticks. const TICKS: bool = false; @@ -1018,7 +1012,7 @@ module econia::market { public fun get_TICKS(): bool {TICKS} #[view] - /// Return maker order counter encoded in market order ID. + /// Return order counter encoded in market order ID. /// /// # Testing /// @@ -1365,7 +1359,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_limit_order< BaseType, QuoteType @@ -1402,7 +1399,10 @@ module econia::market { target_advance_amount: u64, custodian_capability_ref: &CustodianCapability ): u128 - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { place_limit_order_passive_advance< BaseType, QuoteType @@ -1443,7 +1443,10 @@ module econia::market { advance_style: bool, target_advance_amount: u64 ): u128 - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { place_limit_order_passive_advance< BaseType, QuoteType @@ -1488,7 +1491,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_limit_order< BaseType, QuoteType @@ -1527,7 +1533,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_market_order( user_address, market_id, @@ -1559,7 +1568,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_market_order( address_of(user), market_id, @@ -1606,7 +1618,10 @@ module econia::market { min_size: u64, utility_coins: Coin ): u64 - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Register market in global registry, storing market ID. let market_id = registry::register_market_base_coin_internal< BaseType, QuoteType, UtilityType>(lot_size, tick_size, min_size, @@ -1661,7 +1676,10 @@ module econia::market { utility_coins: Coin, underwriter_capability_ref: &UnderwriterCapability ): u64 - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Register market in global registry, storing market ID. let market_id = registry::register_market_base_generic_internal< QuoteType, UtilityType>(base_name_generic, lot_size, tick_size, @@ -1729,7 +1747,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { let user_address = address_of(user); // Get user address. // Register base coin store if user does not have one. if (!coin::is_account_registered(user_address)) @@ -1853,7 +1874,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { let (base_value, quote_value) = // Get coin value amounts. (coin::value(&base_coins), coin::value("e_coins)); // Get option wrapped base coins. @@ -1956,7 +1980,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { let underwriter_id = // Get underwriter ID. registry::get_underwriter_id(underwriter_capability_ref); // Get quote coin value. @@ -2078,7 +2105,10 @@ module econia::market { size: u64, advance_style: bool, target_advance_amount: u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_limit_order_passive_advance_user< BaseType, QuoteType @@ -2109,7 +2139,10 @@ module econia::market { price: u64, restriction: u8, self_match_behavior: u8 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_limit_order_user( user, market_id, integrator, side, size, price, restriction, self_match_behavior); @@ -2130,7 +2163,10 @@ module econia::market { direction: bool, size: u64, self_match_behavior: u8 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { place_market_order_user( user, market_id, integrator, direction, size, self_match_behavior); } @@ -2150,7 +2186,10 @@ module econia::market { lot_size: u64, tick_size: u64, min_size: u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { // Get market registration fee, denominated in utility coins. let fee = incentives::get_market_registration_fee(); // Register market with base coin, paying fees from coin store. @@ -2177,7 +2216,10 @@ module econia::market { min_quote: u64, max_quote: u64, limit_price: u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { swap_between_coinstores( user, market_id, integrator, direction, min_base, max_base, min_quote, max_quote, limit_price); @@ -2554,6 +2596,8 @@ module econia::market { /// # Parameters /// /// * `market_id`: Market ID of market. + /// * `resource_address`: Address of resource account where order + /// books and fill event handles are stored. /// * `order_book_ref_mut`: Mutable reference to market order book. /// * `taker`: Address of taker whose order is matched. Passed as /// `NO_MARKET_ACCOUNT` when taker order originates from a swap. @@ -2608,7 +2652,7 @@ module econia::market { /// /// # Emits /// - /// * `TakerEvent`: Information about a fill against a maker order, + /// * `FillEvent`: Information about a fill against a maker order, /// emitted for each separate maker order that is filled against. /// /// # Aborts @@ -2654,6 +2698,7 @@ module econia::market { QuoteType >( market_id: u64, + resource_address: address, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -2674,12 +2719,7 @@ module econia::market { u64, u64, bool - ) { - /* - Borrow the TakerEventV2HandleHolder for the market ID. - */ - // Increment order counter. - order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + ) acquires FillEventHandles { // Assert price is not too high. assert!(limit_price <= HI_PRICE, E_PRICE_TOO_HIGH); // Taker buy fills against asks, sell against bids. @@ -2702,6 +2742,14 @@ module econia::market { // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; + // Mutably borrow fill event handles map. + let fill_event_handles_map_ref_mut = + &mut borrow_global_mut(resource_address).map; + // Mutably borrow fill event handle for market. + let fill_event_handle_ref_mut = + table::borrow_mut(fill_event_handles_map_ref_mut, market_id); + // Increment order counter. + order_book_ref_mut.counter = order_book_ref_mut.counter + 1; // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -2794,19 +2842,12 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - // Get taker events handle. - let taker_handle = &mut order_book_ref_mut.taker_events; - // Emit corresponding taker event. - event::emit_event(taker_handle, TakerEvent{ - market_id, side, market_order_id, maker, custodian_id: - maker_custodian_id, size: fill_size, price}); - // Get market order ID for taker side of trade. - let market_order_id_taker = - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); - /* - Emit a Taker Event V2. - */ - // If order on book completely filled: + // Emit corresponding fill event. + event::emit_event(fill_event_handle_ref_mut, FillEvent{ + market_id, order_book_counter: order_book_ref_mut.counter, + size: fill_size, price, maker_side: side, + maker_market_order_id: market_order_id, maker, + maker_custodian_id: custodian_id}); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -2989,7 +3030,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { // Assert valid order restriction flag. assert!(restriction <= N_RESTRICTIONS, E_INVALID_RESTRICTION); assert!(price != 0, E_PRICE_0); // Assert nonzero price. @@ -3094,13 +3138,13 @@ module econia::market { // Match against order book, storing optionally modified // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of - // the order. + // the order. (Increments order book counter). (optional_base_coins, quote_coins, base_traded, quote_traded, fees, self_match_cancel) = match( - market_id, order_book_ref_mut, user_address, custodian_id, - integrator, direction, min_base, max_base, min_quote, - max_quote, price, self_match_behavior, optional_base_coins, - quote_coins); + market_id, resource_address, order_book_ref_mut, user_address, + custodian_id, integrator, direction, min_base, max_base, + min_quote, max_quote, price, self_match_behavior, + optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -3276,7 +3320,10 @@ module econia::market { advance_style: bool, target_advance_amount: u64 ): u128 - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); let order_books_map_ref = // Immutably borrow order books map. @@ -3429,7 +3476,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { // Get user's available and ceiling asset counts. let (_, base_available, base_ceiling, _, quote_available, quote_ceiling) = user::get_asset_counts_internal( @@ -3490,9 +3540,9 @@ module econia::market { // Match against order book, storing optionally modified asset // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match(market_id, order_book_ref_mut, user_address, - custodian_id, integrator, direction, min_base, - max_base, min_quote, max_quote, limit_price, + _) = match(market_id, resource_address, order_book_ref_mut, + user_address, custodian_id, integrator, direction, + min_base, max_base, min_quote, max_quote, limit_price, self_match_behavior, optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else @@ -3643,7 +3693,10 @@ module econia::market { min_size: u64, underwriter_id: u64 ): u64 - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Get Econia resource account signer. let resource_account = resource_account::get_signer(); // Get resource account address. @@ -3666,6 +3719,21 @@ module econia::market { account::new_event_handle(&resource_account), taker_events: account::new_event_handle(&resource_account)}); + // If a fill event handles map has not yet been moved to the + // resource account: + if (!exists(resource_address)) { + // Initialize fill event handles map under resource account. + // This is done here rather than in `init_module()` since + // the fill event handles map was implemented in a + // backwards-compatible package upgrade. + move_to(&resource_account, FillEventHandles{map: table::new()}); + }; + // Mutably borrow fill event handles map. + let fill_event_handles_map_ref_mut = + &mut borrow_global_mut(resource_address).map; + table::add( // Add fill event handle to fill event handles map. + fill_event_handles_map_ref_mut, market_id, + account::new_event_handle(&resource_account)); // Register an Econia fee store entry for market quote coin. incentives::register_econia_fee_store_entry(market_id); market_id // Return market ID. @@ -3743,7 +3811,10 @@ module econia::market { u64, u64, u64 - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); let order_books_map_ref_mut = // Mutably borrow order books map. @@ -3765,10 +3836,10 @@ module econia::market { let (base_traded, quote_traded, fees); (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) = match( // Match against order book. - market_id, order_book_ref_mut, NO_MARKET_ACCOUNT, NO_CUSTODIAN, - integrator, direction, min_base, max_base, min_quote, - max_quote, limit_price, ABORT, optional_base_coins, - quote_coins); + market_id, resource_address, order_book_ref_mut, + NO_MARKET_ACCOUNT, NO_CUSTODIAN, integrator, direction, + min_base, max_base, min_quote, max_quote, limit_price, ABORT, + optional_base_coins, quote_coins); // Return optionally modified asset inputs, trade amounts, fees. (optional_base_coins, quote_coins, base_traded, quote_traded, fees) } @@ -3780,6 +3851,17 @@ module econia::market { /// Deprecated struct retained for backwards compatibility. struct Orders has key {asks: vector, bids: vector} + /// Deprecated struct retained for backwards compatibility. + struct TakerEvent has drop, store { + market_id: u64, + side: bool, + market_order_id: u128, + maker: address, + custodian_id: u64, + size: u64, + price: u64 + } + // Deprecated structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Deprecated functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -3833,7 +3915,10 @@ module econia::market { max_bid_price: u64, min_ask_price: u64 ): signer - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); let user_address = address_of(&user); // Get user address. @@ -3913,7 +3998,10 @@ module econia::market { public fun init_markets_users_integrator_test(): ( signer, signer - ) acquires OrderBooks { + ) acquires + FillEventHandles, + OrderBooks + { init_test(); // Init for testing. // Get market registration fee. let fee = incentives::get_market_registration_fee(); @@ -4067,7 +4155,10 @@ module econia::market { /// Verify state updates for cancelling three asks under authority /// of custodian. fun test_cancel_all_orders_ask_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4127,7 +4218,10 @@ module econia::market { /// Verify state updates for cancelling three bids under authority /// of signing user. fun test_cancel_all_orders_bid_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4183,7 +4277,10 @@ module econia::market { /// Verify state updates for cancelling ask under authority of /// custodian. fun test_cancel_order_ask_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4260,7 +4357,10 @@ module econia::market { /// Verify state updates for cancelling bid under authority of /// signing user. fun test_cancel_order_bid_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4332,7 +4432,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_CUSTODIAN)] /// Verify failure for invalid custodian. fun test_cancel_order_invalid_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4373,7 +4476,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_cancel_order_invalid_market_id() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4388,7 +4494,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid bogus market order ID. fun test_cancel_order_invalid_market_order_id_bogus() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4403,7 +4512,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid market order ID passed as `NIL`. fun test_cancel_order_invalid_market_order_id_null() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4418,7 +4530,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_USER)] /// Verify failure for invalid user. fun test_cancel_order_invalid_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, attacker) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4454,7 +4569,10 @@ module econia::market { /// Verify state updates for changing ask under authority of /// custodian, for size increase at tail of price level queue. fun test_change_order_size_ask_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4599,7 +4717,10 @@ module econia::market { /// Verify state updates for changing bid under authority of signing /// user, for size decrease at tail of queue. fun test_change_order_size_bid_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4696,7 +4817,10 @@ module econia::market { /// Verify state updates for changing bid under authority of signing /// user, for size increase not at tail of queue. fun test_change_order_size_bid_user_new_tail() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4785,7 +4909,10 @@ module econia::market { /// queue access key mismatch. Based on /// `test_change_order_size_bid_user_new_tail`. fun test_change_order_size_insertion_error() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4818,7 +4945,7 @@ module econia::market { place_limit_order_user( // Place second maker order. &maker, market_id, integrator, side, size_1, price, restriction, self_match_behavior); - // Get maker order counter from market order ID. + // Get order counter from market order ID. let order_counter = ((market_order_id >> SHIFT_COUNTER) as u64); // Get AVL queue access key from market order ID. let avlq_access_key = ((market_order_id & (HI_64 as u128)) as u64); @@ -4846,7 +4973,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_CUSTODIAN)] /// Verify failure for invalid custodian. fun test_change_order_size_invalid_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4888,7 +5018,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_change_order_size_invalid_market_id() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4904,7 +5037,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid bogus market order ID. fun test_change_order_size_invalid_market_order_id_bogus() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4920,7 +5056,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid market order ID passed as `NIL`. fun test_change_order_size_invalid_market_order_id_null() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4936,7 +5075,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_USER)] /// Verify failure for invalid user. fun test_change_order_size_invalid_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, attacker) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5088,7 +5230,7 @@ module econia::market { #[test] /// Verify return. fun test_get_market_order_id_avl_queue_access_key() { - // Declare mock AVL queue access key, maker counter. + // Declare mock AVL queue access key, order counter. let avlq_access_key = 12345; let counter = 67890; // Construct mock market order ID. @@ -5109,7 +5251,11 @@ module econia::market { #[test] /// Verify indexing results. - fun test_get_open_orders() acquires OrderBooks { + fun test_get_open_orders() + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare common order parameters. @@ -5235,7 +5381,11 @@ module econia::market { #[test] /// Verify indexing results. - fun test_get_price_levels() acquires OrderBooks { + fun test_get_price_levels() + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare common order parameters. @@ -5352,7 +5502,10 @@ module econia::market { /// Verify returns, state updates for complete buy fill with no lots /// left to fill on matched order. fun test_match_complete_fill_no_lots_buy() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -5477,7 +5630,10 @@ module econia::market { /// Verify returns, state updates for complete sell fill with no /// ticks left to fill on matched order. fun test_match_complete_fill_no_ticks_sell() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -5601,7 +5757,10 @@ module econia::market { #[test] /// Verify returns for no orders to match against. fun test_match_empty() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare swap arguments. @@ -5634,7 +5793,10 @@ module econia::market { #[test] /// Verify returns for not enough size to fill. fun test_match_fill_size_0() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -5747,7 +5909,10 @@ module econia::market { /// partial fill on second order during match loop. A taker sell /// where one maker has two bids at different prices. fun test_match_loop_twice() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -5836,6 +6001,8 @@ module econia::market { let (market_order_id_lo, _, _, _) = place_limit_order_user( &maker, market_id, @integrator, side_maker, size_maker_lo, price_lo, restriction, self_match_behavior); + // Assert order book counter. + assert!(get_order_book_counter(market_id) == 2, 0); // Get user-side high-price order access key for later. let (_, _, _, _, order_access_key_hi) = get_order_fields_test(market_id, side_maker, market_order_id_hi); @@ -5844,6 +6011,8 @@ module econia::market { swap_coins(market_id, integrator, direction_taker, min_base, max_base, min_quote, max_quote, price, base_coins, quote_coins); + // Assert order book counter. + assert!(get_order_book_counter(market_id) == 3, 0); // Assert returns. assert!(coin::value(&base_coins) == base_coin_end, 0); assert!(coin::value("e_coins) == quote_coin_end, 0); @@ -5908,7 +6077,10 @@ module econia::market { #[expected_failure(abort_code = E_MIN_BASE_NOT_TRADED)] /// Verify failure for minimum base amount not traded. fun test_match_min_base_not_traded() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare swap arguments. @@ -5937,7 +6109,10 @@ module econia::market { #[expected_failure(abort_code = E_MIN_QUOTE_NOT_TRADED)] /// Verify failure for minimum quote amount not traded. fun test_match_min_quote_not_traded() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare swap arguments. @@ -5965,7 +6140,10 @@ module econia::market { #[test] /// Verify returns for partial sell fill with lot-limited fill size. fun test_match_partial_fill_lot_limited_sell() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -6092,7 +6270,10 @@ module econia::market { #[test] /// Verify returns for partial buy fill with tick-limited fill size. fun test_match_partial_fill_tick_limited_buy() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -6219,7 +6400,10 @@ module econia::market { #[test] /// Verify returns for limit price violation on buy. fun test_match_price_break_buy() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare shared/dependent market parameters. @@ -6323,7 +6507,10 @@ module econia::market { #[test] /// Verify returns for limit price violation on sell. fun test_match_price_break_sell() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare shared/dependent market parameters. @@ -6429,7 +6616,10 @@ module econia::market { /// Verify failure for price mismatch between order and AVL queue /// head key. Test setup based on `test_match_fill_size_0()` fun test_match_price_mismatch() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare shared/dependent market parameters. @@ -6497,7 +6687,10 @@ module econia::market { #[expected_failure(abort_code = E_PRICE_TOO_HIGH)] /// Verify failure for price too high. fun test_match_price_too_high() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare swap arguments. @@ -6526,7 +6719,10 @@ module econia::market { #[expected_failure(abort_code = E_SELF_MATCH)] /// Verify failure for self match with abort behavior. fun test_match_self_match_abort() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare common market parameters. @@ -6571,7 +6767,10 @@ module econia::market { /// the order at the lower price. Here, matching halts after the /// self match. fun test_match_self_match_cancel_both() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -6681,7 +6880,10 @@ module econia::market { /// the order at the lower price. Here, matching continues against /// the order at the higher price. fun test_match_self_match_cancel_maker() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -6815,7 +7017,10 @@ module econia::market { /// the order at the lower price. Here, matching halts after the /// self match. fun test_match_self_match_cancel_taker() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -6929,7 +7134,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_SELF_MATCH_BEHAVIOR)] /// Verify failure for self match with invalid abort behavior. fun test_match_self_match_invalid() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare common market parameters. @@ -6968,7 +7176,10 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_BASE_OVERFLOW)] /// Verify failure for base overflow. fun test_place_limit_order_base_overflow() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = HI_64 / LOT_SIZE_COIN + 1; @@ -6988,7 +7199,10 @@ module econia::market { /// completely and exactly across the spread, under authority of /// signing user. fun test_place_limit_order_crosses_ask_exact() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7093,7 +7307,10 @@ module econia::market { /// partially across the spread, under authority of signing user. /// Based on `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_ask_partial() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7143,6 +7360,8 @@ module econia::market { place_limit_order_user( &user_1, MARKET_ID_COIN, @integrator, side, size, price, restriction, self_match_behavior); + // Assert order book counter. + assert!(get_order_book_counter(MARKET_ID_COIN) == 2, 0); // Assert returns assert!(base_trade_r == base_match, 0); assert!(quote_trade_r == quote_trade, 0); @@ -7203,7 +7422,10 @@ module econia::market { /// signing user. Based on /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_partial_cancel() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7281,7 +7503,10 @@ module econia::market { /// with taker cancellation. Based on /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_self_match_cancel() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -7352,7 +7577,10 @@ module econia::market { /// signing user. Mirror of /// `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_bid_exact() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7457,7 +7685,10 @@ module econia::market { /// partially across the spread, under authority of signing user. /// Mirror of `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_bid_partial() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7569,7 +7800,10 @@ module econia::market { /// enough remaining size to meet minimum size requirement. Based on /// `test_place_limit_order_crosses_bid_partial()`. fun test_place_limit_order_crosses_bid_partial_cancel() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7667,7 +7901,10 @@ module econia::market { /// Verify state updates, returns, for placing limit order that /// evicts another user's order. fun test_place_limit_order_evict() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -7785,7 +8022,10 @@ module econia::market { #[expected_failure(abort_code = E_FILL_OR_ABORT_NOT_CROSS_SPREAD)] /// Verify failure for not crossing spread when fill-or-abort. fun test_place_limit_order_fill_or_abort_not_cross() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -7810,7 +8050,10 @@ module econia::market { /// Verify failure for not filling completely across spread when /// fill-or-abort. fun test_place_limit_order_fill_or_abort_partial() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -7842,7 +8085,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type argument. fun test_place_limit_order_invalid_base() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -7866,7 +8112,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type argument. fun test_place_limit_order_invalid_quote() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -7890,7 +8139,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_RESTRICTION)] /// Verify failure for invalid restriction. fun test_place_limit_order_invalid_restriction() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = 123; @@ -7907,7 +8159,10 @@ module econia::market { /// Verify state updates, returns, for placing ask that does not /// cross the spread, under authority of signing user. fun test_place_limit_order_no_cross_ask_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -7938,7 +8193,7 @@ module econia::market { assert!(quote_trade == 0, 0); assert!(fees == 0, 0); // Assert counter encoded in order ID. - assert!(get_market_order_id_counter(market_order_id) == 0, 0); + assert!(get_market_order_id_counter(market_order_id) == 1, 0); // Assert price encoded in order ID. assert!(get_market_order_id_price(market_order_id) == price, 0); // Assert side encoded in order ID. @@ -7978,7 +8233,7 @@ module econia::market { let (market_order_id, _, _, _) = place_limit_order_user( &user_0, MARKET_ID_COIN, @integrator, !side, size, price - 1, restriction, self_match_behavior); - assert!(get_market_order_id_counter(market_order_id) == 1, 0); + assert!(get_market_order_id_counter(market_order_id) == 2, 0); // Assert order book counter. assert!(get_order_book_counter(MARKET_ID_COIN) == 2, 0); } @@ -7987,7 +8242,10 @@ module econia::market { /// Verify state updates, returns, for placing bid that does not /// cross the spread, under authority of custodian. fun test_place_limit_order_no_cross_bid_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = BID; let size = MIN_SIZE_COIN; @@ -8014,7 +8272,7 @@ module econia::market { @user_0, MARKET_ID_COIN, @integrator, side, size, price, restriction, self_match_behavior, &custodian_capability); // Assert counter encoded in order ID. - assert!(get_market_order_id_counter(market_order_id) == 0, 0); + assert!(get_market_order_id_counter(market_order_id) == 1, 0); // Assert price encoded in order ID. assert!(get_market_order_id_price(market_order_id) == price, 0); // Assert side encoded in order ID. @@ -8057,7 +8315,7 @@ module econia::market { let (market_order_id, _, _, _) = place_limit_order_custodian( @user_0, MARKET_ID_COIN, @integrator, !side, size, price + 1, restriction, self_match_behavior, &custodian_capability); - assert!(get_market_order_id_counter(market_order_id) == 1, 0); + assert!(get_market_order_id_counter(market_order_id) == 2, 0); // Assert order book counter. assert!(get_order_book_counter(MARKET_ID_COIN) == 2, 0); // Drop custodian capability. @@ -8068,7 +8326,10 @@ module econia::market { #[expected_failure(abort_code = E_PRICE_0)] /// Verify failure for invalid price. fun test_place_limit_order_no_price() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = 123; @@ -8085,7 +8346,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type argument. fun test_place_limit_order_passive_advance_invalid_base() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8105,7 +8369,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_place_limit_order_passive_advance_invalid_market_id() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8125,7 +8392,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_PERCENT)] /// Verify failure for invalid percent fun test_place_limit_order_passive_advance_invalid_percent() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = 201; @@ -8147,7 +8417,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type argument. fun test_place_limit_order_passive_advance_invalid_quote() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8166,7 +8439,10 @@ module econia::market { #[test] /// Verify return for no cross price when placing an ask. fun test_place_limit_order_passive_advance_no_cross_price_ask() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = NIL; let min_ask_price = 201; @@ -8189,7 +8465,10 @@ module econia::market { #[test] /// Verify return for no cross price when placing a bid. fun test_place_limit_order_passive_advance_no_cross_price_bid() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = NIL; @@ -8212,7 +8491,10 @@ module econia::market { #[test] /// Verify returns, state updates for full advance is start price. fun test_place_limit_order_passive_advance_no_full_advance() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = 101; @@ -8240,7 +8522,10 @@ module econia::market { #[test] /// Verify returns for no start price. fun test_place_limit_order_passive_advance_no_start_price() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8267,7 +8552,10 @@ module econia::market { #[test] /// Verify returns, state updates for no target advance amount. fun test_place_limit_order_passive_advance_no_target_advance() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = 201; @@ -8294,7 +8582,10 @@ module econia::market { #[test] /// Verify returns, state updates for percent-specified asks. fun test_place_limit_order_passive_advance_percent_ask() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 99; let min_ask_price = 500; @@ -8325,7 +8616,10 @@ module econia::market { #[test] /// Verify returns, state updates for percent-specified bids. fun test_place_limit_order_passive_advance_percent_bid() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = 501; @@ -8356,7 +8650,10 @@ module econia::market { #[test] /// Verify returns, state updates for ticks-specified asks. fun test_place_limit_order_passive_advance_ticks_ask() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = 500; @@ -8405,7 +8702,10 @@ module econia::market { /// Verify returns, state updates for ticks-specified bid, for /// delegated custodian. fun test_place_limit_order_passive_advance_ticks_bid() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Configure spread. let max_bid_price = 100; let min_ask_price = 500; @@ -8456,7 +8756,10 @@ module econia::market { #[expected_failure(abort_code = E_POST_OR_ABORT_CROSSES_SPREAD)] /// Verify failure for not crossing spread as post-or-abort. fun test_place_limit_order_post_or_abort_crosses() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8488,7 +8791,10 @@ module econia::market { #[expected_failure(abort_code = E_PRICE_TOO_HIGH)] /// Verify failure for invalid price. fun test_place_limit_order_price_hi() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = 123; @@ -8506,7 +8812,10 @@ module econia::market { /// Verify failure for unable to insert to AVL queue. Modeled off /// `test_place_limit_order_evict()`. fun test_place_limit_order_price_time_priority_low() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8553,7 +8862,10 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_PRICE_QUOTE_OVERFLOW)] /// Verify failure for quote overflow. fun test_place_limit_order_quote_overflow() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = HI_64 / LOT_SIZE_COIN; @@ -8572,7 +8884,10 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_TOO_SMALL)] /// Verify failure for invalid size. fun test_place_limit_order_size_lo() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN - 1; @@ -8597,7 +8912,10 @@ module econia::market { /// the spread after matching as a taker, under authority of signing /// user. Based on `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_still_crosses_ask() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, taker) = init_markets_users_integrator_test(); let (maker_address, taker_address) = // Get user addresses. @@ -8716,7 +9034,10 @@ module econia::market { /// the spread after matching as a taker, under authority of signing /// user. Based on `test_place_limit_order_still_crosses_ask()`. fun test_place_limit_order_still_crosses_bid() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (maker, taker) = init_markets_users_integrator_test(); let (maker_address, taker_address) = // Get user addresses. @@ -8831,7 +9152,10 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_PRICE_TICKS_OVERFLOW)] /// Verify failure for ticks overflow. fun test_place_limit_order_ticks_overflow() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = HI_64 / LOT_SIZE_COIN; @@ -8850,7 +9174,10 @@ module econia::market { /// Verify state updates for public entry wrapper invocation. Based /// on `test_place_limit_order_no_cross_ask_user()`. fun test_place_limit_order_user_entry() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -8911,7 +9238,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type argument. fun test_place_market_order_invalid_base() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare order arguments. @@ -8932,7 +9262,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type argument. fun test_place_market_order_invalid_quote() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare order arguments. @@ -8953,7 +9286,10 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_TOO_SMALL)] /// Verify failure for invalid size argument. fun test_place_market_order_size_too_small() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare order arguments. @@ -8975,7 +9311,10 @@ module econia::market { /// base trade amount that is less than max possible, under /// authority of signing user. fun test_place_market_order_max_base_adjust_buy_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9080,7 +9419,10 @@ module econia::market { /// max possible base trade amount, under authority of signing /// user. fun test_place_market_order_max_base_buy_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9182,7 +9524,10 @@ module econia::market { /// Verify state updates, returns for market sell when max possible /// base trade amount specified, under authority of custodian. fun test_place_market_order_max_base_sell_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9289,7 +9634,10 @@ module econia::market { /// Verify state updates, returns for market buy when max possible /// quote trade amount specified, under authority of custodian. fun test_place_market_order_max_quote_buy_custodian() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9395,7 +9743,10 @@ module econia::market { /// Verify state updates, returns for market sell when max possible /// quote trade amount specified, under authority of signing user. fun test_place_market_order_max_quote_sell_user() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9497,7 +9848,10 @@ module econia::market { /// Verify state updates for public entry wrapper invocation. Based /// on `test_place_market_order_max_base_buy_user()`. fun test_place_market_order_user_entry() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9756,7 +10110,10 @@ module econia::market { /// 2. Registering generic market. /// 3. Registering pure coin market, not from coin store. fun test_register_markets() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { init_test(); // Init for testing. // Get market registration fee, denominated in utility coins. let fee = incentives::get_market_registration_fee(); @@ -9853,7 +10210,10 @@ module econia::market { /// Verify returns, state updates for specifying max possible base /// during a buy. fun test_swap_between_coinstores_max_possible_base_buy() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -9955,7 +10315,10 @@ module econia::market { /// Verify returns, state updates for specifying max possible base /// during a sell. fun test_swap_between_coinstores_max_possible_base_sell() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10057,7 +10420,10 @@ module econia::market { /// Verify returns, state updates for specifying max possible quote /// during a buy. fun test_swap_between_coinstores_max_possible_quote_buy() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10159,7 +10525,10 @@ module econia::market { /// Verify returns, state updates for specifying max possible quote /// during a sell. fun test_swap_between_coinstores_max_possible_quote_sell() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10260,7 +10629,10 @@ module econia::market { #[test] /// Verify returns, state updates for registering base coin store. fun test_swap_between_coinstores_register_base_store() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10353,7 +10725,10 @@ module econia::market { #[test] /// Verify returns, state updates for registering quote coin store. fun test_swap_between_coinstores_register_quote_store() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10447,7 +10822,10 @@ module econia::market { /// Verify returns, state updates for swap buy for max possible /// base amount specified, with base amount as limiting factor. fun test_swap_coins_buy_max_base_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10552,7 +10930,10 @@ module econia::market { /// Verify returns, state updates for swap buy for max possible /// base amount not specified, with base amount as limiting factor. fun test_swap_coins_buy_no_max_base_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10657,7 +11038,10 @@ module econia::market { /// Verify returns, state updates for swap buy for max possible /// base amount not specified, with quote amount as limiting factor. fun test_swap_coins_buy_no_max_quote_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10761,7 +11145,10 @@ module econia::market { /// Verify returns, state updates for swap sell for max possible /// quote amount specified, with quote amount as limiting factor. fun test_swap_coins_sell_max_quote_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10866,7 +11253,10 @@ module econia::market { /// Verify returns, state updates for swap sell for no max possible /// quote amount specified, with base amount as limiting factor. fun test_swap_coins_sell_no_max_base_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -10971,7 +11361,10 @@ module econia::market { /// Verify returns, state updates for swap sell for no max possible /// quote amount specified, with quote amount as limiting factor. fun test_swap_coins_sell_no_max_quote_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -11075,7 +11468,10 @@ module econia::market { /// Verify returns, state updates for swap buy with base amount as /// limiting factor. fun test_swap_generic_buy_base_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -11179,7 +11575,10 @@ module econia::market { /// Verify returns, state updates for swap buy with quote amount as /// limiting factor. fun test_swap_generic_buy_quote_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -11283,7 +11682,10 @@ module econia::market { /// Verify returns, state updates for swap sell with max possible /// quote flag specified, with quote amount as limiting factor. fun test_swap_generic_sell_max_quote_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -11387,7 +11789,10 @@ module econia::market { /// Verify returns, state updates for swap sell without max possible /// quote flag specified, with base amount as limiting factor. fun test_swap_generic_sell_no_max_base_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -11491,7 +11896,10 @@ module econia::market { /// Verify returns, state updates for swap sell without max possible /// quote flag specified, with quote amount as limiting factor. fun test_swap_generic_sell_no_max_quote_limiting() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get taker fee divisor. @@ -11595,7 +12003,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type. fun test_swap_invalid_base() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Define swap parameters. @@ -11622,7 +12033,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_swap_invalid_market_id() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Define swap parameters. @@ -11649,7 +12063,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type. fun test_swap_invalid_quote() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Define swap parameters. @@ -11676,7 +12093,10 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_UNDERWRITER)] /// Verify failure for invalid underwriter. fun test_swap_invalid_underwriter() - acquires OrderBooks { + acquires + FillEventHandles, + OrderBooks + { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Define swap parameters. From dd839d25ddd73b6db3f31bcb779cf94cfa3f57b4 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:02:55 -0700 Subject: [PATCH 03/56] Add common market order ID for fills/post, docs --- doc/doc-site/docs/move/changelog.md | 8 +- .../econia/doc/img/market_forward_dep.svg | 930 +++++++++--------- src/move/econia/doc/market.md | 774 +++++++++------ src/move/econia/sources/market.move | 229 +++-- 4 files changed, 1104 insertions(+), 837 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 61c62bcb3..6582c132e 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -7,20 +7,20 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] ### Added - Assorted view functions ([#287], [#301]). -- Fill events with order book counter ([#312]). +- Fill events with common order ID ([#314]). ### Deprecated -- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#312]) +- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#314]) - [`market::Orders`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3337) ([#301]) -- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#312]) +- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#314]) - [`market::index_orders_sdk()`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3362) ([#287]) - [`move-to-ts`](https://github.com/hippospace/move-to-ts) attributes ([#292]) [#287]: https://github.com/econia-labs/econia/pull/287 [#292]: https://github.com/econia-labs/econia/pull/292 [#301]: https://github.com/econia-labs/econia/pull/301 -[#312]: https://github.com/econia-labs/econia/pull/312 +[#314]: https://github.com/econia-labs/econia/pull/314 [keep a changelog]: https://keepachangelog.com/en/1.0.0/ [semantic versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/econia-labs/econia/compare/v4.0.2-audited...HEAD diff --git a/src/move/econia/doc/img/market_forward_dep.svg b/src/move/econia/doc/img/market_forward_dep.svg index 7812d7298..f93d639ef 100644 --- a/src/move/econia/doc/img/market_forward_dep.svg +++ b/src/move/econia/doc/img/market_forward_dep.svg @@ -4,928 +4,934 @@ - + G - + market - -market + +market - + +vector + +vector + + + +market->vector + + + + + option - -option + +option - + market->option - - + + - + string - -string + +string - + market->string - - + + - + signer - -signer + +signer - + market->signer - - + + - + type_info - -type_info + +type_info - + market->type_info - - + + - + table - -table + +table - + market->table - - + + - + event - -event + +event - + market->event - - + + - + account - -account + +account - + market->account - - + + - + coin - -coin + +coin - + market->coin - - + + - + avl_queue - -avl_queue + +avl_queue - + market->avl_queue - - + + - + tablist - -tablist + +tablist - + market->tablist - - + + - + resource_account - -resource_account + +resource_account - + market->resource_account - - + + - + incentives - -incentives + +incentives - + market->incentives - - + + - + registry - -registry + +registry - + market->registry - - + + - + user - -user + +user - + market->user - - - - - -vector - -vector + + - + option->vector - - - - - -string->option - - + + - + string->vector - - + + - + +string->option + + + + + type_info->string - - + + error - -error + +error - + type_info->error - - + + features - -features + +features - + type_info->features - - + + bcs - -bcs + +bcs - + type_info->bcs - - + + - + event->bcs - - + + guid - -guid + +guid - + event->guid - - + + - + +account->vector + + + + + account->option - - + + - + account->signer - - + + - + account->type_info - - + + - + account->table - - + + - + account->event - - - - - -account->vector - - + + - + account->error - - + + - + account->bcs - - + + - + account->guid - - + + system_addresses - -system_addresses + +system_addresses - + account->system_addresses - - + + hash - -hash + +hash - + account->hash - - + + ed25519 - -ed25519 + +ed25519 - + account->ed25519 - - + + multi_ed25519 - -multi_ed25519 + +multi_ed25519 - + account->multi_ed25519 - - + + from_bcs - -from_bcs + +from_bcs - + account->from_bcs - - + + create_signer - -create_signer + +create_signer - + account->create_signer - - + + chain_id - -chain_id + +chain_id - + account->chain_id - - + + - + coin->option - - + + - + coin->string - - + + - + coin->signer - - + + - + coin->type_info - - + + - + coin->event - - + + - + coin->account - - + + - + coin->error - - + + - + coin->system_addresses - - + + aggregator - -aggregator + +aggregator - + coin->aggregator - - + + aggregator_factory - -aggregator_factory + +aggregator_factory - + coin->aggregator_factory - - + + optional_aggregator - -optional_aggregator + +optional_aggregator - + coin->optional_aggregator - - + + - + avl_queue->option - - + + - + avl_queue->table - - + + table_with_length - -table_with_length + +table_with_length - + avl_queue->table_with_length - - + + - + tablist->option - - + + - + tablist->table_with_length - - + + - + resource_account->account - - + + - + resource_account->bcs - - + + timestamp - -timestamp + +timestamp - + resource_account->timestamp - - + + - + +incentives->vector + + + + + incentives->signer - - + + - + incentives->type_info - - + + - + incentives->coin - - + + - + incentives->tablist - - + + - + incentives->resource_account - - - - - -incentives->vector - - + + aptos_coin - -aptos_coin + +aptos_coin - + incentives->aptos_coin - - + + - + registry->option - - + + - + registry->string - - + + - + registry->signer - - + + - + registry->type_info - - + + - + registry->table - - + + - + registry->event - - + + - + registry->account - - + + - + registry->coin - - + + - + registry->tablist - - + + - + registry->incentives - - + + - + +user->vector + + + + + user->option - - + + - + user->string - - + + - + user->signer - - + + - + user->type_info - - + + - + user->table - - + + - + user->coin - - + + - + user->tablist - - + + - + user->registry - - - - - -user->vector - - + + - + features->signer - - + + - + features->error - - + + - + system_addresses->signer - - + + - + system_addresses->error - - + + - + ed25519->option - - + + - + ed25519->type_info - - + + - + ed25519->error - - + + - + ed25519->bcs - - + + - + ed25519->hash - - + + - + multi_ed25519->option - - + + - + multi_ed25519->error - - + + - + multi_ed25519->features - - + + - + multi_ed25519->bcs - - + + - + multi_ed25519->hash - - + + - + multi_ed25519->ed25519 - - + + - + from_bcs->string - - + + - + chain_id->system_addresses - - + + - + aggregator_factory->table - - + + - + aggregator_factory->error - - + + - + aggregator_factory->system_addresses - - + + - + aggregator_factory->aggregator - - + + - + optional_aggregator->option - - + + - + optional_aggregator->error - - + + - + optional_aggregator->aggregator - - + + - + optional_aggregator->aggregator_factory - - + + - + table_with_length->table - - + + - + table_with_length->error - - + + - + timestamp->error - - + + - + timestamp->system_addresses - - + + - + +aptos_coin->vector + + + + + aptos_coin->option - - + + - + aptos_coin->string - - + + - + aptos_coin->signer - - + + - + aptos_coin->coin - - - - - -aptos_coin->vector - - + + - + aptos_coin->error - - + + - + aptos_coin->system_addresses - - + + diff --git a/src/move/econia/doc/market.md b/src/move/econia/doc/market.md index 4cf1432ad..9de9ad60a 100644 --- a/src/move/econia/doc/market.md +++ b/src/move/econia/doc/market.md @@ -26,11 +26,15 @@ Multiple API variants are supported for market registration and order management function, to enable diagnostic function returns, public entry calls, etc. -When a maker places a limit order that posts against the book, they -are issued a "market order ID" that is unique to the given market. -The maker order price is encoded in the market order ID, as well as -a counter for the number of orders that have been placed for the -corresponding market. +When someone places an order that result in one or more fills and/or +a post to the book, they are issued a "market order ID" that is +unique to the given market but not necessarily across different +markets. Each market order ID encodes a counter for the number of +orders that have been placed on the corresponding market. For orders +that result in a post to the book, the market order ID additionally +encodes an "AVL queue access key" (essentially a pointer into +order book memory), which is required for order lookup during order +size change and/or order cancellation operations. @@ -105,6 +109,7 @@ corresponding market. ### Market order ID decoders +* did_order_post() * get_market_order_id_counter() * get_market_order_id_price() * get_market_order_id_side() @@ -356,6 +361,8 @@ has_open_order --> get_market_order_id_side has_open_order --> get_market_order_id_avl_queue_access_key get_open_orders --> get_open_orders_for_side get_open_orders_all --> get_open_orders +get_market_order_id_price --> did_order_post +get_market_order_id_side --> did_order_post ``` @@ -653,199 +660,203 @@ The below index is automatically generated from source code: - [Resource `Orders`](#0xc0deb00c_market_Orders) - [Struct `TakerEvent`](#0xc0deb00c_market_TakerEvent) - [Constants](#@Constants_22) -- [Function `get_ABORT`](#0xc0deb00c_market_get_ABORT) +- [Function `did_order_post`](#0xc0deb00c_market_did_order_post) - [Testing](#@Testing_23) -- [Function `get_ASK`](#0xc0deb00c_market_get_ASK) +- [Function `get_ABORT`](#0xc0deb00c_market_get_ABORT) - [Testing](#@Testing_24) -- [Function `get_BID`](#0xc0deb00c_market_get_BID) +- [Function `get_ASK`](#0xc0deb00c_market_get_ASK) - [Testing](#@Testing_25) -- [Function `get_BUY`](#0xc0deb00c_market_get_BUY) +- [Function `get_BID`](#0xc0deb00c_market_get_BID) - [Testing](#@Testing_26) -- [Function `get_CANCEL_BOTH`](#0xc0deb00c_market_get_CANCEL_BOTH) +- [Function `get_BUY`](#0xc0deb00c_market_get_BUY) - [Testing](#@Testing_27) -- [Function `get_CANCEL_MAKER`](#0xc0deb00c_market_get_CANCEL_MAKER) +- [Function `get_CANCEL_BOTH`](#0xc0deb00c_market_get_CANCEL_BOTH) - [Testing](#@Testing_28) -- [Function `get_CANCEL_TAKER`](#0xc0deb00c_market_get_CANCEL_TAKER) +- [Function `get_CANCEL_MAKER`](#0xc0deb00c_market_get_CANCEL_MAKER) - [Testing](#@Testing_29) -- [Function `get_FILL_OR_ABORT`](#0xc0deb00c_market_get_FILL_OR_ABORT) +- [Function `get_CANCEL_TAKER`](#0xc0deb00c_market_get_CANCEL_TAKER) - [Testing](#@Testing_30) -- [Function `get_HI_PRICE`](#0xc0deb00c_market_get_HI_PRICE) +- [Function `get_FILL_OR_ABORT`](#0xc0deb00c_market_get_FILL_OR_ABORT) - [Testing](#@Testing_31) -- [Function `get_IMMEDIATE_OR_CANCEL`](#0xc0deb00c_market_get_IMMEDIATE_OR_CANCEL) +- [Function `get_HI_PRICE`](#0xc0deb00c_market_get_HI_PRICE) - [Testing](#@Testing_32) -- [Function `get_MAX_POSSIBLE`](#0xc0deb00c_market_get_MAX_POSSIBLE) +- [Function `get_IMMEDIATE_OR_CANCEL`](#0xc0deb00c_market_get_IMMEDIATE_OR_CANCEL) - [Testing](#@Testing_33) -- [Function `get_NO_CUSTODIAN`](#0xc0deb00c_market_get_NO_CUSTODIAN) +- [Function `get_MAX_POSSIBLE`](#0xc0deb00c_market_get_MAX_POSSIBLE) - [Testing](#@Testing_34) -- [Function `get_NO_RESTRICTION`](#0xc0deb00c_market_get_NO_RESTRICTION) +- [Function `get_NO_CUSTODIAN`](#0xc0deb00c_market_get_NO_CUSTODIAN) - [Testing](#@Testing_35) -- [Function `get_NO_UNDERWRITER`](#0xc0deb00c_market_get_NO_UNDERWRITER) +- [Function `get_NO_RESTRICTION`](#0xc0deb00c_market_get_NO_RESTRICTION) - [Testing](#@Testing_36) -- [Function `get_POST_OR_ABORT`](#0xc0deb00c_market_get_POST_OR_ABORT) +- [Function `get_NO_UNDERWRITER`](#0xc0deb00c_market_get_NO_UNDERWRITER) - [Testing](#@Testing_37) -- [Function `get_PERCENT`](#0xc0deb00c_market_get_PERCENT) +- [Function `get_POST_OR_ABORT`](#0xc0deb00c_market_get_POST_OR_ABORT) - [Testing](#@Testing_38) -- [Function `get_SELL`](#0xc0deb00c_market_get_SELL) +- [Function `get_PERCENT`](#0xc0deb00c_market_get_PERCENT) - [Testing](#@Testing_39) -- [Function `get_TICKS`](#0xc0deb00c_market_get_TICKS) +- [Function `get_SELL`](#0xc0deb00c_market_get_SELL) - [Testing](#@Testing_40) -- [Function `get_market_order_id_counter`](#0xc0deb00c_market_get_market_order_id_counter) +- [Function `get_TICKS`](#0xc0deb00c_market_get_TICKS) - [Testing](#@Testing_41) -- [Function `get_market_order_id_price`](#0xc0deb00c_market_get_market_order_id_price) +- [Function `get_market_order_id_counter`](#0xc0deb00c_market_get_market_order_id_counter) - [Testing](#@Testing_42) +- [Function `get_market_order_id_price`](#0xc0deb00c_market_get_market_order_id_price) + - [Aborts](#@Aborts_43) + - [Testing](#@Testing_44) - [Function `get_market_order_id_side`](#0xc0deb00c_market_get_market_order_id_side) - - [Testing](#@Testing_43) + - [Aborts](#@Aborts_45) + - [Testing](#@Testing_46) - [Function `get_open_order`](#0xc0deb00c_market_get_open_order) - - [Aborts](#@Aborts_44) - - [Testing](#@Testing_45) -- [Function `get_open_orders`](#0xc0deb00c_market_get_open_orders) - - [Parameters](#@Parameters_46) - [Aborts](#@Aborts_47) - [Testing](#@Testing_48) +- [Function `get_open_orders`](#0xc0deb00c_market_get_open_orders) + - [Parameters](#@Parameters_49) + - [Aborts](#@Aborts_50) + - [Testing](#@Testing_51) - [Function `get_open_orders_all`](#0xc0deb00c_market_get_open_orders_all) - - [Testing](#@Testing_49) + - [Testing](#@Testing_52) - [Function `get_price_levels`](#0xc0deb00c_market_get_price_levels) - - [Parameters](#@Parameters_50) - - [Testing](#@Testing_51) + - [Parameters](#@Parameters_53) + - [Testing](#@Testing_54) - [Function `get_price_levels_all`](#0xc0deb00c_market_get_price_levels_all) - - [Testing](#@Testing_52) + - [Testing](#@Testing_55) - [Function `has_open_order`](#0xc0deb00c_market_has_open_order) - - [Testing](#@Testing_53) + - [Testing](#@Testing_56) - [Function `cancel_all_orders_custodian`](#0xc0deb00c_market_cancel_all_orders_custodian) - - [Invocation testing](#@Invocation_testing_54) + - [Invocation testing](#@Invocation_testing_57) - [Function `cancel_order_custodian`](#0xc0deb00c_market_cancel_order_custodian) - - [Invocation testing](#@Invocation_testing_55) + - [Invocation testing](#@Invocation_testing_58) - [Function `change_order_size_custodian`](#0xc0deb00c_market_change_order_size_custodian) - - [Invocation testing](#@Invocation_testing_56) + - [Invocation testing](#@Invocation_testing_59) - [Function `place_limit_order_custodian`](#0xc0deb00c_market_place_limit_order_custodian) - - [Invocation and return testing](#@Invocation_and_return_testing_57) + - [Invocation and return testing](#@Invocation_and_return_testing_60) - [Function `place_limit_order_passive_advance_custodian`](#0xc0deb00c_market_place_limit_order_passive_advance_custodian) - - [Invocation and return testing](#@Invocation_and_return_testing_58) + - [Invocation and return testing](#@Invocation_and_return_testing_61) - [Function `place_limit_order_passive_advance_user`](#0xc0deb00c_market_place_limit_order_passive_advance_user) - - [Invocation and return testing](#@Invocation_and_return_testing_59) + - [Invocation and return testing](#@Invocation_and_return_testing_62) - [Function `place_limit_order_user`](#0xc0deb00c_market_place_limit_order_user) - - [Invocation and return testing](#@Invocation_and_return_testing_60) + - [Invocation and return testing](#@Invocation_and_return_testing_63) - [Function `place_market_order_custodian`](#0xc0deb00c_market_place_market_order_custodian) - - [Invocation and return testing](#@Invocation_and_return_testing_61) + - [Invocation and return testing](#@Invocation_and_return_testing_64) - [Function `place_market_order_user`](#0xc0deb00c_market_place_market_order_user) - - [Invocation and return testing](#@Invocation_and_return_testing_62) + - [Invocation and return testing](#@Invocation_and_return_testing_65) - [Function `register_market_base_coin`](#0xc0deb00c_market_register_market_base_coin) - - [Type parameters](#@Type_parameters_63) - - [Parameters](#@Parameters_64) - - [Returns](#@Returns_65) - - [Testing](#@Testing_66) + - [Type parameters](#@Type_parameters_66) + - [Parameters](#@Parameters_67) + - [Returns](#@Returns_68) + - [Testing](#@Testing_69) - [Function `register_market_base_generic`](#0xc0deb00c_market_register_market_base_generic) - - [Type parameters](#@Type_parameters_67) - - [Parameters](#@Parameters_68) - - [Returns](#@Returns_69) - - [Testing](#@Testing_70) + - [Type parameters](#@Type_parameters_70) + - [Parameters](#@Parameters_71) + - [Returns](#@Returns_72) + - [Testing](#@Testing_73) - [Function `swap_between_coinstores`](#0xc0deb00c_market_swap_between_coinstores) - - [Type Parameters](#@Type_Parameters_71) - - [Parameters](#@Parameters_72) - - [Returns](#@Returns_73) - - [Testing](#@Testing_74) + - [Type Parameters](#@Type_Parameters_74) + - [Parameters](#@Parameters_75) + - [Returns](#@Returns_76) + - [Testing](#@Testing_77) - [Function `swap_coins`](#0xc0deb00c_market_swap_coins) - - [Type Parameters](#@Type_Parameters_75) - - [Parameters](#@Parameters_76) - - [Returns](#@Returns_77) - - [Terminology](#@Terminology_78) - - [Testing](#@Testing_79) + - [Type Parameters](#@Type_Parameters_78) + - [Parameters](#@Parameters_79) + - [Returns](#@Returns_80) + - [Terminology](#@Terminology_81) + - [Testing](#@Testing_82) - [Function `swap_generic`](#0xc0deb00c_market_swap_generic) - - [Type Parameters](#@Type_Parameters_80) - - [Parameters](#@Parameters_81) - - [Returns](#@Returns_82) - - [Testing](#@Testing_83) + - [Type Parameters](#@Type_Parameters_83) + - [Parameters](#@Parameters_84) + - [Returns](#@Returns_85) + - [Testing](#@Testing_86) - [Function `cancel_all_orders_user`](#0xc0deb00c_market_cancel_all_orders_user) - - [Invocation testing](#@Invocation_testing_84) + - [Invocation testing](#@Invocation_testing_87) - [Function `cancel_order_user`](#0xc0deb00c_market_cancel_order_user) - - [Invocation testing](#@Invocation_testing_85) + - [Invocation testing](#@Invocation_testing_88) - [Function `change_order_size_user`](#0xc0deb00c_market_change_order_size_user) - - [Invocation testing](#@Invocation_testing_86) + - [Invocation testing](#@Invocation_testing_89) - [Function `place_limit_order_passive_advance_user_entry`](#0xc0deb00c_market_place_limit_order_passive_advance_user_entry) - - [Invocation testing](#@Invocation_testing_87) + - [Invocation testing](#@Invocation_testing_90) - [Function `place_limit_order_user_entry`](#0xc0deb00c_market_place_limit_order_user_entry) - - [Invocation testing](#@Invocation_testing_88) + - [Invocation testing](#@Invocation_testing_91) - [Function `place_market_order_user_entry`](#0xc0deb00c_market_place_market_order_user_entry) - - [Invocation testing](#@Invocation_testing_89) + - [Invocation testing](#@Invocation_testing_92) - [Function `register_market_base_coin_from_coinstore`](#0xc0deb00c_market_register_market_base_coin_from_coinstore) - - [Testing](#@Testing_90) + - [Testing](#@Testing_93) - [Function `swap_between_coinstores_entry`](#0xc0deb00c_market_swap_between_coinstores_entry) - - [Invocation testing](#@Invocation_testing_91) + - [Invocation testing](#@Invocation_testing_94) - [Function `cancel_all_orders`](#0xc0deb00c_market_cancel_all_orders) - - [Parameters](#@Parameters_92) - - [Expected value testing](#@Expected_value_testing_93) + - [Parameters](#@Parameters_95) + - [Expected value testing](#@Expected_value_testing_96) - [Function `cancel_order`](#0xc0deb00c_market_cancel_order) - - [Parameters](#@Parameters_94) - - [Aborts](#@Aborts_95) - - [Emits](#@Emits_96) - - [Expected value testing](#@Expected_value_testing_97) - - [Failure testing](#@Failure_testing_98) + - [Parameters](#@Parameters_97) + - [Aborts](#@Aborts_98) + - [Emits](#@Emits_99) + - [Expected value testing](#@Expected_value_testing_100) + - [Failure testing](#@Failure_testing_101) - [Function `change_order_size`](#0xc0deb00c_market_change_order_size) - - [Parameters](#@Parameters_99) - - [Aborts](#@Aborts_100) - - [Emits](#@Emits_101) - - [Expected value testing](#@Expected_value_testing_102) - - [Failure testing](#@Failure_testing_103) + - [Parameters](#@Parameters_102) + - [Aborts](#@Aborts_103) + - [Emits](#@Emits_104) + - [Expected value testing](#@Expected_value_testing_105) + - [Failure testing](#@Failure_testing_106) - [Function `get_market_order_id_avl_queue_access_key`](#0xc0deb00c_market_get_market_order_id_avl_queue_access_key) - - [Testing](#@Testing_104) + - [Testing](#@Testing_107) - [Function `get_open_orders_for_side`](#0xc0deb00c_market_get_open_orders_for_side) - - [Testing](#@Testing_105) + - [Testing](#@Testing_108) - [Function `get_price_levels_for_side`](#0xc0deb00c_market_get_price_levels_for_side) - - [Testing](#@Testing_106) + - [Testing](#@Testing_109) - [Function `init_module`](#0xc0deb00c_market_init_module) - [Function `match`](#0xc0deb00c_market_match) - - [Type Parameters](#@Type_Parameters_107) - - [Parameters](#@Parameters_108) - - [Returns](#@Returns_109) - - [Emits](#@Emits_110) - - [Aborts](#@Aborts_111) - - [Expected value testing](#@Expected_value_testing_112) - - [Failure testing](#@Failure_testing_113) + - [Type Parameters](#@Type_Parameters_110) + - [Parameters](#@Parameters_111) + - [Returns](#@Returns_112) + - [Emits](#@Emits_113) + - [Aborts](#@Aborts_114) + - [Expected value testing](#@Expected_value_testing_115) + - [Failure testing](#@Failure_testing_116) - [Function `place_limit_order`](#0xc0deb00c_market_place_limit_order) - - [Type Parameters](#@Type_Parameters_114) - - [Parameters](#@Parameters_115) - - [Returns](#@Returns_116) - - [Aborts](#@Aborts_117) - - [Emits](#@Emits_118) - - [Restrictions](#@Restrictions_119) - - [Minimum size](#@Minimum_size_120) - - [Self matching](#@Self_matching_121) - - [Expected value testing](#@Expected_value_testing_122) - - [Failure testing](#@Failure_testing_123) + - [Type Parameters](#@Type_Parameters_117) + - [Parameters](#@Parameters_118) + - [Returns](#@Returns_119) + - [Aborts](#@Aborts_120) + - [Emits](#@Emits_121) + - [Restrictions](#@Restrictions_122) + - [Minimum size](#@Minimum_size_123) + - [Self matching](#@Self_matching_124) + - [Expected value testing](#@Expected_value_testing_125) + - [Failure testing](#@Failure_testing_126) - [Function `place_limit_order_passive_advance`](#0xc0deb00c_market_place_limit_order_passive_advance) - - [Price calculations](#@Price_calculations_124) - - [Type Parameters](#@Type_Parameters_125) - - [Parameters](#@Parameters_126) - - [Returns](#@Returns_127) - - [Aborts](#@Aborts_128) - - [Expected value testing](#@Expected_value_testing_129) - - [Failure testing](#@Failure_testing_130) + - [Price calculations](#@Price_calculations_127) + - [Type Parameters](#@Type_Parameters_128) + - [Parameters](#@Parameters_129) + - [Returns](#@Returns_130) + - [Aborts](#@Aborts_131) + - [Expected value testing](#@Expected_value_testing_132) + - [Failure testing](#@Failure_testing_133) - [Function `place_market_order`](#0xc0deb00c_market_place_market_order) - - [Type Parameters](#@Type_Parameters_131) - - [Parameters](#@Parameters_132) - - [Returns](#@Returns_133) - - [Aborts](#@Aborts_134) - - [Expected value testing](#@Expected_value_testing_135) - - [Failure testing](#@Failure_testing_136) + - [Type Parameters](#@Type_Parameters_134) + - [Parameters](#@Parameters_135) + - [Returns](#@Returns_136) + - [Aborts](#@Aborts_137) + - [Expected value testing](#@Expected_value_testing_138) + - [Failure testing](#@Failure_testing_139) - [Function `range_check_trade`](#0xc0deb00c_market_range_check_trade) - - [Terminology](#@Terminology_137) - - [Parameters](#@Parameters_138) - - [Aborts](#@Aborts_139) - - [Failure testing](#@Failure_testing_140) + - [Terminology](#@Terminology_140) + - [Parameters](#@Parameters_141) + - [Aborts](#@Aborts_142) + - [Failure testing](#@Failure_testing_143) - [Function `register_market`](#0xc0deb00c_market_register_market) - - [Type parameters](#@Type_parameters_141) - - [Parameters](#@Parameters_142) - - [Returns](#@Returns_143) - - [Testing](#@Testing_144) + - [Type parameters](#@Type_parameters_144) + - [Parameters](#@Parameters_145) + - [Returns](#@Returns_146) + - [Testing](#@Testing_147) - [Function `swap`](#0xc0deb00c_market_swap) - - [Type Parameters](#@Type_Parameters_145) - - [Parameters](#@Parameters_146) - - [Returns](#@Returns_147) - - [Aborts](#@Aborts_148) - - [Expected value testing](#@Expected_value_testing_149) - - [Failure testing](#@Failure_testing_150) + - [Type Parameters](#@Type_Parameters_148) + - [Parameters](#@Parameters_149) + - [Returns](#@Returns_150) + - [Aborts](#@Aborts_151) + - [Expected value testing](#@Expected_value_testing_152) + - [Failure testing](#@Failure_testing_153) - [Function `index_orders_sdk`](#0xc0deb00c_market_index_orders_sdk) - - [Coverage testing](#@Coverage_testing_151) + - [Coverage testing](#@Coverage_testing_154)
use 0x1::account;
@@ -856,6 +867,7 @@ The below index is automatically generated from source code:
 use 0x1::string;
 use 0x1::table;
 use 0x1::type_info;
+use 0x1::vector;
 use 0xc0deb00c::avl_queue;
 use 0xc0deb00c::incentives;
 use 0xc0deb00c::registry;
@@ -882,11 +894,11 @@ The below index is automatically generated from source code:
 
 ## Struct `FillEvent`
 
-Emitted each time an order fills as a taker. If an order results
-in multiple fills, a separate event is emitted for each one.
+Emitted for each order fill. If an order results in multiple
+fills, a separate event is emitted for each one.
 
 
-
struct FillEvent has drop, store
+
struct FillEvent has copy, drop, store
 
@@ -902,19 +914,6 @@ in multiple fills, a separate event is emitted for each one. Market ID of corresponding market.
-order_book_counter: u64 -
-
- Order book counter at time of fill, incremented for each - order placed on the book. If an order results in multiple - FillEvents, they will all have the same - FillEvent.order_book_counter. If a limit order crosses the - spread and fills first as a taker before posting to the book - as a maker, the FillEvent.order_book_counter field for - each fill is identical to the counter encoded in the - corresponding MakerEvent.market_order_id. -
-
size: u64
@@ -936,7 +935,7 @@ in multiple fills, a separate event is emitted for each one. maker_market_order_id: u128
- Maket order ID of maker order just filled against. + Market order ID of for maker order just filled against.
maker: address @@ -951,6 +950,18 @@ in multiple fills, a separate event is emitted for each one. For given maker, ID of custodian required to approve order operations and withdrawals on given market account. +
+taker_market_order_id: u128 +
+
+ Market order ID for taker side of fill. If multiple + FillEvent(s) are emitted for a single order, they all have + the same FillEvent.taker_order_id. If a limit order that + crosses the spread partially fills as a taker then posts as + a maker, FillEvent.taker_market_order_id for the taker + portion is identical to MakerEvent.market_order_id emitted + for the maker portion. +
@@ -985,7 +996,8 @@ upgrade. ## Struct `MakerEvent` -Emitted when a maker order is placed, cancelled, evicted, or its +Emitted when a maker order (treated as the portion of an order +that posts to the book) is placed, cancelled, evicted, or its size is manually changed. @@ -1014,7 +1026,8 @@ size is manually changed. market_order_id: u128
- Market order ID, unique within given market. + Market order ID, unique within a given market but not + necessarily across markets.
user: address @@ -1908,6 +1921,16 @@ Simulation query called by invalid account. + + +Market order ID corresponds to an order that did not post. + + +
const E_ORDER_DID_NOT_POST: u64 = 31;
+
+ + + Post-or-abort limit order price crosses spread. @@ -2111,6 +2134,43 @@ Flag for passive order specified by advance in ticks. + + +## Function `did_order_post` + +Return true if the market order ID corresponds to an order that +resulted in a post to the order book (including an order that +filled across the spread as a taker before posting as a maker). + + + + +### Testing + + +* test_get_market_order_id_price_did_not_post() +* test_get_market_order_id_side_did_not_post() +* test_place_limit_order_no_cross_ask_user() +* test_place_limit_order_no_cross_bid_custodian() + + +
public fun did_order_post(market_order_id: u128): bool
+
+ + + +##### Implementation + + +
public fun did_order_post(
+    market_order_id: u128
+): bool {
+    (market_order_id & (HI_64 as u128)) != (NIL as u128)
+}
+
+ + + ## Function `get_ABORT` @@ -2118,7 +2178,7 @@ Flag for passive order specified by advance in ticks. Public constant getter for ABORT. - + ### Testing @@ -2146,7 +2206,7 @@ Public constant getter for ABO Public constant getter for ASK. - + ### Testing @@ -2175,7 +2235,7 @@ Public constant getter for ASKBID. - + ### Testing @@ -2204,7 +2264,7 @@ Public constant getter for BIDBUY. - + ### Testing @@ -2233,7 +2293,7 @@ Public constant getter for BUYCANCEL_BOTH. - + ### Testing @@ -2261,7 +2321,7 @@ Public constant getter for CANCEL_MAKER. - + ### Testing @@ -2289,7 +2349,7 @@ Public constant getter for CANCEL_TAKER. - + ### Testing @@ -2317,7 +2377,7 @@ Public constant getter for FILL_OR_ABORT. - + ### Testing @@ -2345,7 +2405,7 @@ Public constant getter for HI_PRICE. - + ### Testing @@ -2373,7 +2433,7 @@ Public constant getter for Public constant getter for IMMEDIATE_OR_CANCEL. - + ### Testing @@ -2401,7 +2461,7 @@ Public constant getter for MAX_POSSIBLE. - + ### Testing @@ -2429,7 +2489,7 @@ Public constant getter for NO_CUSTODIAN. - + ### Testing @@ -2457,7 +2517,7 @@ Public constant getter for NO_RESTRICTION. - + ### Testing @@ -2485,7 +2545,7 @@ Public constant getter for NO_UNDERWRITER. - + ### Testing @@ -2513,7 +2573,7 @@ Public constant getter for POST_OR_ABORT. - + ### Testing @@ -2541,7 +2601,7 @@ Public constant getter for PERCENT. - + ### Testing @@ -2569,7 +2629,7 @@ Public constant getter for P Public constant getter for SELL. - + ### Testing @@ -2598,7 +2658,7 @@ Public constant getter for SELL Public constant getter for TICKS. - + ### Testing @@ -2626,7 +2686,7 @@ Public constant getter for TIC Return order counter encoded in market order ID. - + ### Testing @@ -2656,14 +2716,27 @@ Return order counter encoded in market order ID. ## Function `get_market_order_id_price` -Return order price encoded in market order ID. +For an order that resulted in a post to the order book, return +the order price encoded in its market order ID, corresponding to +the price that the maker portion of the order posted to the book +at. - + + +### Aborts + + +* E_ORDER_DID_NOT_POST: market order ID corresponds to an +order that did not post to the book. + + + ### Testing +* test_get_market_order_id_price_did_not_post() * test_place_limit_order_no_cross_ask_user() * test_place_limit_order_no_cross_bid_custodian() @@ -2679,6 +2752,9 @@ Return order price encoded in market order ID.
public fun get_market_order_id_price(
     market_order_id: u128
 ): u64 {
+    // Assert order posted to the order book.
+    assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST);
+    // Extract encoded price.
     ((market_order_id & (HI_PRICE as u128)) as u64)
 }
 
@@ -2689,14 +2765,27 @@ Return order price encoded in market order ID. ## Function `get_market_order_id_side` -Return order side encoded in market order ID. +For an order that resulted in a post to the order book, return +the order side encoded in its market order ID, corresponding to +the side that the maker portion of the order posted to the book +at. - + + +### Aborts + + +* E_ORDER_DID_NOT_POST: market order ID corresponds to an +order that did not post to the book. + + + ### Testing +* test_get_market_order_id_side_did_not_post() * test_place_limit_order_no_cross_ask_user() * test_place_limit_order_no_cross_bid_custodian() @@ -2712,6 +2801,8 @@ Return order side encoded in market order ID.
public fun get_market_order_id_side(
     market_order_id: u128
 ): bool {
+    // Assert order posted to the order book.
+    assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST);
     // Get AVL queue access key encoded in market order ID.
     let avlq_access_key =
         get_market_order_id_avl_queue_access_key(market_order_id);
@@ -2731,7 +2822,7 @@ Return OrderView
+
 
 ### Aborts
 
@@ -2740,7 +2831,7 @@ Mutates state, so kept as a private view function.
 indicated market.
 
 
-
+
 
 ### Testing
 
@@ -2803,7 +2894,7 @@ Vectors sorted by price-time priority per 
+
 
 ### Parameters
 
@@ -2813,7 +2904,7 @@ Mutates state, so kept as a private view function.
 * n_bids_max: Maximum number of bids to index.
 
 
-
+
 
 ### Aborts
 
@@ -2821,7 +2912,7 @@ Mutates state, so kept as a private view function.
 * E_INVALID_MARKET_ID: No market with given ID.
 
 
-
+
 
 ### Testing
 
@@ -2873,7 +2964,7 @@ Wrapped call to get_
 on both sides.
 
 
-
+
 
 ### Testing
 
@@ -2910,7 +3001,7 @@ Vectors sorted by price priority per 
+
 
 ### Parameters
 
@@ -2922,7 +3013,7 @@ index.
 index.
 
 
-
+
 
 ### Testing
 
@@ -2975,7 +3066,7 @@ Wrapped call to get
 levels on both sides.
 
 
-
+
 
 ### Testing
 
@@ -3011,7 +3102,7 @@ given market_id.
 Kept private to prevent runtime order book state contention.
 
 
-
+
 
 ### Testing
 
@@ -3080,7 +3171,7 @@ Public function wrapper for 
+
 
 ### Invocation testing
 
@@ -3120,7 +3211,7 @@ Public function wrapper for 
+
 
 ### Invocation testing
 
@@ -3162,7 +3253,7 @@ Public function wrapper for 
+
 
 ### Invocation testing
 
@@ -3206,7 +3297,7 @@ Public function wrapper for 
+
 
 ### Invocation and return testing
 
@@ -3272,7 +3363,7 @@ Public function wrapper for
 authority of delegated custodian.
 
 
-
+
 
 ### Invocation and return testing
 
@@ -3331,7 +3422,7 @@ Public function wrapper for
 authority of signing user.
 
 
-
+
 
 ### Invocation and return testing
 
@@ -3395,7 +3486,7 @@ Public function wrapper for 
+
 
 ### Invocation and return testing
 
@@ -3466,7 +3557,7 @@ Public function wrapper for 
+
 
 ### Invocation and return testing
 
@@ -3523,7 +3614,7 @@ Public function wrapper for 
+
 
 ### Invocation and return testing
 
@@ -3580,7 +3671,7 @@ Register pure coin market, return resultant market ID.
 See inner function register_market().
 
 
-
+
 
 ### Type parameters
 
@@ -3591,7 +3682,7 @@ See inner function r
 incentives::IncentiveParameters.utility_coin_type_info.
 
 
-
+
 
 ### Parameters
 
@@ -3603,7 +3694,7 @@ See inner function r
 incentives::IncentiveParameters.market_registration_fee.
 
 
-
+
 
 ### Returns
 
@@ -3611,7 +3702,7 @@ See inner function r
 * u64: Market ID for new market.
 
 
-
+
 
 ### Testing
 
@@ -3667,7 +3758,7 @@ Generic base name restrictions described at
 registry::register_market_base_generic_internal().
 
 
-
+
 
 ### Type parameters
 
@@ -3677,7 +3768,7 @@ Generic base name restrictions described at
 incentives::IncentiveParameters.utility_coin_type_info.
 
 
-
+
 
 ### Parameters
 
@@ -3693,7 +3784,7 @@ for market.
 underwriter capability.
 
 
-
+
 
 ### Returns
 
@@ -3701,7 +3792,7 @@ underwriter capability.
 * u64: Market ID for new market.
 
 
-
+
 
 ### Testing
 
@@ -3756,7 +3847,7 @@ Initializes an aptos_framework::coin::CoinStore for each coin
 type that does not yet have one.
 
 
-
+
 
 ### Type Parameters
 
@@ -3765,7 +3856,7 @@ type that does not yet have one.
 * QuoteType: Same as for match().
 
 
-
+
 
 ### Parameters
 
@@ -3784,7 +3875,7 @@ for coin store.
 * limit_price: Same as for match().
 
 
-
+
 
 ### Returns
 
@@ -3794,7 +3885,7 @@ for coin store.
 * u64: Quote coin fees paid, same as for match().
 
 
-
+
 
 ### Testing
 
@@ -3899,7 +3990,7 @@ intermediate quote match overflow that could occur prior to fee
 assessment.
 
 
-
+
 
 ### Type Parameters
 
@@ -3908,7 +3999,7 @@ assessment.
 * QuoteType: Same as for match().
 
 
-
+
 
 ### Parameters
 
@@ -3930,7 +4021,7 @@ unpacked.
 * quote_coins: Same as for match().
 
 
-
+
 
 ### Returns
 
@@ -3944,7 +4035,7 @@ unpacked.
 * u64: Quote coin fees paid, same as for match().
 
 
-
+
 
 ### Terminology
 
@@ -3955,7 +4046,7 @@ coins in the case of a buy, quote coins in the case of a sell.
 the case of a buy, base coins in the case of a sell.
 
 
-
+
 
 ### Testing
 
@@ -4057,7 +4148,7 @@ intermediate quote match overflow that could occur prior to fee
 assessment.
 
 
-
+
 
 ### Type Parameters
 
@@ -4065,7 +4156,7 @@ assessment.
 * QuoteType: Same as for match().
 
 
-
+
 
 ### Parameters
 
@@ -4085,7 +4176,7 @@ possible amount for passed coin holdings.
 underwriter capability for given market.
 
 
-
+
 
 ### Returns
 
@@ -4097,7 +4188,7 @@ underwriter capability for given market.
 * u64: Quote coin fees paid, same as for match().
 
 
-
+
 
 ### Testing
 
@@ -4190,7 +4281,7 @@ Public entry function wrapper for 
+
 
 ### Invocation testing
 
@@ -4229,7 +4320,7 @@ Public entry function wrapper for 
+
 
 ### Invocation testing
 
@@ -4270,7 +4361,7 @@ Public entry function wrapper for 
+
 
 ### Invocation testing
 
@@ -4313,7 +4404,7 @@ Public entry function wrapper for
 place_limit_order_passive_advance_user().
 
 
-
+
 
 ### Invocation testing
 
@@ -4367,7 +4458,7 @@ Public entry function wrapper for
 Public entry function wrapper for place_limit_order_user().
 
 
-
+
 
 ### Invocation testing
 
@@ -4414,7 +4505,7 @@ Public entry function wrapper for place_market_order_user().
 
 
-
+
 
 ### Invocation testing
 
@@ -4459,7 +4550,7 @@ Wrapped call to 
+
 
 ### Testing
 
@@ -4505,7 +4596,7 @@ coins from an aptos_framework::coin::CoinStore.
 Public entry function wrapper for swap_between_coinstores().
 
 
-
+
 
 ### Invocation testing
 
@@ -4554,7 +4645,7 @@ Public entry function wrapper for 
+
 
 ### Parameters
 
@@ -4565,7 +4656,7 @@ Cancel all of a user's open maker orders.
 * side: Same as for cancel_order().
 
 
-
+
 
 ### Expected value testing
 
@@ -4618,7 +4709,7 @@ verified against the order access key derived from the AVL queue
 removal operation.
 
 
-
+
 
 ### Parameters
 
@@ -4630,7 +4721,7 @@ removal operation.
 * market_order_id: Market order ID of order on order book.
 
 
-
+
 
 ### Aborts
 
@@ -4644,7 +4735,7 @@ on book having given market order ID.
 custodian ID of order on order book having market order ID.
 
 
-
+
 
 ### Emits
 
@@ -4652,7 +4743,7 @@ custodian ID of order on order book having market order ID.
 * MakerEvent: Information about the maker order cancelled.
 
 
-
+
 
 ### Expected value testing
 
@@ -4661,7 +4752,7 @@ custodian ID of order on order book having market order ID.
 * test_cancel_order_bid_user()
 
 
-
+
 
 ### Failure testing
 
@@ -4744,7 +4835,7 @@ again verified against the order access key derived from the AVL
 queue borrow operation.
 
 
-
+
 
 ### Parameters
 
@@ -4757,7 +4848,7 @@ queue borrow operation.
 * new_size: The new order size to change to.
 
 
-
+
 
 ### Aborts
 
@@ -4771,7 +4862,7 @@ on book having given market order ID.
 custodian ID of order on order book having market order ID.
 
 
-
+
 
 ### Emits
 
@@ -4779,7 +4870,7 @@ custodian ID of order on order book having market order ID.
 * MakerEvent: Information about the changed maker order.
 
 
-
+
 
 ### Expected value testing
 
@@ -4789,7 +4880,7 @@ custodian ID of order on order book having market order ID.
 * test_change_order_size_bid_user_new_tail()
 
 
-
+
 
 ### Failure testing
 
@@ -4898,7 +4989,7 @@ custodian ID of order on order book having market order ID.
 Get AVL queue access key encoded in market_order_id.
 
 
-
+
 
 ### Testing
 
@@ -4931,7 +5022,7 @@ Index specified number of open orders for given side of order
 book.
 
 
-
+
 
 ### Testing
 
@@ -4986,7 +5077,7 @@ Index specified number of price levels for given side of order
 book.
 
 
-
+
 
 ### Testing
 
@@ -5089,7 +5180,7 @@ assesses taker fees. Matches up until the point of a self match,
 then proceeds according to specified self match behavior.
 
 
-
+
 
 ### Type Parameters
 
@@ -5099,7 +5190,7 @@ then proceeds according to specified self match behavior.
 * QuoteType: Quote coin type for market.
 
 
-
+
 
 ### Parameters
 
@@ -5107,6 +5198,12 @@ then proceeds according to specified self match behavior.
 * market_id: Market ID of market.
 * resource_address: Address of resource account where order
 books and fill event handles are stored.
+* fill_event_queue_option_ref_mut: Mutable reference to
+optional queue for FillEvents, used to defer event emission
+for limit orders: if a limit order fills across the spread
+before posting to the order book, the market order ID requires
+an encoded AVL queue access key that is not known at the time
+of fills.
 * order_book_ref_mut: Mutable reference to market order book.
 * taker: Address of taker whose order is matched. Passed as
 NO_MARKET_ACCOUNT when taker order originates from a swap.
@@ -5146,7 +5243,7 @@ decremented if direction is SELL.
 
 
-
+
 
 ### Returns
 
@@ -5164,16 +5261,16 @@ net change in taker's quote coin holdings.
 * bool: true if a self match that results in a taker cancel.
 
 
-
+
 
 ### Emits
 
 
-* FillEvent: Information about a fill against a maker order,
-emitted for each separate maker order that is filled against.
+* FillEvent: Information about a fill, emitted for each fill,
+when fill events are not marked for deferral.
 
 
-
+
 
 ### Aborts
 
@@ -5192,7 +5289,7 @@ requirement not met.
 requirement not met.
 
 
-
+
 
 ### Expected value testing
 
@@ -5211,7 +5308,7 @@ requirement not met.
 * test_match_self_match_cancel_taker()
 
 
-
+
 
 ### Failure testing
 
@@ -5224,7 +5321,7 @@ requirement not met.
 * test_match_self_match_invalid()
 
 
-
fun match<BaseType, QuoteType>(market_id: u64, resource_address: address, order_book_ref_mut: &mut market::OrderBook, taker: address, custodian_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, self_match_behavior: u8, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, bool)
+
fun match<BaseType, QuoteType>(market_id: u64, resource_address: address, fill_event_queue_option_ref_mut: &mut option::Option<vector<market::FillEvent>>, order_book_ref_mut: &mut market::OrderBook, taker: address, custodian_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, self_match_behavior: u8, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, bool)
 
@@ -5238,6 +5335,7 @@ requirement not met. >( market_id: u64, resource_address: address, + fill_event_queue_option_ref_mut: &mut Option<vector<FillEvent>>, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -5281,12 +5379,16 @@ requirement not met. // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; - // Mutably borrow fill event handles map. - let fill_event_handles_map_ref_mut = - &mut borrow_global_mut<FillEventHandles>(resource_address).map; - // Mutably borrow fill event handle for market. - let fill_event_handle_ref_mut = - table::borrow_mut(fill_event_handles_map_ref_mut, market_id); + // Determine if fill events should be deferred into a queue. + let defer_events = option::is_some(fill_event_queue_option_ref_mut); + // If should defer events, mutably borrow event queue: + let event_queue_ref_mut = if (defer_events) + option::borrow_mut(fill_event_queue_option_ref_mut) else + &mut vector[]; // Otherwise mutably borrow null vector. + // Mutably borrow fill event handle: + let fill_event_handle_ref_mut = table::borrow_mut( + &mut borrow_global_mut<FillEventHandles>(resource_address).map, + market_id); // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; // While there are orders to match against: @@ -5381,12 +5483,16 @@ requirement not met. fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - // Emit corresponding fill event. - event::emit_event(fill_event_handle_ref_mut, FillEvent{ - market_id, order_book_counter: order_book_ref_mut.counter, - size: fill_size, price, maker_side: side, + let fill_event = FillEvent{ // Create fill event. + market_id, size: fill_size, price, maker_side: side, maker_market_order_id: market_order_id, maker, - maker_custodian_id: custodian_id}); + maker_custodian_id: custodian_id, taker_market_order_id: + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER)}; + // If should defer events, push pack event onto queue: + if (defer_events) + vector::push_back(event_queue_ref_mut, fill_event) else + // Otherwise emit event. + event::emit_event(fill_event_handle_ref_mut, fill_event); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -5435,7 +5541,7 @@ requirement not met. Place limit order against order book from user market account. - + ### Type Parameters @@ -5444,7 +5550,7 @@ Place limit order against order book from user market account. * QuoteType: Same as for match(). - + ### Parameters @@ -5466,7 +5572,7 @@ may take place. Should only be passed as + ### Returns @@ -5481,7 +5587,7 @@ was placed. Else NIL. if order fills across the spread. - + ### Aborts @@ -5510,11 +5616,13 @@ price-time priority if inserted to AVL queue, but AVL queue does not have room for any more orders. - + ### Emits +* FillEvent: Information about the portion of the order that +fills as a taker, if the order fills across the spread. * MakerEvent: Information about the user's maker order placed on the order book, if one was placed. * MakerEvent: Information about the maker order evicted from @@ -5522,7 +5630,7 @@ the order book, if required to fit user's maker order on the book. - + ### Restrictions @@ -5536,7 +5644,7 @@ amount is not filled. then returns. - + ### Minimum size @@ -5546,7 +5654,7 @@ left as a maker, minimum order size condition must be met again for the maker portion. - + ### Self matching @@ -5560,7 +5668,7 @@ restriction, and 3. Self match behavior indicates taker cancellation. - + ### Expected value testing @@ -5579,7 +5687,7 @@ restriction, and * test_place_limit_order_still_crosses_bid() - + ### Failure testing @@ -5718,7 +5826,9 @@ restriction, and base_available, base_ceiling, quote_available, quote_ceiling); // Assume no assets traded as a taker. let (base_traded, quote_traded, fees) = (0, 0, 0); - if (crosses_spread) { // If order price crosses spread: + // Evaluate any potential fills across the spread, which may + // result in deferred fill events: + let fill_event_queue = if (crosses_spread) { // Calculate max base and quote to withdraw. If a buy: let (base_withdraw, quote_withdraw) = if (direction == BUY) // Withdraw quote to buy base, else sell base for quote. @@ -5731,16 +5841,18 @@ restriction, and quote_withdraw, underwriter_id); // Declare return assignment variable. let self_match_cancel; + // Declare empty fill event queue inside of an option. + let fill_event_queue_option = option::some(vector[]); // Match against order book, storing optionally modified // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of // the order. (Increments order book counter). (optional_base_coins, quote_coins, base_traded, quote_traded, fees, self_match_cancel) = match( - market_id, resource_address, order_book_ref_mut, user_address, - custodian_id, integrator, direction, min_base, max_base, - min_quote, max_quote, price, self_match_behavior, - optional_base_coins, quote_coins); + market_id, resource_address, &mut fill_event_queue_option, + order_book_ref_mut, user_address, custodian_id, integrator, + direction, min_base, max_base, min_quote, max_quote, price, + self_match_behavior, optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -5763,16 +5875,31 @@ restriction, and size = if (still_crosses_spread || self_match_cancel) 0 else // Else update size to amount left to fill post-match. size - (base_traded / order_book_ref_mut.lot_size); + // Extract fill event queue packed by matching engine. + option::extract(&mut fill_event_queue_option) } else { // If spread not crossed (matching engine not called): // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + vector[] // There are no fill events to defer. }; - // Return without market order ID if immediate-or-cancel or if - // remaining size to fill after matching does not meet minimum - // size requirement for market. + // Determine if there are fill events to emit. + let fill_events_to_emit = !vector::is_empty(&fill_event_queue); + // Mutably borrow fill event handle: + let fill_event_handle_ref_mut = table::borrow_mut( + &mut borrow_global_mut<FillEventHandles>(resource_address).map, + market_id); + // If immediate-or-cancel or if remaining size to fill after + // matching does not meet minimum size requirement for market: if ((restriction == IMMEDIATE_OR_CANCEL) || - (size < order_book_ref_mut.min_size)) - return ((NIL as u128), base_traded, quote_traded, fees); + (size < order_book_ref_mut.min_size)) { + if (fill_events_to_emit) // If fill events are enqueued: + vector::for_each_ref(&fill_event_queue, |fill_event_ref| { + event::emit_event(fill_event_handle_ref_mut, + *fill_event_ref); + }); // Emit each fill event (first-in-first-out): + // Return without posting. + return ((NIL as u128), base_traded, quote_traded, fees) + }; // Get next order access key for user-side order placement. let order_access_key = user::get_next_order_access_key_internal( user_address, market_id, custodian_id, side); @@ -5792,6 +5919,19 @@ restriction, and // Get market order ID from AVL queue access key, counter. let market_order_id = (avlq_access_key as u128) | ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + // If fill events have been deferred: + if (fill_events_to_emit) { + // For each fill event (first-in-first-out): + vector::for_each_ref(&fill_event_queue, |fill_event_ref| { + // Get a copy of the fill event. + let fill_event: FillEvent = *fill_event_ref; + // Re-assign common market order ID generated from + // portion of order that posts as a maker. + fill_event.taker_market_order_id = market_order_id; + // Emit event. + event::emit_event(fill_event_handle_ref_mut, fill_event); + }) + }; user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, market_order_id, order_access_key); @@ -5853,7 +5993,7 @@ order that aborts for a self match. Advance price is then range-checked by place_limit_order(). - + ### Price calculations @@ -5865,7 +6005,7 @@ operation during the advance amount calculation for the percent case. - + ### Type Parameters @@ -5874,7 +6014,7 @@ case. * QuoteType: Same as for match(). - + ### Parameters @@ -5893,7 +6033,7 @@ percent of the spread to advance, else the number of ticks to advance. - + ### Returns @@ -5901,7 +6041,7 @@ advance. * u128: Market order ID, same as for place_limit_order(). - + ### Aborts @@ -5913,7 +6053,7 @@ advance. target_advance_amount is not less than or equal to 100. - + ### Expected value testing @@ -5929,7 +6069,7 @@ advance. * test_place_limit_order_passive_advance_ticks_bid() - + ### Failure testing @@ -6069,7 +6209,7 @@ advance. Place market order against order book from user market account. - + ### Type Parameters @@ -6078,7 +6218,7 @@ Place market order against order book from user market account. * QuoteType: Same as for match(). - + ### Parameters @@ -6092,7 +6232,7 @@ Place market order against order book from user market account. * self_match_behavior: Same as for match(). - + ### Returns @@ -6102,7 +6242,7 @@ Place market order against order book from user market account. * u64: Quote coin fees paid, same as for match(). - + ### Aborts @@ -6113,7 +6253,7 @@ Place market order against order book from user market account. size for market. - + ### Expected value testing @@ -6125,7 +6265,7 @@ size for market. * test_place_market_order_max_quote_sell_user() - + ### Failure testing @@ -6222,10 +6362,11 @@ size for market. // Match against order book, storing optionally modified asset // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match(market_id, resource_address, order_book_ref_mut, - user_address, custodian_id, integrator, direction, - min_base, max_base, min_quote, max_quote, limit_price, - self_match_behavior, optional_base_coins, quote_coins); + _) = match( + market_id, resource_address, &mut option::none(), + order_book_ref_mut, user_address, custodian_id, integrator, + direction, min_base, max_base, min_quote, max_quote, limit_price, + self_match_behavior, optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -6249,7 +6390,7 @@ Range check minimum and maximum asset trade amounts. Should be called before match(). - + ### Terminology @@ -6272,7 +6413,7 @@ user's aptos_framework::coin::CoinStore or from standalone coins, is the same as available amount. - + ### Parameters @@ -6293,7 +6434,7 @@ trade. SELL. - + ### Aborts @@ -6309,7 +6450,7 @@ received from trade. * E_NOT_ENOUGH_ASSET_OUT: Not enough asset to trade away. - + ### Failure testing @@ -6383,7 +6524,7 @@ See registry::MarketI size, minimum size, and 32-bit prices. - + ### Type parameters @@ -6392,7 +6533,7 @@ size, minimum size, and 32-bit prices. * QuoteType: Quote coin type for market. - + ### Parameters @@ -6406,7 +6547,7 @@ for market. * underwriter_id: registry::MarketInfo.min_size for market. - + ### Returns @@ -6414,7 +6555,7 @@ for market. * u64: Market ID for new market. - + ### Testing @@ -6497,7 +6638,7 @@ for market. Match a taker's swap order against order book for given market. - + ### Type Parameters @@ -6506,7 +6647,7 @@ Match a taker's swap order against order book for given market. * QuoteType: Same as for match(). - + ### Parameters @@ -6526,7 +6667,7 @@ is registry::Generi * quote_coins: Same as for match(). - + ### Returns @@ -6540,7 +6681,7 @@ same as for match() * u64: Quote coin fees paid, same as for match(). - + ### Aborts @@ -6551,7 +6692,7 @@ same as for match() * E_INVALID_QUOTE: Quote asset type is invalid. - + ### Expected value testing @@ -6560,7 +6701,7 @@ same as for match() swap_generic() testing. - + ### Failure testing @@ -6624,11 +6765,12 @@ same as for match() // Declare return assignment variables. let (base_traded, quote_traded, fees); (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) - = match<BaseType, QuoteType>( // Match against order book. - market_id, resource_address, order_book_ref_mut, - NO_MARKET_ACCOUNT, NO_CUSTODIAN, integrator, direction, - min_base, max_base, min_quote, max_quote, limit_price, ABORT, - optional_base_coins, quote_coins); + = match( // Match against order book. + market_id, resource_address, &mut option::none(), + order_book_ref_mut, NO_MARKET_ACCOUNT, NO_CUSTODIAN, + integrator, direction, min_base, max_base, min_quote, + max_quote, limit_price, ABORT, optional_base_coins, + quote_coins); // Return optionally modified asset inputs, trade amounts, fees. (optional_base_coins, quote_coins, base_traded, quote_traded, fees) } @@ -6643,7 +6785,7 @@ same as for match() Deprecated function retained for backwards compatibility. - + ### Coverage testing diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 67b629423..775b56945 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -21,11 +21,15 @@ /// order management function, to enable diagnostic function returns, /// public entry calls, etc. /// -/// When a maker places a limit order that posts against the book, they -/// are issued a "market order ID" that is unique to the given market. -/// The maker order price is encoded in the market order ID, as well as -/// a counter for the number of orders that have been placed for the -/// corresponding market. +/// When someone places an order that result in one or more fills and/or +/// a post to the book, they are issued a "market order ID" that is +/// unique to the given market but not necessarily across different +/// markets. Each market order ID encodes a counter for the number of +/// orders that have been placed on the corresponding market. For orders +/// that result in a post to the book, the market order ID additionally +/// encodes an "AVL queue access key" (essentially a pointer into +/// order book memory), which is required for order lookup during order +/// size change and/or order cancellation operations. /// /// # General overview sections /// @@ -84,6 +88,7 @@ /// /// ## Market order ID decoders /// +/// * `did_order_post()` /// * `get_market_order_id_counter()` /// * `get_market_order_id_price()` /// * `get_market_order_id_side()` @@ -291,6 +296,8 @@ /// has_open_order --> get_market_order_id_avl_queue_access_key /// get_open_orders --> get_open_orders_for_side /// get_open_orders_all --> get_open_orders +/// get_market_order_id_price --> did_order_post +/// get_market_order_id_side --> did_order_post /// /// ``` /// @@ -555,33 +562,32 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /// Emitted each time an order fills as a taker. If an order results - /// in multiple fills, a separate event is emitted for each one. - struct FillEvent has drop, store { + /// Emitted for each order fill. If an order results in multiple + /// fills, a separate event is emitted for each one. + struct FillEvent has copy, drop, store { /// Market ID of corresponding market. market_id: u64, - /// Order book counter at time of fill, incremented for each - /// order placed on the book. If an order results in multiple - /// `FillEvent`s, they will all have the same - /// `FillEvent.order_book_counter`. If a limit order crosses the - /// spread and fills first as a taker before posting to the book - /// as a maker, the `FillEvent.order_book_counter` field for - /// each fill is identical to the counter encoded in the - /// corresponding `MakerEvent.market_order_id`. - order_book_counter: u64, /// The size filled, in lots. size: u64, /// Fill price, in ticks per lot. price: u64, /// `ASK` or `BID`, the side of the maker order filled against. maker_side: bool, - /// Maket order ID of maker order just filled against. + /// Market order ID of for maker order just filled against. maker_market_order_id: u128, /// Address of user holding maker order. maker: address, /// For given maker, ID of custodian required to approve order /// operations and withdrawals on given market account. - maker_custodian_id: u64 + maker_custodian_id: u64, + /// Market order ID for taker side of fill. If multiple + /// `FillEvent`(s) are emitted for a single order, they all have + /// the same `FillEvent.taker_order_id`. If a limit order that + /// crosses the spread partially fills as a taker then posts as + /// a maker, `FillEvent.taker_market_order_id` for the taker + /// portion is identical to `MakerEvent.market_order_id` emitted + /// for the maker portion. + taker_market_order_id: u128 } /// Map of `FillEvent` handles, implemented as a replacement for @@ -592,14 +598,16 @@ module econia::market { map: Table> } - /// Emitted when a maker order is placed, cancelled, evicted, or its + /// Emitted when a maker order (treated as the portion of an order + /// that posts to the book) is placed, cancelled, evicted, or its /// size is manually changed. struct MakerEvent has drop, store { /// Market ID of corresponding market. market_id: u64, /// `ASK` or `BID`, the side of the maker order. side: bool, - /// Market order ID, unique within given market. + /// Market order ID, unique within a given market but not + /// necessarily across markets. market_order_id: u128, /// Address of user holding maker order. user: address, @@ -787,6 +795,8 @@ module econia::market { /// Order size change requiring insertion resulted in an AVL queue /// access key mismatch. const E_SIZE_CHANGE_INSERTION_ERROR: u64 = 30; + /// Market order ID corresponds to an order that did not post. + const E_ORDER_DID_NOT_POST: u64 = 31; // Error codes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -863,6 +873,23 @@ module econia::market { // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #[view] + /// Return true if the market order ID corresponds to an order that + /// resulted in a post to the order book (including an order that + /// filled across the spread as a taker before posting as a maker). + /// + /// # Testing + /// + /// * `test_get_market_order_id_price_did_not_post()` + /// * `test_get_market_order_id_side_did_not_post()` + /// * `test_place_limit_order_no_cross_ask_user()` + /// * `test_place_limit_order_no_cross_bid_custodian()` + public fun did_order_post( + market_order_id: u128 + ): bool { + (market_order_id & (HI_64 as u128)) != (NIL as u128) + } + #[view] /// Public constant getter for `ABORT`. /// @@ -1025,28 +1052,51 @@ module econia::market { } #[view] - /// Return order price encoded in market order ID. + /// For an order that resulted in a post to the order book, return + /// the order price encoded in its market order ID, corresponding to + /// the price that the maker portion of the order posted to the book + /// at. + /// + /// # Aborts + /// + /// * `E_ORDER_DID_NOT_POST`: market order ID corresponds to an + /// order that did not post to the book. /// /// # Testing /// + /// * `test_get_market_order_id_price_did_not_post()` /// * `test_place_limit_order_no_cross_ask_user()` /// * `test_place_limit_order_no_cross_bid_custodian()` public fun get_market_order_id_price( market_order_id: u128 ): u64 { + // Assert order posted to the order book. + assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST); + // Extract encoded price. ((market_order_id & (HI_PRICE as u128)) as u64) } #[view] - /// Return order side encoded in market order ID. + /// For an order that resulted in a post to the order book, return + /// the order side encoded in its market order ID, corresponding to + /// the side that the maker portion of the order posted to the book + /// at. + /// + /// # Aborts + /// + /// * `E_ORDER_DID_NOT_POST`: market order ID corresponds to an + /// order that did not post to the book. /// /// # Testing /// + /// * `test_get_market_order_id_side_did_not_post()` /// * `test_place_limit_order_no_cross_ask_user()` /// * `test_place_limit_order_no_cross_bid_custodian()` public fun get_market_order_id_side( market_order_id: u128 ): bool { + // Assert order posted to the order book. + assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST); // Get AVL queue access key encoded in market order ID. let avlq_access_key = get_market_order_id_avl_queue_access_key(market_order_id); @@ -2598,6 +2648,12 @@ module econia::market { /// * `market_id`: Market ID of market. /// * `resource_address`: Address of resource account where order /// books and fill event handles are stored. + /// * `fill_event_queue_option_ref_mut`: Mutable reference to + /// optional queue for `FillEvent`s, used to defer event emission + /// for limit orders: if a limit order fills across the spread + /// before posting to the order book, the market order ID requires + /// an encoded AVL queue access key that is not known at the time + /// of fills. /// * `order_book_ref_mut`: Mutable reference to market order book. /// * `taker`: Address of taker whose order is matched. Passed as /// `NO_MARKET_ACCOUNT` when taker order originates from a swap. @@ -2652,8 +2708,8 @@ module econia::market { /// /// # Emits /// - /// * `FillEvent`: Information about a fill against a maker order, - /// emitted for each separate maker order that is filled against. + /// * `FillEvent`: Information about a fill, emitted for each fill, + /// when fill events are not marked for deferral. /// /// # Aborts /// @@ -2699,6 +2755,7 @@ module econia::market { >( market_id: u64, resource_address: address, + fill_event_queue_option_ref_mut: &mut Option>, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -2742,12 +2799,16 @@ module econia::market { // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; - // Mutably borrow fill event handles map. - let fill_event_handles_map_ref_mut = - &mut borrow_global_mut(resource_address).map; - // Mutably borrow fill event handle for market. - let fill_event_handle_ref_mut = - table::borrow_mut(fill_event_handles_map_ref_mut, market_id); + // Determine if fill events should be deferred into a queue. + let defer_events = option::is_some(fill_event_queue_option_ref_mut); + // If should defer events, mutably borrow event queue: + let event_queue_ref_mut = if (defer_events) + option::borrow_mut(fill_event_queue_option_ref_mut) else + &mut vector[]; // Otherwise mutably borrow null vector. + // Mutably borrow fill event handle: + let fill_event_handle_ref_mut = table::borrow_mut( + &mut borrow_global_mut(resource_address).map, + market_id); // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; // While there are orders to match against: @@ -2842,12 +2903,16 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - // Emit corresponding fill event. - event::emit_event(fill_event_handle_ref_mut, FillEvent{ - market_id, order_book_counter: order_book_ref_mut.counter, - size: fill_size, price, maker_side: side, + let fill_event = FillEvent{ // Create fill event. + market_id, size: fill_size, price, maker_side: side, maker_market_order_id: market_order_id, maker, - maker_custodian_id: custodian_id}); + maker_custodian_id: custodian_id, taker_market_order_id: + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER)}; + // If should defer events, push pack event onto queue: + if (defer_events) + vector::push_back(event_queue_ref_mut, fill_event) else + // Otherwise emit event. + event::emit_event(fill_event_handle_ref_mut, fill_event); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -2949,6 +3014,8 @@ module econia::market { /// /// # Emits /// + /// * `FillEvent`: Information about the portion of the order that + /// fills as a taker, if the order fills across the spread. /// * `MakerEvent`: Information about the user's maker order placed /// on the order book, if one was placed. /// * `MakerEvent`: Information about the maker order evicted from @@ -3122,7 +3189,9 @@ module econia::market { base_available, base_ceiling, quote_available, quote_ceiling); // Assume no assets traded as a taker. let (base_traded, quote_traded, fees) = (0, 0, 0); - if (crosses_spread) { // If order price crosses spread: + // Evaluate any potential fills across the spread, which may + // result in deferred fill events: + let fill_event_queue = if (crosses_spread) { // Calculate max base and quote to withdraw. If a buy: let (base_withdraw, quote_withdraw) = if (direction == BUY) // Withdraw quote to buy base, else sell base for quote. @@ -3135,16 +3204,18 @@ module econia::market { quote_withdraw, underwriter_id); // Declare return assignment variable. let self_match_cancel; + // Declare empty fill event queue inside of an option. + let fill_event_queue_option = option::some(vector[]); // Match against order book, storing optionally modified // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of // the order. (Increments order book counter). (optional_base_coins, quote_coins, base_traded, quote_traded, fees, self_match_cancel) = match( - market_id, resource_address, order_book_ref_mut, user_address, - custodian_id, integrator, direction, min_base, max_base, - min_quote, max_quote, price, self_match_behavior, - optional_base_coins, quote_coins); + market_id, resource_address, &mut fill_event_queue_option, + order_book_ref_mut, user_address, custodian_id, integrator, + direction, min_base, max_base, min_quote, max_quote, price, + self_match_behavior, optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -3167,16 +3238,31 @@ module econia::market { size = if (still_crosses_spread || self_match_cancel) 0 else // Else update size to amount left to fill post-match. size - (base_traded / order_book_ref_mut.lot_size); + // Extract fill event queue packed by matching engine. + option::extract(&mut fill_event_queue_option) } else { // If spread not crossed (matching engine not called): // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + vector[] // There are no fill events to defer. }; - // Return without market order ID if immediate-or-cancel or if - // remaining size to fill after matching does not meet minimum - // size requirement for market. + // Determine if there are fill events to emit. + let fill_events_to_emit = !vector::is_empty(&fill_event_queue); + // Mutably borrow fill event handle: + let fill_event_handle_ref_mut = table::borrow_mut( + &mut borrow_global_mut(resource_address).map, + market_id); + // If immediate-or-cancel or if remaining size to fill after + // matching does not meet minimum size requirement for market: if ((restriction == IMMEDIATE_OR_CANCEL) || - (size < order_book_ref_mut.min_size)) - return ((NIL as u128), base_traded, quote_traded, fees); + (size < order_book_ref_mut.min_size)) { + if (fill_events_to_emit) // If fill events are enqueued: + vector::for_each_ref(&fill_event_queue, |fill_event_ref| { + event::emit_event(fill_event_handle_ref_mut, + *fill_event_ref); + }); // Emit each fill event (first-in-first-out): + // Return without posting. + return ((NIL as u128), base_traded, quote_traded, fees) + }; // Get next order access key for user-side order placement. let order_access_key = user::get_next_order_access_key_internal( user_address, market_id, custodian_id, side); @@ -3196,6 +3282,19 @@ module econia::market { // Get market order ID from AVL queue access key, counter. let market_order_id = (avlq_access_key as u128) | ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + // If fill events have been deferred: + if (fill_events_to_emit) { + // For each fill event (first-in-first-out): + vector::for_each_ref(&fill_event_queue, |fill_event_ref| { + // Get a copy of the fill event. + let fill_event: FillEvent = *fill_event_ref; + // Re-assign common market order ID generated from + // portion of order that posts as a maker. + fill_event.taker_market_order_id = market_order_id; + // Emit event. + event::emit_event(fill_event_handle_ref_mut, fill_event); + }) + }; user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, market_order_id, order_access_key); @@ -3540,10 +3639,11 @@ module econia::market { // Match against order book, storing optionally modified asset // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match(market_id, resource_address, order_book_ref_mut, - user_address, custodian_id, integrator, direction, - min_base, max_base, min_quote, max_quote, limit_price, - self_match_behavior, optional_base_coins, quote_coins); + _) = match( + market_id, resource_address, &mut option::none(), + order_book_ref_mut, user_address, custodian_id, integrator, + direction, min_base, max_base, min_quote, max_quote, limit_price, + self_match_behavior, optional_base_coins, quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -3835,11 +3935,12 @@ module econia::market { // Declare return assignment variables. let (base_traded, quote_traded, fees); (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) - = match( // Match against order book. - market_id, resource_address, order_book_ref_mut, - NO_MARKET_ACCOUNT, NO_CUSTODIAN, integrator, direction, - min_base, max_base, min_quote, max_quote, limit_price, ABORT, - optional_base_coins, quote_coins); + = match( // Match against order book. + market_id, resource_address, &mut option::none(), + order_book_ref_mut, NO_MARKET_ACCOUNT, NO_CUSTODIAN, + integrator, direction, min_base, max_base, min_quote, + max_quote, limit_price, ABORT, optional_base_coins, + quote_coins); // Return optionally modified asset inputs, trade amounts, fees. (optional_base_coins, quote_coins, base_traded, quote_traded, fees) } @@ -5241,6 +5342,20 @@ module econia::market { avlq_access_key, 0); } + #[test] + #[expected_failure(abort_code = E_ORDER_DID_NOT_POST)] + /// Verify failure for market order ID corresponding to fills only. + fun test_get_market_order_id_price_did_not_post() { + get_market_order_id_price((1 as u128) << SHIFT_COUNTER); + } + + #[test] + #[expected_failure(abort_code = E_ORDER_DID_NOT_POST)] + /// Verify failure for market order ID corresponding to fills only. + fun test_get_market_order_id_side_did_not_post() { + get_market_order_id_side((1 as u128) << SHIFT_COUNTER); + } + #[test] #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for unregistered market. @@ -8194,6 +8309,8 @@ module econia::market { assert!(fees == 0, 0); // Assert counter encoded in order ID. assert!(get_market_order_id_counter(market_order_id) == 1, 0); + // Assert market order ID marked as posting. + assert!(did_order_post(market_order_id), 0); // Assert price encoded in order ID. assert!(get_market_order_id_price(market_order_id) == price, 0); // Assert side encoded in order ID. @@ -8273,6 +8390,8 @@ module econia::market { restriction, self_match_behavior, &custodian_capability); // Assert counter encoded in order ID. assert!(get_market_order_id_counter(market_order_id) == 1, 0); + // Assert market order ID marked as posting. + assert!(did_order_post(market_order_id), 0); // Assert price encoded in order ID. assert!(get_market_order_id_price(market_order_id) == price, 0); // Assert side encoded in order ID. From bac3bf2438d1dbea095f32cfcbea19bb65cb3789 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:18:30 -0700 Subject: [PATCH 04/56] Update changelog for PR linking --- doc/doc-site/docs/move/changelog.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 6582c132e..95c9c94db 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -6,21 +6,21 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] ### Added -- Assorted view functions ([#287], [#301]). -- Fill events with common order ID ([#314]). +- Assorted view functions ([#287], [#301], [#315]). +- Fill events with common market order ID ([#315]). ### Deprecated -- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#314]) +- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#315]) - [`market::Orders`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3337) ([#301]) -- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#314]) +- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#315]) - [`market::index_orders_sdk()`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3362) ([#287]) - [`move-to-ts`](https://github.com/hippospace/move-to-ts) attributes ([#292]) [#287]: https://github.com/econia-labs/econia/pull/287 [#292]: https://github.com/econia-labs/econia/pull/292 [#301]: https://github.com/econia-labs/econia/pull/301 -[#314]: https://github.com/econia-labs/econia/pull/314 +[#315]: https://github.com/econia-labs/econia/pull/315 [keep a changelog]: https://keepachangelog.com/en/1.0.0/ [semantic versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/econia-labs/econia/compare/v4.0.2-audited...HEAD From a8634fd88e26635272cc4c285d3f6a39a0900187 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 30 Jun 2023 10:27:24 -0700 Subject: [PATCH 05/56] Remove unnecessary parentheses --- src/move/econia/doc/market.md | 2 +- src/move/econia/sources/market.move | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/move/econia/doc/market.md b/src/move/econia/doc/market.md index 9de9ad60a..78267a2a4 100644 --- a/src/move/econia/doc/market.md +++ b/src/move/econia/doc/market.md @@ -955,7 +955,7 @@ fills, a separate event is emitted for each one.
Market order ID for taker side of fill. If multiple - FillEvent(s) are emitted for a single order, they all have + FillEvents are emitted for a single order, they all have the same FillEvent.taker_order_id. If a limit order that crosses the spread partially fills as a taker then posts as a maker, FillEvent.taker_market_order_id for the taker diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 775b56945..24b1c03b2 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -581,7 +581,7 @@ module econia::market { /// operations and withdrawals on given market account. maker_custodian_id: u64, /// Market order ID for taker side of fill. If multiple - /// `FillEvent`(s) are emitted for a single order, they all have + /// `FillEvent`s are emitted for a single order, they all have /// the same `FillEvent.taker_order_id`. If a limit order that /// crosses the spread partially fills as a taker then posts as /// a maker, `FillEvent.taker_market_order_id` for the taker From 4aec09eb167b1f306b0c0172aa44a3b40fee958b Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 3 Jul 2023 07:28:56 -0700 Subject: [PATCH 06/56] Add draft MarketEvents struct --- src/move/econia/sources/market.move | 52 +++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 24b1c03b2..0d70365dd 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -676,6 +676,58 @@ module econia::market { map: Tablist } + struct MarketEvents has key { + map: Tablist + } + + struct UserWithCustodian has copy, drop, store { + user: address, + custodian_id: u64 + } + + /// An event handle can be looked up via a view functions, then + /// passed into the REST API to query events emitted to the handle. + /// + /// Events are emitted to handle for the market, and to a handle for + /// affected user/custodian ID tuple (affected signer in the case of + /// a swap, which is is not affiliated with a market account). + struct MarketEventHandles has store { + market_id: u64, + /// place_limit_order() + new_limit_order_events_market: EventHandle, + new_limit_order_events_user: + map>, + /// place_market_order() + new_market_order_events_market: EventHandle, + new_market_order_events_user: + map>, + /// swap() + new_swap_order_events_market: EventHandle, + new_swap_order_events_signer: + map>, + /// match() (events deferred to calling function) + match_events_market: EventHandle, + match_events_user: + map>, + /// place_limit_order() (only amount that posts to book) + order_post_events_market: EventHandle, + order_post_events_user: + map>, + /// change_order_size() + change_order_size_event_market: EventHandle, + change_order_size_event_user: + map>, + /// cancel_order() + cancel_order_event_market: EventHandle, + cancel_order_event_user: + map>, + cancel_order_event_market: EventHandle, + /// place_limit_order() + order_evict_event_market: EventHandle, + order_evict_event_user: + map>, + } + /// User-friendly representation of an open order on the order book, /// combining fields from `Order` and the corresponding /// `MakerEvent` emitted when order was first placed. From c5aa3175bd2598674bd46ef0a2b1247194c75369 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 4 Jul 2023 20:47:11 -0700 Subject: [PATCH 07/56] Add MarketEventHandles struct, draft MatchEvent --- src/move/econia/sources/market.move | 721 +++++++++++++++------------- 1 file changed, 379 insertions(+), 342 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 0d70365dd..dda5f9bd1 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -562,68 +562,27 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /// Emitted for each order fill. If an order results in multiple - /// fills, a separate event is emitted for each one. - struct FillEvent has copy, drop, store { - /// Market ID of corresponding market. + struct MatchEvent has copy, drop, store { market_id: u64, - /// The size filled, in lots. size: u64, - /// Fill price, in ticks per lot. price: u64, - /// `ASK` or `BID`, the side of the maker order filled against. maker_side: bool, - /// Market order ID of for maker order just filled against. - maker_market_order_id: u128, - /// Address of user holding maker order. maker: address, - /// For given maker, ID of custodian required to approve order - /// operations and withdrawals on given market account. maker_custodian_id: u64, - /// Market order ID for taker side of fill. If multiple - /// `FillEvent`s are emitted for a single order, they all have - /// the same `FillEvent.taker_order_id`. If a limit order that - /// crosses the spread partially fills as a taker then posts as - /// a maker, `FillEvent.taker_market_order_id` for the taker - /// portion is identical to `MakerEvent.market_order_id` emitted - /// for the maker portion. - taker_market_order_id: u128 - } - - /// Map of `FillEvent` handles, implemented as a replacement for - /// `OrderBook.taker_events` through a backwards-compatible package - /// upgrade. - struct FillEventHandles has key { - /// Map from market ID to `FillEvent` event handle. - map: Table> - } - - /// Emitted when a maker order (treated as the portion of an order - /// that posts to the book) is placed, cancelled, evicted, or its - /// size is manually changed. - struct MakerEvent has drop, store { - /// Market ID of corresponding market. - market_id: u64, - /// `ASK` or `BID`, the side of the maker order. - side: bool, - /// Market order ID, unique within a given market but not - /// necessarily across markets. - market_order_id: u128, - /// Address of user holding maker order. - user: address, - /// For given maker, ID of custodian required to approve order - /// operations and withdrawals on given market account. - custodian_id: u64, - /// `CANCEL`, `CHANGE`, `EVICT`, or `PLACE`, the event type. - type: u8, - /// The size, in lots, on the book after an order has been - /// placed or its size has been manually changed. Else the size - /// on the book before the order was cancelled or evicted. - size: u64, - /// Order price, in ticks per lot. - price: u64 + maker_order_id: u128, + taker: address, + taker_custodian_id: u64, + taker_order_id: u128, } + /* + TODO: Cancel event, flag for is_self_match_cancel + */ + + /* + TODO: Fee event should be for integrator, taker fee divisor, amounts assessed? + */ + /// An order on the order book. struct Order has store { /// Number of lots to be filled. @@ -663,7 +622,7 @@ module econia::market { bids: AVLqueue, /// Cumulative number of orders placed. counter: u64, - /// Event handle for maker events. + /// Deprecated field retained for backwards compatibility. maker_events: EventHandle, /// Deprecated field retained for backwards compatibility. taker_events: EventHandle @@ -676,11 +635,8 @@ module econia::market { map: Tablist } - struct MarketEvents has key { - map: Tablist - } - - struct UserWithCustodian has copy, drop, store { + struct MarketAccountInfo has copy, drop, store { + market_id: u64, user: address, custodian_id: u64 } @@ -691,8 +647,13 @@ module econia::market { /// Events are emitted to handle for the market, and to a handle for /// affected user/custodian ID tuple (affected signer in the case of /// a swap, which is is not affiliated with a market account). - struct MarketEventHandles has store { - market_id: u64, + struct MarketEventHandles has key { + /// match() (events deferred to calling function) + match_events_by_market: + Table>, + match_events_by_market_account: + Table>, + /* /// place_limit_order() new_limit_order_events_market: EventHandle, new_limit_order_events_user: @@ -705,10 +666,6 @@ module econia::market { new_swap_order_events_market: EventHandle, new_swap_order_events_signer: map>, - /// match() (events deferred to calling function) - match_events_market: EventHandle, - match_events_user: - map>, /// place_limit_order() (only amount that posts to book) order_post_events_market: EventHandle, order_post_events_user: @@ -726,6 +683,7 @@ module econia::market { order_evict_event_market: EventHandle, order_evict_event_user: map>, + */ } /// User-friendly representation of an open order on the order book, @@ -1462,7 +1420,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_limit_order< @@ -1502,7 +1460,7 @@ module econia::market { custodian_capability_ref: &CustodianCapability ): u128 acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_limit_order_passive_advance< @@ -1546,7 +1504,7 @@ module econia::market { target_advance_amount: u64 ): u128 acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_limit_order_passive_advance< @@ -1594,7 +1552,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_limit_order< @@ -1636,7 +1594,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_market_order( @@ -1671,7 +1629,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_market_order( @@ -1720,10 +1678,7 @@ module econia::market { min_size: u64, utility_coins: Coin ): u64 - acquires - FillEventHandles, - OrderBooks - { + acquires OrderBooks { // Register market in global registry, storing market ID. let market_id = registry::register_market_base_coin_internal< BaseType, QuoteType, UtilityType>(lot_size, tick_size, min_size, @@ -1778,10 +1733,7 @@ module econia::market { utility_coins: Coin, underwriter_capability_ref: &UnderwriterCapability ): u64 - acquires - FillEventHandles, - OrderBooks - { + acquires OrderBooks { // Register market in global registry, storing market ID. let market_id = registry::register_market_base_generic_internal< QuoteType, UtilityType>(base_name_generic, lot_size, tick_size, @@ -1850,7 +1802,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { let user_address = address_of(user); // Get user address. @@ -1977,7 +1929,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { let (base_value, quote_value) = // Get coin value amounts. @@ -2083,7 +2035,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { let underwriter_id = // Get underwriter ID. @@ -2208,7 +2160,7 @@ module econia::market { advance_style: bool, target_advance_amount: u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_limit_order_passive_advance_user< @@ -2242,7 +2194,7 @@ module econia::market { restriction: u8, self_match_behavior: u8 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_limit_order_user( @@ -2266,7 +2218,7 @@ module econia::market { size: u64, self_match_behavior: u8 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { place_market_order_user( @@ -2288,10 +2240,7 @@ module econia::market { lot_size: u64, tick_size: u64, min_size: u64 - ) acquires - FillEventHandles, - OrderBooks - { + ) acquires OrderBooks { // Get market registration fee, denominated in utility coins. let fee = incentives::get_market_registration_fee(); // Register market with base coin, paying fees from coin store. @@ -2319,7 +2268,7 @@ module econia::market { max_quote: u64, limit_price: u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { swap_between_coinstores( @@ -2576,6 +2525,83 @@ module econia::market { size: new_size, price}); } + inline fun emit_match_events( + handles_ref_mut: &mut MarketEventHandles, + match_events_queue_ref_mut: &mut vector, + new_taker_order_id: u128, + ): u128 { + vector::for_each_ref(match_events_queue_ref_mut, |event_ref| { + let event: MatchEvent = *event_ref; + if (new_taker_order_id != (NIL as u128)) { + event.taker_order_id = new_taker_order_id + }; + // Event for market. + let has_market_handle = table::contains( + &handles_ref_mut.match_events_by_market, + event.market_id); + if (!has_market_handle) { + table::add( + &mut handles_ref_mut.match_events_by_market, + event.market_id, + account::new_event_handle( + &resource_account::get_signer())); + }; + let market_handle_ref_mut = table::borrow_mut( + &mut handles_ref_mut.match_events_by_market, + event.market_id); + event::emit_event(market_handle_ref_mut, copy event); + // Event for taker. + if (event.taker != NO_MARKET_ACCOUNT) { + let taker_market_account_info = MarketAccountInfo{ + market_id: event.market_id, + user: event.taker, + custodian_id: event.taker_custodian_id + }; + let has_taker_handle = table::contains( + &handles_ref_mut.match_events_by_market_account, + taker_market_account_info); + if (!has_taker_handle) { + table::add( + &mut handles_ref_mut.match_events_by_market_account, + taker_market_account_info, + account::new_event_handle( + &resource_account::get_signer())); + }; + let taker_handle_ref_mut = table::borrow_mut( + &mut handles_ref_mut.match_events_by_market_account, + taker_market_account_info); + event::emit_event(taker_handle_ref_mut, copy event); + }; + // Event for maker. + let maker_market_account_info = MarketAccountInfo{ + market_id: event.market_id, + user: event.maker, + custodian_id: event.maker_custodian_id + }; + let has_maker_handle = table::contains( + &handles_ref_mut.match_events_by_market_account, + maker_market_account_info); + if (!has_maker_handle) { + table::add( + &mut handles_ref_mut.match_events_by_market_account, + maker_market_account_info, + account::new_event_handle( + &resource_account::get_signer())); + }; + let maker_handle_ref_mut = table::borrow_mut( + &mut handles_ref_mut.match_events_by_market_account, + maker_market_account_info); + event::emit_event(maker_handle_ref_mut, copy event); + }); + if (vector::is_empty(match_events_queue_ref_mut)) { + (NIL as u128) + } else if (new_taker_order_id != (NIL as u128)) { + new_taker_order_id + } else { + vector::borrow(match_events_queue_ref_mut, 0).taker_order_id + } + } + /// Get AVL queue access key encoded in `market_order_id`. /// /// # Testing @@ -2683,6 +2709,21 @@ module econia::market { move_to(&resource_account, OrderBooks{map: tablist::new()}) } + inline fun market_event_handles_borrow_mut( + resource_address: address, + ): &mut MarketEventHandles + acquires MarketEventHandles { + if (!exists(resource_address)) + move_to( + &resource_account::get_signer(), + MarketEventHandles{ + match_events_by_market: table::new(), + match_events_by_market_account: table::new() + } + ); + borrow_global_mut(resource_address) + } + /// Match a taker order against the order book. /// /// Calculates maximum amount of quote coins to match, matches, then @@ -2806,8 +2847,8 @@ module econia::market { QuoteType >( market_id: u64, - resource_address: address, - fill_event_queue_option_ref_mut: &mut Option>, + _event_handles_ref_mut: &mut MarketEventHandles, + event_queue_ref_mut: &mut vector, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -2828,7 +2869,7 @@ module econia::market { u64, u64, bool - ) acquires FillEventHandles { + ) { // Assert price is not too high. assert!(limit_price <= HI_PRICE, E_PRICE_TOO_HIGH); // Taker buy fills against asks, sell against bids. @@ -2851,16 +2892,6 @@ module econia::market { // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; - // Determine if fill events should be deferred into a queue. - let defer_events = option::is_some(fill_event_queue_option_ref_mut); - // If should defer events, mutably borrow event queue: - let event_queue_ref_mut = if (defer_events) - option::borrow_mut(fill_event_queue_option_ref_mut) else - &mut vector[]; // Otherwise mutably borrow null vector. - // Mutably borrow fill event handle: - let fill_event_handle_ref_mut = table::borrow_mut( - &mut borrow_global_mut(resource_address).map, - market_id); // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; // While there are orders to match against: @@ -2955,16 +2986,19 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - let fill_event = FillEvent{ // Create fill event. - market_id, size: fill_size, price, maker_side: side, - maker_market_order_id: market_order_id, maker, - maker_custodian_id: custodian_id, taker_market_order_id: - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER)}; - // If should defer events, push pack event onto queue: - if (defer_events) - vector::push_back(event_queue_ref_mut, fill_event) else - // Otherwise emit event. - event::emit_event(fill_event_handle_ref_mut, fill_event); + vector::push_back(event_queue_ref_mut, MatchEvent{ + market_id, + size: fill_size, + price, + maker_side: side, + maker, + maker_custodian_id: maker_custodian_id, + maker_order_id: market_order_id, + taker, + taker_custodian_id: custodian_id, + taker_order_id: + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER) + }); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -3030,8 +3064,8 @@ module econia::market { /// /// # Returns /// - /// * `u128`: Market order ID of limit order placed on book, if one - /// was placed. Else `NIL`. + /// * `u128`: Order ID assigned if limit order took and/or posted on + /// book, else `NIL`. /// * `u64`: Base asset trade amount as a taker, same as for /// `match()`, if order fills across the spread. /// * `u64`: Quote asset trade amount as a taker, same as for @@ -3150,7 +3184,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Assert valid order restriction flag. @@ -3240,10 +3274,11 @@ module econia::market { direction, min_base, max_base, min_quote, max_quote, base_available, base_ceiling, quote_available, quote_ceiling); // Assume no assets traded as a taker. - let (base_traded, quote_traded, fees) = (0, 0, 0); - // Evaluate any potential fills across the spread, which may - // result in deferred fill events: - let fill_event_queue = if (crosses_spread) { + let (base_traded, quote_traded, fees, match_event_queue) = + (0, 0, 0, vector[]); + let market_event_handles_ref_mut = + market_event_handles_borrow_mut(resource_address); + if (crosses_spread) { // Calculate max base and quote to withdraw. If a buy: let (base_withdraw, quote_withdraw) = if (direction == BUY) // Withdraw quote to buy base, else sell base for quote. @@ -3256,18 +3291,28 @@ module econia::market { quote_withdraw, underwriter_id); // Declare return assignment variable. let self_match_cancel; - // Declare empty fill event queue inside of an option. - let fill_event_queue_option = option::some(vector[]); // Match against order book, storing optionally modified // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of // the order. (Increments order book counter). (optional_base_coins, quote_coins, base_traded, quote_traded, fees, self_match_cancel) = match( - market_id, resource_address, &mut fill_event_queue_option, - order_book_ref_mut, user_address, custodian_id, integrator, - direction, min_base, max_base, min_quote, max_quote, price, - self_match_behavior, optional_base_coins, quote_coins); + market_id, + market_event_handles_ref_mut, + &mut match_event_queue, + order_book_ref_mut, + user_address, + custodian_id, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + price, + self_match_behavior, + optional_base_coins, + quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -3290,86 +3335,61 @@ module econia::market { size = if (still_crosses_spread || self_match_cancel) 0 else // Else update size to amount left to fill post-match. size - (base_traded / order_book_ref_mut.lot_size); - // Extract fill event queue packed by matching engine. - option::extract(&mut fill_event_queue_option) } else { // If spread not crossed (matching engine not called): - // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; - vector[] // There are no fill events to defer. - }; - // Determine if there are fill events to emit. - let fill_events_to_emit = !vector::is_empty(&fill_event_queue); - // Mutably borrow fill event handle: - let fill_event_handle_ref_mut = table::borrow_mut( - &mut borrow_global_mut(resource_address).map, - market_id); - // If immediate-or-cancel or if remaining size to fill after - // matching does not meet minimum size requirement for market: - if ((restriction == IMMEDIATE_OR_CANCEL) || - (size < order_book_ref_mut.min_size)) { - if (fill_events_to_emit) // If fill events are enqueued: - vector::for_each_ref(&fill_event_queue, |fill_event_ref| { - event::emit_event(fill_event_handle_ref_mut, - *fill_event_ref); - }); // Emit each fill event (first-in-first-out): - // Return without posting. - return ((NIL as u128), base_traded, quote_traded, fees) - }; - // Get next order access key for user-side order placement. - let order_access_key = user::get_next_order_access_key_internal( - user_address, market_id, custodian_id, side); - // Get orders AVL queue for maker side. - let orders_ref_mut = if (side == ASK) &mut order_book_ref_mut.asks else - &mut order_book_ref_mut.bids; - // Declare order to insert to book. - let order = Order{size, price, user: user_address, custodian_id, - order_access_key}; - // Get new AVL queue access key, evictee access key, and evictee - // value by attempting to insert for given critical height. - let (avlq_access_key, evictee_access_key, evictee_value) = - avl_queue::insert_check_eviction( - orders_ref_mut, price, order, critical_height); - // Assert that order could be inserted to AVL queue. - assert!(avlq_access_key != NIL, E_PRICE_TIME_PRIORITY_TOO_LOW); - // Get market order ID from AVL queue access key, counter. - let market_order_id = (avlq_access_key as u128) | - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); - // If fill events have been deferred: - if (fill_events_to_emit) { - // For each fill event (first-in-first-out): - vector::for_each_ref(&fill_event_queue, |fill_event_ref| { - // Get a copy of the fill event. - let fill_event: FillEvent = *fill_event_ref; - // Re-assign common market order ID generated from - // portion of order that posts as a maker. - fill_event.taker_market_order_id = market_order_id; - // Emit event. - event::emit_event(fill_event_handle_ref_mut, fill_event); - }) }; - user::place_order_internal( // Place order user-side. - user_address, market_id, custodian_id, side, size, price, - market_order_id, order_access_key); - // Emit a maker place event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id, user: user_address, - custodian_id, type: PLACE, size, price}); - if (evictee_access_key == NIL) { // If no eviction required: - // Destroy empty evictee value option. - option::destroy_none(evictee_value); - } else { // If had to evict order at AVL queue tail: - // Unpack evicted order, storing fields for event. - let Order{size, price, user, custodian_id, order_access_key} = - option::destroy_some(evictee_value); - // Cancel order user-side, storing its market order ID. - let market_order_id_cancel = user::cancel_order_internal( - user, market_id, custodian_id, side, size, price, - order_access_key, (NIL as u128)); - // Emit a maker evict event. + let order_id_as_maker = (NIL as u128); // Assume no post. + // If size big enough to post and not immediate-or-cancel: + if ((size >= order_book_ref_mut.min_size) && + (restriction != IMMEDIATE_OR_CANCEL)) { + // Get next order access key for user-side order placement. + let order_access_key = user::get_next_order_access_key_internal( + user_address, market_id, custodian_id, side); + // Get orders AVL queue for maker side. + let orders_ref_mut = if (side == ASK) + &mut order_book_ref_mut.asks else &mut order_book_ref_mut.bids; + // Declare order to insert to book. + let order = Order{size, price, user: user_address, custodian_id, + order_access_key}; + // Get new AVL queue access key, evictee access key, and evictee + // value by attempting to insert for given critical height. + let (avlq_access_key, evictee_access_key, evictee_value) = + avl_queue::insert_check_eviction( + orders_ref_mut, price, order, critical_height); + // Assert that order could be inserted to AVL queue. + assert!(avlq_access_key != NIL, E_PRICE_TIME_PRIORITY_TOO_LOW); + // Get market order ID from AVL queue access key, counter. + let market_order_id = (avlq_access_key as u128) | + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + user::place_order_internal( // Place order user-side. + user_address, market_id, custodian_id, side, size, price, + market_order_id, order_access_key); + // Emit a maker place event. event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id: market_order_id_cancel, user, - custodian_id, type: EVICT, size, price}); + market_id, side, market_order_id, user: user_address, + custodian_id, type: PLACE, size, price}); + if (evictee_access_key == NIL) { // If no eviction required: + // Destroy empty evictee value option. + option::destroy_none(evictee_value); + } else { // If had to evict order at AVL queue tail: + // Unpack evicted order, storing fields for event. + let Order{size, price, user, custodian_id, order_access_key} = + option::destroy_some(evictee_value); + // Cancel order user-side, storing its market order ID. + let market_order_id_cancel = user::cancel_order_internal( + user, market_id, custodian_id, side, size, price, + order_access_key, (NIL as u128)); + // Emit a maker evict event. + event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ + market_id, side, market_order_id: market_order_id_cancel, user, + custodian_id, type: EVICT, size, price}); + }; + // Order ID as maker is from post to book. + order_id_as_maker = market_order_id }; + let market_order_id = emit_match_events( + market_event_handles_ref_mut, &mut match_event_queue, + order_id_as_maker); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } @@ -3472,7 +3492,7 @@ module econia::market { target_advance_amount: u64 ): u128 acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Get address of resource account where order books are stored. @@ -3628,7 +3648,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Get user's available and ceiling asset counts. @@ -3692,10 +3712,22 @@ module econia::market { // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) = match( - market_id, resource_address, &mut option::none(), - order_book_ref_mut, user_address, custodian_id, integrator, - direction, min_base, max_base, min_quote, max_quote, limit_price, - self_match_behavior, optional_base_coins, quote_coins); + market_id, + market_event_handles_borrow_mut(resource_address), + &mut vector[], + order_book_ref_mut, + user_address, + custodian_id, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + self_match_behavior, + optional_base_coins, + quote_coins); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -3845,10 +3877,7 @@ module econia::market { min_size: u64, underwriter_id: u64 ): u64 - acquires - FillEventHandles, - OrderBooks - { + acquires OrderBooks { // Get Econia resource account signer. let resource_account = resource_account::get_signer(); // Get resource account address. @@ -3871,21 +3900,6 @@ module econia::market { account::new_event_handle(&resource_account), taker_events: account::new_event_handle(&resource_account)}); - // If a fill event handles map has not yet been moved to the - // resource account: - if (!exists(resource_address)) { - // Initialize fill event handles map under resource account. - // This is done here rather than in `init_module()` since - // the fill event handles map was implemented in a - // backwards-compatible package upgrade. - move_to(&resource_account, FillEventHandles{map: table::new()}); - }; - // Mutably borrow fill event handles map. - let fill_event_handles_map_ref_mut = - &mut borrow_global_mut(resource_address).map; - table::add( // Add fill event handle to fill event handles map. - fill_event_handles_map_ref_mut, market_id, - account::new_event_handle(&resource_account)); // Register an Econia fee store entry for market quote coin. incentives::register_econia_fee_store_entry(market_id); market_id // Return market ID. @@ -3964,7 +3978,7 @@ module econia::market { u64, u64 ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Get address of resource account where order books are stored. @@ -3988,10 +4002,21 @@ module econia::market { let (base_traded, quote_traded, fees); (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) = match( // Match against order book. - market_id, resource_address, &mut option::none(), - order_book_ref_mut, NO_MARKET_ACCOUNT, NO_CUSTODIAN, - integrator, direction, min_base, max_base, min_quote, - max_quote, limit_price, ABORT, optional_base_coins, + market_id, + market_event_handles_borrow_mut(resource_address), + &mut vector[], + order_book_ref_mut, + NO_MARKET_ACCOUNT, + NO_CUSTODIAN, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + ABORT, + optional_base_coins, quote_coins); // Return optionally modified asset inputs, trade amounts, fees. (optional_base_coins, quote_coins, base_traded, quote_traded, fees) @@ -4001,6 +4026,18 @@ module econia::market { // Deprecated structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + /// Deprecated struct retained for backwards compatibility. + struct MakerEvent has drop, store { + market_id: u64, + side: bool, + market_order_id: u128, + user: address, + custodian_id: u64, + type: u8, + size: u64, + price: u64 + } + /// Deprecated struct retained for backwards compatibility. struct Orders has key {asks: vector, bids: vector} @@ -4069,7 +4106,7 @@ module econia::market { min_ask_price: u64 ): signer acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4152,7 +4189,7 @@ module econia::market { signer, signer ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { init_test(); // Init for testing. @@ -4309,7 +4346,7 @@ module econia::market { /// of custodian. fun test_cancel_all_orders_ask_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4372,7 +4409,7 @@ module econia::market { /// of signing user. fun test_cancel_all_orders_bid_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4431,7 +4468,7 @@ module econia::market { /// custodian. fun test_cancel_order_ask_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4511,7 +4548,7 @@ module econia::market { /// signing user. fun test_cancel_order_bid_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4586,7 +4623,7 @@ module econia::market { /// Verify failure for invalid custodian. fun test_cancel_order_invalid_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4630,7 +4667,7 @@ module econia::market { /// Verify failure for invalid market ID. fun test_cancel_order_invalid_market_id() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4648,7 +4685,7 @@ module econia::market { /// Verify failure for invalid bogus market order ID. fun test_cancel_order_invalid_market_order_id_bogus() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4666,7 +4703,7 @@ module econia::market { /// Verify failure for invalid market order ID passed as `NIL`. fun test_cancel_order_invalid_market_order_id_null() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4684,7 +4721,7 @@ module econia::market { /// Verify failure for invalid user. fun test_cancel_order_invalid_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4723,7 +4760,7 @@ module econia::market { /// custodian, for size increase at tail of price level queue. fun test_change_order_size_ask_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4871,7 +4908,7 @@ module econia::market { /// user, for size decrease at tail of queue. fun test_change_order_size_bid_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4971,7 +5008,7 @@ module econia::market { /// user, for size increase not at tail of queue. fun test_change_order_size_bid_user_new_tail() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5063,7 +5100,7 @@ module econia::market { /// `test_change_order_size_bid_user_new_tail`. fun test_change_order_size_insertion_error() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5127,7 +5164,7 @@ module econia::market { /// Verify failure for invalid custodian. fun test_change_order_size_invalid_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5172,7 +5209,7 @@ module econia::market { /// Verify failure for invalid market ID. fun test_change_order_size_invalid_market_id() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5191,7 +5228,7 @@ module econia::market { /// Verify failure for invalid bogus market order ID. fun test_change_order_size_invalid_market_order_id_bogus() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5210,7 +5247,7 @@ module econia::market { /// Verify failure for invalid market order ID passed as `NIL`. fun test_change_order_size_invalid_market_order_id_null() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5229,7 +5266,7 @@ module econia::market { /// Verify failure for invalid user. fun test_change_order_size_invalid_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5420,7 +5457,7 @@ module econia::market { /// Verify indexing results. fun test_get_open_orders() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5550,7 +5587,7 @@ module econia::market { /// Verify indexing results. fun test_get_price_levels() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5670,7 +5707,7 @@ module econia::market { /// left to fill on matched order. fun test_match_complete_fill_no_lots_buy() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5798,7 +5835,7 @@ module econia::market { /// ticks left to fill on matched order. fun test_match_complete_fill_no_ticks_sell() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5925,7 +5962,7 @@ module econia::market { /// Verify returns for no orders to match against. fun test_match_empty() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5961,7 +5998,7 @@ module econia::market { /// Verify returns for not enough size to fill. fun test_match_fill_size_0() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6077,7 +6114,7 @@ module econia::market { /// where one maker has two bids at different prices. fun test_match_loop_twice() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6245,7 +6282,7 @@ module econia::market { /// Verify failure for minimum base amount not traded. fun test_match_min_base_not_traded() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6277,7 +6314,7 @@ module econia::market { /// Verify failure for minimum quote amount not traded. fun test_match_min_quote_not_traded() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6308,7 +6345,7 @@ module econia::market { /// Verify returns for partial sell fill with lot-limited fill size. fun test_match_partial_fill_lot_limited_sell() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6438,7 +6475,7 @@ module econia::market { /// Verify returns for partial buy fill with tick-limited fill size. fun test_match_partial_fill_tick_limited_buy() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6568,7 +6605,7 @@ module econia::market { /// Verify returns for limit price violation on buy. fun test_match_price_break_buy() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6675,7 +6712,7 @@ module econia::market { /// Verify returns for limit price violation on sell. fun test_match_price_break_sell() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6784,7 +6821,7 @@ module econia::market { /// head key. Test setup based on `test_match_fill_size_0()` fun test_match_price_mismatch() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6855,7 +6892,7 @@ module econia::market { /// Verify failure for price too high. fun test_match_price_too_high() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6887,7 +6924,7 @@ module econia::market { /// Verify failure for self match with abort behavior. fun test_match_self_match_abort() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -6935,7 +6972,7 @@ module econia::market { /// self match. fun test_match_self_match_cancel_both() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7048,7 +7085,7 @@ module econia::market { /// the order at the higher price. fun test_match_self_match_cancel_maker() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7185,7 +7222,7 @@ module econia::market { /// self match. fun test_match_self_match_cancel_taker() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7302,7 +7339,7 @@ module econia::market { /// Verify failure for self match with invalid abort behavior. fun test_match_self_match_invalid() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7344,7 +7381,7 @@ module econia::market { /// Verify failure for base overflow. fun test_place_limit_order_base_overflow() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -7367,7 +7404,7 @@ module econia::market { /// signing user. fun test_place_limit_order_crosses_ask_exact() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7475,7 +7512,7 @@ module econia::market { /// Based on `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_ask_partial() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7590,7 +7627,7 @@ module econia::market { /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_partial_cancel() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7671,7 +7708,7 @@ module econia::market { /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_self_match_cancel() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7745,7 +7782,7 @@ module econia::market { /// `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_bid_exact() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7853,7 +7890,7 @@ module econia::market { /// Mirror of `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_bid_partial() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7968,7 +8005,7 @@ module econia::market { /// `test_place_limit_order_crosses_bid_partial()`. fun test_place_limit_order_crosses_bid_partial_cancel() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8069,7 +8106,7 @@ module econia::market { /// evicts another user's order. fun test_place_limit_order_evict() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8190,7 +8227,7 @@ module econia::market { /// Verify failure for not crossing spread when fill-or-abort. fun test_place_limit_order_fill_or_abort_not_cross() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8218,7 +8255,7 @@ module econia::market { /// fill-or-abort. fun test_place_limit_order_fill_or_abort_partial() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8253,7 +8290,7 @@ module econia::market { /// Verify failure for invalid base type argument. fun test_place_limit_order_invalid_base() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8280,7 +8317,7 @@ module econia::market { /// Verify failure for invalid quote type argument. fun test_place_limit_order_invalid_quote() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8307,7 +8344,7 @@ module econia::market { /// Verify failure for invalid restriction. fun test_place_limit_order_invalid_restriction() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8327,7 +8364,7 @@ module econia::market { /// cross the spread, under authority of signing user. fun test_place_limit_order_no_cross_ask_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8412,7 +8449,7 @@ module econia::market { /// cross the spread, under authority of custodian. fun test_place_limit_order_no_cross_bid_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8498,7 +8535,7 @@ module econia::market { /// Verify failure for invalid price. fun test_place_limit_order_no_price() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8518,7 +8555,7 @@ module econia::market { /// Verify failure for invalid base type argument. fun test_place_limit_order_passive_advance_invalid_base() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8541,7 +8578,7 @@ module econia::market { /// Verify failure for invalid market ID. fun test_place_limit_order_passive_advance_invalid_market_id() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8564,7 +8601,7 @@ module econia::market { /// Verify failure for invalid percent fun test_place_limit_order_passive_advance_invalid_percent() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8589,7 +8626,7 @@ module econia::market { /// Verify failure for invalid quote type argument. fun test_place_limit_order_passive_advance_invalid_quote() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8611,7 +8648,7 @@ module econia::market { /// Verify return for no cross price when placing an ask. fun test_place_limit_order_passive_advance_no_cross_price_ask() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8637,7 +8674,7 @@ module econia::market { /// Verify return for no cross price when placing a bid. fun test_place_limit_order_passive_advance_no_cross_price_bid() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8663,7 +8700,7 @@ module econia::market { /// Verify returns, state updates for full advance is start price. fun test_place_limit_order_passive_advance_no_full_advance() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8694,7 +8731,7 @@ module econia::market { /// Verify returns for no start price. fun test_place_limit_order_passive_advance_no_start_price() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8724,7 +8761,7 @@ module econia::market { /// Verify returns, state updates for no target advance amount. fun test_place_limit_order_passive_advance_no_target_advance() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8754,7 +8791,7 @@ module econia::market { /// Verify returns, state updates for percent-specified asks. fun test_place_limit_order_passive_advance_percent_ask() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8788,7 +8825,7 @@ module econia::market { /// Verify returns, state updates for percent-specified bids. fun test_place_limit_order_passive_advance_percent_bid() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8822,7 +8859,7 @@ module econia::market { /// Verify returns, state updates for ticks-specified asks. fun test_place_limit_order_passive_advance_ticks_ask() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8874,7 +8911,7 @@ module econia::market { /// delegated custodian. fun test_place_limit_order_passive_advance_ticks_bid() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Configure spread. @@ -8928,7 +8965,7 @@ module econia::market { /// Verify failure for not crossing spread as post-or-abort. fun test_place_limit_order_post_or_abort_crosses() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8963,7 +9000,7 @@ module econia::market { /// Verify failure for invalid price. fun test_place_limit_order_price_hi() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8984,7 +9021,7 @@ module econia::market { /// `test_place_limit_order_evict()`. fun test_place_limit_order_price_time_priority_low() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9034,7 +9071,7 @@ module econia::market { /// Verify failure for quote overflow. fun test_place_limit_order_quote_overflow() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9056,7 +9093,7 @@ module econia::market { /// Verify failure for invalid size. fun test_place_limit_order_size_lo() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9084,7 +9121,7 @@ module econia::market { /// user. Based on `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_still_crosses_ask() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9206,7 +9243,7 @@ module econia::market { /// user. Based on `test_place_limit_order_still_crosses_ask()`. fun test_place_limit_order_still_crosses_bid() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9324,7 +9361,7 @@ module econia::market { /// Verify failure for ticks overflow. fun test_place_limit_order_ticks_overflow() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9346,7 +9383,7 @@ module econia::market { /// on `test_place_limit_order_no_cross_ask_user()`. fun test_place_limit_order_user_entry() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9410,7 +9447,7 @@ module econia::market { /// Verify failure for invalid base type argument. fun test_place_market_order_invalid_base() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9434,7 +9471,7 @@ module econia::market { /// Verify failure for invalid quote type argument. fun test_place_market_order_invalid_quote() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9458,7 +9495,7 @@ module econia::market { /// Verify failure for invalid size argument. fun test_place_market_order_size_too_small() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9483,7 +9520,7 @@ module econia::market { /// authority of signing user. fun test_place_market_order_max_base_adjust_buy_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9591,7 +9628,7 @@ module econia::market { /// user. fun test_place_market_order_max_base_buy_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9696,7 +9733,7 @@ module econia::market { /// base trade amount specified, under authority of custodian. fun test_place_market_order_max_base_sell_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9806,7 +9843,7 @@ module econia::market { /// quote trade amount specified, under authority of custodian. fun test_place_market_order_max_quote_buy_custodian() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9915,7 +9952,7 @@ module econia::market { /// quote trade amount specified, under authority of signing user. fun test_place_market_order_max_quote_sell_user() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10020,7 +10057,7 @@ module econia::market { /// on `test_place_market_order_max_base_buy_user()`. fun test_place_market_order_user_entry() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10282,7 +10319,7 @@ module econia::market { /// 3. Registering pure coin market, not from coin store. fun test_register_markets() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { init_test(); // Init for testing. @@ -10382,7 +10419,7 @@ module econia::market { /// during a buy. fun test_swap_between_coinstores_max_possible_base_buy() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10487,7 +10524,7 @@ module econia::market { /// during a sell. fun test_swap_between_coinstores_max_possible_base_sell() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10592,7 +10629,7 @@ module econia::market { /// during a buy. fun test_swap_between_coinstores_max_possible_quote_buy() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10697,7 +10734,7 @@ module econia::market { /// during a sell. fun test_swap_between_coinstores_max_possible_quote_sell() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10801,7 +10838,7 @@ module econia::market { /// Verify returns, state updates for registering base coin store. fun test_swap_between_coinstores_register_base_store() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10897,7 +10934,7 @@ module econia::market { /// Verify returns, state updates for registering quote coin store. fun test_swap_between_coinstores_register_quote_store() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10994,7 +11031,7 @@ module econia::market { /// base amount specified, with base amount as limiting factor. fun test_swap_coins_buy_max_base_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11102,7 +11139,7 @@ module econia::market { /// base amount not specified, with base amount as limiting factor. fun test_swap_coins_buy_no_max_base_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11210,7 +11247,7 @@ module econia::market { /// base amount not specified, with quote amount as limiting factor. fun test_swap_coins_buy_no_max_quote_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11317,7 +11354,7 @@ module econia::market { /// quote amount specified, with quote amount as limiting factor. fun test_swap_coins_sell_max_quote_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11425,7 +11462,7 @@ module econia::market { /// quote amount specified, with base amount as limiting factor. fun test_swap_coins_sell_no_max_base_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11533,7 +11570,7 @@ module econia::market { /// quote amount specified, with quote amount as limiting factor. fun test_swap_coins_sell_no_max_quote_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11640,7 +11677,7 @@ module econia::market { /// limiting factor. fun test_swap_generic_buy_base_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11747,7 +11784,7 @@ module econia::market { /// limiting factor. fun test_swap_generic_buy_quote_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11854,7 +11891,7 @@ module econia::market { /// quote flag specified, with quote amount as limiting factor. fun test_swap_generic_sell_max_quote_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -11961,7 +11998,7 @@ module econia::market { /// quote flag specified, with base amount as limiting factor. fun test_swap_generic_sell_no_max_base_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -12068,7 +12105,7 @@ module econia::market { /// quote flag specified, with quote amount as limiting factor. fun test_swap_generic_sell_no_max_quote_limiting() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -12175,7 +12212,7 @@ module econia::market { /// Verify failure for invalid base type. fun test_swap_invalid_base() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -12205,7 +12242,7 @@ module econia::market { /// Verify failure for invalid market ID. fun test_swap_invalid_market_id() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -12235,7 +12272,7 @@ module econia::market { /// Verify failure for invalid quote type. fun test_swap_invalid_quote() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -12265,7 +12302,7 @@ module econia::market { /// Verify failure for invalid underwriter. fun test_swap_invalid_underwriter() acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. From 1befb8ac6f2fe9b0dc85607fa3e8c5f815928ba8 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:45:49 -0700 Subject: [PATCH 08/56] Move user handles to be under user account --- src/move/econia/sources/market.move | 164 ++++++----------- src/move/econia/sources/user.move | 265 +++++++++++++++++++++++----- 2 files changed, 268 insertions(+), 161 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index dda5f9bd1..5aa4f734b 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -545,7 +545,7 @@ module econia::market { Self, CustodianCapability, GenericAsset, UnderwriterCapability}; use econia::resource_account; use econia::tablist::{Self, Tablist}; - use econia::user; + use econia::user::{Self, FillEvent}; use std::option::{Self, Option}; use std::signer::address_of; use std::string::{Self, String}; @@ -562,19 +562,6 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - struct MatchEvent has copy, drop, store { - market_id: u64, - size: u64, - price: u64, - maker_side: bool, - maker: address, - maker_custodian_id: u64, - maker_order_id: u128, - taker: address, - taker_custodian_id: u64, - taker_order_id: u128, - } - /* TODO: Cancel event, flag for is_self_match_cancel */ @@ -635,12 +622,6 @@ module econia::market { map: Tablist } - struct MarketAccountInfo has copy, drop, store { - market_id: u64, - user: address, - custodian_id: u64 - } - /// An event handle can be looked up via a view functions, then /// passed into the REST API to query events emitted to the handle. /// @@ -649,10 +630,7 @@ module econia::market { /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { /// match() (events deferred to calling function) - match_events_by_market: - Table>, - match_events_by_market_account: - Table>, + fill_events: Table>, /* /// place_limit_order() new_limit_order_events_market: EventHandle, @@ -2525,80 +2503,46 @@ module econia::market { size: new_size, price}); } - inline fun emit_match_events( + /// Return taker order ID (assumed constant across all fill events): + /// * Null if no events + /// * New taker order ID if one provided + /// * Otherwise the taker order ID of the first element in queue. + fun emit_fill_events( + market_id: u64, + fill_events_queue_ref: &vector, handles_ref_mut: &mut MarketEventHandles, - match_events_queue_ref_mut: &mut vector, - new_taker_order_id: u128, + new_taker_order_id: u128 ): u128 { - vector::for_each_ref(match_events_queue_ref_mut, |event_ref| { - let event: MatchEvent = *event_ref; - if (new_taker_order_id != (NIL as u128)) { - event.taker_order_id = new_taker_order_id - }; - // Event for market. - let has_market_handle = table::contains( - &handles_ref_mut.match_events_by_market, - event.market_id); - if (!has_market_handle) { - table::add( - &mut handles_ref_mut.match_events_by_market, - event.market_id, - account::new_event_handle( - &resource_account::get_signer())); + let update_taker_order_id = new_taker_order_id != (NIL as u128); + vector::for_each_ref(fill_events_queue_ref, |event_ref| { + let event: FillEvent = *event_ref; + if (update_taker_order_id) { + user::set_fill_event_taker_order_id( + &mut event, new_taker_order_id); }; - let market_handle_ref_mut = table::borrow_mut( - &mut handles_ref_mut.match_events_by_market, - event.market_id); - event::emit_event(market_handle_ref_mut, copy event); - // Event for taker. - if (event.taker != NO_MARKET_ACCOUNT) { - let taker_market_account_info = MarketAccountInfo{ - market_id: event.market_id, - user: event.taker, - custodian_id: event.taker_custodian_id - }; - let has_taker_handle = table::contains( - &handles_ref_mut.match_events_by_market_account, - taker_market_account_info); - if (!has_taker_handle) { - table::add( - &mut handles_ref_mut.match_events_by_market_account, - taker_market_account_info, - account::new_event_handle( - &resource_account::get_signer())); - }; - let taker_handle_ref_mut = table::borrow_mut( - &mut handles_ref_mut.match_events_by_market_account, - taker_market_account_info); - event::emit_event(taker_handle_ref_mut, copy event); - }; - // Event for maker. - let maker_market_account_info = MarketAccountInfo{ - market_id: event.market_id, - user: event.maker, - custodian_id: event.maker_custodian_id - }; - let has_maker_handle = table::contains( - &handles_ref_mut.match_events_by_market_account, - maker_market_account_info); - if (!has_maker_handle) { + user::emit_fill_event_for_maker_and_taker(event); + // Emit event for market, creating handle as needed. + let has_handle = table::contains( + &handles_ref_mut.fill_events, market_id); + if (!has_handle) { table::add( - &mut handles_ref_mut.match_events_by_market_account, - maker_market_account_info, - account::new_event_handle( + &mut handles_ref_mut.fill_events, + market_id, + account::new_event_handle( &resource_account::get_signer())); }; - let maker_handle_ref_mut = table::borrow_mut( - &mut handles_ref_mut.match_events_by_market_account, - maker_market_account_info); - event::emit_event(maker_handle_ref_mut, copy event); + let handle_ref_mut = table::borrow_mut( + &mut handles_ref_mut.fill_events, + market_id); + event::emit_event(handle_ref_mut, event); }); - if (vector::is_empty(match_events_queue_ref_mut)) { + if (vector::is_empty(fill_events_queue_ref)) { (NIL as u128) - } else if (new_taker_order_id != (NIL as u128)) { + } else if (update_taker_order_id) { new_taker_order_id } else { - vector::borrow(match_events_queue_ref_mut, 0).taker_order_id + user::get_fill_event_taker_order_id( + vector::borrow(fill_events_queue_ref, 0)) } } @@ -2717,8 +2661,7 @@ module econia::market { move_to( &resource_account::get_signer(), MarketEventHandles{ - match_events_by_market: table::new(), - match_events_by_market_account: table::new() + fill_events: table::new(), } ); borrow_global_mut(resource_address) @@ -2848,7 +2791,7 @@ module econia::market { >( market_id: u64, _event_handles_ref_mut: &mut MarketEventHandles, - event_queue_ref_mut: &mut vector, + event_queue_ref_mut: &mut vector, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -2986,19 +2929,18 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - vector::push_back(event_queue_ref_mut, MatchEvent{ + vector::push_back(event_queue_ref_mut, user::get_fill_event( market_id, - size: fill_size, + fill_size, price, - maker_side: side, + side, maker, - maker_custodian_id: maker_custodian_id, - maker_order_id: market_order_id, + maker_custodian_id, + market_order_id, taker, - taker_custodian_id: custodian_id, - taker_order_id: - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER) - }); + custodian_id, + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER) + )); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -3274,7 +3216,7 @@ module econia::market { direction, min_base, max_base, min_quote, max_quote, base_available, base_ceiling, quote_available, quote_ceiling); // Assume no assets traded as a taker. - let (base_traded, quote_traded, fees, match_event_queue) = + let (base_traded, quote_traded, fees, fill_event_queue) = (0, 0, 0, vector[]); let market_event_handles_ref_mut = market_event_handles_borrow_mut(resource_address); @@ -3299,7 +3241,7 @@ module econia::market { self_match_cancel) = match( market_id, market_event_handles_ref_mut, - &mut match_event_queue, + &mut fill_event_queue, order_book_ref_mut, user_address, custodian_id, @@ -3387,8 +3329,8 @@ module econia::market { // Order ID as maker is from post to book. order_id_as_maker = market_order_id }; - let market_order_id = emit_match_events( - market_event_handles_ref_mut, &mut match_event_queue, + let market_order_id = emit_fill_events( + market_id, &mut fill_event_queue, market_event_handles_ref_mut, order_id_as_maker); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) @@ -4189,7 +4131,6 @@ module econia::market { signer, signer ) acquires - MarketEventHandles, OrderBooks { init_test(); // Init for testing. @@ -4667,7 +4608,6 @@ module econia::market { /// Verify failure for invalid market ID. fun test_cancel_order_invalid_market_id() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4685,7 +4625,6 @@ module econia::market { /// Verify failure for invalid bogus market order ID. fun test_cancel_order_invalid_market_order_id_bogus() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4703,7 +4642,6 @@ module econia::market { /// Verify failure for invalid market order ID passed as `NIL`. fun test_cancel_order_invalid_market_order_id_null() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5209,7 +5147,6 @@ module econia::market { /// Verify failure for invalid market ID. fun test_change_order_size_invalid_market_id() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5228,7 +5165,6 @@ module econia::market { /// Verify failure for invalid bogus market order ID. fun test_change_order_size_invalid_market_order_id_bogus() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5247,7 +5183,6 @@ module econia::market { /// Verify failure for invalid market order ID passed as `NIL`. fun test_change_order_size_invalid_market_order_id_null() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5382,6 +5317,12 @@ module econia::market { assert!(get_NO_CUSTODIAN() == registry::get_NO_CUSTODIAN(), 0); } + #[test] + /// Verify constant is same across modules. + fun test_get_NO_MARKET_ACCOUNT() { + assert!(user::get_NO_MARKET_ACCOUNT_test() == NO_MARKET_ACCOUNT, 0) + } + #[test] /// Verify constant getter return. fun test_get_NO_RESTRICTION() { @@ -10319,7 +10260,6 @@ module econia::market { /// 3. Registering pure coin market, not from coin store. fun test_register_markets() acquires - MarketEventHandles, OrderBooks { init_test(); // Init for testing. diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index cea82b3a0..92352c775 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -281,8 +281,10 @@ module econia::user { // Uses >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + use aptos_framework::account; use aptos_framework::coin::{Self, Coin}; use aptos_framework::table::{Self, Table}; + use aptos_framework::event::{Self, EventHandle}; use aptos_framework::type_info::{Self, TypeInfo}; use econia::tablist::{Self, Tablist}; use econia::registry::{ @@ -302,8 +304,6 @@ module econia::user { // Test-only uses >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - #[test_only] - use aptos_framework::account; #[test_only] use econia::avl_queue::{u_128_by_32, u_64_by_32}; #[test_only] @@ -400,6 +400,24 @@ module econia::user { custodians: Tablist> } + /// Table keys are market account IDs. + struct MarketEventHandles has key { + fill_events: Table>, + } + + struct FillEvent has copy, drop, store { + market_id: u64, + size: u64, + price: u64, + maker_side: bool, + maker: address, + maker_custodian_id: u64, + maker_order_id: u128, + taker: address, + taker_custodian_id: u64, + taker_order_id: u128 + } + /// An open order, either ask or bid. struct Order has store { /// Market order ID. `NIL` if inactive. @@ -476,6 +494,9 @@ module econia::user { const NO_CUSTODIAN: u64 = 0; /// Underwriter ID flag for no underwriter. const NO_UNDERWRITER: u64 = 0; + /// Taker address flag for when taker order does not originate from + /// a market account. + const NO_MARKET_ACCOUNT: address = @0x0; /// Number of bits market ID is shifted in market account ID. const SHIFT_MARKET_ID: u8 = 64; @@ -1077,6 +1098,33 @@ module econia::user { coin::withdraw(user, amount)); } + public entry fun init_market_event_handles_if_missing( + user: &signer, + market_id: u64, + custodian_id: u64 + ) acquires + MarketAccounts, + MarketEventHandles + { + let user_address = address_of(user); + assert!(has_market_account(user_address, market_id, custodian_id), + E_NO_MARKET_ACCOUNT); + if (!exists(address_of(user))) + move_to(user, MarketEventHandles{ + fill_events: table::new() + }); + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let market_account_id = + get_market_account_id(market_id, custodian_id); + let fill_events_ref_mut = + &mut market_event_handles_ref_mut.fill_events; + if (!table::contains(fill_events_ref_mut, market_account_id)) { + table::add(fill_events_ref_mut, market_account_id, + account::new_event_handle(user)); + }; + } + /// Register market account for indicated market and custodian. /// /// Verifies market ID and asset types via internal call to @@ -1114,7 +1162,8 @@ module econia::user { custodian_id: u64 ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // If custodian ID indicated, assert it is registered. if (custodian_id != NO_CUSTODIAN) assert!( @@ -1135,6 +1184,7 @@ module econia::user { // (quote type for a verified market must be a coin). register_market_account_collateral_entry( user, market_account_id); + init_market_event_handles_if_missing(user, market_id, custodian_id); } /// Wrapped `register_market_account()` call for generic base asset. @@ -1150,7 +1200,8 @@ module econia::user { custodian_id: u64 ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_account( user, market_id, custodian_id); @@ -1438,6 +1489,77 @@ module econia::user { user_address, market_id, custodian_id, quote_coins); } + /// Emit fill event for either maker or taker, if handle exists. + public(friend) fun emit_fill_event( + event: FillEvent, + is_maker: bool + ) acquires MarketEventHandles { + let (user_address, custodian_id) = if (is_maker) + (event.maker, event.maker_custodian_id) else + (event.taker, event.taker_custodian_id); + if ((exists(user_address)) && + (user_address != NO_MARKET_ACCOUNT)) { + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let fill_events_ref_mut = + &mut market_event_handles_ref_mut.fill_events; + let market_account_id = + get_market_account_id(event.market_id, custodian_id); + if (table::contains(fill_events_ref_mut, market_account_id)) { + let fill_event_handle_ref_mut = table::borrow_mut( + fill_events_ref_mut, market_account_id); + event::emit_event(fill_event_handle_ref_mut, event) + } + } + } + + /// Emit fill event to specified handle, if handle exists. + public(friend) fun emit_fill_event_for_maker_and_taker( + event: FillEvent + ) acquires MarketEventHandles { + emit_fill_event(event, true); + emit_fill_event(event, false); + } + + public(friend) fun get_fill_event( + market_id: u64, + size: u64, + price: u64, + maker_side: bool, + maker: address, + maker_custodian_id: u64, + maker_order_id: u128, + taker: address, + taker_custodian_id: u64, + taker_order_id: u128, + ): FillEvent { + FillEvent{ + market_id, + size, + price, + maker_side, + maker, + maker_custodian_id, + maker_order_id, + taker, + taker_custodian_id, + taker_order_id + } + } + + public(friend) fun get_fill_event_taker_order_id( + fill_event_ref: &FillEvent, + ): u128 { + fill_event_ref.taker_order_id + } + + public(friend) fun set_fill_event_taker_order_id( + fill_event_ref_mut: &mut FillEvent, + taker_order_id: u128 + ) { + fill_event_ref_mut.taker_order_id = taker_order_id + } + /// Fill a user's order, routing collateral appropriately. /// /// Updates asset counts in a user's market account. Transfers @@ -2567,6 +2689,16 @@ module econia::user { // Test-only functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #[test_only] + /// Return `HI_PRICE`, for testing synchronization with + /// `market.move`. + public fun get_HI_PRICE_test(): u64 {HI_PRICE} + + #[test_only] + /// Return `NO_MARKET_ACCOUNT`, for testing synchronization with + /// `market.move`. + public fun get_NO_MARKET_ACCOUNT_test(): address {NO_MARKET_ACCOUNT} + #[test_only] /// Like `get_collateral_value_test()`, but accepts market id and /// custodian ID. @@ -2599,11 +2731,6 @@ module econia::user { coin::value(coin_ref) // Return coin value. } - #[test_only] - /// Return `HI_PRICE`, for testing synchronization with - /// `market.move`. - public fun get_HI_PRICE_test(): u64 {HI_PRICE} - #[test_only] /// Get order access key at top of inactive order stack. public fun get_inactive_stack_top_test( @@ -2742,7 +2869,8 @@ module econia::user { u128 ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Get signer for test user account. let user = account::create_signer_with_capability( @@ -2848,7 +2976,8 @@ module econia::user { fun test_cancel_order_internal_invalid_market_order_id() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register test markets. // Define order parameters. @@ -2875,7 +3004,8 @@ module econia::user { fun test_cancel_order_internal_start_size_mismatch() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register test markets. // Define order parameters. @@ -2902,7 +3032,8 @@ module econia::user { fun test_change_order_size_internal_ask() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register test markets. // Define order parameters. @@ -2956,7 +3087,8 @@ module econia::user { fun test_change_order_size_internal_bid() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register test markets. // Define order parameters. @@ -3004,7 +3136,8 @@ module econia::user { fun test_change_order_size_internal_no_change() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register test markets. // Define order parameters. @@ -3031,7 +3164,8 @@ module econia::user { fun test_deposit_asset_amount_mismatch() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3053,7 +3187,8 @@ module econia::user { fun test_deposit_asset_no_account() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3079,7 +3214,8 @@ module econia::user { fun test_deposit_asset_not_in_pair() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3094,7 +3230,8 @@ module econia::user { fun test_deposit_asset_overflow() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3116,7 +3253,8 @@ module econia::user { fun test_deposit_asset_underwriter() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3156,7 +3294,8 @@ module econia::user { fun test_deposit_withdraw_assets_internal() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Get test market account IDs. let (_, _, market_account_id_coin_delegated, @@ -3277,7 +3416,8 @@ module econia::user { vector acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Declare deposit parameters let coin_amount = 700; @@ -3377,7 +3517,8 @@ module econia::user { fun test_fill_order_internal_ask_complete_base_coin() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, get market account ID for pure coin // market with delegated custodian. @@ -3463,7 +3604,8 @@ module econia::user { fun test_fill_order_internal_bid_complete_base_coin() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, get market account ID for pure coin // market with delegated custodian. @@ -3541,7 +3683,8 @@ module econia::user { fun test_fill_order_internal_bid_partial_base_generic() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, get market account ID for generic // market with delegated custodian. @@ -3618,7 +3761,8 @@ module econia::user { fun test_fill_order_internal_start_size_mismatch() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register test markets. // Define order parameters. @@ -3657,7 +3801,8 @@ module econia::user { fun test_get_active_market_order_ids_internal() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3714,7 +3859,8 @@ module econia::user { fun test_get_active_market_order_ids_internal_no_account() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3743,7 +3889,8 @@ module econia::user { fun test_get_asset_counts_internal_no_account() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3770,7 +3917,8 @@ module econia::user { fun test_get_market_account_market_info_no_account() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3803,7 +3951,8 @@ module econia::user { vector> acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Initialize empty vector to return instead of dropping. let return_instead_of_dropping = vector::empty(); @@ -3911,7 +4060,8 @@ module econia::user { fun test_get_next_order_access_key_internal_no_account() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. register_market_accounts_test(); @@ -3940,7 +4090,8 @@ module econia::user { fun test_market_account_getters() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Get market account IDs for test accounts. let market_account_id_coin_self = get_market_account_id( @@ -4068,7 +4219,8 @@ module econia::user { fun test_place_cancel_order_ask() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, get market account ID for pure coin // market with delegated custodian. @@ -4154,7 +4306,8 @@ module econia::user { fun test_place_cancel_order_bid() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, get market account ID for pure coin // market with delegated custodian. @@ -4232,7 +4385,8 @@ module econia::user { fun test_place_cancel_order_stack() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, get market account ID for pure coin // market with delegated custodian. @@ -4320,7 +4474,8 @@ module econia::user { fun test_place_order_internal_access_key_mismatch() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register market accounts. // Declare order parameters @@ -4348,7 +4503,8 @@ module econia::user { fun test_place_order_internal_in_overflow() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register market accounts. // Declare order parameters @@ -4377,7 +4533,8 @@ module econia::user { fun test_place_order_internal_out_underflow() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register market accounts. // Declare order parameters @@ -4430,7 +4587,8 @@ module econia::user { fun test_place_order_internal_size_lo() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register market accounts. // Declare order parameters @@ -4449,7 +4607,8 @@ module econia::user { fun test_place_order_internal_ticks_overflow() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_accounts_test(); // Register market accounts. // Declare order parameters @@ -4469,7 +4628,8 @@ module econia::user { user: &signer ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, storing pure coin market ID. let (market_id_pure_coin, _, _, _, _, _, _, _, _, _, _, _) = @@ -4489,7 +4649,8 @@ module econia::user { user: &signer ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { registry::init_test(); // Initialize registry. // Attempt invalid invocation. @@ -4508,7 +4669,8 @@ module econia::user { user: &signer ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test markets, storing market info. let (market_id_pure_coin, base_name_generic_pure_coin, @@ -4687,7 +4849,8 @@ module econia::user { fun test_withdraw_asset_no_account() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. let (user, _, _, _, _) = register_market_accounts_test(); @@ -4714,7 +4877,8 @@ module econia::user { fun test_withdraw_asset_not_in_pair() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. let (user, _, _, _, _) = register_market_accounts_test(); @@ -4728,7 +4892,8 @@ module econia::user { fun test_withdraw_asset_underflow() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. let (user, _, _, _, _) = register_market_accounts_test(); @@ -4742,7 +4907,8 @@ module econia::user { fun test_withdraw_asset_underwriter() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Register test market accounts. let (user, _, _, _, _) = register_market_accounts_test(); @@ -4760,7 +4926,8 @@ module econia::user { fun test_withdrawals() acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // Declare start amount parameters. let amount_start_coin = 700; From 9c135b1bacfb7ef202a3149d7167f7ca1f451320 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Wed, 5 Jul 2023 16:34:57 -0700 Subject: [PATCH 09/56] Fix fill event taker order ID algo, broken tests --- src/move/econia/sources/market.move | 42 ++++++++++++++++++----------- src/move/econia/sources/user.move | 2 ++ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 5aa4f734b..81f3adc25 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -629,7 +629,6 @@ module econia::market { /// affected user/custodian ID tuple (affected signer in the case of /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { - /// match() (events deferred to calling function) fill_events: Table>, /* /// place_limit_order() @@ -2504,21 +2503,23 @@ module econia::market { } /// Return taker order ID (assumed constant across all fill events): - /// * Null if no events - /// * New taker order ID if one provided - /// * Otherwise the taker order ID of the first element in queue. + /// * If posted order ID given (if fill events from limit order that + /// took then posted), return posted order ID + /// * If no post and no fill events, then taker order ID is null + /// * Otherwise, order did not post but it did result in fills, so + /// get the taker order ID from the first fill event fun emit_fill_events( market_id: u64, fill_events_queue_ref: &vector, handles_ref_mut: &mut MarketEventHandles, - new_taker_order_id: u128 + posted_order_id: u128 ): u128 { - let update_taker_order_id = new_taker_order_id != (NIL as u128); + let update_taker_order_id = posted_order_id != (NIL as u128); vector::for_each_ref(fill_events_queue_ref, |event_ref| { let event: FillEvent = *event_ref; if (update_taker_order_id) { user::set_fill_event_taker_order_id( - &mut event, new_taker_order_id); + &mut event, posted_order_id); }; user::emit_fill_event_for_maker_and_taker(event); // Emit event for market, creating handle as needed. @@ -2536,10 +2537,10 @@ module econia::market { market_id); event::emit_event(handle_ref_mut, event); }); - if (vector::is_empty(fill_events_queue_ref)) { + if (update_taker_order_id) { + posted_order_id + } else if (vector::is_empty(fill_events_queue_ref)) { (NIL as u128) - } else if (update_taker_order_id) { - new_taker_order_id } else { user::get_fill_event_taker_order_id( vector::borrow(fill_events_queue_ref, 0)) @@ -4233,6 +4234,15 @@ module econia::market { avl_queue::is_local_tail(orders_ref, avlq_access_key) } + #[test_only] + /// Return order ID derived solely from order book counter for a + /// limit order that took without posting. + public fun order_id_no_post( + counter: u64 + ): u128 { + (counter as u128) << SHIFT_COUNTER + } + // Test-only functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Test-only constants >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -7394,7 +7404,7 @@ module econia::market { &user_1, MARKET_ID_COIN, @integrator, side, size, price, restriction, self_match_behavior); // Assert returns. - assert!(market_order_id_1 == (NIL as u128), 0); + assert!(market_order_id_1 == order_id_no_post(2), 0); assert!(base_trade_r == base, 0); assert!(quote_trade_r == quote_trade, 0); assert!(fee_r == fee, 0); @@ -7618,7 +7628,7 @@ module econia::market { &user_1, MARKET_ID_COIN, @integrator, side, size, price, restriction, self_match_behavior); // Assert returns - assert!(market_order_id_1 == (NIL as u128), 0); + assert!(market_order_id_1 == order_id_no_post(2), 0); assert!(base_trade_r == base_match, 0); assert!(quote_trade_r == quote_trade, 0); assert!(fee_r == fee, 0); @@ -7772,7 +7782,7 @@ module econia::market { &user_1, MARKET_ID_COIN, @integrator, side, size, price, restriction, self_match_behavior); // Assert returns. - assert!(market_order_id_1 == (NIL as u128), 0); + assert!(market_order_id_1 == order_id_no_post(2), 0); assert!(base_trade_r == base, 0); assert!(quote_trade_r == quote_trade, 0); assert!(fee_r == fee, 0); @@ -8000,7 +8010,7 @@ module econia::market { &user_1, MARKET_ID_COIN, @integrator, side, size, price, restriction, self_match_behavior); // Assert returns - assert!(market_order_id_1 == (NIL as u128), 0); + assert!(market_order_id_1 == order_id_no_post(2), 0); assert!(base_trade_r == base_match, 0); assert!(quote_trade_r == quote_trade, 0); assert!(fee_r == fee, 0); @@ -9121,7 +9131,7 @@ module econia::market { &taker, MARKET_ID_COIN, @integrator, side_taker, size_taker_requested, price, restriction, self_match_behavior); // Assert returns - assert!(market_order_id_1 == (NIL as u128), 0); + assert!(market_order_id_1 == order_id_no_post(2), 0); assert!(base_trade_r == base_taker, 0); assert!(quote_trade_r == quote_trade, 0); assert!(fee_r == fee, 0); @@ -9242,7 +9252,7 @@ module econia::market { &taker, MARKET_ID_COIN, @integrator, side_taker, size_taker_requested, price, restriction, self_match_behavior); // Assert returns - assert!(market_order_id_1 == (NIL as u128), 0); + assert!(market_order_id_1 == order_id_no_post(2), 0); assert!(base_trade_r == base_taker, 0); assert!(quote_trade_r == quote_trade, 0); assert!(fee_r == fee, 0); diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 92352c775..e22d1d77c 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -4631,6 +4631,7 @@ module econia::user { MarketAccounts, MarketEventHandles { + account::create_account_for_test(address_of(user)); // Register test markets, storing pure coin market ID. let (market_id_pure_coin, _, _, _, _, _, _, _, _, _, _, _) = registry::register_markets_test(); @@ -4672,6 +4673,7 @@ module econia::user { MarketAccounts, MarketEventHandles { + account::create_account_for_test(address_of(user)); // Register test markets, storing market info. let (market_id_pure_coin, base_name_generic_pure_coin, lot_size_pure_coin, tick_size_pure_coin, min_size_pure_coin, From 308c76f75dfbecb110b250504aa9e843e028de1d Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:09:45 -0700 Subject: [PATCH 10/56] Add draft LimitOrderEvent support --- src/move/econia/sources/market.move | 83 +++++++++-------- src/move/econia/sources/user.move | 138 +++++++++++++++++++++------- 2 files changed, 150 insertions(+), 71 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 81f3adc25..33bb36f89 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -545,7 +545,11 @@ module econia::market { Self, CustodianCapability, GenericAsset, UnderwriterCapability}; use econia::resource_account; use econia::tablist::{Self, Tablist}; - use econia::user::{Self, FillEvent}; + use econia::user::{ + Self, + FillEvent, + LimitOrderEvent + }; use std::option::{Self, Option}; use std::signer::address_of; use std::string::{Self, String}; @@ -562,14 +566,6 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /* - TODO: Cancel event, flag for is_self_match_cancel - */ - - /* - TODO: Fee event should be for integrator, taker fee divisor, amounts assessed? - */ - /// An order on the order book. struct Order has store { /// Number of lots to be filled. @@ -630,36 +626,18 @@ module econia::market { /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { fill_events: Table>, + limit_order_events: Table> /* - /// place_limit_order() - new_limit_order_events_market: EventHandle, - new_limit_order_events_user: - map>, /// place_market_order() - new_market_order_events_market: EventHandle, - new_market_order_events_user: - map>, + market_order_events: EventHandle, /// swap() - new_swap_order_events_market: EventHandle, - new_swap_order_events_signer: - map>, - /// place_limit_order() (only amount that posts to book) - order_post_events_market: EventHandle, - order_post_events_user: - map>, + swap_events_market: EventHandle, + swap_events_signer: + map>, /// change_order_size() - change_order_size_event_market: EventHandle, - change_order_size_event_user: - map>, - /// cancel_order() + change_order_size_events: EventHandle, + /// cancel_order() (and place_limit_order(), for flag on eviction) cancel_order_event_market: EventHandle, - cancel_order_event_user: - map>, - cancel_order_event_market: EventHandle, - /// place_limit_order() - order_evict_event_market: EventHandle, - order_evict_event_user: - map>, */ } @@ -2663,6 +2641,7 @@ module econia::market { &resource_account::get_signer(), MarketEventHandles{ fill_events: table::new(), + limit_order_events: table::new() } ); borrow_global_mut(resource_address) @@ -3281,7 +3260,8 @@ module econia::market { } else { // If spread not crossed (matching engine not called): order_book_ref_mut.counter = order_book_ref_mut.counter + 1; }; - let order_id_as_maker = (NIL as u128); // Assume no post. + // Assume no size posted to book. + let (size_posted, order_id_as_maker) = (0, (NIL as u128)); // If size big enough to post and not immediate-or-cancel: if ((size >= order_book_ref_mut.min_size) && (restriction != IMMEDIATE_OR_CANCEL)) { @@ -3307,10 +3287,7 @@ module econia::market { user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, market_order_id, order_access_key); - // Emit a maker place event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id, user: user_address, - custodian_id, type: PLACE, size, price}); + size_posted = size; // Mark size posted as maker. if (evictee_access_key == NIL) { // If no eviction required: // Destroy empty evictee value option. option::destroy_none(evictee_value); @@ -3333,6 +3310,34 @@ module econia::market { let market_order_id = emit_fill_events( market_id, &mut fill_event_queue, market_event_handles_ref_mut, order_id_as_maker); + // Emit a limit order event, creating handle as needed. + let limit_order_event = user::get_limit_order_event( + market_id, + user_address, + custodian_id, + integrator, + side, + size, + price, + restriction, + self_match_behavior, + base_traded, + quote_traded, + fees, + size_posted, + market_order_id); + let has_limit_order_handle = table::contains( + &market_event_handles_ref_mut.limit_order_events, market_id); + if (!has_limit_order_handle) table::add( + &mut market_event_handles_ref_mut.limit_order_events, + market_id, + account::new_event_handle( + &resource_account::get_signer())); + let limit_order_handle_ref_mut = table::borrow_mut( + &mut market_event_handles_ref_mut.limit_order_events, + market_id); + event::emit_event(limit_order_handle_ref_mut, limit_order_event); + user::emit_limit_order_event(limit_order_event); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index e22d1d77c..bdd2c8830 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -400,9 +400,19 @@ module econia::user { custodians: Tablist> } + /// An open order, either ask or bid. + struct Order has store { + /// Market order ID. `NIL` if inactive. + market_order_id: u128, + /// Order size left to fill, in lots. When `market_order_id` is + /// `NIL`, indicates access key of next inactive order in stack. + size: u64 + } + /// Table keys are market account IDs. struct MarketEventHandles has key { fill_events: Table>, + limit_order_events: Table> } struct FillEvent has copy, drop, store { @@ -418,13 +428,21 @@ module econia::user { taker_order_id: u128 } - /// An open order, either ask or bid. - struct Order has store { - /// Market order ID. `NIL` if inactive. - market_order_id: u128, - /// Order size left to fill, in lots. When `market_order_id` is - /// `NIL`, indicates access key of next inactive order in stack. - size: u64 + struct LimitOrderEvent has copy, drop, store { + market_id: u64, + user: address, + custodian_id: u64, + integrator: address, + side: bool, + size: u64, + price: u64, + restriction: u8, + self_match_behavior: u8, + base_traded_as_taker: u64, + quote_traded_as_taker: u64, + fees_as_taker: u64, + size_posted_as_maker: u64, + order_id: u128 } // Structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -1111,7 +1129,8 @@ module econia::user { E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) move_to(user, MarketEventHandles{ - fill_events: table::new() + fill_events: table::new(), + limit_order_events: table::new() }); let market_event_handles_ref_mut = borrow_global_mut(user_address); @@ -1489,30 +1508,6 @@ module econia::user { user_address, market_id, custodian_id, quote_coins); } - /// Emit fill event for either maker or taker, if handle exists. - public(friend) fun emit_fill_event( - event: FillEvent, - is_maker: bool - ) acquires MarketEventHandles { - let (user_address, custodian_id) = if (is_maker) - (event.maker, event.maker_custodian_id) else - (event.taker, event.taker_custodian_id); - if ((exists(user_address)) && - (user_address != NO_MARKET_ACCOUNT)) { - let market_event_handles_ref_mut = - borrow_global_mut(user_address); - let fill_events_ref_mut = - &mut market_event_handles_ref_mut.fill_events; - let market_account_id = - get_market_account_id(event.market_id, custodian_id); - if (table::contains(fill_events_ref_mut, market_account_id)) { - let fill_event_handle_ref_mut = table::borrow_mut( - fill_events_ref_mut, market_account_id); - event::emit_event(fill_event_handle_ref_mut, event) - } - } - } - /// Emit fill event to specified handle, if handle exists. public(friend) fun emit_fill_event_for_maker_and_taker( event: FillEvent @@ -1521,6 +1516,27 @@ module econia::user { emit_fill_event(event, false); } + public(friend) fun emit_limit_order_event( + event: LimitOrderEvent + ) acquires MarketEventHandles { + let user_address = event.user; + if (exists(user_address)) { + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let limit_order_events_ref_mut = + &mut market_event_handles_ref_mut.limit_order_events; + let market_account_id = + get_market_account_id(event.market_id, event.custodian_id); + let has_handle = table::contains( + limit_order_events_ref_mut, market_account_id); + if (has_handle) { + let limit_order_event_handle_ref_mut = table::borrow_mut( + limit_order_events_ref_mut, market_account_id); + event::emit_event(limit_order_event_handle_ref_mut, event) + } + } + } + public(friend) fun get_fill_event( market_id: u64, size: u64, @@ -1560,6 +1576,40 @@ module econia::user { fill_event_ref_mut.taker_order_id = taker_order_id } + public(friend) fun get_limit_order_event( + market_id: u64, + user: address, + custodian_id: u64, + integrator: address, + side: bool, + size: u64, + price: u64, + restriction: u8, + self_match_behavior: u8, + base_traded_as_taker: u64, + quote_traded_as_taker: u64, + fees_as_taker: u64, + size_posted_as_maker: u64, + order_id: u128 + ): LimitOrderEvent { + LimitOrderEvent { + market_id, + user, + custodian_id, + integrator, + side, + size, + price, + restriction, + self_match_behavior, + base_traded_as_taker, + quote_traded_as_taker, + fees_as_taker, + size_posted_as_maker, + order_id + } + } + /// Fill a user's order, routing collateral appropriately. /// /// Updates asset counts in a user's market account. Transfers @@ -2275,6 +2325,30 @@ module econia::user { }; } + /// Emit fill event for either maker or taker, if handle exists. + inline fun emit_fill_event( + event: FillEvent, + is_maker: bool + ) acquires MarketEventHandles { + let (user_address, custodian_id) = if (is_maker) + (event.maker, event.maker_custodian_id) else + (event.taker, event.taker_custodian_id); + if ((exists(user_address)) && + (user_address != NO_MARKET_ACCOUNT)) { + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let fill_events_ref_mut = + &mut market_event_handles_ref_mut.fill_events; + let market_account_id = + get_market_account_id(event.market_id, custodian_id); + if (table::contains(fill_events_ref_mut, market_account_id)) { + let fill_event_handle_ref_mut = table::borrow_mut( + fill_events_ref_mut, market_account_id); + event::emit_event(fill_event_handle_ref_mut, event) + } + } + } + /// Return `registry::MarketInfo` fields stored in market account. /// /// # Parameters From 69f05ea0fce584b6262457f301a1fbd1046875e3 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:30:16 -0700 Subject: [PATCH 11/56] Clarify deprecation/upgrade policy --- src/move/econia/sources/market.move | 12 ++++++------ src/move/template.move | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 33bb36f89..4fe3b3259 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -605,9 +605,9 @@ module econia::market { bids: AVLqueue, /// Cumulative number of orders placed. counter: u64, - /// Deprecated field retained for backwards compatibility. + /// Deprecated field retained for compatible upgrade policy. maker_events: EventHandle, - /// Deprecated field retained for backwards compatibility. + /// Deprecated field retained for compatible upgrade policy. taker_events: EventHandle } @@ -3974,7 +3974,7 @@ module econia::market { // Deprecated structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /// Deprecated struct retained for backwards compatibility. + /// Deprecated struct retained for compatible upgrade policy. struct MakerEvent has drop, store { market_id: u64, side: bool, @@ -3986,10 +3986,10 @@ module econia::market { price: u64 } - /// Deprecated struct retained for backwards compatibility. + /// Deprecated struct retained for compatible upgrade policy. struct Orders has key {asks: vector, bids: vector} - /// Deprecated struct retained for backwards compatibility. + /// Deprecated struct retained for compatible upgrade policy. struct TakerEvent has drop, store { market_id: u64, side: bool, @@ -4006,7 +4006,7 @@ module econia::market { // Deprecated functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /// Deprecated function retained for backwards compatibility. + /// Deprecated function retained for compatible upgrade policy. /// /// # Coverage testing /// diff --git a/src/move/template.move b/src/move/template.move index 5d951e6a7..3b69e613f 100644 --- a/src/move/template.move +++ b/src/move/template.move @@ -80,13 +80,13 @@ module econia::template { // Deprecated structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /// Deprecated struct retained for backwards compatibility. + /// Deprecated struct retained for compatible upgrade policy. // Deprecated structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Deprecated functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - /// Deprecated function retained for backwards compatibility. + /// Deprecated function retained for compatible upgrade policy. /// /// # Coverage testing /// From 58a7aa9c1b3d626c57dcd0e1119d5ae8b8a30b13 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 6 Jul 2023 15:41:16 -0700 Subject: [PATCH 12/56] Rename PlaceLimitOrderEvent, pack_x_event helpers --- src/move/econia/sources/market.move | 32 +++++++++++++++-------------- src/move/econia/sources/user.move | 32 +++++++++++++++-------------- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 4fe3b3259..5db1d7132 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -548,7 +548,7 @@ module econia::market { use econia::user::{ Self, FillEvent, - LimitOrderEvent + PlaceLimitOrderEvent }; use std::option::{Self, Option}; use std::signer::address_of; @@ -626,7 +626,8 @@ module econia::market { /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { fill_events: Table>, - limit_order_events: Table> + place_limit_order_events: + Table> /* /// place_market_order() market_order_events: EventHandle, @@ -2641,7 +2642,7 @@ module econia::market { &resource_account::get_signer(), MarketEventHandles{ fill_events: table::new(), - limit_order_events: table::new() + place_limit_order_events: table::new() } ); borrow_global_mut(resource_address) @@ -2909,7 +2910,7 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - vector::push_back(event_queue_ref_mut, user::get_fill_event( + vector::push_back(event_queue_ref_mut, user::pack_fill_event( market_id, fill_size, price, @@ -3310,8 +3311,8 @@ module econia::market { let market_order_id = emit_fill_events( market_id, &mut fill_event_queue, market_event_handles_ref_mut, order_id_as_maker); - // Emit a limit order event, creating handle as needed. - let limit_order_event = user::get_limit_order_event( + // Emit a place limit order event, creating handle as needed. + let place_limit_order_event = user::pack_place_limit_order_event( market_id, user_address, custodian_id, @@ -3326,18 +3327,19 @@ module econia::market { fees, size_posted, market_order_id); - let has_limit_order_handle = table::contains( - &market_event_handles_ref_mut.limit_order_events, market_id); - if (!has_limit_order_handle) table::add( - &mut market_event_handles_ref_mut.limit_order_events, + let has_place_limit_order_event_handle = table::contains( + &market_event_handles_ref_mut.place_limit_order_events, market_id); + if (!has_place_limit_order_event_handle) table::add( + &mut market_event_handles_ref_mut.place_limit_order_events, market_id, - account::new_event_handle( + account::new_event_handle( &resource_account::get_signer())); - let limit_order_handle_ref_mut = table::borrow_mut( - &mut market_event_handles_ref_mut.limit_order_events, + let place_limit_order_event_handle_ref_mut = table::borrow_mut( + &mut market_event_handles_ref_mut.place_limit_order_events, market_id); - event::emit_event(limit_order_handle_ref_mut, limit_order_event); - user::emit_limit_order_event(limit_order_event); + event::emit_event(place_limit_order_event_handle_ref_mut, + place_limit_order_event); + user::emit_place_limit_order_event(place_limit_order_event); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index bdd2c8830..ed49ce7ba 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -412,7 +412,8 @@ module econia::user { /// Table keys are market account IDs. struct MarketEventHandles has key { fill_events: Table>, - limit_order_events: Table> + place_limit_order_events: + Table> } struct FillEvent has copy, drop, store { @@ -428,7 +429,7 @@ module econia::user { taker_order_id: u128 } - struct LimitOrderEvent has copy, drop, store { + struct PlaceLimitOrderEvent has copy, drop, store { market_id: u64, user: address, custodian_id: u64, @@ -1130,7 +1131,7 @@ module econia::user { if (!exists(address_of(user))) move_to(user, MarketEventHandles{ fill_events: table::new(), - limit_order_events: table::new() + place_limit_order_events: table::new() }); let market_event_handles_ref_mut = borrow_global_mut(user_address); @@ -1516,28 +1517,29 @@ module econia::user { emit_fill_event(event, false); } - public(friend) fun emit_limit_order_event( - event: LimitOrderEvent + public(friend) fun emit_place_limit_order_event( + event: PlaceLimitOrderEvent ) acquires MarketEventHandles { let user_address = event.user; if (exists(user_address)) { let market_event_handles_ref_mut = borrow_global_mut(user_address); - let limit_order_events_ref_mut = - &mut market_event_handles_ref_mut.limit_order_events; + let place_limit_order_events_ref_mut = + &mut market_event_handles_ref_mut.place_limit_order_events; let market_account_id = get_market_account_id(event.market_id, event.custodian_id); let has_handle = table::contains( - limit_order_events_ref_mut, market_account_id); + place_limit_order_events_ref_mut, market_account_id); if (has_handle) { - let limit_order_event_handle_ref_mut = table::borrow_mut( - limit_order_events_ref_mut, market_account_id); - event::emit_event(limit_order_event_handle_ref_mut, event) + let place_limit_order_event_handle_ref_mut = table::borrow_mut( + place_limit_order_events_ref_mut, market_account_id); + event::emit_event( + place_limit_order_event_handle_ref_mut, event) } } } - public(friend) fun get_fill_event( + public(friend) fun pack_fill_event( market_id: u64, size: u64, price: u64, @@ -1576,7 +1578,7 @@ module econia::user { fill_event_ref_mut.taker_order_id = taker_order_id } - public(friend) fun get_limit_order_event( + public(friend) fun pack_place_limit_order_event( market_id: u64, user: address, custodian_id: u64, @@ -1591,8 +1593,8 @@ module econia::user { fees_as_taker: u64, size_posted_as_maker: u64, order_id: u128 - ): LimitOrderEvent { - LimitOrderEvent { + ): PlaceLimitOrderEvent { + PlaceLimitOrderEvent { market_id, user, custodian_id, From 1cbc3124a1ef61f094e3bb19aff023793dda8e95 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:11:08 -0700 Subject: [PATCH 13/56] Add PlaceMarketEvent support --- src/move/econia/sources/market.move | 102 ++++++++++++++---------- src/move/econia/sources/user.move | 117 +++++++++++++++++++++------- 2 files changed, 152 insertions(+), 67 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 5db1d7132..99bed1878 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -537,7 +537,6 @@ module econia::market { use aptos_framework::account; use aptos_framework::coin::{Self, Coin}; use aptos_framework::event::{Self, EventHandle}; - use aptos_framework::table::{Self, Table}; use aptos_framework::type_info::{Self, TypeInfo}; use econia::avl_queue::{Self, AVLqueue}; use econia::incentives; @@ -548,7 +547,8 @@ module econia::market { use econia::user::{ Self, FillEvent, - PlaceLimitOrderEvent + PlaceLimitOrderEvent, + PlaceMarketOrderEvent }; use std::option::{Self, Option}; use std::signer::address_of; @@ -625,9 +625,11 @@ module econia::market { /// affected user/custodian ID tuple (affected signer in the case of /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { - fill_events: Table>, + fill_events: Tablist>, place_limit_order_events: - Table> + Tablist>, + place_market_order_events: + Tablist> /* /// place_market_order() market_order_events: EventHandle, @@ -2481,49 +2483,35 @@ module econia::market { size: new_size, price}); } - /// Return taker order ID (assumed constant across all fill events): - /// * If posted order ID given (if fill events from limit order that - /// took then posted), return posted order ID - /// * If no post and no fill events, then taker order ID is null - /// * Otherwise, order did not post but it did result in fills, so - /// get the taker order ID from the first fill event fun emit_fill_events( market_id: u64, fill_events_queue_ref: &vector, handles_ref_mut: &mut MarketEventHandles, - posted_order_id: u128 - ): u128 { - let update_taker_order_id = posted_order_id != (NIL as u128); + new_taker_order_id: u128 + ) { + let update_taker_order_id = new_taker_order_id == (NIL as u128); vector::for_each_ref(fill_events_queue_ref, |event_ref| { let event: FillEvent = *event_ref; if (update_taker_order_id) { user::set_fill_event_taker_order_id( - &mut event, posted_order_id); + &mut event, new_taker_order_id); }; user::emit_fill_event_for_maker_and_taker(event); // Emit event for market, creating handle as needed. - let has_handle = table::contains( + let has_handle = tablist::contains( &handles_ref_mut.fill_events, market_id); if (!has_handle) { - table::add( + tablist::add( &mut handles_ref_mut.fill_events, market_id, account::new_event_handle( &resource_account::get_signer())); }; - let handle_ref_mut = table::borrow_mut( + let handle_ref_mut = tablist::borrow_mut( &mut handles_ref_mut.fill_events, market_id); event::emit_event(handle_ref_mut, event); }); - if (update_taker_order_id) { - posted_order_id - } else if (vector::is_empty(fill_events_queue_ref)) { - (NIL as u128) - } else { - user::get_fill_event_taker_order_id( - vector::borrow(fill_events_queue_ref, 0)) - } } /// Get AVL queue access key encoded in `market_order_id`. @@ -2641,8 +2629,9 @@ module econia::market { move_to( &resource_account::get_signer(), MarketEventHandles{ - fill_events: table::new(), - place_limit_order_events: table::new() + fill_events: tablist::new(), + place_limit_order_events: tablist::new(), + place_market_order_events: tablist::new() } ); borrow_global_mut(resource_address) @@ -3262,7 +3251,8 @@ module econia::market { order_book_ref_mut.counter = order_book_ref_mut.counter + 1; }; // Assume no size posted to book. - let (size_posted, order_id_as_maker) = (0, (NIL as u128)); + let (size_posted, market_order_id) = + (0, ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER)); // If size big enough to post and not immediate-or-cancel: if ((size >= order_book_ref_mut.min_size) && (restriction != IMMEDIATE_OR_CANCEL)) { @@ -3283,7 +3273,7 @@ module econia::market { // Assert that order could be inserted to AVL queue. assert!(avlq_access_key != NIL, E_PRICE_TIME_PRIORITY_TOO_LOW); // Get market order ID from AVL queue access key, counter. - let market_order_id = (avlq_access_key as u128) | + market_order_id = (avlq_access_key as u128) | ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, @@ -3305,12 +3295,10 @@ module econia::market { market_id, side, market_order_id: market_order_id_cancel, user, custodian_id, type: EVICT, size, price}); }; - // Order ID as maker is from post to book. - order_id_as_maker = market_order_id }; - let market_order_id = emit_fill_events( + emit_fill_events( market_id, &mut fill_event_queue, market_event_handles_ref_mut, - order_id_as_maker); + market_order_id); // Emit a place limit order event, creating handle as needed. let place_limit_order_event = user::pack_place_limit_order_event( market_id, @@ -3327,14 +3315,14 @@ module econia::market { fees, size_posted, market_order_id); - let has_place_limit_order_event_handle = table::contains( + let has_place_limit_order_event_handle = tablist::contains( &market_event_handles_ref_mut.place_limit_order_events, market_id); - if (!has_place_limit_order_event_handle) table::add( + if (!has_place_limit_order_event_handle) tablist::add( &mut market_event_handles_ref_mut.place_limit_order_events, market_id, account::new_event_handle( &resource_account::get_signer())); - let place_limit_order_event_handle_ref_mut = table::borrow_mut( + let place_limit_order_event_handle_ref_mut = tablist::borrow_mut( &mut market_event_handles_ref_mut.place_limit_order_events, market_id); event::emit_event(place_limit_order_event_handle_ref_mut, @@ -3658,13 +3646,16 @@ module econia::market { // Calculate limit price for matching engine: 0 when selling, // max price possible when buying. let limit_price = if (direction == SELL) 0 else HI_PRICE; + let market_event_handles_ref_mut = + market_event_handles_borrow_mut(resource_address); + let fill_event_queue = vector[]; // Match against order book, storing optionally modified asset // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match( + _) = match( market_id, - market_event_handles_borrow_mut(resource_address), - &mut vector[], + market_event_handles_ref_mut, + &mut fill_event_queue, order_book_ref_mut, user_address, custodian_id, @@ -3678,6 +3669,8 @@ module econia::market { self_match_behavior, optional_base_coins, quote_coins); + let market_order_id = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -3685,6 +3678,35 @@ module econia::market { user::deposit_assets_internal( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); + emit_fill_events( + market_id, &mut fill_event_queue, market_event_handles_ref_mut, + (NIL as u128)); + // Emit a place market order event, creating handle as needed. + let place_market_order_event = user::pack_place_market_order_event( + market_id, + user_address, + custodian_id, + integrator, + direction, + size, + self_match_behavior, + base_traded, + quote_traded, + fees, + market_order_id); + let has_place_market_order_event_handle = tablist::contains( + &market_event_handles_ref_mut.place_market_order_events, market_id); + if (!has_place_market_order_event_handle) tablist::add( + &mut market_event_handles_ref_mut.place_market_order_events, + market_id, + account::new_event_handle( + &resource_account::get_signer())); + let place_market_order_event_handle_ref_mut = tablist::borrow_mut( + &mut market_event_handles_ref_mut.place_market_order_events, + market_id); + event::emit_event(place_market_order_event_handle_ref_mut, + place_market_order_event); + user::emit_place_market_order_event(place_market_order_event); // Return base and quote traded by user, fees paid. (base_traded, quote_traded, fees) } @@ -7701,7 +7723,7 @@ module econia::market { &user, MARKET_ID_COIN, @integrator, side_taker, size, price, restriction, self_match_behavior); // Assert returns - assert!(market_order_id_r == (NIL as u128), 0); + assert!(market_order_id_r == order_id_no_post(2), 0); assert!(base_trade_r == 0, 0); assert!(quote_trade_r == 0, 0); assert!(fee_r == 0, 0); diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index ed49ce7ba..38a0eb6a9 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -411,9 +411,11 @@ module econia::user { /// Table keys are market account IDs. struct MarketEventHandles has key { - fill_events: Table>, + fill_events: Tablist>, place_limit_order_events: - Table> + Tablist>, + place_market_order_events: + Tablist> } struct FillEvent has copy, drop, store { @@ -441,11 +443,25 @@ module econia::user { self_match_behavior: u8, base_traded_as_taker: u64, quote_traded_as_taker: u64, - fees_as_taker: u64, + quote_fee_paid_as_taker: u64, size_posted_as_maker: u64, order_id: u128 } + struct PlaceMarketOrderEvent has copy, drop, store { + market_id: u64, + user: address, + custodian_id: u64, + integrator: address, + direction: bool, + size: u64, + self_match_behavior: u8, + base_traded: u64, + quote_traded: u64, + quote_fee_paid: u64, + order_id: u128 + } + // Structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Error codes >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -1130,8 +1146,9 @@ module econia::user { E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) move_to(user, MarketEventHandles{ - fill_events: table::new(), - place_limit_order_events: table::new() + fill_events: tablist::new(), + place_limit_order_events: tablist::new(), + place_market_order_events: tablist::new() }); let market_event_handles_ref_mut = borrow_global_mut(user_address); @@ -1139,8 +1156,8 @@ module econia::user { get_market_account_id(market_id, custodian_id); let fill_events_ref_mut = &mut market_event_handles_ref_mut.fill_events; - if (!table::contains(fill_events_ref_mut, market_account_id)) { - table::add(fill_events_ref_mut, market_account_id, + if (!tablist::contains(fill_events_ref_mut, market_account_id)) { + tablist::add(fill_events_ref_mut, market_account_id, account::new_event_handle(user)); }; } @@ -1521,22 +1538,40 @@ module econia::user { event: PlaceLimitOrderEvent ) acquires MarketEventHandles { let user_address = event.user; - if (exists(user_address)) { - let market_event_handles_ref_mut = - borrow_global_mut(user_address); - let place_limit_order_events_ref_mut = - &mut market_event_handles_ref_mut.place_limit_order_events; - let market_account_id = - get_market_account_id(event.market_id, event.custodian_id); - let has_handle = table::contains( - place_limit_order_events_ref_mut, market_account_id); - if (has_handle) { - let place_limit_order_event_handle_ref_mut = table::borrow_mut( - place_limit_order_events_ref_mut, market_account_id); - event::emit_event( - place_limit_order_event_handle_ref_mut, event) - } - } + if (!exists(user_address)) return; + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let market_account_id = + get_market_account_id(event.market_id, event.custodian_id); + let place_limit_order_events_ref_mut = + &mut market_event_handles_ref_mut.place_limit_order_events; + let has_handle = tablist::contains( + place_limit_order_events_ref_mut, market_account_id); + if (!has_handle) return; + let place_limit_order_event_handle_ref_mut = tablist::borrow_mut( + place_limit_order_events_ref_mut, market_account_id); + event::emit_event( + place_limit_order_event_handle_ref_mut, event) + } + + public(friend) fun emit_place_market_order_event( + event: PlaceMarketOrderEvent + ) acquires MarketEventHandles { + let user_address = event.user; + if (!exists(user_address)) return; + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let market_account_id = + get_market_account_id(event.market_id, event.custodian_id); + let place_market_order_events_ref_mut = + &mut market_event_handles_ref_mut.place_market_order_events; + let has_handle = tablist::contains( + place_market_order_events_ref_mut, market_account_id); + if (!has_handle) return; + let place_market_order_event_handle_ref_mut = tablist::borrow_mut( + place_market_order_events_ref_mut, market_account_id); + event::emit_event( + place_market_order_event_handle_ref_mut, event) } public(friend) fun pack_fill_event( @@ -1590,7 +1625,7 @@ module econia::user { self_match_behavior: u8, base_traded_as_taker: u64, quote_traded_as_taker: u64, - fees_as_taker: u64, + quote_fee_paid_as_taker: u64, size_posted_as_maker: u64, order_id: u128 ): PlaceLimitOrderEvent { @@ -1606,12 +1641,40 @@ module econia::user { self_match_behavior, base_traded_as_taker, quote_traded_as_taker, - fees_as_taker, + quote_fee_paid_as_taker, size_posted_as_maker, order_id } } + public(friend) fun pack_place_market_order_event( + market_id: u64, + user: address, + custodian_id: u64, + integrator: address, + direction: bool, + size: u64, + self_match_behavior: u8, + base_traded: u64, + quote_traded: u64, + quote_fee_paid: u64, + order_id: u128 + ): PlaceMarketOrderEvent { + PlaceMarketOrderEvent { + market_id, + user, + custodian_id, + integrator, + direction, + size, + self_match_behavior, + base_traded, + quote_traded, + quote_fee_paid, + order_id + } + } + /// Fill a user's order, routing collateral appropriately. /// /// Updates asset counts in a user's market account. Transfers @@ -2343,8 +2406,8 @@ module econia::user { &mut market_event_handles_ref_mut.fill_events; let market_account_id = get_market_account_id(event.market_id, custodian_id); - if (table::contains(fill_events_ref_mut, market_account_id)) { - let fill_event_handle_ref_mut = table::borrow_mut( + if (tablist::contains(fill_events_ref_mut, market_account_id)) { + let fill_event_handle_ref_mut = tablist::borrow_mut( fill_events_ref_mut, market_account_id); event::emit_event(fill_event_handle_ref_mut, event) } From 9985609b8f9e8c6a7edac864c9ff1d17eb0ab95d Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 6 Jul 2023 17:57:27 -0700 Subject: [PATCH 14/56] Add SwapEvent support --- src/move/econia/sources/market.move | 216 ++++++++++++++++++++-------- 1 file changed, 160 insertions(+), 56 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 99bed1878..d4783579d 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -629,21 +629,40 @@ module econia::market { place_limit_order_events: Tablist>, place_market_order_events: - Tablist> + Tablist>, + swap_events: + Tablist> /* - /// place_market_order() - market_order_events: EventHandle, - /// swap() - swap_events_market: EventHandle, - swap_events_signer: - map>, /// change_order_size() change_order_size_events: EventHandle, - /// cancel_order() (and place_limit_order(), for flag on eviction) + /// assorted (direct cancel, self match cancel, and eviction) cancel_order_event_market: EventHandle, */ } + /// Stored under a signing user's account (not market account), + /// since swaps are processed outside of a market account and do not + /// always require a signature. + struct SwapperEventHandles has key { + map: Tablist> + } + + struct SwapEvent has copy, drop, store { + market_id: u64, + signing_account: address, + integrator: address, + direction: bool, + min_base: u64, + max_base: u64, + min_quote: u64, + max_quote: u64, + limit_price: u64, + base_traded: u64, + quote_traded: u64, + quote_fee_paid: u64, + order_id: u128 + } + /// User-friendly representation of an open order on the order book, /// combining fields from `Order` and the corresponding /// `MakerEvent` emitted when order was first placed. @@ -1761,7 +1780,8 @@ module econia::market { u64 ) acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { let user_address = address_of(user); // Get user address. // Register base coin store if user does not have one. @@ -1795,11 +1815,35 @@ module econia::market { (option::some(coin::withdraw(user, max_base)), coin::zero()); // Swap against order book, storing optionally modified coin - // inputs, base and quote trade amounts, and quote fees paid. - let (optional_base_coins, quote_coins, base_traded, quote_traded, fees) - = swap(market_id, NO_UNDERWRITER, integrator, direction, min_base, - max_base, min_quote, max_quote, limit_price, - optional_base_coins, quote_coins); + // inputs, base and quote trade amounts, quote fees paid, and + // swap event. + let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, + swap_event) = swap( + user_address, + market_id, + NO_UNDERWRITER, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + optional_base_coins, + quote_coins); + // Create swapper event handle as needed, then emit event. + if (!exists(user_address)) + move_to(user, SwapperEventHandles{map: tablist::new()}); + let swapper_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; + if (!tablist::contains(swapper_event_handles_map_ref_mut, market_id)) + tablist::add( + swapper_event_handles_map_ref_mut, + market_id, + account::new_event_handle(user)); + let swapper_event_handle_ref_mut = tablist::borrow_mut( + swapper_event_handles_map_ref_mut, market_id); + event::emit_event(swapper_event_handle_ref_mut, swap_event); // Deposit base coins back to user's coin store. coin::deposit(user_address, option::destroy_some(optional_base_coins)); // Deposit quote coins back to user's coin store. @@ -1919,10 +1963,19 @@ module econia::market { // Swap against order book, storing optionally modified coin // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins_matched, base_traded, - quote_traded, fees) = swap( - market_id, NO_UNDERWRITER, integrator, direction, min_base, - max_base, min_quote, max_quote, limit_price, - optional_base_coins, quote_coins_to_match); + quote_traded, fees, _) = swap( + NO_MARKET_ACCOUNT, + market_id, + NO_UNDERWRITER, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + optional_base_coins, + quote_coins_to_match); // Merge matched quote coins back into holdings. coin::merge(&mut quote_coins, quote_coins_matched); // Get base coins from option. @@ -2023,9 +2076,18 @@ module econia::market { // Swap against order book, storing optionally modified quote // coin input, base and quote trade amounts, quote fees paid. let (optional_base_coins, quote_coins_matched, base_traded, - quote_traded, fees) = swap( - market_id, underwriter_id, integrator, direction, min_base, - max_base, min_quote, max_quote, limit_price, option::none(), + quote_traded, fees, _) = swap( + NO_MARKET_ACCOUNT, + market_id, + underwriter_id, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + option::none(), quote_coins_to_match); // Destroy empty base coin option. option::destroy_none>(optional_base_coins); @@ -2227,7 +2289,8 @@ module econia::market { limit_price: u64 ) acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { swap_between_coinstores( user, market_id, integrator, direction, min_base, max_base, @@ -2504,7 +2567,7 @@ module econia::market { tablist::add( &mut handles_ref_mut.fill_events, market_id, - account::new_event_handle( + account::new_event_handle( &resource_account::get_signer())); }; let handle_ref_mut = tablist::borrow_mut( @@ -2631,7 +2694,8 @@ module econia::market { MarketEventHandles{ fill_events: tablist::new(), place_limit_order_events: tablist::new(), - place_market_order_events: tablist::new() + place_market_order_events: tablist::new(), + swap_events: tablist::new() } ); borrow_global_mut(resource_address) @@ -2909,7 +2973,7 @@ module econia::market { market_order_id, taker, custodian_id, - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER) + order_id_no_post(order_book_ref_mut.counter) )); if (complete_fill) { let avlq_access_key = // Get AVL queue access key. @@ -2949,6 +3013,14 @@ module econia::market { self_match_taker_cancel) } + /// Return order ID derived solely from order book counter for an + /// order that did not post. + inline fun order_id_no_post( + counter: u64 + ): u128 { + (counter as u128) << SHIFT_COUNTER + } + /// Place limit order against order book from user market account. /// /// # Type Parameters @@ -3252,7 +3324,7 @@ module econia::market { }; // Assume no size posted to book. let (size_posted, market_order_id) = - (0, ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER)); + (0, order_id_no_post(order_book_ref_mut.counter)); // If size big enough to post and not immediate-or-cancel: if ((size >= order_book_ref_mut.min_size) && (restriction != IMMEDIATE_OR_CANCEL)) { @@ -3272,9 +3344,8 @@ module econia::market { orders_ref_mut, price, order, critical_height); // Assert that order could be inserted to AVL queue. assert!(avlq_access_key != NIL, E_PRICE_TIME_PRIORITY_TOO_LOW); - // Get market order ID from AVL queue access key, counter. - market_order_id = (avlq_access_key as u128) | - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + // Encode AVL queue access key in market order ID. + market_order_id = market_order_id | (avlq_access_key as u128); user::place_order_internal( // Place order user-side. user_address, market_id, custodian_id, side, size, price, market_order_id, order_access_key); @@ -3320,8 +3391,7 @@ module econia::market { if (!has_place_limit_order_event_handle) tablist::add( &mut market_event_handles_ref_mut.place_limit_order_events, market_id, - account::new_event_handle( - &resource_account::get_signer())); + account::new_event_handle(&resource_account::get_signer())); let place_limit_order_event_handle_ref_mut = tablist::borrow_mut( &mut market_event_handles_ref_mut.place_limit_order_events, market_id); @@ -3669,8 +3739,7 @@ module econia::market { self_match_behavior, optional_base_coins, quote_coins); - let market_order_id = - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + let market_order_id = order_id_no_post(order_book_ref_mut.counter); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -3699,8 +3768,7 @@ module econia::market { if (!has_place_market_order_event_handle) tablist::add( &mut market_event_handles_ref_mut.place_market_order_events, market_id, - account::new_event_handle( - &resource_account::get_signer())); + account::new_event_handle(&resource_account::get_signer())); let place_market_order_event_handle_ref_mut = tablist::borrow_mut( &mut market_event_handles_ref_mut.place_market_order_events, market_id); @@ -3886,6 +3954,8 @@ module econia::market { /// /// # Parameters /// + /// * `signer_address`: Address of signing user if applicable, else + /// `NO_MARKET_ACCOUNT`. /// * `market_id`: Same as for `match()`. /// * `underwriter_id`: ID of underwriter to verify if `BaseType` /// is `registry::GenericAsset`, else may be passed as @@ -3909,6 +3979,7 @@ module econia::market { /// * `u64`: Base asset trade amount, same as for `match()`. /// * `u64`: Quote coin trade amount, same as for `match()`. /// * `u64`: Quote coin fees paid, same as for `match()`. + /// * `SwapEvent`: Information about the swap. /// /// # Aborts /// @@ -3932,6 +4003,7 @@ module econia::market { BaseType, QuoteType >( + signer_address: address, market_id: u64, underwriter_id: u64, integrator: address, @@ -3948,7 +4020,8 @@ module econia::market { Coin, u64, u64, - u64 + u64, + SwapEvent ) acquires MarketEventHandles, OrderBooks @@ -3972,13 +4045,16 @@ module econia::market { == order_book_ref_mut.quote_type, E_INVALID_QUOTE); // Declare return assignment variables. let (base_traded, quote_traded, fees); + let market_event_handles_ref_mut = + market_event_handles_borrow_mut(resource_address); + let fill_event_queue = vector[]; (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) = match( // Match against order book. market_id, - market_event_handles_borrow_mut(resource_address), - &mut vector[], + market_event_handles_ref_mut, + &mut fill_event_queue, order_book_ref_mut, - NO_MARKET_ACCOUNT, + signer_address, NO_CUSTODIAN, integrator, direction, @@ -3990,8 +4066,39 @@ module econia::market { ABORT, optional_base_coins, quote_coins); - // Return optionally modified asset inputs, trade amounts, fees. - (optional_base_coins, quote_coins, base_traded, quote_traded, fees) + let market_order_id = order_id_no_post(order_book_ref_mut.counter); + emit_fill_events( + market_id, &mut fill_event_queue, market_event_handles_ref_mut, + (NIL as u128)); + let swap_event = SwapEvent{ + market_id, + signing_account: signer_address, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + base_traded, + quote_traded, + quote_fee_paid: fees, + order_id: market_order_id}; + let has_swap_event_handle_for_market = tablist::contains( + &market_event_handles_ref_mut.swap_events, market_id); + if (!has_swap_event_handle_for_market) tablist::add( + &mut market_event_handles_ref_mut.swap_events, + market_id, + account::new_event_handle(&resource_account::get_signer())); + let swap_event_handle_for_market_ref_mut = tablist::borrow_mut( + &mut market_event_handles_ref_mut.swap_events, + market_id); + event::emit_event(swap_event_handle_for_market_ref_mut, + swap_event); + // Return optionally modified asset inputs, trade amounts, fees, + // and swap event. + (optional_base_coins, quote_coins, base_traded, quote_traded, fees, + swap_event) } // Private functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -4263,15 +4370,6 @@ module econia::market { avl_queue::is_local_tail(orders_ref, avlq_access_key) } - #[test_only] - /// Return order ID derived solely from order book counter for a - /// limit order that took without posting. - public fun order_id_no_post( - counter: u64 - ): u128 { - (counter as u128) << SHIFT_COUNTER - } - // Test-only functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Test-only constants >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -10399,7 +10497,8 @@ module econia::market { fun test_swap_between_coinstores_max_possible_base_buy() acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); @@ -10504,7 +10603,8 @@ module econia::market { fun test_swap_between_coinstores_max_possible_base_sell() acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); @@ -10609,7 +10709,8 @@ module econia::market { fun test_swap_between_coinstores_max_possible_quote_buy() acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); @@ -10714,7 +10815,8 @@ module econia::market { fun test_swap_between_coinstores_max_possible_quote_sell() acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); @@ -10818,7 +10920,8 @@ module econia::market { fun test_swap_between_coinstores_register_base_store() acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); @@ -10914,7 +11017,8 @@ module econia::market { fun test_swap_between_coinstores_register_quote_store() acquires MarketEventHandles, - OrderBooks + OrderBooks, + SwapperEventHandles { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); From c23189a7bcf6a8e927b2ac7fb24d88f6cbf87dfb Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 7 Jul 2023 09:30:04 -0700 Subject: [PATCH 15/56] Add TradeSummary struct, refactor swap events --- src/move/econia/sources/market.move | 142 ++++++++++++++++------------ src/move/econia/sources/user.move | 79 +++++++++++----- 2 files changed, 137 insertions(+), 84 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index d4783579d..2c613d64c 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -630,8 +630,8 @@ module econia::market { Tablist>, place_market_order_events: Tablist>, - swap_events: - Tablist> + place_swap_order_events: + Tablist> /* /// change_order_size() change_order_size_events: EventHandle, @@ -644,10 +644,12 @@ module econia::market { /// since swaps are processed outside of a market account and do not /// always require a signature. struct SwapperEventHandles has key { - map: Tablist> + place_swap_order_events: + Tablist>, + fill_events: Tablist> } - struct SwapEvent has copy, drop, store { + struct PlaceSwapOrderEvent has copy, drop, store { market_id: u64, signing_account: address, integrator: address, @@ -657,9 +659,6 @@ module econia::market { min_quote: u64, max_quote: u64, limit_price: u64, - base_traded: u64, - quote_traded: u64, - quote_fee_paid: u64, order_id: u128 } @@ -1814,11 +1813,13 @@ module econia::market { // If a sell, need max base but not quote. (option::some(coin::withdraw(user, max_base)), coin::zero()); + let fill_event_queue = vector[]; // Swap against order book, storing optionally modified coin // inputs, base and quote trade amounts, quote fees paid, and - // swap event. + // place swap order event. let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - swap_event) = swap( + place_swap_order_event, ) = swap( + &mut fill_event_queue, user_address, market_id, NO_UNDERWRITER, @@ -1831,19 +1832,39 @@ module econia::market { limit_price, optional_base_coins, quote_coins); - // Create swapper event handle as needed, then emit event. if (!exists(user_address)) - move_to(user, SwapperEventHandles{map: tablist::new()}); - let swapper_event_handles_map_ref_mut = - &mut borrow_global_mut(user_address).map; - if (!tablist::contains(swapper_event_handles_map_ref_mut, market_id)) + move_to(user, SwapperEventHandles{ + place_swap_order_events: tablist::new(), + fill_events: tablist::new()}); + let swapper_event_handles_ref_mut = + borrow_global_mut(user_address); + // Emit place swap order event, initting handle as needed. + let place_swap_order_events_ref_mut = + &mut swapper_event_handles_ref_mut.place_swap_order_events; + if (!tablist::contains(place_swap_order_events_ref_mut, market_id)) + tablist::add( + place_swap_order_events_ref_mut, + market_id, + account::new_event_handle(user)); + let place_swap_order_event_handle_ref_mut = tablist::borrow_mut( + place_swap_order_events_ref_mut, market_id); + event::emit_event(place_swap_order_event_handle_ref_mut, + place_swap_order_event); + // Emit fill events, initting handle as needed. + let fill_events_ref_mut = + &mut swapper_event_handles_ref_mut.fill_events; + if (!tablist::contains(fill_events_ref_mut, market_id)) tablist::add( - swapper_event_handles_map_ref_mut, + fill_events_ref_mut, market_id, account::new_event_handle(user)); - let swapper_event_handle_ref_mut = tablist::borrow_mut( - swapper_event_handles_map_ref_mut, market_id); - event::emit_event(swapper_event_handle_ref_mut, swap_event); + let fill_events_handle_ref_mut = tablist::borrow_mut( + fill_events_ref_mut, market_id); + vector::for_each_ref(&fill_event_queue, |fill_event_ref| { + let fill_event: FillEvent = *fill_event_ref; + event::emit_event(fill_events_handle_ref_mut, + fill_event); + }); // Deposit base coins back to user's coin store. coin::deposit(user_address, option::destroy_some(optional_base_coins)); // Deposit quote coins back to user's coin store. @@ -1964,6 +1985,7 @@ module econia::market { // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins_matched, base_traded, quote_traded, fees, _) = swap( + &mut vector[], NO_MARKET_ACCOUNT, market_id, NO_UNDERWRITER, @@ -2077,6 +2099,7 @@ module econia::market { // coin input, base and quote trade amounts, quote fees paid. let (optional_base_coins, quote_coins_matched, base_traded, quote_traded, fees, _) = swap( + &mut vector[], NO_MARKET_ACCOUNT, market_id, underwriter_id, @@ -2546,20 +2569,25 @@ module econia::market { size: new_size, price}); } - fun emit_fill_events( + fun emit_fill_events_for_market_and_market_accounts( market_id: u64, - fill_events_queue_ref: &vector, + fill_event_queue_ref: &vector, handles_ref_mut: &mut MarketEventHandles, - new_taker_order_id: u128 + taker_is_swapper: bool, + new_taker_order_id: u128, ) { let update_taker_order_id = new_taker_order_id == (NIL as u128); - vector::for_each_ref(fill_events_queue_ref, |event_ref| { + vector::for_each_ref(fill_event_queue_ref, |event_ref| { let event: FillEvent = *event_ref; if (update_taker_order_id) { user::set_fill_event_taker_order_id( &mut event, new_taker_order_id); }; - user::emit_fill_event_for_maker_and_taker(event); + if (taker_is_swapper) { + user::emit_fill_event_for_maker(event); + } else { + user::emit_fill_event_for_maker_and_taker(event); + }; // Emit event for market, creating handle as needed. let has_handle = tablist::contains( &handles_ref_mut.fill_events, market_id); @@ -2695,7 +2723,7 @@ module econia::market { fill_events: tablist::new(), place_limit_order_events: tablist::new(), place_market_order_events: tablist::new(), - swap_events: tablist::new() + place_swap_order_events: tablist::new() } ); borrow_global_mut(resource_address) @@ -2871,6 +2899,7 @@ module econia::market { let self_match_taker_cancel = false; // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + let fill_count = 0; // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -2973,8 +3002,10 @@ module econia::market { market_order_id, taker, custodian_id, - order_id_no_post(order_book_ref_mut.counter) + order_id_no_post(order_book_ref_mut.counter), + fill_count )); + fill_count = fill_count + 1; if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -3367,9 +3398,6 @@ module econia::market { custodian_id, type: EVICT, size, price}); }; }; - emit_fill_events( - market_id, &mut fill_event_queue, market_event_handles_ref_mut, - market_order_id); // Emit a place limit order event, creating handle as needed. let place_limit_order_event = user::pack_place_limit_order_event( market_id, @@ -3381,9 +3409,6 @@ module econia::market { price, restriction, self_match_behavior, - base_traded, - quote_traded, - fees, size_posted, market_order_id); let has_place_limit_order_event_handle = tablist::contains( @@ -3398,6 +3423,9 @@ module econia::market { event::emit_event(place_limit_order_event_handle_ref_mut, place_limit_order_event); user::emit_place_limit_order_event(place_limit_order_event); + emit_fill_events_for_market_and_market_accounts( + market_id, &mut fill_event_queue, market_event_handles_ref_mut, + false, market_order_id); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } @@ -3747,9 +3775,6 @@ module econia::market { user::deposit_assets_internal( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); - emit_fill_events( - market_id, &mut fill_event_queue, market_event_handles_ref_mut, - (NIL as u128)); // Emit a place market order event, creating handle as needed. let place_market_order_event = user::pack_place_market_order_event( market_id, @@ -3759,9 +3784,6 @@ module econia::market { direction, size, self_match_behavior, - base_traded, - quote_traded, - fees, market_order_id); let has_place_market_order_event_handle = tablist::contains( &market_event_handles_ref_mut.place_market_order_events, market_id); @@ -3775,6 +3797,9 @@ module econia::market { event::emit_event(place_market_order_event_handle_ref_mut, place_market_order_event); user::emit_place_market_order_event(place_market_order_event); + emit_fill_events_for_market_and_market_accounts( + market_id, &mut fill_event_queue, market_event_handles_ref_mut, + false, (NIL as u128)); // Return base and quote traded by user, fees paid. (base_traded, quote_traded, fees) } @@ -3979,7 +4004,6 @@ module econia::market { /// * `u64`: Base asset trade amount, same as for `match()`. /// * `u64`: Quote coin trade amount, same as for `match()`. /// * `u64`: Quote coin fees paid, same as for `match()`. - /// * `SwapEvent`: Information about the swap. /// /// # Aborts /// @@ -4003,6 +4027,7 @@ module econia::market { BaseType, QuoteType >( + fill_event_queue_ref_mut: &mut vector, signer_address: address, market_id: u64, underwriter_id: u64, @@ -4021,7 +4046,7 @@ module econia::market { u64, u64, u64, - SwapEvent + PlaceSwapOrderEvent ) acquires MarketEventHandles, OrderBooks @@ -4047,12 +4072,11 @@ module econia::market { let (base_traded, quote_traded, fees); let market_event_handles_ref_mut = market_event_handles_borrow_mut(resource_address); - let fill_event_queue = vector[]; (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) = match( // Match against order book. market_id, market_event_handles_ref_mut, - &mut fill_event_queue, + fill_event_queue_ref_mut, order_book_ref_mut, signer_address, NO_CUSTODIAN, @@ -4067,10 +4091,7 @@ module econia::market { optional_base_coins, quote_coins); let market_order_id = order_id_no_post(order_book_ref_mut.counter); - emit_fill_events( - market_id, &mut fill_event_queue, market_event_handles_ref_mut, - (NIL as u128)); - let swap_event = SwapEvent{ + let place_swap_order_event = PlaceSwapOrderEvent{ market_id, signing_account: signer_address, integrator, @@ -4080,25 +4101,28 @@ module econia::market { min_quote, max_quote, limit_price, - base_traded, - quote_traded, - quote_fee_paid: fees, order_id: market_order_id}; - let has_swap_event_handle_for_market = tablist::contains( - &market_event_handles_ref_mut.swap_events, market_id); - if (!has_swap_event_handle_for_market) tablist::add( - &mut market_event_handles_ref_mut.swap_events, + let has_place_swap_order_event_handle_for_market = tablist::contains( + &market_event_handles_ref_mut.place_swap_order_events, + market_id); + if (!has_place_swap_order_event_handle_for_market) tablist::add( + &mut market_event_handles_ref_mut.place_swap_order_events, market_id, account::new_event_handle(&resource_account::get_signer())); - let swap_event_handle_for_market_ref_mut = tablist::borrow_mut( - &mut market_event_handles_ref_mut.swap_events, - market_id); - event::emit_event(swap_event_handle_for_market_ref_mut, - swap_event); + let place_swap_order_event_handle_for_market_ref_mut = + tablist::borrow_mut( + &mut market_event_handles_ref_mut.place_swap_order_events, + market_id); + event::emit_event(place_swap_order_event_handle_for_market_ref_mut, + place_swap_order_event); + emit_fill_events_for_market_and_market_accounts( + market_id, fill_event_queue_ref_mut, market_event_handles_ref_mut, + true, (NIL as u128)); + // TODO: ensure trade events emitted to swapper/market account holder. // Return optionally modified asset inputs, trade amounts, fees, - // and swap event. + // and place swap order event. (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - swap_event) + place_swap_order_event) } // Private functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 38a0eb6a9..7e5d42e45 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -428,7 +428,20 @@ module econia::user { maker_order_id: u128, taker: address, taker_custodian_id: u64, - taker_order_id: u128 + taker_order_id: u128, + sequence_number_for_trade: u64 + } + + struct TradeSummaryEvent has copy, drop, store { + market_id: u64, + taker: address, + custodian_id: u64, + is_swap: bool, + n_fills: u64, + base_traded: u64, + quote_traded: u64, + quote_fee_paid: u64, + order_id: u128 } struct PlaceLimitOrderEvent has copy, drop, store { @@ -441,10 +454,7 @@ module econia::user { price: u64, restriction: u8, self_match_behavior: u8, - base_traded_as_taker: u64, - quote_traded_as_taker: u64, - quote_fee_paid_as_taker: u64, - size_posted_as_maker: u64, + size_posted: u64, order_id: u128 } @@ -456,9 +466,6 @@ module econia::user { direction: bool, size: u64, self_match_behavior: u8, - base_traded: u64, - quote_traded: u64, - quote_fee_paid: u64, order_id: u128 } @@ -1150,15 +1157,41 @@ module econia::user { place_limit_order_events: tablist::new(), place_market_order_events: tablist::new() }); + + /////////// Also init handle below if no handle: + let market_event_handles_ref_mut = borrow_global_mut(user_address); let market_account_id = get_market_account_id(market_id, custodian_id); + let fill_events_ref_mut = &mut market_event_handles_ref_mut.fill_events; - if (!tablist::contains(fill_events_ref_mut, market_account_id)) { + let has_fill_events_handle = + tablist::contains(fill_events_ref_mut, market_account_id); + if (!has_fill_events_handle) { tablist::add(fill_events_ref_mut, market_account_id, - account::new_event_handle(user)); + account::new_event_handle(user)); + }; + + let place_limit_order_events_ref_mut = + &mut market_event_handles_ref_mut.place_limit_order_events; + let has_place_limit_order_events_handle = + tablist::contains(place_limit_order_events_ref_mut, + market_account_id); + if (!has_place_limit_order_events_handle) { + tablist::add(place_limit_order_events_ref_mut, market_account_id, + account::new_event_handle(user)); + }; + + let place_market_order_events_ref_mut = + &mut market_event_handles_ref_mut.place_market_order_events; + let has_place_market_order_events_handle = + tablist::contains(place_market_order_events_ref_mut, + market_account_id); + if (!has_place_market_order_events_handle) { + tablist::add(place_market_order_events_ref_mut, market_account_id, + account::new_event_handle(user)); }; } @@ -1534,6 +1567,12 @@ module econia::user { emit_fill_event(event, false); } + public(friend) fun emit_fill_event_for_maker( + event: FillEvent + ) acquires MarketEventHandles { + emit_fill_event(event, true); + } + public(friend) fun emit_place_limit_order_event( event: PlaceLimitOrderEvent ) acquires MarketEventHandles { @@ -1585,6 +1624,7 @@ module econia::user { taker: address, taker_custodian_id: u64, taker_order_id: u128, + sequence_number_for_trade: u64 ): FillEvent { FillEvent{ market_id, @@ -1596,7 +1636,8 @@ module econia::user { maker_order_id, taker, taker_custodian_id, - taker_order_id + taker_order_id, + sequence_number_for_trade } } @@ -1623,10 +1664,7 @@ module econia::user { price: u64, restriction: u8, self_match_behavior: u8, - base_traded_as_taker: u64, - quote_traded_as_taker: u64, - quote_fee_paid_as_taker: u64, - size_posted_as_maker: u64, + size_posted: u64, order_id: u128 ): PlaceLimitOrderEvent { PlaceLimitOrderEvent { @@ -1639,10 +1677,7 @@ module econia::user { price, restriction, self_match_behavior, - base_traded_as_taker, - quote_traded_as_taker, - quote_fee_paid_as_taker, - size_posted_as_maker, + size_posted, order_id } } @@ -1655,9 +1690,6 @@ module econia::user { direction: bool, size: u64, self_match_behavior: u8, - base_traded: u64, - quote_traded: u64, - quote_fee_paid: u64, order_id: u128 ): PlaceMarketOrderEvent { PlaceMarketOrderEvent { @@ -1668,9 +1700,6 @@ module econia::user { direction, size, self_match_behavior, - base_traded, - quote_traded, - quote_fee_paid, order_id } } From 308f9176826529bc6e3dd955849104f99a3e9c69 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 7 Jul 2023 14:05:31 -0700 Subject: [PATCH 16/56] Rename TakerFillSummaryEvent --- src/move/econia/sources/user.move | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 7e5d42e45..b080e828c 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -432,7 +432,7 @@ module econia::user { sequence_number_for_trade: u64 } - struct TradeSummaryEvent has copy, drop, store { + struct TakerFillSummaryEvent has copy, drop, store { market_id: u64, taker: address, custodian_id: u64, From 7fbc7364bddea01822df96f5deb017ad46436781 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 10 Jul 2023 08:30:11 -0700 Subject: [PATCH 17/56] Rename struct creation helpers --- src/move/econia/sources/market.move | 6 +++--- src/move/econia/sources/user.move | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 2c613d64c..61981f6df 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2992,7 +2992,7 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); - vector::push_back(event_queue_ref_mut, user::pack_fill_event( + vector::push_back(event_queue_ref_mut, user::create_fill_event( market_id, fill_size, price, @@ -3399,7 +3399,7 @@ module econia::market { }; }; // Emit a place limit order event, creating handle as needed. - let place_limit_order_event = user::pack_place_limit_order_event( + let place_limit_order_event = user::create_place_limit_order_event( market_id, user_address, custodian_id, @@ -3776,7 +3776,7 @@ module econia::market { user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); // Emit a place market order event, creating handle as needed. - let place_market_order_event = user::pack_place_market_order_event( + let place_market_order_event = user::create_place_market_order_event( market_id, user_address, custodian_id, diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index b080e828c..1f78272f0 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -1613,7 +1613,7 @@ module econia::user { place_market_order_event_handle_ref_mut, event) } - public(friend) fun pack_fill_event( + public(friend) fun create_fill_event( market_id: u64, size: u64, price: u64, @@ -1654,7 +1654,7 @@ module econia::user { fill_event_ref_mut.taker_order_id = taker_order_id } - public(friend) fun pack_place_limit_order_event( + public(friend) fun create_place_limit_order_event( market_id: u64, user: address, custodian_id: u64, @@ -1682,7 +1682,7 @@ module econia::user { } } - public(friend) fun pack_place_market_order_event( + public(friend) fun create_place_market_order_event( market_id: u64, user: address, custodian_id: u64, From fd2f570bffeb9cdca041b933c984558ddffdabdb Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 10 Jul 2023 09:04:28 -0700 Subject: [PATCH 18/56] Update fee schema to be per fill, not per trade --- doc/doc-site/docs/move/changelog.md | 14 +++++++++----- src/move/econia/sources/market.move | 12 ++++++++---- src/move/econia/sources/user.move | 15 +++------------ 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 95c9c94db..dfbbec078 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -6,21 +6,25 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] ### Added -- Assorted view functions ([#287], [#301], [#315]). -- Fill events with common market order ID ([#315]). +- Assorted view functions ([#287], [#301], [#321]). +- Fill events with common market order ID ([#321]). + +### Changed + +- Fee assessment updated to be processed per fill, rather than per trade ([#321]) ### Deprecated -- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#315]) +- [`market::OrderBook.taker_events`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L587) ([#321]) - [`market::Orders`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3337) ([#301]) -- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#315]) +- [`market::TakerEvent`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L600) ([#321]) - [`market::index_orders_sdk()`](https://github.com/econia-labs/econia/blob/v4.0.2-audited/src/move/econia/sources/market.move#L3362) ([#287]) - [`move-to-ts`](https://github.com/hippospace/move-to-ts) attributes ([#292]) [#287]: https://github.com/econia-labs/econia/pull/287 [#292]: https://github.com/econia-labs/econia/pull/292 [#301]: https://github.com/econia-labs/econia/pull/301 -[#315]: https://github.com/econia-labs/econia/pull/315 +[#321]: https://github.com/econia-labs/econia/pull/321 [keep a changelog]: https://keepachangelog.com/en/1.0.0/ [semantic versioning]: https://semver.org/spec/v2.0.0.html [unreleased]: https://github.com/econia-labs/econia/compare/v4.0.2-audited...HEAD diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 61981f6df..a298c679c 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2900,6 +2900,8 @@ module econia::market { // Increment order counter. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; let fill_count = 0; + let fees_paid = 0; + let fees_paid_for_fill; // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -2992,6 +2994,10 @@ module econia::market { fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, ticks_filled * tick_size); + (quote_coins, fees_paid_for_fill) = + incentives::assess_taker_fees( + market_id, integrator, taker_fee_divisor, + ticks_filled * tick_size, quote_coins); vector::push_back(event_queue_ref_mut, user::create_fill_event( market_id, fill_size, @@ -3003,9 +3009,11 @@ module econia::market { taker, custodian_id, order_id_no_post(order_book_ref_mut.counter), + fees_paid_for_fill, fill_count )); fill_count = fill_count + 1; + fees_paid = fees_paid + fees_paid_for_fill; if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -3025,10 +3033,6 @@ module econia::market { let (base_fill, quote_fill) = // Calculate base and quote fills. (((max_lots - lots_until_max ) * lot_size), ((max_ticks - ticks_until_max) * tick_size)); - // Assess taker fees, storing taker fees paid. - let (quote_coins, fees_paid) = incentives::assess_taker_fees< - QuoteType>(market_id, integrator, taker_fee_divisor, quote_fill, - quote_coins); // If a buy, taker pays quote required for fills, and additional // fee assessed after matching. If a sell, taker receives quote // from fills, then has a portion assessed as fees. diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 1f78272f0..e3d42679b 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -429,21 +429,10 @@ module econia::user { taker: address, taker_custodian_id: u64, taker_order_id: u128, + taker_quote_fees_paid: u64, sequence_number_for_trade: u64 } - struct TakerFillSummaryEvent has copy, drop, store { - market_id: u64, - taker: address, - custodian_id: u64, - is_swap: bool, - n_fills: u64, - base_traded: u64, - quote_traded: u64, - quote_fee_paid: u64, - order_id: u128 - } - struct PlaceLimitOrderEvent has copy, drop, store { market_id: u64, user: address, @@ -1624,6 +1613,7 @@ module econia::user { taker: address, taker_custodian_id: u64, taker_order_id: u128, + taker_quote_fees_paid: u64, sequence_number_for_trade: u64 ): FillEvent { FillEvent{ @@ -1637,6 +1627,7 @@ module econia::user { taker, taker_custodian_id, taker_order_id, + taker_quote_fees_paid, sequence_number_for_trade } } From d7fe4aca7c884fe51ad18b958c2eaff78aee4283 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:21:59 -0700 Subject: [PATCH 19/56] Eliminate redundant market-level emissions --- src/move/econia/sources/market.move | 34 +++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index a298c679c..b3051ec3c 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -544,12 +544,7 @@ module econia::market { Self, CustodianCapability, GenericAsset, UnderwriterCapability}; use econia::resource_account; use econia::tablist::{Self, Tablist}; - use econia::user::{ - Self, - FillEvent, - PlaceLimitOrderEvent, - PlaceMarketOrderEvent - }; + use econia::user::{Self, FillEvent}; use std::option::{Self, Option}; use std::signer::address_of; use std::string::{Self, String}; @@ -625,13 +620,16 @@ module econia::market { /// affected user/custodian ID tuple (affected signer in the case of /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { + /// Not emitted at user level when swapper doesn't sign. + place_swap_order_events: + Tablist> + /* fill_events: Tablist>, place_limit_order_events: Tablist>, place_market_order_events: Tablist>, - place_swap_order_events: - Tablist> + */ /* /// change_order_size() change_order_size_events: EventHandle, @@ -2569,10 +2567,10 @@ module econia::market { size: new_size, price}); } - fun emit_fill_events_for_market_and_market_accounts( - market_id: u64, + fun emit_fill_events_for_market_accounts( + _market_id: u64, fill_event_queue_ref: &vector, - handles_ref_mut: &mut MarketEventHandles, + _handles_ref_mut: &mut MarketEventHandles, taker_is_swapper: bool, new_taker_order_id: u128, ) { @@ -2588,6 +2586,7 @@ module econia::market { } else { user::emit_fill_event_for_maker_and_taker(event); }; + /* Commented-out algorithm to emit at market level: // Emit event for market, creating handle as needed. let has_handle = tablist::contains( &handles_ref_mut.fill_events, market_id); @@ -2602,6 +2601,7 @@ module econia::market { &mut handles_ref_mut.fill_events, market_id); event::emit_event(handle_ref_mut, event); + */ }); } @@ -2720,9 +2720,11 @@ module econia::market { move_to( &resource_account::get_signer(), MarketEventHandles{ + /* fill_events: tablist::new(), place_limit_order_events: tablist::new(), place_market_order_events: tablist::new(), + */ place_swap_order_events: tablist::new() } ); @@ -3415,6 +3417,7 @@ module econia::market { self_match_behavior, size_posted, market_order_id); + /* Commented-out algorithm to emit at market level: let has_place_limit_order_event_handle = tablist::contains( &market_event_handles_ref_mut.place_limit_order_events, market_id); if (!has_place_limit_order_event_handle) tablist::add( @@ -3426,8 +3429,9 @@ module econia::market { market_id); event::emit_event(place_limit_order_event_handle_ref_mut, place_limit_order_event); + */ user::emit_place_limit_order_event(place_limit_order_event); - emit_fill_events_for_market_and_market_accounts( + emit_fill_events_for_market_accounts( market_id, &mut fill_event_queue, market_event_handles_ref_mut, false, market_order_id); // Return market order ID and taker trade amounts. @@ -3789,6 +3793,7 @@ module econia::market { size, self_match_behavior, market_order_id); + /* Commented-out algorithm to emit at market level: let has_place_market_order_event_handle = tablist::contains( &market_event_handles_ref_mut.place_market_order_events, market_id); if (!has_place_market_order_event_handle) tablist::add( @@ -3800,8 +3805,9 @@ module econia::market { market_id); event::emit_event(place_market_order_event_handle_ref_mut, place_market_order_event); + */ user::emit_place_market_order_event(place_market_order_event); - emit_fill_events_for_market_and_market_accounts( + emit_fill_events_for_market_accounts( market_id, &mut fill_event_queue, market_event_handles_ref_mut, false, (NIL as u128)); // Return base and quote traded by user, fees paid. @@ -4119,7 +4125,7 @@ module econia::market { market_id); event::emit_event(place_swap_order_event_handle_for_market_ref_mut, place_swap_order_event); - emit_fill_events_for_market_and_market_accounts( + emit_fill_events_for_market_accounts( market_id, fill_event_queue_ref_mut, market_event_handles_ref_mut, true, (NIL as u128)); // TODO: ensure trade events emitted to swapper/market account holder. From bb1a575f7e64798a37e978f1868f1863c2fdf3cc Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:39:21 -0700 Subject: [PATCH 20/56] Add ChangeOrderSizeEvent support --- src/move/econia/sources/market.move | 14 +++++-- src/move/econia/sources/user.move | 60 +++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index b3051ec3c..842f8bb77 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2561,10 +2561,16 @@ module econia::market { assert!(new_avlq_access_key == avlq_access_key, E_SIZE_CHANGE_INSERTION_ERROR); }; - // Emit a maker change event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id, user, custodian_id, type: CHANGE, - size: new_size, price}); + user::emit_change_order_size_event( + user::create_change_order_size_event( + market_id, + market_order_id, + user, + custodian_id, + side, + new_size + ) + ); } fun emit_fill_events_for_market_accounts( diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index e3d42679b..5d250e0cd 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -411,6 +411,8 @@ module econia::user { /// Table keys are market account IDs. struct MarketEventHandles has key { + change_order_size_events: + Tablist>, fill_events: Tablist>, place_limit_order_events: Tablist>, @@ -418,6 +420,15 @@ module econia::user { Tablist> } + struct ChangeOrderSizeEvent has copy, drop, store { + market_id: u64, + order_id: u128, + user: address, + custodian_id: u64, + side: bool, + new_size: u64 + } + struct FillEvent has copy, drop, store { market_id: u64, size: u64, @@ -1142,6 +1153,7 @@ module econia::user { E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) move_to(user, MarketEventHandles{ + change_order_size_events: tablist::new(), fill_events: tablist::new(), place_limit_order_events: tablist::new(), place_market_order_events: tablist::new() @@ -1154,6 +1166,16 @@ module econia::user { let market_account_id = get_market_account_id(market_id, custodian_id); + let change_order_size_events_ref_mut = + &mut market_event_handles_ref_mut.change_order_size_events; + let has_change_order_size_events_handle = + tablist::contains(change_order_size_events_ref_mut, + market_account_id); + if (!has_change_order_size_events_handle) { + tablist::add(change_order_size_events_ref_mut, market_account_id, + account::new_event_handle(user)); + }; + let fill_events_ref_mut = &mut market_event_handles_ref_mut.fill_events; let has_fill_events_handle = @@ -1562,6 +1584,26 @@ module econia::user { emit_fill_event(event, true); } + public(friend) fun emit_change_order_size_event( + event: ChangeOrderSizeEvent + ) acquires MarketEventHandles { + let user_address = event.user; + if (!exists(user_address)) return; + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let market_account_id = + get_market_account_id(event.market_id, event.custodian_id); + let change_order_size_events_ref_mut = + &mut market_event_handles_ref_mut.change_order_size_events; + let has_handle = tablist::contains( + change_order_size_events_ref_mut, market_account_id); + if (!has_handle) return; + let change_order_size_event_handle_ref_mut = tablist::borrow_mut( + change_order_size_events_ref_mut, market_account_id); + event::emit_event( + change_order_size_event_handle_ref_mut, event) + } + public(friend) fun emit_place_limit_order_event( event: PlaceLimitOrderEvent ) acquires MarketEventHandles { @@ -1602,6 +1644,24 @@ module econia::user { place_market_order_event_handle_ref_mut, event) } + public(friend) fun create_change_order_size_event( + market_id: u64, + order_id: u128, + user: address, + custodian_id: u64, + side: bool, + new_size: u64 + ): ChangeOrderSizeEvent { + ChangeOrderSizeEvent{ + market_id, + order_id, + user, + custodian_id, + side, + new_size + } + } + public(friend) fun create_fill_event( market_id: u64, size: u64, From 2e227e5b59aacd7136d620c982c80a999526de02 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:57:32 -0700 Subject: [PATCH 21/56] Add CancelPostedOrderEvent support --- src/move/econia/sources/market.move | 50 +++++++++++++++-------- src/move/econia/sources/user.move | 62 +++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 16 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 842f8bb77..ff579cca0 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2434,10 +2434,17 @@ module econia::market { // Cancel order user-side, thus verifying market order ID. user::cancel_order_internal(user, market_id, custodian_id, side, size, price, order_access_key, market_order_id); - // Emit a maker cancel event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id, user, custodian_id, - type: CANCEL, size, price}); + user::emit_cancel_posted_order_event( + user::create_cancel_posted_order_event( + market_id, + market_order_id, + user, + custodian_id, + side, + false, + false + ) + ); } /// Change maker order size on book and in user's market account. @@ -2972,16 +2979,20 @@ module econia::market { let avlq_access_key = ((market_order_id & (HI_64 as u128)) as u64); // Remove order from AVL queue, storing size. - let Order{size, price: _, user: _, custodian_id: _, + let Order{size: _, price: _, user: _, custodian_id: _, order_access_key: _} = avl_queue::remove( orders_ref_mut, avlq_access_key); - // Get maker events handle. - let maker_handle = &mut order_book_ref_mut.maker_events; - // Emit a maker cancel event. - event::emit_event(maker_handle, MakerEvent{ - market_id, side, market_order_id, user: maker, - custodian_id: maker_custodian_id, type: CANCEL, - size, price}); + user::emit_cancel_posted_order_event( + user::create_cancel_posted_order_event( + market_id, + market_order_id, + maker, + maker_custodian_id, + side, + false, + true + ) + ); }; // Optional maker order cancellation complete. // Break out of loop if a self match taker cancel. if (self_match_taker_cancel) break; @@ -3404,10 +3415,17 @@ module econia::market { let market_order_id_cancel = user::cancel_order_internal( user, market_id, custodian_id, side, size, price, order_access_key, (NIL as u128)); - // Emit a maker evict event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id: market_order_id_cancel, user, - custodian_id, type: EVICT, size, price}); + user::emit_cancel_posted_order_event( + user::create_cancel_posted_order_event( + market_id, + market_order_id_cancel, + user, + custodian_id, + side, + true, + false + ) + ); }; }; // Emit a place limit order event, creating handle as needed. diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 5d250e0cd..be2a5f6b9 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -411,6 +411,8 @@ module econia::user { /// Table keys are market account IDs. struct MarketEventHandles has key { + cancel_posted_order_events: + Tablist>, change_order_size_events: Tablist>, fill_events: Tablist>, @@ -420,6 +422,16 @@ module econia::user { Tablist> } + struct CancelPostedOrderEvent has copy, drop, store { + market_id: u64, + order_id: u128, + user: address, + custodian_id: u64, + side: bool, + is_eviction: bool, + is_self_match_cancel: bool + } + struct ChangeOrderSizeEvent has copy, drop, store { market_id: u64, order_id: u128, @@ -1153,6 +1165,7 @@ module econia::user { E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) move_to(user, MarketEventHandles{ + cancel_posted_order_events: tablist::new(), change_order_size_events: tablist::new(), fill_events: tablist::new(), place_limit_order_events: tablist::new(), @@ -1166,6 +1179,16 @@ module econia::user { let market_account_id = get_market_account_id(market_id, custodian_id); + let cancel_posted_order_events_ref_mut = + &mut market_event_handles_ref_mut.cancel_posted_order_events; + let has_cancel_posted_order_events_handle = + tablist::contains(cancel_posted_order_events_ref_mut, + market_account_id); + if (!has_cancel_posted_order_events_handle) { + tablist::add(cancel_posted_order_events_ref_mut, market_account_id, + account::new_event_handle(user)); + }; + let change_order_size_events_ref_mut = &mut market_event_handles_ref_mut.change_order_size_events; let has_change_order_size_events_handle = @@ -1584,6 +1607,25 @@ module econia::user { emit_fill_event(event, true); } + public(friend) fun emit_cancel_posted_order_event( + event: CancelPostedOrderEvent + ) acquires MarketEventHandles { + let user_address = event.user; + if (!exists(user_address)) return; + let market_event_handles_ref_mut = + borrow_global_mut(user_address); + let market_account_id = + get_market_account_id(event.market_id, event.custodian_id); + let cancel_posted_order_events_ref_mut = + &mut market_event_handles_ref_mut.cancel_posted_order_events; + let has_handle = tablist::contains( + cancel_posted_order_events_ref_mut, market_account_id); + if (!has_handle) return; + let cancel_posted_order_event_handle_ref_mut = tablist::borrow_mut( + cancel_posted_order_events_ref_mut, market_account_id); + event::emit_event( + cancel_posted_order_event_handle_ref_mut, event) + } public(friend) fun emit_change_order_size_event( event: ChangeOrderSizeEvent ) acquires MarketEventHandles { @@ -1644,6 +1686,26 @@ module econia::user { place_market_order_event_handle_ref_mut, event) } + public(friend) fun create_cancel_posted_order_event( + market_id: u64, + order_id: u128, + user: address, + custodian_id: u64, + side: bool, + is_eviction: bool, + is_self_match_cancel: bool + ): CancelPostedOrderEvent { + CancelPostedOrderEvent{ + market_id, + order_id, + user, + custodian_id, + side, + is_eviction, + is_self_match_cancel + } + } + public(friend) fun create_change_order_size_event( market_id: u64, order_id: u128, From d341906d51e78dea69455963815f60e63303abde Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:05:02 -0700 Subject: [PATCH 22/56] Clean up market module struct commentary --- src/move/econia/sources/market.move | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index ff579cca0..5737bb2f5 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -613,29 +613,10 @@ module econia::market { map: Tablist } - /// An event handle can be looked up via a view functions, then - /// passed into the REST API to query events emitted to the handle. - /// - /// Events are emitted to handle for the market, and to a handle for - /// affected user/custodian ID tuple (affected signer in the case of - /// a swap, which is is not affiliated with a market account). struct MarketEventHandles has key { /// Not emitted at user level when swapper doesn't sign. place_swap_order_events: Tablist> - /* - fill_events: Tablist>, - place_limit_order_events: - Tablist>, - place_market_order_events: - Tablist>, - */ - /* - /// change_order_size() - change_order_size_events: EventHandle, - /// assorted (direct cancel, self match cancel, and eviction) - cancel_order_event_market: EventHandle, - */ } /// Stored under a signing user's account (not market account), From b227eb35bbd8c4c350336f29bdd72cc02d65b8e5 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Wed, 12 Jul 2023 06:59:32 -0700 Subject: [PATCH 23/56] Add cancel reason enum support --- src/move/econia/sources/market.move | 23 +++++++++++++++++------ src/move/econia/sources/user.move | 27 +++++++++++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 5737bb2f5..5fe533121 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -762,6 +762,9 @@ module econia::market { const E_SIZE_CHANGE_INSERTION_ERROR: u64 = 30; /// Market order ID corresponds to an order that did not post. const E_ORDER_DID_NOT_POST: u64 = 31; + const CANCEL_REASON_DIRECT_CANCEL: u8 = 0; + const CANCEL_REASON_EVICTION: u8 = 1; + const CANCEL_REASON_SELF_MATCH_CANCEL: u8 = 2; // Error codes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -2422,8 +2425,7 @@ module econia::market { user, custodian_id, side, - false, - false + CANCEL_REASON_DIRECT_CANCEL ) ); } @@ -2970,8 +2972,7 @@ module econia::market { maker, maker_custodian_id, side, - false, - true + CANCEL_REASON_SELF_MATCH_CANCEL ) ); }; // Optional maker order cancellation complete. @@ -3403,8 +3404,7 @@ module econia::market { user, custodian_id, side, - true, - false + CANCEL_REASON_EVICTION ) ); }; @@ -4869,6 +4869,17 @@ module econia::market { &attacker, market_id, side, market_order_id); } + #[test] + /// Verify cancel reasons are constant across modules. + fun test_cancel_reasons() { + assert!(user::get_CANCEL_REASON_DIRECT_CANCEL() == + CANCEL_REASON_DIRECT_CANCEL, 0); + assert!(user::get_CANCEL_REASON_EVICTION() == + CANCEL_REASON_EVICTION, 0); + assert!(user::get_CANCEL_REASON_SELF_MATCH_CANCEL() == + CANCEL_REASON_SELF_MATCH_CANCEL, 0); + } + #[test] /// Verify state updates for changing ask under authority of /// custodian, for size increase at tail of price level queue. diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index be2a5f6b9..3fb8a2468 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -428,8 +428,7 @@ module econia::user { user: address, custodian_id: u64, side: bool, - is_eviction: bool, - is_self_match_cancel: bool + reason: u8 } struct ChangeOrderSizeEvent has copy, drop, store { @@ -553,11 +552,29 @@ module econia::user { const NO_MARKET_ACCOUNT: address = @0x0; /// Number of bits market ID is shifted in market account ID. const SHIFT_MARKET_ID: u8 = 64; + const CANCEL_REASON_DIRECT_CANCEL: u8 = 0; + const CANCEL_REASON_EVICTION: u8 = 1; + const CANCEL_REASON_SELF_MATCH_CANCEL: u8 = 2; // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #[view] + public fun get_CANCEL_REASON_DIRECT_CANCEL(): u8 { + CANCEL_REASON_DIRECT_CANCEL + } + + #[view] + public fun get_CANCEL_REASON_EVICTION(): u8 { + CANCEL_REASON_EVICTION + } + + #[view] + public fun get_CANCEL_REASON_SELF_MATCH_CANCEL(): u8 { + CANCEL_REASON_SELF_MATCH_CANCEL + } + #[view] /// Public constant getter for `ASK`. /// @@ -1692,8 +1709,7 @@ module econia::user { user: address, custodian_id: u64, side: bool, - is_eviction: bool, - is_self_match_cancel: bool + reason: u8 ): CancelPostedOrderEvent { CancelPostedOrderEvent{ market_id, @@ -1701,8 +1717,7 @@ module econia::user { user, custodian_id, side, - is_eviction, - is_self_match_cancel + reason } } From 1610c4e83566175175d44a1a3dc03320eb0676a8 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 13 Jul 2023 11:11:06 -0700 Subject: [PATCH 24/56] Update cancel schema/reasons for non-post orders --- src/move/econia/sources/market.move | 55 ++++++++++++-------- src/move/econia/sources/user.move | 81 ++++++++++++++++++----------- 2 files changed, 84 insertions(+), 52 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 5fe533121..85b83c116 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -544,7 +544,7 @@ module econia::market { Self, CustodianCapability, GenericAsset, UnderwriterCapability}; use econia::resource_account; use econia::tablist::{Self, Tablist}; - use econia::user::{Self, FillEvent}; + use econia::user::{Self, CancelOrderEvent, FillEvent}; use std::option::{Self, Option}; use std::signer::address_of; use std::string::{Self, String}; @@ -623,9 +623,10 @@ module econia::market { /// since swaps are processed outside of a market account and do not /// always require a signature. struct SwapperEventHandles has key { + cancel_order_events: Tablist>, + fill_events: Tablist>, place_swap_order_events: - Tablist>, - fill_events: Tablist> + Tablist> } struct PlaceSwapOrderEvent has copy, drop, store { @@ -762,9 +763,13 @@ module econia::market { const E_SIZE_CHANGE_INSERTION_ERROR: u64 = 30; /// Market order ID corresponds to an order that did not post. const E_ORDER_DID_NOT_POST: u64 = 31; - const CANCEL_REASON_DIRECT_CANCEL: u8 = 0; + const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_SELF_MATCH_CANCEL: u8 = 2; + const CANCEL_REASON_NO_LIQUIDITY: u8 = 2; + const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; + const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; + const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; + const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; // Error codes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -1816,8 +1821,9 @@ module econia::market { quote_coins); if (!exists(user_address)) move_to(user, SwapperEventHandles{ - place_swap_order_events: tablist::new(), - fill_events: tablist::new()}); + cancel_order_events: tablist::new(), + fill_events: tablist::new(), + place_swap_order_events: tablist::new()}); let swapper_event_handles_ref_mut = borrow_global_mut(user_address); // Emit place swap order event, initting handle as needed. @@ -2418,14 +2424,13 @@ module econia::market { // Cancel order user-side, thus verifying market order ID. user::cancel_order_internal(user, market_id, custodian_id, side, size, price, order_access_key, market_order_id); - user::emit_cancel_posted_order_event( - user::create_cancel_posted_order_event( + user::emit_cancel_order_event( + user::create_cancel_order_event( market_id, market_order_id, user, custodian_id, - side, - CANCEL_REASON_DIRECT_CANCEL + CANCEL_REASON_MANUAL_CANCEL ) ); } @@ -2965,14 +2970,13 @@ module econia::market { let Order{size: _, price: _, user: _, custodian_id: _, order_access_key: _} = avl_queue::remove( orders_ref_mut, avlq_access_key); - user::emit_cancel_posted_order_event( - user::create_cancel_posted_order_event( + user::emit_cancel_order_event( + user::create_cancel_order_event( market_id, market_order_id, maker, maker_custodian_id, - side, - CANCEL_REASON_SELF_MATCH_CANCEL + CANCEL_REASON_SELF_MATCH_MAKER ) ); }; // Optional maker order cancellation complete. @@ -3397,13 +3401,12 @@ module econia::market { let market_order_id_cancel = user::cancel_order_internal( user, market_id, custodian_id, side, size, price, order_access_key, (NIL as u128)); - user::emit_cancel_posted_order_event( - user::create_cancel_posted_order_event( + user::emit_cancel_order_event( + user::create_cancel_order_event( market_id, market_order_id_cancel, user, custodian_id, - side, CANCEL_REASON_EVICTION ) ); @@ -4872,12 +4875,20 @@ module econia::market { #[test] /// Verify cancel reasons are constant across modules. fun test_cancel_reasons() { - assert!(user::get_CANCEL_REASON_DIRECT_CANCEL() == - CANCEL_REASON_DIRECT_CANCEL, 0); + assert!(user::get_CANCEL_REASON_MANUAL_CANCEL() == + CANCEL_REASON_MANUAL_CANCEL, 0); assert!(user::get_CANCEL_REASON_EVICTION() == CANCEL_REASON_EVICTION, 0); - assert!(user::get_CANCEL_REASON_SELF_MATCH_CANCEL() == - CANCEL_REASON_SELF_MATCH_CANCEL, 0); + assert!(user::get_CANCEL_REASON_NO_LIQUIDITY() == + CANCEL_REASON_NO_LIQUIDITY, 0); + assert!(user::get_CANCEL_REASON_SELF_MATCH_MAKER() == + CANCEL_REASON_SELF_MATCH_MAKER, 0); + assert!(user::get_CANCEL_REASON_SELF_MATCH_TAKER() == + CANCEL_REASON_SELF_MATCH_TAKER, 0); + assert!(user::get_CANCEL_REASON_IMMEDIATE_OR_CANCEL() == + CANCEL_REASON_IMMEDIATE_OR_CANCEL, 0); + assert!(user::get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING() == + CANCEL_REASON_TOO_SMALL_AFTER_MATCHING, 0); } #[test] diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 3fb8a2468..228ff2932 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -411,8 +411,8 @@ module econia::user { /// Table keys are market account IDs. struct MarketEventHandles has key { - cancel_posted_order_events: - Tablist>, + cancel_order_events: + Tablist>, change_order_size_events: Tablist>, fill_events: Tablist>, @@ -422,12 +422,11 @@ module econia::user { Tablist> } - struct CancelPostedOrderEvent has copy, drop, store { + struct CancelOrderEvent has copy, drop, store { market_id: u64, order_id: u128, user: address, custodian_id: u64, - side: bool, reason: u8 } @@ -552,17 +551,21 @@ module econia::user { const NO_MARKET_ACCOUNT: address = @0x0; /// Number of bits market ID is shifted in market account ID. const SHIFT_MARKET_ID: u8 = 64; - const CANCEL_REASON_DIRECT_CANCEL: u8 = 0; + const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_SELF_MATCH_CANCEL: u8 = 2; + const CANCEL_REASON_NO_LIQUIDITY: u8 = 2; + const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; + const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; + const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; + const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #[view] - public fun get_CANCEL_REASON_DIRECT_CANCEL(): u8 { - CANCEL_REASON_DIRECT_CANCEL + public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8 { + CANCEL_REASON_MANUAL_CANCEL } #[view] @@ -571,8 +574,28 @@ module econia::user { } #[view] - public fun get_CANCEL_REASON_SELF_MATCH_CANCEL(): u8 { - CANCEL_REASON_SELF_MATCH_CANCEL + public fun get_CANCEL_REASON_NO_LIQUIDITY(): u8 { + CANCEL_REASON_NO_LIQUIDITY + } + + #[view] + public fun get_CANCEL_REASON_SELF_MATCH_MAKER(): u8 { + CANCEL_REASON_SELF_MATCH_MAKER + } + + #[view] + public fun get_CANCEL_REASON_SELF_MATCH_TAKER(): u8 { + CANCEL_REASON_SELF_MATCH_TAKER + } + + #[view] + public fun get_CANCEL_REASON_IMMEDIATE_OR_CANCEL(): u8 { + CANCEL_REASON_IMMEDIATE_OR_CANCEL + } + + #[view] + public fun get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING(): u8 { + CANCEL_REASON_TOO_SMALL_AFTER_MATCHING } #[view] @@ -1182,7 +1205,7 @@ module econia::user { E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) move_to(user, MarketEventHandles{ - cancel_posted_order_events: tablist::new(), + cancel_order_events: tablist::new(), change_order_size_events: tablist::new(), fill_events: tablist::new(), place_limit_order_events: tablist::new(), @@ -1196,13 +1219,13 @@ module econia::user { let market_account_id = get_market_account_id(market_id, custodian_id); - let cancel_posted_order_events_ref_mut = - &mut market_event_handles_ref_mut.cancel_posted_order_events; - let has_cancel_posted_order_events_handle = - tablist::contains(cancel_posted_order_events_ref_mut, + let cancel_order_events_ref_mut = + &mut market_event_handles_ref_mut.cancel_order_events; + let has_cancel_order_events_handle = + tablist::contains(cancel_order_events_ref_mut, market_account_id); - if (!has_cancel_posted_order_events_handle) { - tablist::add(cancel_posted_order_events_ref_mut, market_account_id, + if (!has_cancel_order_events_handle) { + tablist::add(cancel_order_events_ref_mut, market_account_id, account::new_event_handle(user)); }; @@ -1624,8 +1647,8 @@ module econia::user { emit_fill_event(event, true); } - public(friend) fun emit_cancel_posted_order_event( - event: CancelPostedOrderEvent + public(friend) fun emit_cancel_order_event( + event: CancelOrderEvent ) acquires MarketEventHandles { let user_address = event.user; if (!exists(user_address)) return; @@ -1633,15 +1656,15 @@ module econia::user { borrow_global_mut(user_address); let market_account_id = get_market_account_id(event.market_id, event.custodian_id); - let cancel_posted_order_events_ref_mut = - &mut market_event_handles_ref_mut.cancel_posted_order_events; + let cancel_order_events_ref_mut = + &mut market_event_handles_ref_mut.cancel_order_events; let has_handle = tablist::contains( - cancel_posted_order_events_ref_mut, market_account_id); + cancel_order_events_ref_mut, market_account_id); if (!has_handle) return; - let cancel_posted_order_event_handle_ref_mut = tablist::borrow_mut( - cancel_posted_order_events_ref_mut, market_account_id); + let cancel_order_event_handle_ref_mut = tablist::borrow_mut( + cancel_order_events_ref_mut, market_account_id); event::emit_event( - cancel_posted_order_event_handle_ref_mut, event) + cancel_order_event_handle_ref_mut, event) } public(friend) fun emit_change_order_size_event( event: ChangeOrderSizeEvent @@ -1703,20 +1726,18 @@ module econia::user { place_market_order_event_handle_ref_mut, event) } - public(friend) fun create_cancel_posted_order_event( + public(friend) fun create_cancel_order_event( market_id: u64, order_id: u128, user: address, custodian_id: u64, - side: bool, reason: u8 - ): CancelPostedOrderEvent { - CancelPostedOrderEvent{ + ): CancelOrderEvent { + CancelOrderEvent{ market_id, order_id, user, custodian_id, - side, reason } } From 1e4140dfa1bf5acf0ad7fdb335420c5edd24589c Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:51:31 -0700 Subject: [PATCH 25/56] Remove automatic adjustment of market order size --- doc/doc-site/docs/move/changelog.md | 1 + src/move/econia/sources/market.move | 81 ++++++++++++++--------------- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 5a0013135..f7d5af7ab 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -12,6 +12,7 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] ### Changed - Fee assessment updated to be processed per fill, rather than per trade ([#321]). +- Market order size is no longer automatically adjusted based on available market account holdings ([#321]). ### Deprecated diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 85b83c116..b6e340825 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -3655,7 +3655,7 @@ module econia::market { /// * `custodian_id`: Same as for `match()`. /// * `integrator`: Same as for `match()`. /// * `direction`: Same as for `match()`. - /// * `size`: The maximum size, in lots, to fill. + /// * `size`: Size, in lots, to fill. /// * `self_match_behavior`: Same as for `match()`. /// /// # Returns @@ -3670,6 +3670,8 @@ module econia::market { /// * `E_INVALID_QUOTE`: Quote asset type is invalid. /// * `E_SIZE_TOO_SMALL`: Market order size does not meet minimum /// size for market. + /// * `E_SIZE_BASE_OVERFLOW`: The product of order size and market + /// lot size results in a base asset unit overflow. /// /// # Expected value testing /// @@ -3720,29 +3722,20 @@ module econia::market { == order_book_ref_mut.quote_type, E_INVALID_QUOTE); // Assert order size is at least minimum size for market. assert!(size >= order_book_ref_mut.min_size, E_SIZE_TOO_SMALL); + // Calculate base asset amount corresponding to size in lots. + let base = (size as u128) * (order_book_ref_mut.lot_size as u128); + // Assert corresponding base asset amount fits in a u64. + assert!(base <= (HI_64 as u128), E_SIZE_BASE_OVERFLOW); // Get market underwriter ID. let underwriter_id = order_book_ref_mut.underwriter_id; - // Calculate max base that can be traded: if a buy, max base - // that can fit in market account. If a sell, base available in - // market account. - let max_base = if (direction == BUY) - (HI_64 - base_ceiling) else base_available; - // Get max lots that can be traded by user. - let max_lots_user_can_trade = max_base / order_book_ref_mut.lot_size; - // If market order size is less than number of lots user can - // trade based on account limits, adjust the max base trade - // amount to correspond with the market order size. - if (size < max_lots_user_can_trade) - max_base = size * order_book_ref_mut.lot_size; + // Max base to trade is amount calculated from size, lot size. + let max_base = (base as u64); // Calculate max quote that can be traded: if a buy, quote // available in market account. If a sell, max quote that can // fit in market account. let max_quote = if (direction == BUY) quote_available else (HI_64 - quote_ceiling); - // Declare min base and quote trade amounts 0, enabling silent - // return without fills if there is no depth on the book, and - // silent return with max possible fills if order takes all - // liquidity before filling user-indicated size. + // Set min base/quote to match as 0. let (min_base, min_quote) = (0, 0); range_check_trade( // Range check trade amounts. direction, min_base, max_base, min_quote, max_quote, @@ -7081,7 +7074,7 @@ module econia::market { // Declare taker order parameters. let direction_taker = if (side_maker == ASK) BUY else SELL; let self_match_behavior = ABORT; - let size = MAX_POSSIBLE; + let size = size_maker; // Declare deposit amounts. let deposit_base = HI_64 / 2; let deposit_quote = HI_64 / 2; @@ -7136,7 +7129,7 @@ module econia::market { let price_hi = integrator_divisor * taker_divisor * 2; // Declare taker order parameters. let direction_taker = if (side_maker == ASK) BUY else SELL; - let size_taker = MAX_POSSIBLE; + let size_taker = size_maker; let self_match_behavior_taker = CANCEL_BOTH; // Declare deposit amounts. let deposit_base = HI_64 / 2; @@ -7249,7 +7242,7 @@ module econia::market { let price_hi = integrator_divisor * taker_divisor * 2; // Declare taker order parameters. let direction_taker = if (side_maker == ASK) BUY else SELL; - let size_taker = MAX_POSSIBLE; + let size_taker = size_maker; let self_match_behavior_taker = CANCEL_MAKER; // Declare taker match amounts. let size_taker_match = size_maker; @@ -7386,7 +7379,7 @@ module econia::market { let price_hi = integrator_divisor * taker_divisor * 2; // Declare taker order parameters. let direction_taker = if (side_maker == ASK) BUY else SELL; - let size_taker = MAX_POSSIBLE; + let size_taker = size_maker; let self_match_behavior_taker = CANCEL_TAKER; // Declare deposit amounts. let deposit_base = HI_64 / 2; @@ -7496,7 +7489,7 @@ module econia::market { // Declare taker order parameters. let direction_taker = if (side_maker == ASK) BUY else SELL; let self_match_behavior = 0xff; - let size_taker = MAX_POSSIBLE; + let size_taker = size_maker; // Declare deposit amounts. let deposit_base = HI_64 / 2; let deposit_quote = HI_64 / 2; @@ -9779,8 +9772,8 @@ module econia::market { // Declare order parameters with price set to product of // divisors, to prevent truncation effects on estimates. let side = ASK; // Maker sell. - let size_match = 1; // Only one lot ends up filling. - let size_post = MIN_SIZE_COIN; // Maker order size. + let size_match = MIN_SIZE_COIN; + let size_post = size_match + 1; // Maker order size. let base_match = size_match * LOT_SIZE_COIN; let base_post = size_post * LOT_SIZE_COIN; let price = integrator_divisor * taker_divisor; @@ -9793,6 +9786,7 @@ module econia::market { let quote_trade = quote_match + fee; let quote_deposit = quote_trade + TICK_SIZE_COIN; let self_match_behavior = ABORT; + let size_taker = size_match; // Deposit to maker's account enough to impinge on min and max // amounts after fill. user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, @@ -9811,7 +9805,7 @@ module econia::market { NO_RESTRICTION, self_match_behavior); // Place taker order. let (base_trade_r, quote_trade_r, fee_r) = place_market_order_user< - BC, QC>(&user_1, MARKET_ID_COIN, @integrator, BUY, MAX_POSSIBLE, + BC, QC>(&user_1, MARKET_ID_COIN, @integrator, BUY, size_taker, self_match_behavior); // Assert returns. assert!(base_trade_r == base_match, 0); @@ -9884,8 +9878,8 @@ module econia::market { // Declare order parameters with price set to product of // divisors, to prevent truncation effects on estimates. let side = BID; // Maker buy. - let size_match = 1; // Only one lot ends up filling. - let size_post = MIN_SIZE_COIN; // Maker order size. + let size_match = MIN_SIZE_COIN; + let size_post = size_match + 1; // Maker order size. let base_match = size_match * LOT_SIZE_COIN; let base_post = size_post * LOT_SIZE_COIN; let price = integrator_divisor * taker_divisor; @@ -9899,6 +9893,7 @@ module econia::market { let max_quote = quote_trade + TICK_SIZE_COIN; let quote_deposit = HI_64 - max_quote; let self_match_behavior = ABORT; + let size_taker = size_match; // Deposit to maker's account enough to impinge on min and max // amounts after fill. user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, @@ -9918,9 +9913,8 @@ module econia::market { CUSTODIAN_ID_USER_1); // Get custodian capability. let (base_trade_r, quote_trade_r, fee_r) = place_market_order_custodian( // Place taker order. - @user_1, MARKET_ID_COIN, @integrator, SELL, MAX_POSSIBLE, - self_match_behavior, - &custodian_capability); + @user_1, MARKET_ID_COIN, @integrator, SELL, size_taker, + self_match_behavior, &custodian_capability); // Drop custodian capability. registry::drop_custodian_capability_test(custodian_capability); // Assert returns. @@ -9994,8 +9988,8 @@ module econia::market { // Declare order parameters with price set to product of // divisors, to prevent truncation effects on estimates. let side = ASK; // Maker sell. - let size_match = 1; // Only one lot ends up filling. - let size_post = MIN_SIZE_COIN; // Maker order size. + let size_match = MIN_SIZE_COIN; + let size_post = size_match + 1; // Maker order size. let base_match = size_match * LOT_SIZE_COIN; let base_post = size_post * LOT_SIZE_COIN; let price = integrator_divisor * taker_divisor; @@ -10006,8 +10000,8 @@ module econia::market { quote_match / taker_divisor - integrator_share; let fee = integrator_share + econia_share; let quote_trade = quote_match + fee; - let size_taker = base_match + LOT_SIZE_COIN; - let base_deposit = HI_64 - size_taker; + let size_taker = size_match; + let base_deposit = HI_64 - (size_taker * LOT_SIZE_COIN); let self_match_behavior = ABORT; // Deposit to maker's account enough to impinge on min and max // amounts after fill. @@ -10103,8 +10097,8 @@ module econia::market { // Declare order parameters with price set to product of // divisors, to prevent truncation effects on estimates. let side = BID; // Maker buy. - let size_match = 1; // Only one lot ends up filling. - let size_post = MIN_SIZE_COIN; // Maker order size. + let size_match = MIN_SIZE_COIN; + let size_post = size_match + 1; // Maker order size. let base_match = size_match * LOT_SIZE_COIN; let base_post = size_post * LOT_SIZE_COIN; let price = integrator_divisor * taker_divisor; @@ -10115,8 +10109,8 @@ module econia::market { quote_match / taker_divisor - integrator_share; let fee = integrator_share + econia_share; let quote_trade = quote_match - fee; - let size_taker = base_match + LOT_SIZE_COIN; - let base_deposit = size_taker; + let size_taker = size_match; + let base_deposit = HI_64 - (size_taker * LOT_SIZE_COIN); let self_match_behavior = ABORT; // Deposit to maker's account enough to impinge on min and max // amounts after fill. @@ -10135,8 +10129,8 @@ module econia::market { NO_RESTRICTION, self_match_behavior); // Place maker order. let (base_trade_r, quote_trade_r, fee_r) = place_market_order_user( // Place taker order. - &user_1, MARKET_ID_COIN, @integrator, SELL, - MAX_POSSIBLE, self_match_behavior); + &user_1, MARKET_ID_COIN, @integrator, SELL, size_taker, + self_match_behavior); // Assert returns. assert!(base_trade_r == base_match, 0); assert!(quote_trade_r == quote_trade, 0); @@ -10208,8 +10202,8 @@ module econia::market { // Declare order parameters with price set to product of // divisors, to prevent truncation effects on estimates. let side = ASK; // Maker sell. - let size_match = 1; // Only one lot ends up filling. - let size_post = MIN_SIZE_COIN; // Maker order size. + let size_match = MIN_SIZE_COIN; + let size_post = size_match + 1; // Maker order size. let base_match = size_match * LOT_SIZE_COIN; let base_post = size_post * LOT_SIZE_COIN; let price = integrator_divisor * taker_divisor; @@ -10222,6 +10216,7 @@ module econia::market { let quote_trade = quote_match + fee; let quote_deposit = quote_trade + TICK_SIZE_COIN; let self_match_behavior = ABORT; + let size_taker = size_match; // Deposit to maker's account enough to impinge on min and max // amounts after fill. user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, @@ -10238,7 +10233,7 @@ module econia::market { &user_0, MARKET_ID_COIN, @integrator, side, size_post, price, NO_RESTRICTION, self_match_behavior); // Place maker order. place_market_order_user_entry( // Place taker order. - &user_1, MARKET_ID_COIN, @integrator, BUY, MAX_POSSIBLE, + &user_1, MARKET_ID_COIN, @integrator, BUY, size_taker, self_match_behavior); // Get fields for maker order on book. let (size_r, price_r, user_r, custodian_id_r, order_access_key) = From 662454b01e3faf2c3f4250420b684a3d8733b2ee Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 13 Jul 2023 14:21:40 -0700 Subject: [PATCH 26/56] Update cancel order events for swappers --- doc/doc-site/docs/move/changelog.md | 1 + src/move/econia/sources/market.move | 243 ++++++++++++++++++++-------- src/move/econia/sources/user.move | 6 + 3 files changed, 183 insertions(+), 67 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index f7d5af7ab..13549b4c2 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -13,6 +13,7 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] - Fee assessment updated to be processed per fill, rather than per trade ([#321]). - Market order size is no longer automatically adjusted based on available market account holdings ([#321]). +- Default self match behavior for swaps (signing swapper self match against signing market account) changed from `ABORT` to `CANCEL_TAKER` ([#321]). ### Deprecated diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index b6e340825..4e7fdf400 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -613,10 +613,12 @@ module econia::market { map: Tablist } + /// Not emitted at market account level when a swap order is placed + /// by a non-signing swapper. struct MarketEventHandles has key { - /// Not emitted at user level when swapper doesn't sign. place_swap_order_events: - Tablist> + Tablist>, + cancel_order_events: Tablist>, } /// Stored under a signing user's account (not market account), @@ -763,13 +765,6 @@ module econia::market { const E_SIZE_CHANGE_INSERTION_ERROR: u64 = 30; /// Market order ID corresponds to an order that did not post. const E_ORDER_DID_NOT_POST: u64 = 31; - const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; - const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_NO_LIQUIDITY: u8 = 2; - const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; - const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; - const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; - const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; // Error codes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -842,6 +837,15 @@ module econia::market { /// Flag for passive order specified by advance in ticks. const TICKS: bool = false; + const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; + const CANCEL_REASON_EVICTION: u8 = 1; + const CANCEL_REASON_NO_LIQUIDITY: u8 = 2; + const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; + const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; + const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; + const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; + const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 7; + // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -1804,21 +1808,29 @@ module econia::market { // Swap against order book, storing optionally modified coin // inputs, base and quote trade amounts, quote fees paid, and // place swap order event. - let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - place_swap_order_event, ) = swap( - &mut fill_event_queue, - user_address, - market_id, - NO_UNDERWRITER, - integrator, - direction, - min_base, - max_base, - min_quote, - max_quote, - limit_price, - optional_base_coins, - quote_coins); + let ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + place_swap_order_event, + cancel_order_event_option + ) = swap( + &mut fill_event_queue, + user_address, + market_id, + NO_UNDERWRITER, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + optional_base_coins, + quote_coins + ); if (!exists(user_address)) move_to(user, SwapperEventHandles{ cancel_order_events: tablist::new(), @@ -1853,6 +1865,20 @@ module econia::market { event::emit_event(fill_events_handle_ref_mut, fill_event); }); + // Optionally emit cancel event, initting handle as needed. + if (option::is_some(&cancel_order_event_option)) { + let cancel_order_events_ref_mut = + &mut swapper_event_handles_ref_mut.cancel_order_events; + if (!tablist::contains(cancel_order_events_ref_mut, market_id)) + tablist::add( + cancel_order_events_ref_mut, + market_id, + account::new_event_handle(user)); + let cancel_order_events_handle_ref_mut = tablist::borrow_mut( + cancel_order_events_ref_mut, market_id); + event::emit_event(cancel_order_events_handle_ref_mut, + option::destroy_some(cancel_order_event_option)); + }; // Deposit base coins back to user's coin store. coin::deposit(user_address, option::destroy_some(optional_base_coins)); // Deposit quote coins back to user's coin store. @@ -1972,7 +1998,7 @@ module econia::market { // Swap against order book, storing optionally modified coin // inputs, base and quote trade amounts, and quote fees paid. let (optional_base_coins, quote_coins_matched, base_traded, - quote_traded, fees, _) = swap( + quote_traded, fees, _, _) = swap( &mut vector[], NO_MARKET_ACCOUNT, market_id, @@ -2086,7 +2112,7 @@ module econia::market { // Swap against order book, storing optionally modified quote // coin input, base and quote trade amounts, quote fees paid. let (optional_base_coins, quote_coins_matched, base_traded, - quote_traded, fees, _) = swap( + quote_traded, fees, _, _) = swap( &mut vector[], NO_MARKET_ACCOUNT, market_id, @@ -2726,6 +2752,7 @@ module econia::market { place_limit_order_events: tablist::new(), place_market_order_events: tablist::new(), */ + cancel_order_events: tablist::new(), place_swap_order_events: tablist::new() } ); @@ -2806,6 +2833,8 @@ module econia::market { /// net change in taker's quote coin holdings. /// * `u64`: Amount of quote coin fees paid. /// * `bool`: `true` if a self match that results in a taker cancel. + /// * `bool`: `true` if liquidity is gone from order book on + /// corresponding side after matching. /// /// # Emits /// @@ -2876,6 +2905,7 @@ module econia::market { u64, u64, u64, + bool, bool ) { // Assert price is not too high. @@ -3050,7 +3080,7 @@ module econia::market { // Return optional base coin, quote coins, trade amounts, and // self match taker cancel flag. (optional_base_coins, quote_coins, base_fill, quote_traded, fees_paid, - self_match_taker_cancel) + self_match_taker_cancel, avl_queue::is_empty(orders_ref_mut)) } /// Return order ID derived solely from order book counter for an @@ -3319,8 +3349,15 @@ module econia::market { // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of // the order. (Increments order book counter). - (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - self_match_cancel) = match( + ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + self_match_cancel, + _, + ) = match( market_id, market_event_handles_ref_mut, &mut fill_event_queue, @@ -3336,7 +3373,8 @@ module econia::market { price, self_match_behavior, optional_base_coins, - quote_coins); + quote_coins + ); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -3756,10 +3794,15 @@ module econia::market { let market_event_handles_ref_mut = market_event_handles_borrow_mut(resource_address); let fill_event_queue = vector[]; - // Match against order book, storing optionally modified asset - // inputs, base and quote trade amounts, and quote fees paid. - let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match( + let ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + self_match_taker_cancel, + liquidity_gone + ) = match( market_id, market_event_handles_ref_mut, &mut fill_event_queue, @@ -3775,7 +3818,8 @@ module econia::market { limit_price, self_match_behavior, optional_base_coins, - quote_coins); + quote_coins + ); let market_order_id = order_id_no_post(order_book_ref_mut.counter); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else @@ -3784,16 +3828,6 @@ module econia::market { user::deposit_assets_internal( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); - // Emit a place market order event, creating handle as needed. - let place_market_order_event = user::create_place_market_order_event( - market_id, - user_address, - custodian_id, - integrator, - direction, - size, - self_match_behavior, - market_order_id); /* Commented-out algorithm to emit at market level: let has_place_market_order_event_handle = tablist::contains( &market_event_handles_ref_mut.place_market_order_events, market_id); @@ -3807,10 +3841,39 @@ module econia::market { event::emit_event(place_market_order_event_handle_ref_mut, place_market_order_event); */ - user::emit_place_market_order_event(place_market_order_event); + user::emit_place_market_order_event( + user::create_place_market_order_event( + market_id, + user_address, + custodian_id, + integrator, + direction, + size, + self_match_behavior, + market_order_id) + ); emit_fill_events_for_market_accounts( market_id, &mut fill_event_queue, market_event_handles_ref_mut, false, (NIL as u128)); + // If order needs to be cancelled: + if ((self_match_taker_cancel) || (base_traded < max_base)) { + let cancel_reason = if (self_match_taker_cancel) { + CANCEL_REASON_SELF_MATCH_TAKER + } else if (liquidity_gone) { + CANCEL_REASON_NO_LIQUIDITY + } else { + CANCEL_REASON_MAX_QUOTE_TRADED + }; + user::emit_cancel_order_event( + user::create_cancel_order_event( + market_id, + market_order_id, + user_address, + custodian_id, + cancel_reason + ) + ); + }; // Return base and quote traded by user, fees paid. (base_traded, quote_traded, fees) } @@ -4057,7 +4120,8 @@ module econia::market { u64, u64, u64, - PlaceSwapOrderEvent + PlaceSwapOrderEvent, + Option ) acquires MarketEventHandles, OrderBooks @@ -4080,27 +4144,36 @@ module econia::market { assert!(type_info::type_of() // Assert quote type. == order_book_ref_mut.quote_type, E_INVALID_QUOTE); // Declare return assignment variables. - let (base_traded, quote_traded, fees); + let (base_traded, quote_traded, fees, self_match_taker_cancel, + liquidity_gone); let market_event_handles_ref_mut = market_event_handles_borrow_mut(resource_address); - (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) - = match( // Match against order book. - market_id, - market_event_handles_ref_mut, - fill_event_queue_ref_mut, - order_book_ref_mut, - signer_address, - NO_CUSTODIAN, - integrator, - direction, - min_base, - max_base, - min_quote, - max_quote, - limit_price, - ABORT, - optional_base_coins, - quote_coins); + ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + self_match_taker_cancel, + liquidity_gone + ) = match( // Match against order book. + market_id, + market_event_handles_ref_mut, + fill_event_queue_ref_mut, + order_book_ref_mut, + signer_address, + NO_CUSTODIAN, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + CANCEL_TAKER, + optional_base_coins, + quote_coins + ); let market_order_id = order_id_no_post(order_book_ref_mut.counter); let place_swap_order_event = PlaceSwapOrderEvent{ market_id, @@ -4129,11 +4202,45 @@ module econia::market { emit_fill_events_for_market_accounts( market_id, fill_event_queue_ref_mut, market_event_handles_ref_mut, true, (NIL as u128)); + let need_to_cancel_order = + (self_match_taker_cancel) || (base_traded < max_base); + let cancel_order_event_option = if (need_to_cancel_order) { + let cancel_reason = if (self_match_taker_cancel) { + CANCEL_REASON_SELF_MATCH_TAKER + } else if (liquidity_gone) { + CANCEL_REASON_NO_LIQUIDITY + } else { + CANCEL_REASON_MAX_QUOTE_TRADED + }; + let cancel_order_event = user::create_cancel_order_event( + market_id, + market_order_id, + signer_address, + NO_CUSTODIAN, + cancel_reason + ); + let has_cancel_order_event_handle_for_market = tablist::contains( + &market_event_handles_ref_mut.cancel_order_events, + market_id); + if (!has_cancel_order_event_handle_for_market) tablist::add( + &mut market_event_handles_ref_mut.cancel_order_events, + market_id, + account::new_event_handle(&resource_account::get_signer())); + let cancel_order_event_handle_for_market_ref_mut = + tablist::borrow_mut( + &mut market_event_handles_ref_mut.cancel_order_events, + market_id); + event::emit_event(cancel_order_event_handle_for_market_ref_mut, + cancel_order_event); + option::some(cancel_order_event) + } else { + option::none() + }; // TODO: ensure trade events emitted to swapper/market account holder. // Return optionally modified asset inputs, trade amounts, fees, // and place swap order event. (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - place_swap_order_event) + place_swap_order_event, cancel_order_event_option) } // Private functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -4882,6 +4989,8 @@ module econia::market { CANCEL_REASON_IMMEDIATE_OR_CANCEL, 0); assert!(user::get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING() == CANCEL_REASON_TOO_SMALL_AFTER_MATCHING, 0); + assert!(user::get_CANCEL_REASON_MAX_QUOTE_TRADED() == + CANCEL_REASON_MAX_QUOTE_TRADED, 0); } #[test] diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 228ff2932..fb4ac7458 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -558,6 +558,7 @@ module econia::user { const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; + const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 7; // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -598,6 +599,11 @@ module econia::user { CANCEL_REASON_TOO_SMALL_AFTER_MATCHING } + #[view] + public fun get_CANCEL_REASON_MAX_QUOTE_TRADED(): u8 { + CANCEL_REASON_MAX_QUOTE_TRADED + } + #[view] /// Public constant getter for `ASK`. /// From 331ef85d9f74a1644f8c7580c9d6e958b03bbf18 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:38:52 -0700 Subject: [PATCH 27/56] Add limit order cancel event support --- src/move/econia/sources/market.move | 113 +++++++++++++++++++--------- src/move/econia/sources/user.move | 12 +-- 2 files changed, 83 insertions(+), 42 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 4e7fdf400..ddcdc907e 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -839,7 +839,7 @@ module econia::market { const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_NO_LIQUIDITY: u8 = 2; + const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 2; const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; @@ -2784,7 +2784,8 @@ module econia::market { /// of fills. /// * `order_book_ref_mut`: Mutable reference to market order book. /// * `taker`: Address of taker whose order is matched. Passed as - /// `NO_MARKET_ACCOUNT` when taker order originates from a swap. + /// `NO_MARKET_ACCOUNT` when taker order originates from a swap + /// without a signature. /// * `custodian_id`: Custodian ID associated with a taker market /// account, if any. Should be passed as `NO_CUSTODIAN` if `taker` /// is `NO_MARKET_ACCOUNT`. @@ -3332,6 +3333,8 @@ module econia::market { (0, 0, 0, vector[]); let market_event_handles_ref_mut = market_event_handles_borrow_mut(resource_address); + let cancel_reason_option = option::none(); + let remaining_size = size; if (crosses_spread) { // Calculate max base and quote to withdraw. If a buy: let (base_withdraw, quote_withdraw) = if (direction == BUY) @@ -3343,8 +3346,8 @@ module econia::market { user::withdraw_assets_internal( user_address, market_id, custodian_id, base_withdraw, quote_withdraw, underwriter_id); - // Declare return assignment variable. - let self_match_cancel; + // Declare return assignment variables. + let self_match_taker_cancel; // Match against order book, storing optionally modified // asset inputs, base and quote trade amounts, quote fees // paid, and if a self match requires canceling the rest of @@ -3355,7 +3358,7 @@ module econia::market { base_traded, quote_traded, fees, - self_match_cancel, + self_match_taker_cancel, _, ) = match( market_id, @@ -3391,21 +3394,40 @@ module econia::market { !avl_queue::would_update_head(&order_book_ref_mut.bids, price) else !avl_queue::would_update_head(&order_book_ref_mut.asks, price); + remaining_size = + size - (base_traded / order_book_ref_mut.lot_size); + if (self_match_taker_cancel) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_SELF_MATCH_TAKER); + } else if ((remaining_size > 0) && + (restriction == IMMEDIATE_OR_CANCEL)) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_IMMEDIATE_OR_CANCEL); + } else if (still_crosses_spread) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_MAX_QUOTE_TRADED); + } else { + if (remaining_size < order_book_ref_mut.min_size) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_TOO_SMALL_AFTER_MATCHING); + } + }; + /* // If matching engine halted but order still crosses spread, // or if a self match that requires canceling the rest of // of the order, then mark no size left to post as a maker. size = if (still_crosses_spread || self_match_cancel) 0 else - // Else update size to amount left to fill post-match. - size - (base_traded / order_book_ref_mut.lot_size); + */ } else { // If spread not crossed (matching engine not called): order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + if (restriction == IMMEDIATE_OR_CANCEL) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_IMMEDIATE_OR_CANCEL); + }; }; - // Assume no size posted to book. - let (size_posted, market_order_id) = - (0, order_id_no_post(order_book_ref_mut.counter)); - // If size big enough to post and not immediate-or-cancel: - if ((size >= order_book_ref_mut.min_size) && - (restriction != IMMEDIATE_OR_CANCEL)) { + let market_order_id = order_id_no_post(order_book_ref_mut.counter); + // If order still eligible to post: + if (option::is_none(&cancel_reason_option)) { // Get next order access key for user-side order placement. let order_access_key = user::get_next_order_access_key_internal( user_address, market_id, custodian_id, side); @@ -3413,8 +3435,13 @@ module econia::market { let orders_ref_mut = if (side == ASK) &mut order_book_ref_mut.asks else &mut order_book_ref_mut.bids; // Declare order to insert to book. - let order = Order{size, price, user: user_address, custodian_id, - order_access_key}; + let order = Order{ + size: remaining_size, + price, + user: user_address, + custodian_id, + order_access_key + }; // Get new AVL queue access key, evictee access key, and evictee // value by attempting to insert for given critical height. let (avlq_access_key, evictee_access_key, evictee_value) = @@ -3425,9 +3452,8 @@ module econia::market { // Encode AVL queue access key in market order ID. market_order_id = market_order_id | (avlq_access_key as u128); user::place_order_internal( // Place order user-side. - user_address, market_id, custodian_id, side, size, price, - market_order_id, order_access_key); - size_posted = size; // Mark size posted as maker. + user_address, market_id, custodian_id, side, remaining_size, + price, market_order_id, order_access_key); if (evictee_access_key == NIL) { // If no eviction required: // Destroy empty evictee value option. option::destroy_none(evictee_value); @@ -3449,20 +3475,9 @@ module econia::market { ) ); }; + } else { + remaining_size = 0; }; - // Emit a place limit order event, creating handle as needed. - let place_limit_order_event = user::create_place_limit_order_event( - market_id, - user_address, - custodian_id, - integrator, - side, - size, - price, - restriction, - self_match_behavior, - size_posted, - market_order_id); /* Commented-out algorithm to emit at market level: let has_place_limit_order_event_handle = tablist::contains( &market_event_handles_ref_mut.place_limit_order_events, market_id); @@ -3476,10 +3491,36 @@ module econia::market { event::emit_event(place_limit_order_event_handle_ref_mut, place_limit_order_event); */ - user::emit_place_limit_order_event(place_limit_order_event); + // Emit a place limit order event, creating handle as needed. + user::emit_place_limit_order_event( + user::create_place_limit_order_event( + market_id, + user_address, + custodian_id, + integrator, + side, + size, + price, + restriction, + self_match_behavior, + remaining_size, + market_order_id + ) + ); emit_fill_events_for_market_accounts( market_id, &mut fill_event_queue, market_event_handles_ref_mut, false, market_order_id); + if (option::is_some(&cancel_reason_option)) { + user::emit_cancel_order_event( + user::create_cancel_order_event( + market_id, + market_order_id, + user_address, + custodian_id, + option::destroy_some(cancel_reason_option) + ) + ); + }; // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } @@ -3860,7 +3901,7 @@ module econia::market { let cancel_reason = if (self_match_taker_cancel) { CANCEL_REASON_SELF_MATCH_TAKER } else if (liquidity_gone) { - CANCEL_REASON_NO_LIQUIDITY + CANCEL_REASON_NOT_ENOUGH_LIQUIDITY } else { CANCEL_REASON_MAX_QUOTE_TRADED }; @@ -4208,7 +4249,7 @@ module econia::market { let cancel_reason = if (self_match_taker_cancel) { CANCEL_REASON_SELF_MATCH_TAKER } else if (liquidity_gone) { - CANCEL_REASON_NO_LIQUIDITY + CANCEL_REASON_NOT_ENOUGH_LIQUIDITY } else { CANCEL_REASON_MAX_QUOTE_TRADED }; @@ -4979,8 +5020,8 @@ module econia::market { CANCEL_REASON_MANUAL_CANCEL, 0); assert!(user::get_CANCEL_REASON_EVICTION() == CANCEL_REASON_EVICTION, 0); - assert!(user::get_CANCEL_REASON_NO_LIQUIDITY() == - CANCEL_REASON_NO_LIQUIDITY, 0); + assert!(user::get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY() == + CANCEL_REASON_NOT_ENOUGH_LIQUIDITY, 0); assert!(user::get_CANCEL_REASON_SELF_MATCH_MAKER() == CANCEL_REASON_SELF_MATCH_MAKER, 0); assert!(user::get_CANCEL_REASON_SELF_MATCH_TAKER() == diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index fb4ac7458..1e7ac0a5a 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -464,7 +464,7 @@ module econia::user { price: u64, restriction: u8, self_match_behavior: u8, - size_posted: u64, + remaining_size: u64, order_id: u128 } @@ -553,7 +553,7 @@ module econia::user { const SHIFT_MARKET_ID: u8 = 64; const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_NO_LIQUIDITY: u8 = 2; + const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 2; const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; @@ -575,8 +575,8 @@ module econia::user { } #[view] - public fun get_CANCEL_REASON_NO_LIQUIDITY(): u8 { - CANCEL_REASON_NO_LIQUIDITY + public fun get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY(): u8 { + CANCEL_REASON_NOT_ENOUGH_LIQUIDITY } #[view] @@ -1819,7 +1819,7 @@ module econia::user { price: u64, restriction: u8, self_match_behavior: u8, - size_posted: u64, + remaining_size: u64, order_id: u128 ): PlaceLimitOrderEvent { PlaceLimitOrderEvent { @@ -1832,7 +1832,7 @@ module econia::user { price, restriction, self_match_behavior, - size_posted, + remaining_size, order_id } } From ddbdeb4215d80e180e957ba34a103609eb6450e6 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Thu, 13 Jul 2023 15:47:04 -0700 Subject: [PATCH 28/56] Use `Table` instead of `Tablist` for event handles --- src/move/econia/sources/market.move | 58 ++++++++++----------- src/move/econia/sources/user.move | 79 ++++++++++++++--------------- 2 files changed, 65 insertions(+), 72 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index ddcdc907e..58cdb40b1 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -537,6 +537,7 @@ module econia::market { use aptos_framework::account; use aptos_framework::coin::{Self, Coin}; use aptos_framework::event::{Self, EventHandle}; + use aptos_framework::table::{Self, Table}; use aptos_framework::type_info::{Self, TypeInfo}; use econia::avl_queue::{Self, AVLqueue}; use econia::incentives; @@ -616,19 +617,17 @@ module econia::market { /// Not emitted at market account level when a swap order is placed /// by a non-signing swapper. struct MarketEventHandles has key { - place_swap_order_events: - Tablist>, - cancel_order_events: Tablist>, + place_swap_order_events: Table>, + cancel_order_events: Table>, } /// Stored under a signing user's account (not market account), /// since swaps are processed outside of a market account and do not /// always require a signature. struct SwapperEventHandles has key { - cancel_order_events: Tablist>, - fill_events: Tablist>, - place_swap_order_events: - Tablist> + cancel_order_events: Table>, + fill_events: Table>, + place_swap_order_events: Table> } struct PlaceSwapOrderEvent has copy, drop, store { @@ -1833,32 +1832,32 @@ module econia::market { ); if (!exists(user_address)) move_to(user, SwapperEventHandles{ - cancel_order_events: tablist::new(), - fill_events: tablist::new(), - place_swap_order_events: tablist::new()}); + cancel_order_events: table::new(), + fill_events: table::new(), + place_swap_order_events: table::new()}); let swapper_event_handles_ref_mut = borrow_global_mut(user_address); // Emit place swap order event, initting handle as needed. let place_swap_order_events_ref_mut = &mut swapper_event_handles_ref_mut.place_swap_order_events; - if (!tablist::contains(place_swap_order_events_ref_mut, market_id)) - tablist::add( + if (!table::contains(place_swap_order_events_ref_mut, market_id)) + table::add( place_swap_order_events_ref_mut, market_id, account::new_event_handle(user)); - let place_swap_order_event_handle_ref_mut = tablist::borrow_mut( + let place_swap_order_event_handle_ref_mut = table::borrow_mut( place_swap_order_events_ref_mut, market_id); event::emit_event(place_swap_order_event_handle_ref_mut, place_swap_order_event); // Emit fill events, initting handle as needed. let fill_events_ref_mut = &mut swapper_event_handles_ref_mut.fill_events; - if (!tablist::contains(fill_events_ref_mut, market_id)) - tablist::add( + if (!table::contains(fill_events_ref_mut, market_id)) + table::add( fill_events_ref_mut, market_id, account::new_event_handle(user)); - let fill_events_handle_ref_mut = tablist::borrow_mut( + let fill_events_handle_ref_mut = table::borrow_mut( fill_events_ref_mut, market_id); vector::for_each_ref(&fill_event_queue, |fill_event_ref| { let fill_event: FillEvent = *fill_event_ref; @@ -1869,12 +1868,12 @@ module econia::market { if (option::is_some(&cancel_order_event_option)) { let cancel_order_events_ref_mut = &mut swapper_event_handles_ref_mut.cancel_order_events; - if (!tablist::contains(cancel_order_events_ref_mut, market_id)) - tablist::add( + if (!table::contains(cancel_order_events_ref_mut, market_id)) + table::add( cancel_order_events_ref_mut, market_id, account::new_event_handle(user)); - let cancel_order_events_handle_ref_mut = tablist::borrow_mut( + let cancel_order_events_handle_ref_mut = table::borrow_mut( cancel_order_events_ref_mut, market_id); event::emit_event(cancel_order_events_handle_ref_mut, option::destroy_some(cancel_order_event_option)); @@ -2747,13 +2746,8 @@ module econia::market { move_to( &resource_account::get_signer(), MarketEventHandles{ - /* - fill_events: tablist::new(), - place_limit_order_events: tablist::new(), - place_market_order_events: tablist::new(), - */ - cancel_order_events: tablist::new(), - place_swap_order_events: tablist::new() + cancel_order_events: table::new(), + place_swap_order_events: table::new() } ); borrow_global_mut(resource_address) @@ -4227,15 +4221,15 @@ module econia::market { max_quote, limit_price, order_id: market_order_id}; - let has_place_swap_order_event_handle_for_market = tablist::contains( + let has_place_swap_order_event_handle_for_market = table::contains( &market_event_handles_ref_mut.place_swap_order_events, market_id); - if (!has_place_swap_order_event_handle_for_market) tablist::add( + if (!has_place_swap_order_event_handle_for_market) table::add( &mut market_event_handles_ref_mut.place_swap_order_events, market_id, account::new_event_handle(&resource_account::get_signer())); let place_swap_order_event_handle_for_market_ref_mut = - tablist::borrow_mut( + table::borrow_mut( &mut market_event_handles_ref_mut.place_swap_order_events, market_id); event::emit_event(place_swap_order_event_handle_for_market_ref_mut, @@ -4260,15 +4254,15 @@ module econia::market { NO_CUSTODIAN, cancel_reason ); - let has_cancel_order_event_handle_for_market = tablist::contains( + let has_cancel_order_event_handle_for_market = table::contains( &market_event_handles_ref_mut.cancel_order_events, market_id); - if (!has_cancel_order_event_handle_for_market) tablist::add( + if (!has_cancel_order_event_handle_for_market) table::add( &mut market_event_handles_ref_mut.cancel_order_events, market_id, account::new_event_handle(&resource_account::get_signer())); let cancel_order_event_handle_for_market_ref_mut = - tablist::borrow_mut( + table::borrow_mut( &mut market_event_handles_ref_mut.cancel_order_events, market_id); event::emit_event(cancel_order_event_handle_for_market_ref_mut, diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 1e7ac0a5a..6911ed1b5 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -411,15 +411,14 @@ module econia::user { /// Table keys are market account IDs. struct MarketEventHandles has key { - cancel_order_events: - Tablist>, + cancel_order_events: Table>, change_order_size_events: - Tablist>, - fill_events: Tablist>, + Table>, + fill_events: Table>, place_limit_order_events: - Tablist>, + Table>, place_market_order_events: - Tablist> + Table> } struct CancelOrderEvent has copy, drop, store { @@ -1211,11 +1210,11 @@ module econia::user { E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) move_to(user, MarketEventHandles{ - cancel_order_events: tablist::new(), - change_order_size_events: tablist::new(), - fill_events: tablist::new(), - place_limit_order_events: tablist::new(), - place_market_order_events: tablist::new() + cancel_order_events: table::new(), + change_order_size_events: table::new(), + fill_events: table::new(), + place_limit_order_events: table::new(), + place_market_order_events: table::new() }); /////////// Also init handle below if no handle: @@ -1228,50 +1227,50 @@ module econia::user { let cancel_order_events_ref_mut = &mut market_event_handles_ref_mut.cancel_order_events; let has_cancel_order_events_handle = - tablist::contains(cancel_order_events_ref_mut, - market_account_id); + table::contains(cancel_order_events_ref_mut, + market_account_id); if (!has_cancel_order_events_handle) { - tablist::add(cancel_order_events_ref_mut, market_account_id, - account::new_event_handle(user)); + table::add(cancel_order_events_ref_mut, market_account_id, + account::new_event_handle(user)); }; let change_order_size_events_ref_mut = &mut market_event_handles_ref_mut.change_order_size_events; let has_change_order_size_events_handle = - tablist::contains(change_order_size_events_ref_mut, - market_account_id); + table::contains(change_order_size_events_ref_mut, + market_account_id); if (!has_change_order_size_events_handle) { - tablist::add(change_order_size_events_ref_mut, market_account_id, - account::new_event_handle(user)); + table::add(change_order_size_events_ref_mut, market_account_id, + account::new_event_handle(user)); }; let fill_events_ref_mut = &mut market_event_handles_ref_mut.fill_events; let has_fill_events_handle = - tablist::contains(fill_events_ref_mut, market_account_id); + table::contains(fill_events_ref_mut, market_account_id); if (!has_fill_events_handle) { - tablist::add(fill_events_ref_mut, market_account_id, - account::new_event_handle(user)); + table::add(fill_events_ref_mut, market_account_id, + account::new_event_handle(user)); }; let place_limit_order_events_ref_mut = &mut market_event_handles_ref_mut.place_limit_order_events; let has_place_limit_order_events_handle = - tablist::contains(place_limit_order_events_ref_mut, - market_account_id); + table::contains(place_limit_order_events_ref_mut, + market_account_id); if (!has_place_limit_order_events_handle) { - tablist::add(place_limit_order_events_ref_mut, market_account_id, - account::new_event_handle(user)); + table::add(place_limit_order_events_ref_mut, market_account_id, + account::new_event_handle(user)); }; let place_market_order_events_ref_mut = &mut market_event_handles_ref_mut.place_market_order_events; let has_place_market_order_events_handle = - tablist::contains(place_market_order_events_ref_mut, - market_account_id); + table::contains(place_market_order_events_ref_mut, + market_account_id); if (!has_place_market_order_events_handle) { - tablist::add(place_market_order_events_ref_mut, market_account_id, - account::new_event_handle(user)); + table::add(place_market_order_events_ref_mut, market_account_id, + account::new_event_handle(user)); }; } @@ -1664,10 +1663,10 @@ module econia::user { get_market_account_id(event.market_id, event.custodian_id); let cancel_order_events_ref_mut = &mut market_event_handles_ref_mut.cancel_order_events; - let has_handle = tablist::contains( + let has_handle = table::contains( cancel_order_events_ref_mut, market_account_id); if (!has_handle) return; - let cancel_order_event_handle_ref_mut = tablist::borrow_mut( + let cancel_order_event_handle_ref_mut = table::borrow_mut( cancel_order_events_ref_mut, market_account_id); event::emit_event( cancel_order_event_handle_ref_mut, event) @@ -1683,10 +1682,10 @@ module econia::user { get_market_account_id(event.market_id, event.custodian_id); let change_order_size_events_ref_mut = &mut market_event_handles_ref_mut.change_order_size_events; - let has_handle = tablist::contains( + let has_handle = table::contains( change_order_size_events_ref_mut, market_account_id); if (!has_handle) return; - let change_order_size_event_handle_ref_mut = tablist::borrow_mut( + let change_order_size_event_handle_ref_mut = table::borrow_mut( change_order_size_events_ref_mut, market_account_id); event::emit_event( change_order_size_event_handle_ref_mut, event) @@ -1703,10 +1702,10 @@ module econia::user { get_market_account_id(event.market_id, event.custodian_id); let place_limit_order_events_ref_mut = &mut market_event_handles_ref_mut.place_limit_order_events; - let has_handle = tablist::contains( + let has_handle = table::contains( place_limit_order_events_ref_mut, market_account_id); if (!has_handle) return; - let place_limit_order_event_handle_ref_mut = tablist::borrow_mut( + let place_limit_order_event_handle_ref_mut = table::borrow_mut( place_limit_order_events_ref_mut, market_account_id); event::emit_event( place_limit_order_event_handle_ref_mut, event) @@ -1723,10 +1722,10 @@ module econia::user { get_market_account_id(event.market_id, event.custodian_id); let place_market_order_events_ref_mut = &mut market_event_handles_ref_mut.place_market_order_events; - let has_handle = tablist::contains( + let has_handle = table::contains( place_market_order_events_ref_mut, market_account_id); if (!has_handle) return; - let place_market_order_event_handle_ref_mut = tablist::borrow_mut( + let place_market_order_event_handle_ref_mut = table::borrow_mut( place_market_order_events_ref_mut, market_account_id); event::emit_event( place_market_order_event_handle_ref_mut, event) @@ -2590,8 +2589,8 @@ module econia::user { &mut market_event_handles_ref_mut.fill_events; let market_account_id = get_market_account_id(event.market_id, custodian_id); - if (tablist::contains(fill_events_ref_mut, market_account_id)) { - let fill_event_handle_ref_mut = tablist::borrow_mut( + if (table::contains(fill_events_ref_mut, market_account_id)) { + let fill_event_handle_ref_mut = table::borrow_mut( fill_events_ref_mut, market_account_id); event::emit_event(fill_event_handle_ref_mut, event) } From aca841a5db5196f94a2f35b9fbe71820595a46c2 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 13:45:02 -0700 Subject: [PATCH 29/56] Update get open order to return option --- src/move/econia/sources/market.move | 33 ++++++++++++----------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 58cdb40b1..c2e137ba3 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -1085,24 +1085,18 @@ module econia::market { /// /// Mutates state, so kept as a private view function. /// - /// # Aborts - /// - /// * `E_INVALID_MARKET_ORDER_ID`: No market order with given ID for - /// indicated market. - /// /// # Testing /// /// * `test_change_order_size_ask_custodian()` /// * `test_change_order_size_bid_user()` - /// * `test_get_open_order_invalid_market_order_id()` + /// * `test_get_open_order_no_such_order()` fun get_open_order( market_id: u64, market_order_id: u128 - ): OrderView + ): Option acquires OrderBooks { - // Assert market has an open order with given market order ID. - assert!(has_open_order(market_id, market_order_id), - E_INVALID_MARKET_ORDER_ID); + // Return empty option if no such order. + if (!has_open_order(market_id, market_order_id)) return option::none(); // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); // Mutably borrow order books map. @@ -1122,8 +1116,9 @@ module econia::market { // order access key. let Order{size, price, user, custodian_id, order_access_key: _} = avl_queue::remove(orders_ref_mut, avlq_access_key); - OrderView{market_id, side, market_order_id, size, price, user, - custodian_id} // Pack and return an order view. + // Pack and return an order view in an option. + option::some(OrderView{market_id, side, market_order_id, size, price, + user, custodian_id}) } #[view] @@ -1251,9 +1246,9 @@ module econia::market { /// /// # Testing /// - /// * `test_has_open_order_no_market()` /// * `test_change_order_size_ask_custodian()` /// * `test_change_order_size_bid_user()` + /// * `test_has_open_order_no_market()` fun has_open_order( market_id: u64, market_order_id: u128 @@ -5165,7 +5160,7 @@ module econia::market { price: price_r, user: user_r, custodian_id: custodian_id_r, - } = get_open_order(market_id, market_order_id); + } = option::destroy_some(get_open_order(market_id, market_order_id)); // Assert field returns. assert!(market_id_r == market_id, 0); assert!(side_r == side, 0); @@ -5265,7 +5260,7 @@ module econia::market { price: price_r, user: user_r, custodian_id: custodian_id_r, - } = get_open_order(market_id, market_order_id); + } = option::destroy_some(get_open_order(market_id, market_order_id)); // Assert field returns. assert!(market_id_r == market_id, 0); assert!(side_r == side, 0); @@ -5722,11 +5717,11 @@ module econia::market { } #[test] - #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] - /// Verify failure for unregistered market. - fun test_get_open_order_invalid_market_order_id() acquires OrderBooks { + /// Verify return for no such order. + fun test_get_open_order_no_such_order() acquires OrderBooks { init_test(); // Initialize for testing. - get_open_order(0, 0); // Attempt invalid lookup. + // Assert empty option return. + assert!(get_open_order(0, 0) == option::none(), 0); } #[test] From 4b3276aa2e75ae14704474272d5befdc9fbae0c9 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 14:20:11 -0700 Subject: [PATCH 30/56] Update new implementations to use `order_id` --- doc/doc-site/docs/move/changelog.md | 1 + src/move/econia/sources/market.move | 152 ++++++++++++++-------------- 2 files changed, 76 insertions(+), 77 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 13549b4c2..75f08ab03 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -14,6 +14,7 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] - Fee assessment updated to be processed per fill, rather than per trade ([#321]). - Market order size is no longer automatically adjusted based on available market account holdings ([#321]). - Default self match behavior for swaps (signing swapper self match against signing market account) changed from `ABORT` to `CANCEL_TAKER` ([#321]). +- Started using `order_id` instead of `market_order_id` for new implementations ([#321]). ### Deprecated diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index c2e137ba3..e6c53cf25 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -289,11 +289,11 @@ /// get_price_levels_all --> get_price_levels /// get_open_order --> has_open_order /// get_open_order --> get_market_order_id_side -/// get_open_order --> get_market_order_id_avl_queue_access_key +/// get_open_order --> get_order_id_avl_queue_access_key /// get_market_order_id_side --> -/// get_market_order_id_avl_queue_access_key +/// get_order_id_avl_queue_access_key /// has_open_order --> get_market_order_id_side -/// has_open_order --> get_market_order_id_avl_queue_access_key +/// has_open_order --> get_order_id_avl_queue_access_key /// get_open_orders --> get_open_orders_for_side /// get_open_orders_all --> get_open_orders /// get_market_order_id_price --> did_order_post @@ -643,23 +643,22 @@ module econia::market { order_id: u128 } - /// User-friendly representation of an open order on the order book, - /// combining fields from `Order` and the corresponding - /// `MakerEvent` emitted when order was first placed. + /// User-friendly representation of an open order on the order book. struct OrderView has copy, drop { - /// `MakerEvent.market_id`. + /// Market ID for open order. market_id: u64, - /// `MakerEvent.side`. + /// `ASK` or `BID`. side: bool, - /// `MakerEvent.market_order_id`. - market_order_id: u128, - /// `Order.size`. - size: u64, - /// `Order.price`. + /// The order ID for the posted order. + order_id: u128, + /// Remaining number of lots to be filled. + remaining_size: u64, + /// Order price, in ticks per lot. price: u64, - /// `Order.user`. + /// Address of user holding order. user: address, - /// `Order.custodian_id`. + /// For given user, ID of custodian required to approve order + /// operations and withdrawals on given market account. custodian_id: u64 } @@ -762,7 +761,7 @@ module econia::market { /// Order size change requiring insertion resulted in an AVL queue /// access key mismatch. const E_SIZE_CHANGE_INSERTION_ERROR: u64 = 30; - /// Market order ID corresponds to an order that did not post. + /// Order ID corresponds to an order that did not post. const E_ORDER_DID_NOT_POST: u64 = 31; // Error codes <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -850,7 +849,7 @@ module econia::market { // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #[view] - /// Return true if the market order ID corresponds to an order that + /// Return true if the order ID corresponds to an order that /// resulted in a post to the order book (including an order that /// filled across the spread as a taker before posting as a maker). /// @@ -861,9 +860,9 @@ module econia::market { /// * `test_place_limit_order_no_cross_ask_user()` /// * `test_place_limit_order_no_cross_bid_custodian()` public fun did_order_post( - market_order_id: u128 + order_id: u128 ): bool { - (market_order_id & (HI_64 as u128)) != (NIL as u128) + (order_id & (HI_64 as u128)) != (NIL as u128) } #[view] @@ -1035,8 +1034,8 @@ module econia::market { /// /// # Aborts /// - /// * `E_ORDER_DID_NOT_POST`: market order ID corresponds to an - /// order that did not post to the book. + /// * `E_ORDER_DID_NOT_POST`: Order ID corresponds to an order that + /// did not post to the book. /// /// # Testing /// @@ -1054,34 +1053,33 @@ module econia::market { #[view] /// For an order that resulted in a post to the order book, return - /// the order side encoded in its market order ID, corresponding to - /// the side that the maker portion of the order posted to the book - /// at. + /// the order side encoded in its order ID, corresponding to the + /// side that the maker portion of the order posted to the book at. /// /// # Aborts /// - /// * `E_ORDER_DID_NOT_POST`: market order ID corresponds to an - /// order that did not post to the book. + /// * `E_ORDER_DID_NOT_POST`: Order ID corresponds to an order that + /// did not post to the book. /// /// # Testing /// /// * `test_get_market_order_id_side_did_not_post()` /// * `test_place_limit_order_no_cross_ask_user()` /// * `test_place_limit_order_no_cross_bid_custodian()` - public fun get_market_order_id_side( - market_order_id: u128 + public fun get_posted_order_id_side( + order_id: u128 ): bool { // Assert order posted to the order book. - assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST); - // Get AVL queue access key encoded in market order ID. + assert!(did_order_post(order_id), E_ORDER_DID_NOT_POST); + // Get AVL queue access key encoded in order ID. let avlq_access_key = - get_market_order_id_avl_queue_access_key(market_order_id); + get_order_id_avl_queue_access_key(order_id); // If ascending AVL queue indicated is an ask, else a bid. if (avl_queue::is_ascending_access_key(avlq_access_key)) ASK else BID } #[view] - /// Return `OrderView` for `market_id` and `market_order_id`. + /// Return `OrderView` for `market_id` and `order_id`. /// /// Mutates state, so kept as a private view function. /// @@ -1092,11 +1090,11 @@ module econia::market { /// * `test_get_open_order_no_such_order()` fun get_open_order( market_id: u64, - market_order_id: u128 + order_id: u128 ): Option acquires OrderBooks { // Return empty option if no such order. - if (!has_open_order(market_id, market_order_id)) return option::none(); + if (!has_open_order(market_id, order_id)) return option::none(); // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); // Mutably borrow order books map. @@ -1105,20 +1103,20 @@ module econia::market { // Mutably borrow market order book. let order_book_ref_mut = tablist::borrow_mut( order_books_map_ref_mut, market_id); - // Get market order ID side. - let side = get_market_order_id_side(market_order_id); + // Get order ID side. + let side = get_posted_order_id_side(order_id); // Get open orders for given side. let orders_ref_mut = if (side == ASK) &mut order_book_ref_mut.asks else &mut order_book_ref_mut.bids; let avlq_access_key = // Get AVL queue access key. - get_market_order_id_avl_queue_access_key(market_order_id); + get_order_id_avl_queue_access_key(order_id); // Remove and unpack order with given access key, discarding // order access key. let Order{size, price, user, custodian_id, order_access_key: _} = avl_queue::remove(orders_ref_mut, avlq_access_key); // Pack and return an order view in an option. - option::some(OrderView{market_id, side, market_order_id, size, price, - user, custodian_id}) + option::some(OrderView{market_id, side, order_id, remaining_size: size, + price, user, custodian_id}) } #[view] @@ -1239,8 +1237,8 @@ module econia::market { } #[view] - /// Return `true` if `market_order_id` corresponds to open order for - /// given `market_id`. + /// Return `true` if `order_id` corresponds to open order for given + /// `market_id`. /// /// Kept private to prevent runtime order book state contention. /// @@ -1251,7 +1249,7 @@ module econia::market { /// * `test_has_open_order_no_market()` fun has_open_order( market_id: u64, - market_order_id: u128 + order_id: u128 ): bool acquires OrderBooks { // Get address of resource account where order books are stored. @@ -1262,14 +1260,14 @@ module econia::market { return false; // Return false if no market with market ID. // Immutably borrow order book for given market ID. let order_book_ref = tablist::borrow(order_books_map_ref, market_id); - // Determine side indicated by market order ID. - let side = get_market_order_id_side(market_order_id); + // Determine side indicated by order ID. + let side = get_posted_order_id_side(order_id); // Get open orders for given side. let orders_ref = if (side == ASK) &order_book_ref.asks else &order_book_ref.bids; - // Get AVL queue access key from market order ID. + // Get AVL queue access key from order ID. let avlq_access_key = - get_market_order_id_avl_queue_access_key(market_order_id); + get_order_id_avl_queue_access_key(order_id); // Check if borrowing from the AVL queue is even possible. let borrow_possible = avl_queue::contains_active_list_node_id( orders_ref, avlq_access_key); @@ -1277,16 +1275,16 @@ module econia::market { if (!borrow_possible) return false; // Immutably borrow order having list node ID. let order_ref = avl_queue::borrow(orders_ref, avlq_access_key); - // Check if user has corresponding open order market order ID. - let optional_market_order_id = user::get_open_order_id_internal( + // Check if user has corresponding open order order ID. + let optional_order_id = user::get_open_order_id_internal( order_ref.user, market_id, order_ref.custodian_id, side, order_ref.order_access_key); - // If user has no corresponding market order ID return false. - if (option::is_none(&optional_market_order_id)) return false; - let user_market_order_id = // Get user's market order ID. - option::destroy_some(optional_market_order_id); - // Return if user-indicated market order ID matches passed one. - user_market_order_id == market_order_id + // If user has no corresponding order ID return false. + if (option::is_none(&optional_order_id)) return false; + let user_order_id = // Get user's order ID. + option::destroy_some(optional_order_id); + // Return if user-indicated order ID matches passed one. + user_order_id == order_id } // View functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -2626,15 +2624,15 @@ module econia::market { }); } - /// Get AVL queue access key encoded in `market_order_id`. + /// Get AVL queue access key encoded in `order_id`. /// /// # Testing /// /// * `test_get_market_order_id_avl_queue_access_key()` - inline fun get_market_order_id_avl_queue_access_key( - market_order_id: u128 + inline fun get_order_id_avl_queue_access_key( + order_id: u128 ): u64 { - ((market_order_id & (HI_64 as u128)) as u64) + ((order_id & (HI_64 as u128)) as u64) } /// Index specified number of open orders for given side of order @@ -2659,13 +2657,13 @@ module econia::market { // Remove and unpack order at head of queue. let Order{size, price, user, custodian_id, order_access_key} = avl_queue::pop_head(avlq_ref_mut); - // Get market order ID from user-side order memory. - let market_order_id = option::destroy_some( + // Get order ID from user-side order memory. + let order_id = option::destroy_some( user::get_open_order_id_internal(user, market_id, custodian_id, side, order_access_key)); // Push back an order view to orders view vector. vector::push_back(&mut orders, OrderView{ - market_id, side, market_order_id, size, price, user, + market_id, side, order_id, remaining_size: size, price, user, custodian_id}); }; orders // Return vector of view-friendly orders. @@ -5136,7 +5134,7 @@ module econia::market { order_books_map_ref_mut, market_id).asks; // Get AVL queue access key encoded in market order ID. let avl_queue_access_key = - get_market_order_id_avl_queue_access_key(market_order_id); + get_order_id_avl_queue_access_key(market_order_id); avl_queue::borrow_mut(asks_ref_mut, avl_queue_access_key).user = @econia; // Manually doctor book-side user field. // Assert order marked as not open due to user market order ID @@ -5155,8 +5153,8 @@ module econia::market { let OrderView{ market_id: market_id_r, side: side_r, - market_order_id: market_order_id_r, - size: size_r, + order_id: market_order_id_r, + remaining_size: size_r, price: price_r, user: user_r, custodian_id: custodian_id_r, @@ -5255,8 +5253,8 @@ module econia::market { let OrderView{ market_id: market_id_r, side: side_r, - market_order_id: market_order_id_r, - size: size_r, + order_id: market_order_id_r, + remaining_size: size_r, price: price_r, user: user_r, custodian_id: custodian_id_r, @@ -5698,7 +5696,7 @@ module econia::market { let market_order_id = (avlq_access_key as u128) | ((counter as u128) << SHIFT_COUNTER); // Assert AVL queue access key lookup. - assert!(get_market_order_id_avl_queue_access_key(market_order_id) == + assert!(get_order_id_avl_queue_access_key(market_order_id) == avlq_access_key, 0); } @@ -5713,7 +5711,7 @@ module econia::market { #[expected_failure(abort_code = E_ORDER_DID_NOT_POST)] /// Verify failure for market order ID corresponding to fills only. fun test_get_market_order_id_side_did_not_post() { - get_market_order_id_side((1 as u128) << SHIFT_COUNTER); + get_posted_order_id_side((1 as u128) << SHIFT_COUNTER); } #[test] @@ -5775,28 +5773,28 @@ module econia::market { let order_ref = vector::borrow(&orders.asks, 1); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == ASK, 0); - assert!(order_ref.market_order_id == market_order_id_ask_1, 0); + assert!(order_ref.order_id == market_order_id_ask_1, 0); assert!(order_ref.price == ask_1_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); order_ref = vector::borrow(&orders.asks, 0); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == ASK, 0); - assert!(order_ref.market_order_id == market_order_id_ask_0, 0); + assert!(order_ref.order_id == market_order_id_ask_0, 0); assert!(order_ref.price == ask_0_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); order_ref = vector::borrow(&orders.bids, 0); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == BID, 0); - assert!(order_ref.market_order_id == market_order_id_bid_0, 0); + assert!(order_ref.order_id == market_order_id_bid_0, 0); assert!(order_ref.price == bid_0_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); order_ref = vector::borrow(&orders.bids, 1); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == BID, 0); - assert!(order_ref.market_order_id == market_order_id_bid_1, 0); + assert!(order_ref.order_id == market_order_id_bid_1, 0); assert!(order_ref.price == bid_1_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); @@ -5821,7 +5819,7 @@ module econia::market { order_ref = vector::borrow(&orders.asks, 0); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == ASK, 0); - assert!(order_ref.market_order_id == market_order_id_ask_0, 0); + assert!(order_ref.order_id == market_order_id_ask_0, 0); assert!(order_ref.price == ask_0_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); @@ -5833,14 +5831,14 @@ module econia::market { order_ref = vector::borrow(&orders.bids, 0); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == BID, 0); - assert!(order_ref.market_order_id == market_order_id_bid_0, 0); + assert!(order_ref.order_id == market_order_id_bid_0, 0); assert!(order_ref.price == bid_0_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); order_ref = vector::borrow(&orders.bids, 1); assert!(order_ref.market_id == market_id, 0); assert!(order_ref.side == BID, 0); - assert!(order_ref.market_order_id == market_order_id_bid_1, 0); + assert!(order_ref.order_id == market_order_id_bid_1, 0); assert!(order_ref.price == bid_1_price, 0); assert!(order_ref.user == maker_address, 0); assert!(order_ref.custodian_id == custodian_id, 0); @@ -8674,7 +8672,7 @@ module econia::market { // Assert price encoded in order ID. assert!(get_market_order_id_price(market_order_id) == price, 0); // Assert side encoded in order ID. - assert!(get_market_order_id_side(market_order_id) == side, 0); + assert!(get_posted_order_id_side(market_order_id) == side, 0); // Assert order book counter. assert!(get_order_book_counter(MARKET_ID_COIN) == 1, 0); // Get order fields. @@ -8755,7 +8753,7 @@ module econia::market { // Assert price encoded in order ID. assert!(get_market_order_id_price(market_order_id) == price, 0); // Assert side encoded in order ID. - assert!(get_market_order_id_side(market_order_id) == side, 0); + assert!(get_posted_order_id_side(market_order_id) == side, 0); // Assert trade amount returns. assert!(base_trade == 0, 0); assert!(quote_trade == 0, 0); From 485549c06ee8eb2224310802a67a93c6acbd6afa Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 15:24:16 -0700 Subject: [PATCH 31/56] Add handle info getter view function support --- src/move/econia/sources/market.move | 238 +++++++++++++++++----------- src/move/econia/sources/user.move | 55 +++++++ 2 files changed, 197 insertions(+), 96 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index e6c53cf25..dacb2efc6 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -537,6 +537,7 @@ module econia::market { use aptos_framework::account; use aptos_framework::coin::{Self, Coin}; use aptos_framework::event::{Self, EventHandle}; + use aptos_framework::guid; use aptos_framework::table::{Self, Table}; use aptos_framework::type_info::{Self, TypeInfo}; use econia::avl_queue::{Self, AVLqueue}; @@ -617,8 +618,15 @@ module econia::market { /// Not emitted at market account level when a swap order is placed /// by a non-signing swapper. struct MarketEventHandles has key { - place_swap_order_events: Table>, cancel_order_events: Table>, + place_swap_order_events: Table> + } + + /// View function return for getting event handle creation numbers. + struct MarketEventHandleCreationInfo has copy, drop { + resource_account_address: address, + cancel_order_events_handle_creation_num: u64, + place_swap_order_events_handle_creation_num: u64 } /// Stored under a signing user's account (not market account), @@ -630,6 +638,13 @@ module econia::market { place_swap_order_events: Table> } + /// View function return for getting event handle creation numbers. + struct SwapperEventHandleCreationNumbers has copy, drop { + cancel_order_events_handle_creation_num: u64, + fill_events_handle_creation_num: u64, + place_swap_order_events_handle_creation_num: u64, + } + struct PlaceSwapOrderEvent has copy, drop, store { market_id: u64, signing_account: address, @@ -848,6 +863,71 @@ module econia::market { // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #[view] + /// Private view function to reduce runtime handle contention. + fun get_market_event_handle_creation_info( + market_id: u64 + ): Option + acquires MarketEventHandles { + let resource_account_address = resource_account::get_address(); + if (!exists(resource_account_address)) + return option::none(); + let market_event_handles_ref = + borrow_global(resource_account_address); + // Handles for market initialized at the same time, so assume if + // one exist that all exist. + let handles_exist_for_market = table::contains( + &market_event_handles_ref.cancel_order_events, market_id); + if (!handles_exist_for_market) return option::none(); + option::some(MarketEventHandleCreationInfo{ + resource_account_address: resource_account_address, + cancel_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.cancel_order_events, + market_id + ))), + place_swap_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.place_swap_order_events, + market_id + ))), + }) + } + + #[view] + /// Private view function to reduce runtime handle contention. + fun get_swapper_event_handle_creation_numbers( + swapper: address, + market_id: u64 + ): Option + acquires SwapperEventHandles { + if (!exists(swapper)) return option::none(); + let swapper_event_handles_ref = + borrow_global(swapper); + // Handles for market initialized at the same time, so assume if + // one exist that all exist. + let handles_exist_for_market = table::contains( + &swapper_event_handles_ref.cancel_order_events, market_id); + if (!handles_exist_for_market) return option::none(); + option::some(SwapperEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &swapper_event_handles_ref.cancel_order_events, + market_id + ))), + fill_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &swapper_event_handles_ref.fill_events, + market_id + ))), + place_swap_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &swapper_event_handles_ref.place_swap_order_events, + market_id + ))), + }) + } + #[view] /// Return true if the order ID corresponds to an order that /// resulted in a post to the order book (including an order that @@ -1823,6 +1903,7 @@ module econia::market { optional_base_coins, quote_coins ); + // Create swapper event handles for market as needed. if (!exists(user_address)) move_to(user, SwapperEventHandles{ cancel_order_events: table::new(), @@ -1830,44 +1911,40 @@ module econia::market { place_swap_order_events: table::new()}); let swapper_event_handles_ref_mut = borrow_global_mut(user_address); - // Emit place swap order event, initting handle as needed. - let place_swap_order_events_ref_mut = + let cancel_order_events_table_ref_mut = + &mut swapper_event_handles_ref_mut.cancel_order_events; + let fill_events_table_ref_mut = + &mut swapper_event_handles_ref_mut.fill_events; + let place_swap_order_events_table_ref_mut = &mut swapper_event_handles_ref_mut.place_swap_order_events; - if (!table::contains(place_swap_order_events_ref_mut, market_id)) - table::add( - place_swap_order_events_ref_mut, - market_id, - account::new_event_handle(user)); + // If doesn't have one handle for market, assume has none and + // thus create all handles for market. + let has_cancel_order_events_handle = + table::contains(cancel_order_events_table_ref_mut, market_id); + if (!has_cancel_order_events_handle) { + table::add(cancel_order_events_table_ref_mut, market_id, + account::new_event_handle(user)); + table::add(fill_events_table_ref_mut, market_id, + account::new_event_handle(user)); + table::add(place_swap_order_events_table_ref_mut, market_id, + account::new_event_handle(user)); + }; + // Emit place swap order event. let place_swap_order_event_handle_ref_mut = table::borrow_mut( - place_swap_order_events_ref_mut, market_id); + place_swap_order_events_table_ref_mut, market_id); event::emit_event(place_swap_order_event_handle_ref_mut, place_swap_order_event); - // Emit fill events, initting handle as needed. - let fill_events_ref_mut = - &mut swapper_event_handles_ref_mut.fill_events; - if (!table::contains(fill_events_ref_mut, market_id)) - table::add( - fill_events_ref_mut, - market_id, - account::new_event_handle(user)); + // Emit fill events first-in-first-out. let fill_events_handle_ref_mut = table::borrow_mut( - fill_events_ref_mut, market_id); + fill_events_table_ref_mut, market_id); vector::for_each_ref(&fill_event_queue, |fill_event_ref| { let fill_event: FillEvent = *fill_event_ref; - event::emit_event(fill_events_handle_ref_mut, - fill_event); + event::emit_event(fill_events_handle_ref_mut, fill_event); }); - // Optionally emit cancel event, initting handle as needed. + // Optionally emit cancel event. if (option::is_some(&cancel_order_event_option)) { - let cancel_order_events_ref_mut = - &mut swapper_event_handles_ref_mut.cancel_order_events; - if (!table::contains(cancel_order_events_ref_mut, market_id)) - table::add( - cancel_order_events_ref_mut, - market_id, - account::new_event_handle(user)); let cancel_order_events_handle_ref_mut = table::borrow_mut( - cancel_order_events_ref_mut, market_id); + cancel_order_events_table_ref_mut, market_id); event::emit_event(cancel_order_events_handle_ref_mut, option::destroy_some(cancel_order_event_option)); }; @@ -2605,22 +2682,6 @@ module econia::market { } else { user::emit_fill_event_for_maker_and_taker(event); }; - /* Commented-out algorithm to emit at market level: - // Emit event for market, creating handle as needed. - let has_handle = tablist::contains( - &handles_ref_mut.fill_events, market_id); - if (!has_handle) { - tablist::add( - &mut handles_ref_mut.fill_events, - market_id, - account::new_event_handle( - &resource_account::get_signer())); - }; - let handle_ref_mut = tablist::borrow_mut( - &mut handles_ref_mut.fill_events, - market_id); - event::emit_event(handle_ref_mut, event); - */ }); } @@ -3465,19 +3526,6 @@ module econia::market { } else { remaining_size = 0; }; - /* Commented-out algorithm to emit at market level: - let has_place_limit_order_event_handle = tablist::contains( - &market_event_handles_ref_mut.place_limit_order_events, market_id); - if (!has_place_limit_order_event_handle) tablist::add( - &mut market_event_handles_ref_mut.place_limit_order_events, - market_id, - account::new_event_handle(&resource_account::get_signer())); - let place_limit_order_event_handle_ref_mut = tablist::borrow_mut( - &mut market_event_handles_ref_mut.place_limit_order_events, - market_id); - event::emit_event(place_limit_order_event_handle_ref_mut, - place_limit_order_event); - */ // Emit a place limit order event, creating handle as needed. user::emit_place_limit_order_event( user::create_place_limit_order_event( @@ -3856,19 +3904,6 @@ module econia::market { user::deposit_assets_internal( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); - /* Commented-out algorithm to emit at market level: - let has_place_market_order_event_handle = tablist::contains( - &market_event_handles_ref_mut.place_market_order_events, market_id); - if (!has_place_market_order_event_handle) tablist::add( - &mut market_event_handles_ref_mut.place_market_order_events, - market_id, - account::new_event_handle(&resource_account::get_signer())); - let place_market_order_event_handle_ref_mut = tablist::borrow_mut( - &mut market_event_handles_ref_mut.place_market_order_events, - market_id); - event::emit_event(place_market_order_event_handle_ref_mut, - place_market_order_event); - */ user::emit_place_market_order_event( user::create_place_market_order_event( market_id, @@ -4203,6 +4238,32 @@ module econia::market { quote_coins ); let market_order_id = order_id_no_post(order_book_ref_mut.counter); + // Create market event handles for market as needed. + if (!exists(resource_address)) + move_to( + &resource_account::get_signer(), + MarketEventHandles{ + cancel_order_events: table::new(), + place_swap_order_events: table::new() + } + ); + let market_event_handles_ref_mut = + borrow_global_mut(resource_address); + let cancel_order_events_table_ref_mut = + &mut market_event_handles_ref_mut.cancel_order_events; + let place_swap_order_events_table_ref_mut = + &mut market_event_handles_ref_mut.place_swap_order_events; + // If doesn't have one handle for market, assume has none and + // thus create all handles for market. + let has_cancel_order_events_handle = + table::contains(cancel_order_events_table_ref_mut, market_id); + if (!has_cancel_order_events_handle) { + let resource_signer = resource_account::get_signer(); + table::add(cancel_order_events_table_ref_mut, market_id, + account::new_event_handle(&resource_signer)); + table::add(place_swap_order_events_table_ref_mut, market_id, + account::new_event_handle(&resource_signer)); + }; let place_swap_order_event = PlaceSwapOrderEvent{ market_id, signing_account: signer_address, @@ -4214,18 +4275,10 @@ module econia::market { max_quote, limit_price, order_id: market_order_id}; - let has_place_swap_order_event_handle_for_market = table::contains( - &market_event_handles_ref_mut.place_swap_order_events, - market_id); - if (!has_place_swap_order_event_handle_for_market) table::add( - &mut market_event_handles_ref_mut.place_swap_order_events, - market_id, - account::new_event_handle(&resource_account::get_signer())); - let place_swap_order_event_handle_for_market_ref_mut = - table::borrow_mut( - &mut market_event_handles_ref_mut.place_swap_order_events, - market_id); - event::emit_event(place_swap_order_event_handle_for_market_ref_mut, + // Emit place swap order event. + let place_swap_order_event_handle_ref_mut = table::borrow_mut( + place_swap_order_events_table_ref_mut, market_id); + event::emit_event(place_swap_order_event_handle_ref_mut, place_swap_order_event); emit_fill_events_for_market_accounts( market_id, fill_event_queue_ref_mut, market_event_handles_ref_mut, @@ -4247,19 +4300,12 @@ module econia::market { NO_CUSTODIAN, cancel_reason ); - let has_cancel_order_event_handle_for_market = table::contains( - &market_event_handles_ref_mut.cancel_order_events, - market_id); - if (!has_cancel_order_event_handle_for_market) table::add( - &mut market_event_handles_ref_mut.cancel_order_events, - market_id, - account::new_event_handle(&resource_account::get_signer())); - let cancel_order_event_handle_for_market_ref_mut = - table::borrow_mut( - &mut market_event_handles_ref_mut.cancel_order_events, - market_id); - event::emit_event(cancel_order_event_handle_for_market_ref_mut, - cancel_order_event); + let cancel_order_events_table_ref_mut = + &mut market_event_handles_ref_mut.cancel_order_events; + let cancel_order_events_handle_ref_mut = table::borrow_mut( + cancel_order_events_table_ref_mut, market_id); + event::emit_event(cancel_order_events_handle_ref_mut, + cancel_order_event); option::some(cancel_order_event) } else { option::none() diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 6911ed1b5..36aea1012 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -283,6 +283,7 @@ module econia::user { use aptos_framework::account; use aptos_framework::coin::{Self, Coin}; + use aptos_framework::guid; use aptos_framework::table::{Self, Table}; use aptos_framework::event::{Self, EventHandle}; use aptos_framework::type_info::{Self, TypeInfo}; @@ -421,6 +422,15 @@ module econia::user { Table> } + /// View function return for getting event handle creation numbers. + struct MarketEventHandleCreationNumbers has copy, drop { + cancel_order_events_handle_creation_num: u64, + change_order_size_events_handle_creation_num: u64, + fill_events_handle_creation_num: u64, + place_limit_order_events_handle_creation_num: u64, + place_market_order_events_handle_creation_num: u64 + } + struct CancelOrderEvent has copy, drop, store { market_id: u64, order_id: u128, @@ -563,6 +573,51 @@ module econia::user { // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #[view] + /// Private view function to reduce runtime handle contention. + fun get_market_event_handle_creation_numbers( + user: address, + market_id: u64, + custodian_id: u64 + ): Option + acquires MarketEventHandles { + if (!exists(user)) return option::none(); + let market_event_handles_ref = borrow_global(user); + let market_account_id = get_market_account_id(market_id, custodian_id); + // Handles for market account initialized at the same time, so + // assume if one exist that all exist. + let handles_exist_for_market_account = table::contains( + &market_event_handles_ref.cancel_order_events, market_account_id); + if (!handles_exist_for_market_account) return option::none(); + option::some(MarketEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.cancel_order_events, + market_account_id + ))), + change_order_size_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.change_order_size_events, + market_account_id + ))), + fill_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.fill_events, + market_account_id + ))), + place_limit_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.place_limit_order_events, + market_account_id + ))), + place_market_order_events_handle_creation_num: + guid::creation_num(event::guid(table::borrow( + &market_event_handles_ref.place_market_order_events, + market_account_id + ))), + }) + } + #[view] public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8 { CANCEL_REASON_MANUAL_CANCEL From 212fa6492852e07f342d28f1ce33709d0450f39f Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 15:37:49 -0700 Subject: [PATCH 32/56] Remove extraneous parameters/acquisitions --- src/move/econia/sources/market.move | 116 +--------------------------- 1 file changed, 3 insertions(+), 113 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index dacb2efc6..75c85ebda 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -1459,7 +1459,6 @@ module econia::market { u64, u64 ) acquires - MarketEventHandles, OrderBooks { place_limit_order< @@ -1499,7 +1498,6 @@ module econia::market { custodian_capability_ref: &CustodianCapability ): u128 acquires - MarketEventHandles, OrderBooks { place_limit_order_passive_advance< @@ -1543,7 +1541,6 @@ module econia::market { target_advance_amount: u64 ): u128 acquires - MarketEventHandles, OrderBooks { place_limit_order_passive_advance< @@ -1591,7 +1588,6 @@ module econia::market { u64, u64 ) acquires - MarketEventHandles, OrderBooks { place_limit_order< @@ -1633,7 +1629,6 @@ module econia::market { u64, u64 ) acquires - MarketEventHandles, OrderBooks { place_market_order( @@ -1668,7 +1663,6 @@ module econia::market { u64, u64 ) acquires - MarketEventHandles, OrderBooks { place_market_order( @@ -2286,7 +2280,6 @@ module econia::market { advance_style: bool, target_advance_amount: u64 ) acquires - MarketEventHandles, OrderBooks { place_limit_order_passive_advance_user< @@ -2320,7 +2313,6 @@ module econia::market { restriction: u8, self_match_behavior: u8 ) acquires - MarketEventHandles, OrderBooks { place_limit_order_user( @@ -2344,7 +2336,6 @@ module econia::market { size: u64, self_match_behavior: u8 ) acquires - MarketEventHandles, OrderBooks { place_market_order_user( @@ -2664,9 +2655,7 @@ module econia::market { } fun emit_fill_events_for_market_accounts( - _market_id: u64, fill_event_queue_ref: &vector, - _handles_ref_mut: &mut MarketEventHandles, taker_is_swapper: bool, new_taker_order_id: u128, ) { @@ -2792,21 +2781,6 @@ module econia::market { move_to(&resource_account, OrderBooks{map: tablist::new()}) } - inline fun market_event_handles_borrow_mut( - resource_address: address, - ): &mut MarketEventHandles - acquires MarketEventHandles { - if (!exists(resource_address)) - move_to( - &resource_account::get_signer(), - MarketEventHandles{ - cancel_order_events: table::new(), - place_swap_order_events: table::new() - } - ); - borrow_global_mut(resource_address) - } - /// Match a taker order against the order book. /// /// Calculates maximum amount of quote coins to match, matches, then @@ -2933,7 +2907,6 @@ module econia::market { QuoteType >( market_id: u64, - _event_handles_ref_mut: &mut MarketEventHandles, event_queue_ref_mut: &mut vector, order_book_ref_mut: &mut OrderBook, taker: address, @@ -3287,7 +3260,6 @@ module econia::market { u64, u64 ) acquires - MarketEventHandles, OrderBooks { // Assert valid order restriction flag. @@ -3379,8 +3351,6 @@ module econia::market { // Assume no assets traded as a taker. let (base_traded, quote_traded, fees, fill_event_queue) = (0, 0, 0, vector[]); - let market_event_handles_ref_mut = - market_event_handles_borrow_mut(resource_address); let cancel_reason_option = option::none(); let remaining_size = size; if (crosses_spread) { @@ -3410,7 +3380,6 @@ module econia::market { _, ) = match( market_id, - market_event_handles_ref_mut, &mut fill_event_queue, order_book_ref_mut, user_address, @@ -3543,8 +3512,7 @@ module econia::market { ) ); emit_fill_events_for_market_accounts( - market_id, &mut fill_event_queue, market_event_handles_ref_mut, - false, market_order_id); + &mut fill_event_queue, false, market_order_id); if (option::is_some(&cancel_reason_option)) { user::emit_cancel_order_event( user::create_cancel_order_event( @@ -3658,7 +3626,6 @@ module econia::market { target_advance_amount: u64 ): u128 acquires - MarketEventHandles, OrderBooks { // Get address of resource account where order books are stored. @@ -3816,7 +3783,6 @@ module econia::market { u64, u64 ) acquires - MarketEventHandles, OrderBooks { // Get user's available and ceiling asset counts. @@ -3867,8 +3833,6 @@ module econia::market { // Calculate limit price for matching engine: 0 when selling, // max price possible when buying. let limit_price = if (direction == SELL) 0 else HI_PRICE; - let market_event_handles_ref_mut = - market_event_handles_borrow_mut(resource_address); let fill_event_queue = vector[]; let ( optional_base_coins, @@ -3880,7 +3844,6 @@ module econia::market { liquidity_gone ) = match( market_id, - market_event_handles_ref_mut, &mut fill_event_queue, order_book_ref_mut, user_address, @@ -3916,8 +3879,7 @@ module econia::market { market_order_id) ); emit_fill_events_for_market_accounts( - market_id, &mut fill_event_queue, market_event_handles_ref_mut, - false, (NIL as u128)); + &mut fill_event_queue, false, (NIL as u128)); // If order needs to be cancelled: if ((self_match_taker_cancel) || (base_traded < max_base)) { let cancel_reason = if (self_match_taker_cancel) { @@ -4209,8 +4171,6 @@ module econia::market { // Declare return assignment variables. let (base_traded, quote_traded, fees, self_match_taker_cancel, liquidity_gone); - let market_event_handles_ref_mut = - market_event_handles_borrow_mut(resource_address); ( optional_base_coins, quote_coins, @@ -4221,7 +4181,6 @@ module econia::market { liquidity_gone ) = match( // Match against order book. market_id, - market_event_handles_ref_mut, fill_event_queue_ref_mut, order_book_ref_mut, signer_address, @@ -4281,8 +4240,7 @@ module econia::market { event::emit_event(place_swap_order_event_handle_ref_mut, place_swap_order_event); emit_fill_events_for_market_accounts( - market_id, fill_event_queue_ref_mut, market_event_handles_ref_mut, - true, (NIL as u128)); + fill_event_queue_ref_mut, true, (NIL as u128)); let need_to_cancel_order = (self_match_taker_cancel) || (base_traded < max_base); let cancel_order_event_option = if (need_to_cancel_order) { @@ -4401,7 +4359,6 @@ module econia::market { min_ask_price: u64 ): signer acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4640,7 +4597,6 @@ module econia::market { /// of custodian. fun test_cancel_all_orders_ask_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4703,7 +4659,6 @@ module econia::market { /// of signing user. fun test_cancel_all_orders_bid_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4762,7 +4717,6 @@ module econia::market { /// custodian. fun test_cancel_order_ask_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4842,7 +4796,6 @@ module econia::market { /// signing user. fun test_cancel_order_bid_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -4917,7 +4870,6 @@ module econia::market { /// Verify failure for invalid custodian. fun test_cancel_order_invalid_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5012,7 +4964,6 @@ module econia::market { /// Verify failure for invalid user. fun test_cancel_order_invalid_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5072,7 +5023,6 @@ module econia::market { /// custodian, for size increase at tail of price level queue. fun test_change_order_size_ask_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5220,7 +5170,6 @@ module econia::market { /// user, for size decrease at tail of queue. fun test_change_order_size_bid_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5320,7 +5269,6 @@ module econia::market { /// user, for size increase not at tail of queue. fun test_change_order_size_bid_user_new_tail() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5412,7 +5360,6 @@ module econia::market { /// `test_change_order_size_bid_user_new_tail`. fun test_change_order_size_insertion_error() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5476,7 +5423,6 @@ module econia::market { /// Verify failure for invalid custodian. fun test_change_order_size_invalid_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5575,7 +5521,6 @@ module econia::market { /// Verify failure for invalid user. fun test_change_order_size_invalid_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5772,7 +5717,6 @@ module econia::market { /// Verify indexing results. fun test_get_open_orders() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -5902,7 +5846,6 @@ module econia::market { /// Verify indexing results. fun test_get_price_levels() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7239,7 +7182,6 @@ module econia::market { /// Verify failure for self match with abort behavior. fun test_match_self_match_abort() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7287,7 +7229,6 @@ module econia::market { /// self match. fun test_match_self_match_cancel_both() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7400,7 +7341,6 @@ module econia::market { /// the order at the higher price. fun test_match_self_match_cancel_maker() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7537,7 +7477,6 @@ module econia::market { /// self match. fun test_match_self_match_cancel_taker() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7654,7 +7593,6 @@ module econia::market { /// Verify failure for self match with invalid abort behavior. fun test_match_self_match_invalid() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7696,7 +7634,6 @@ module econia::market { /// Verify failure for base overflow. fun test_place_limit_order_base_overflow() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -7719,7 +7656,6 @@ module econia::market { /// signing user. fun test_place_limit_order_crosses_ask_exact() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7827,7 +7763,6 @@ module econia::market { /// Based on `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_ask_partial() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -7942,7 +7877,6 @@ module econia::market { /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_partial_cancel() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8023,7 +7957,6 @@ module econia::market { /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_self_match_cancel() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8097,7 +8030,6 @@ module econia::market { /// `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_bid_exact() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8205,7 +8137,6 @@ module econia::market { /// Mirror of `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_bid_partial() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8320,7 +8251,6 @@ module econia::market { /// `test_place_limit_order_crosses_bid_partial()`. fun test_place_limit_order_crosses_bid_partial_cancel() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8421,7 +8351,6 @@ module econia::market { /// evicts another user's order. fun test_place_limit_order_evict() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8542,7 +8471,6 @@ module econia::market { /// Verify failure for not crossing spread when fill-or-abort. fun test_place_limit_order_fill_or_abort_not_cross() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8570,7 +8498,6 @@ module econia::market { /// fill-or-abort. fun test_place_limit_order_fill_or_abort_partial() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8605,7 +8532,6 @@ module econia::market { /// Verify failure for invalid base type argument. fun test_place_limit_order_invalid_base() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8632,7 +8558,6 @@ module econia::market { /// Verify failure for invalid quote type argument. fun test_place_limit_order_invalid_quote() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8659,7 +8584,6 @@ module econia::market { /// Verify failure for invalid restriction. fun test_place_limit_order_invalid_restriction() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8679,7 +8603,6 @@ module econia::market { /// cross the spread, under authority of signing user. fun test_place_limit_order_no_cross_ask_user() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8764,7 +8687,6 @@ module econia::market { /// cross the spread, under authority of custodian. fun test_place_limit_order_no_cross_bid_custodian() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8850,7 +8772,6 @@ module econia::market { /// Verify failure for invalid price. fun test_place_limit_order_no_price() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -8870,7 +8791,6 @@ module econia::market { /// Verify failure for invalid base type argument. fun test_place_limit_order_passive_advance_invalid_base() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8893,7 +8813,6 @@ module econia::market { /// Verify failure for invalid market ID. fun test_place_limit_order_passive_advance_invalid_market_id() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8916,7 +8835,6 @@ module econia::market { /// Verify failure for invalid percent fun test_place_limit_order_passive_advance_invalid_percent() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -8941,7 +8859,6 @@ module econia::market { /// Verify failure for invalid quote type argument. fun test_place_limit_order_passive_advance_invalid_quote() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -8963,7 +8880,6 @@ module econia::market { /// Verify return for no cross price when placing an ask. fun test_place_limit_order_passive_advance_no_cross_price_ask() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -8989,7 +8905,6 @@ module econia::market { /// Verify return for no cross price when placing a bid. fun test_place_limit_order_passive_advance_no_cross_price_bid() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9015,7 +8930,6 @@ module econia::market { /// Verify returns, state updates for full advance is start price. fun test_place_limit_order_passive_advance_no_full_advance() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9046,7 +8960,6 @@ module econia::market { /// Verify returns for no start price. fun test_place_limit_order_passive_advance_no_start_price() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9076,7 +8989,6 @@ module econia::market { /// Verify returns, state updates for no target advance amount. fun test_place_limit_order_passive_advance_no_target_advance() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9106,7 +9018,6 @@ module econia::market { /// Verify returns, state updates for percent-specified asks. fun test_place_limit_order_passive_advance_percent_ask() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9140,7 +9051,6 @@ module econia::market { /// Verify returns, state updates for percent-specified bids. fun test_place_limit_order_passive_advance_percent_bid() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9174,7 +9084,6 @@ module econia::market { /// Verify returns, state updates for ticks-specified asks. fun test_place_limit_order_passive_advance_ticks_ask() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9226,7 +9135,6 @@ module econia::market { /// delegated custodian. fun test_place_limit_order_passive_advance_ticks_bid() acquires - MarketEventHandles, OrderBooks { // Configure spread. @@ -9280,7 +9188,6 @@ module econia::market { /// Verify failure for not crossing spread as post-or-abort. fun test_place_limit_order_post_or_abort_crosses() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9315,7 +9222,6 @@ module econia::market { /// Verify failure for invalid price. fun test_place_limit_order_price_hi() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9336,7 +9242,6 @@ module econia::market { /// `test_place_limit_order_evict()`. fun test_place_limit_order_price_time_priority_low() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9386,7 +9291,6 @@ module econia::market { /// Verify failure for quote overflow. fun test_place_limit_order_quote_overflow() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9408,7 +9312,6 @@ module econia::market { /// Verify failure for invalid size. fun test_place_limit_order_size_lo() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9436,7 +9339,6 @@ module econia::market { /// user. Based on `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_still_crosses_ask() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9558,7 +9460,6 @@ module econia::market { /// user. Based on `test_place_limit_order_still_crosses_ask()`. fun test_place_limit_order_still_crosses_bid() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9676,7 +9577,6 @@ module econia::market { /// Verify failure for ticks overflow. fun test_place_limit_order_ticks_overflow() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9698,7 +9598,6 @@ module econia::market { /// on `test_place_limit_order_no_cross_ask_user()`. fun test_place_limit_order_user_entry() acquires - MarketEventHandles, OrderBooks { // Declare order parameters. @@ -9762,7 +9661,6 @@ module econia::market { /// Verify failure for invalid base type argument. fun test_place_market_order_invalid_base() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9786,7 +9684,6 @@ module econia::market { /// Verify failure for invalid quote type argument. fun test_place_market_order_invalid_quote() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9810,7 +9707,6 @@ module econia::market { /// Verify failure for invalid size argument. fun test_place_market_order_size_too_small() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9835,7 +9731,6 @@ module econia::market { /// authority of signing user. fun test_place_market_order_max_base_adjust_buy_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -9943,7 +9838,6 @@ module econia::market { /// user. fun test_place_market_order_max_base_buy_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10049,7 +9943,6 @@ module econia::market { /// base trade amount specified, under authority of custodian. fun test_place_market_order_max_base_sell_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10159,7 +10052,6 @@ module econia::market { /// quote trade amount specified, under authority of custodian. fun test_place_market_order_max_quote_buy_custodian() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10268,7 +10160,6 @@ module econia::market { /// quote trade amount specified, under authority of signing user. fun test_place_market_order_max_quote_sell_user() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. @@ -10373,7 +10264,6 @@ module econia::market { /// on `test_place_market_order_max_base_buy_user()`. fun test_place_market_order_user_entry() acquires - MarketEventHandles, OrderBooks { // Initialize markets, users, and an integrator. From 4948d6034239b4503a3142732a84255fc7d6f849 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:26:15 -0700 Subject: [PATCH 33/56] Consolidate event handles for market account --- src/move/econia/sources/user.move | 251 ++++++++++++++---------------- 1 file changed, 120 insertions(+), 131 deletions(-) diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 36aea1012..a12a4030a 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -410,16 +410,17 @@ module econia::user { size: u64 } + struct MarketEventHandlesForMarketAccount has store { + cancel_order_events: EventHandle, + change_order_size_events: EventHandle, + fill_events: EventHandle, + place_limit_order_events: EventHandle, + place_market_order_events: EventHandle + } + /// Table keys are market account IDs. struct MarketEventHandles has key { - cancel_order_events: Table>, - change_order_size_events: - Table>, - fill_events: Table>, - place_limit_order_events: - Table>, - place_market_order_events: - Table> + map: Table } /// View function return for getting event handle creation numbers. @@ -582,39 +583,30 @@ module econia::user { ): Option acquires MarketEventHandles { if (!exists(user)) return option::none(); - let market_event_handles_ref = borrow_global(user); + let market_event_handles_map_ref = + &borrow_global(user).map; let market_account_id = get_market_account_id(market_id, custodian_id); - // Handles for market account initialized at the same time, so - // assume if one exist that all exist. - let handles_exist_for_market_account = table::contains( - &market_event_handles_ref.cancel_order_events, market_account_id); - if (!handles_exist_for_market_account) return option::none(); + let has_handles = table::contains( + market_event_handles_map_ref, market_account_id); + if (!has_handles) return option::none(); + let market_account_handles_ref = table::borrow( + market_event_handles_map_ref, market_account_id); option::some(MarketEventHandleCreationNumbers{ cancel_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.cancel_order_events, - market_account_id - ))), + guid::creation_num(event::guid( + &market_account_handles_ref.cancel_order_events)), change_order_size_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.change_order_size_events, - market_account_id - ))), + guid::creation_num(event::guid( + &market_account_handles_ref.change_order_size_events)), fill_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.fill_events, - market_account_id - ))), + guid::creation_num(event::guid( + &market_account_handles_ref.fill_events)), place_limit_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.place_limit_order_events, - market_account_id - ))), + guid::creation_num(event::guid( + &market_account_handles_ref.place_limit_order_events)), place_market_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.place_market_order_events, - market_account_id - ))), + guid::creation_num(event::guid( + &market_account_handles_ref.place_market_order_events)), }) } @@ -1264,68 +1256,22 @@ module econia::user { assert!(has_market_account(user_address, market_id, custodian_id), E_NO_MARKET_ACCOUNT); if (!exists(address_of(user))) - move_to(user, MarketEventHandles{ - cancel_order_events: table::new(), - change_order_size_events: table::new(), - fill_events: table::new(), - place_limit_order_events: table::new(), - place_market_order_events: table::new() - }); - - /////////// Also init handle below if no handle: - - let market_event_handles_ref_mut = - borrow_global_mut(user_address); - let market_account_id = - get_market_account_id(market_id, custodian_id); - - let cancel_order_events_ref_mut = - &mut market_event_handles_ref_mut.cancel_order_events; - let has_cancel_order_events_handle = - table::contains(cancel_order_events_ref_mut, - market_account_id); - if (!has_cancel_order_events_handle) { - table::add(cancel_order_events_ref_mut, market_account_id, - account::new_event_handle(user)); - }; - - let change_order_size_events_ref_mut = - &mut market_event_handles_ref_mut.change_order_size_events; - let has_change_order_size_events_handle = - table::contains(change_order_size_events_ref_mut, - market_account_id); - if (!has_change_order_size_events_handle) { - table::add(change_order_size_events_ref_mut, market_account_id, - account::new_event_handle(user)); - }; - - let fill_events_ref_mut = - &mut market_event_handles_ref_mut.fill_events; - let has_fill_events_handle = - table::contains(fill_events_ref_mut, market_account_id); - if (!has_fill_events_handle) { - table::add(fill_events_ref_mut, market_account_id, - account::new_event_handle(user)); - }; - - let place_limit_order_events_ref_mut = - &mut market_event_handles_ref_mut.place_limit_order_events; - let has_place_limit_order_events_handle = - table::contains(place_limit_order_events_ref_mut, - market_account_id); - if (!has_place_limit_order_events_handle) { - table::add(place_limit_order_events_ref_mut, market_account_id, - account::new_event_handle(user)); - }; - - let place_market_order_events_ref_mut = - &mut market_event_handles_ref_mut.place_market_order_events; - let has_place_market_order_events_handle = - table::contains(place_market_order_events_ref_mut, - market_account_id); - if (!has_place_market_order_events_handle) { - table::add(place_market_order_events_ref_mut, market_account_id, - account::new_event_handle(user)); + move_to(user, MarketEventHandles{map: table::new()}); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; + let market_account_id = get_market_account_id(market_id, custodian_id); + let has_handles = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (!has_handles) { + let handles = MarketEventHandlesForMarketAccount{ + cancel_order_events: account::new_event_handle(user), + change_order_size_events: account::new_event_handle(user), + fill_events: account::new_event_handle(user), + place_limit_order_events: account::new_event_handle(user), + place_market_order_events: account::new_event_handle(user) + }; + table::add( + market_event_handles_map_ref_mut, market_account_id, handles); }; } @@ -1693,6 +1639,47 @@ module econia::user { user_address, market_id, custodian_id, quote_coins); } +/* TODO: + public(friend) fun emit_limit_order_events( + market_id: u64, + user: address, + custodian_id: u64, + integrator: address, + side: bool, + size: u64, + price: u64, + restriction: u8, + self_match_behavior: u8, + remaining_size: u64, + order_id: u128, + fill_event_queue_ref_mut: &mut vector, + cancel_reason_option_ref: &Option + ) acquires MarketEventHandles { + if (exists(user_address)) { + let market_event_handles_ref_mut_mut = + borrow_global_mut(user); + let market_account_id = + get_market_account_id(market_id, custodian_id); + // Handles for market account initialized at the same time, so + // assume if one exist that all exist. + let handles_exist_for_market_account = table::contains( + &market_event_handles_ref_mut.cancel_order_events, + market_account_id); + if (handles_exist_for_market_account) { + let cancel_order_events_table_ref_mut = + &mut market_event_handles_ref_mut.cancel_order_events; + let fill_events_table_ref_mut = + &mut market_event_handles_ref_mut.fill_events; + let place_limit_order_events_table_ref_mut = + &mut market_event_handles_ref_mut.place_limit_order_events; + } + } + + // Then loop over fill events again and emit for each maker. + } + +*/ + /// Emit fill event to specified handle, if handle exists. public(friend) fun emit_fill_event_for_maker_and_taker( event: FillEvent @@ -1712,17 +1699,17 @@ module econia::user { ) acquires MarketEventHandles { let user_address = event.user; if (!exists(user_address)) return; - let market_event_handles_ref_mut = - borrow_global_mut(user_address); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; let market_account_id = get_market_account_id(event.market_id, event.custodian_id); - let cancel_order_events_ref_mut = - &mut market_event_handles_ref_mut.cancel_order_events; let has_handle = table::contains( - cancel_order_events_ref_mut, market_account_id); + market_event_handles_map_ref_mut, market_account_id); if (!has_handle) return; - let cancel_order_event_handle_ref_mut = table::borrow_mut( - cancel_order_events_ref_mut, market_account_id); + let cancel_order_event_handle_ref_mut = &mut table::borrow_mut( + market_event_handles_map_ref_mut, + market_account_id + ).cancel_order_events; event::emit_event( cancel_order_event_handle_ref_mut, event) } @@ -1731,17 +1718,17 @@ module econia::user { ) acquires MarketEventHandles { let user_address = event.user; if (!exists(user_address)) return; - let market_event_handles_ref_mut = - borrow_global_mut(user_address); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; let market_account_id = get_market_account_id(event.market_id, event.custodian_id); - let change_order_size_events_ref_mut = - &mut market_event_handles_ref_mut.change_order_size_events; let has_handle = table::contains( - change_order_size_events_ref_mut, market_account_id); + market_event_handles_map_ref_mut, market_account_id); if (!has_handle) return; - let change_order_size_event_handle_ref_mut = table::borrow_mut( - change_order_size_events_ref_mut, market_account_id); + let change_order_size_event_handle_ref_mut = &mut table::borrow_mut( + market_event_handles_map_ref_mut, + market_account_id + ).change_order_size_events; event::emit_event( change_order_size_event_handle_ref_mut, event) } @@ -1751,17 +1738,17 @@ module econia::user { ) acquires MarketEventHandles { let user_address = event.user; if (!exists(user_address)) return; - let market_event_handles_ref_mut = - borrow_global_mut(user_address); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; let market_account_id = get_market_account_id(event.market_id, event.custodian_id); - let place_limit_order_events_ref_mut = - &mut market_event_handles_ref_mut.place_limit_order_events; let has_handle = table::contains( - place_limit_order_events_ref_mut, market_account_id); + market_event_handles_map_ref_mut, market_account_id); if (!has_handle) return; - let place_limit_order_event_handle_ref_mut = table::borrow_mut( - place_limit_order_events_ref_mut, market_account_id); + let place_limit_order_event_handle_ref_mut = &mut table::borrow_mut( + market_event_handles_map_ref_mut, + market_account_id + ).place_limit_order_events; event::emit_event( place_limit_order_event_handle_ref_mut, event) } @@ -1771,17 +1758,17 @@ module econia::user { ) acquires MarketEventHandles { let user_address = event.user; if (!exists(user_address)) return; - let market_event_handles_ref_mut = - borrow_global_mut(user_address); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; let market_account_id = get_market_account_id(event.market_id, event.custodian_id); - let place_market_order_events_ref_mut = - &mut market_event_handles_ref_mut.place_market_order_events; let has_handle = table::contains( - place_market_order_events_ref_mut, market_account_id); + market_event_handles_map_ref_mut, market_account_id); if (!has_handle) return; - let place_market_order_event_handle_ref_mut = table::borrow_mut( - place_market_order_events_ref_mut, market_account_id); + let place_market_order_event_handle_ref_mut = &mut table::borrow_mut( + market_event_handles_map_ref_mut, + market_account_id + ).place_market_order_events; event::emit_event( place_market_order_event_handle_ref_mut, event) } @@ -2638,15 +2625,17 @@ module econia::user { (event.taker, event.taker_custodian_id); if ((exists(user_address)) && (user_address != NO_MARKET_ACCOUNT)) { - let market_event_handles_ref_mut = - borrow_global_mut(user_address); - let fill_events_ref_mut = - &mut market_event_handles_ref_mut.fill_events; + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; let market_account_id = get_market_account_id(event.market_id, custodian_id); - if (table::contains(fill_events_ref_mut, market_account_id)) { - let fill_event_handle_ref_mut = table::borrow_mut( - fill_events_ref_mut, market_account_id); + let has_handle = table::contains(market_event_handles_map_ref_mut, + market_account_id); + if (has_handle) { + let fill_event_handle_ref_mut = &mut table::borrow_mut( + market_event_handles_map_ref_mut, + market_account_id + ).fill_events; event::emit_event(fill_event_handle_ref_mut, event) } } From 1f685169b1dd8c463c136e623fc2a6eeb62b92c8 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 16:52:16 -0700 Subject: [PATCH 34/56] Consolidate market-level event handles --- src/move/econia/sources/market.move | 192 ++++++++++++---------------- 1 file changed, 84 insertions(+), 108 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 75c85ebda..c2a9f20ff 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -617,9 +617,13 @@ module econia::market { /// Not emitted at market account level when a swap order is placed /// by a non-signing swapper. + struct MarketEventHandlesForMarket has store { + cancel_order_events: EventHandle, + place_swap_order_events: EventHandle + } + struct MarketEventHandles has key { - cancel_order_events: Table>, - place_swap_order_events: Table> + map: Table } /// View function return for getting event handle creation numbers. @@ -632,10 +636,14 @@ module econia::market { /// Stored under a signing user's account (not market account), /// since swaps are processed outside of a market account and do not /// always require a signature. + struct SwapperEventHandlesForMarket has store { + cancel_order_events: EventHandle, + fill_events: EventHandle, + place_swap_order_events: EventHandle + } + struct SwapperEventHandles has key { - cancel_order_events: Table>, - fill_events: Table>, - place_swap_order_events: Table> + map: Table } /// View function return for getting event handle creation numbers. @@ -872,25 +880,21 @@ module econia::market { let resource_account_address = resource_account::get_address(); if (!exists(resource_account_address)) return option::none(); - let market_event_handles_ref = - borrow_global(resource_account_address); - // Handles for market initialized at the same time, so assume if - // one exist that all exist. - let handles_exist_for_market = table::contains( - &market_event_handles_ref.cancel_order_events, market_id); - if (!handles_exist_for_market) return option::none(); + let market_event_handles_map_ref = + &borrow_global(resource_account_address).map; + let has_handles = table::contains( + market_event_handles_map_ref, market_id); + if (!has_handles) return option::none(); + let market_handles_ref = table::borrow( + market_event_handles_map_ref, market_id); option::some(MarketEventHandleCreationInfo{ resource_account_address: resource_account_address, cancel_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.cancel_order_events, - market_id - ))), + guid::creation_num(event::guid( + &market_handles_ref.cancel_order_events)), place_swap_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &market_event_handles_ref.place_swap_order_events, - market_id - ))), + guid::creation_num(event::guid( + &market_handles_ref.place_swap_order_events)) }) } @@ -902,29 +906,23 @@ module econia::market { ): Option acquires SwapperEventHandles { if (!exists(swapper)) return option::none(); - let swapper_event_handles_ref = - borrow_global(swapper); - // Handles for market initialized at the same time, so assume if - // one exist that all exist. - let handles_exist_for_market = table::contains( - &swapper_event_handles_ref.cancel_order_events, market_id); - if (!handles_exist_for_market) return option::none(); + let swapper_event_handles_map_ref = + &borrow_global(swapper).map; + let has_handles = table::contains( + swapper_event_handles_map_ref, market_id); + if (!has_handles) return option::none(); + let swapper_handles_ref = table::borrow( + swapper_event_handles_map_ref, market_id); option::some(SwapperEventHandleCreationNumbers{ cancel_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &swapper_event_handles_ref.cancel_order_events, - market_id - ))), + guid::creation_num(event::guid( + &swapper_handles_ref.cancel_order_events)), fill_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &swapper_event_handles_ref.fill_events, - market_id - ))), + guid::creation_num(event::guid( + &swapper_handles_ref.fill_events)), place_swap_order_events_handle_creation_num: - guid::creation_num(event::guid(table::borrow( - &swapper_event_handles_ref.place_swap_order_events, - market_id - ))), + guid::creation_num(event::guid( + &swapper_handles_ref.place_swap_order_events)) }) } @@ -1899,47 +1897,33 @@ module econia::market { ); // Create swapper event handles for market as needed. if (!exists(user_address)) - move_to(user, SwapperEventHandles{ - cancel_order_events: table::new(), - fill_events: table::new(), - place_swap_order_events: table::new()}); - let swapper_event_handles_ref_mut = - borrow_global_mut(user_address); - let cancel_order_events_table_ref_mut = - &mut swapper_event_handles_ref_mut.cancel_order_events; - let fill_events_table_ref_mut = - &mut swapper_event_handles_ref_mut.fill_events; - let place_swap_order_events_table_ref_mut = - &mut swapper_event_handles_ref_mut.place_swap_order_events; - // If doesn't have one handle for market, assume has none and - // thus create all handles for market. - let has_cancel_order_events_handle = - table::contains(cancel_order_events_table_ref_mut, market_id); - if (!has_cancel_order_events_handle) { - table::add(cancel_order_events_table_ref_mut, market_id, - account::new_event_handle(user)); - table::add(fill_events_table_ref_mut, market_id, - account::new_event_handle(user)); - table::add(place_swap_order_events_table_ref_mut, market_id, - account::new_event_handle(user)); + move_to(user, SwapperEventHandles{map: table::new()}); + let swapper_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; + let has_handles = + table::contains(swapper_event_handles_map_ref_mut, market_id); + if (!has_handles) { + let handles = SwapperEventHandlesForMarket{ + cancel_order_events: account::new_event_handle(user), + fill_events: account::new_event_handle(user), + place_swap_order_events: account::new_event_handle(user) + }; + table::add( + swapper_event_handles_map_ref_mut, market_id, handles); }; + let handles_ref_mut = + table::borrow_mut(swapper_event_handles_map_ref_mut, market_id); // Emit place swap order event. - let place_swap_order_event_handle_ref_mut = table::borrow_mut( - place_swap_order_events_table_ref_mut, market_id); - event::emit_event(place_swap_order_event_handle_ref_mut, + event::emit_event(&mut handles_ref_mut.place_swap_order_events, place_swap_order_event); // Emit fill events first-in-first-out. - let fill_events_handle_ref_mut = table::borrow_mut( - fill_events_table_ref_mut, market_id); vector::for_each_ref(&fill_event_queue, |fill_event_ref| { let fill_event: FillEvent = *fill_event_ref; - event::emit_event(fill_events_handle_ref_mut, fill_event); + event::emit_event(&mut handles_ref_mut.fill_events, fill_event); }); // Optionally emit cancel event. if (option::is_some(&cancel_order_event_option)) { - let cancel_order_events_handle_ref_mut = table::borrow_mut( - cancel_order_events_table_ref_mut, market_id); - event::emit_event(cancel_order_events_handle_ref_mut, + event::emit_event(&mut handles_ref_mut.cancel_order_events, option::destroy_some(cancel_order_event_option)); }; // Deposit base coins back to user's coin store. @@ -4197,32 +4181,6 @@ module econia::market { quote_coins ); let market_order_id = order_id_no_post(order_book_ref_mut.counter); - // Create market event handles for market as needed. - if (!exists(resource_address)) - move_to( - &resource_account::get_signer(), - MarketEventHandles{ - cancel_order_events: table::new(), - place_swap_order_events: table::new() - } - ); - let market_event_handles_ref_mut = - borrow_global_mut(resource_address); - let cancel_order_events_table_ref_mut = - &mut market_event_handles_ref_mut.cancel_order_events; - let place_swap_order_events_table_ref_mut = - &mut market_event_handles_ref_mut.place_swap_order_events; - // If doesn't have one handle for market, assume has none and - // thus create all handles for market. - let has_cancel_order_events_handle = - table::contains(cancel_order_events_table_ref_mut, market_id); - if (!has_cancel_order_events_handle) { - let resource_signer = resource_account::get_signer(); - table::add(cancel_order_events_table_ref_mut, market_id, - account::new_event_handle(&resource_signer)); - table::add(place_swap_order_events_table_ref_mut, market_id, - account::new_event_handle(&resource_signer)); - }; let place_swap_order_event = PlaceSwapOrderEvent{ market_id, signing_account: signer_address, @@ -4233,12 +4191,33 @@ module econia::market { min_quote, max_quote, limit_price, - order_id: market_order_id}; + order_id: market_order_id + }; + // Create market event handles for market as needed. + if (!exists(resource_address)) + move_to(&resource_account::get_signer(), + MarketEventHandles{map: table::new()}); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(resource_address).map; + let has_handles = + table::contains(market_event_handles_map_ref_mut, market_id); + if (!has_handles) { + let resource_signer = resource_account::get_signer(); + let handles = MarketEventHandlesForMarket{ + cancel_order_events: + account::new_event_handle(&resource_signer), + place_swap_order_events: + account::new_event_handle(&resource_signer) + }; + table::add( + market_event_handles_map_ref_mut, market_id, handles); + }; + let handles_ref_mut = + table::borrow_mut(market_event_handles_map_ref_mut, market_id); // Emit place swap order event. - let place_swap_order_event_handle_ref_mut = table::borrow_mut( - place_swap_order_events_table_ref_mut, market_id); - event::emit_event(place_swap_order_event_handle_ref_mut, - place_swap_order_event); + event::emit_event( + &mut handles_ref_mut.place_swap_order_events, + place_swap_order_event); emit_fill_events_for_market_accounts( fill_event_queue_ref_mut, true, (NIL as u128)); let need_to_cancel_order = @@ -4258,12 +4237,9 @@ module econia::market { NO_CUSTODIAN, cancel_reason ); - let cancel_order_events_table_ref_mut = - &mut market_event_handles_ref_mut.cancel_order_events; - let cancel_order_events_handle_ref_mut = table::borrow_mut( - cancel_order_events_table_ref_mut, market_id); - event::emit_event(cancel_order_events_handle_ref_mut, - cancel_order_event); + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + cancel_order_event); option::some(cancel_order_event) } else { option::none() From 8567b819d4c4ca594f4ad192261af7ed5ed78368 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Fri, 14 Jul 2023 17:12:28 -0700 Subject: [PATCH 35/56] Update `NO_TAKER_ADDRESS` emission support --- src/move/econia/sources/market.move | 46 +++++++++++++---------------- src/move/econia/sources/user.move | 13 ++------ 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index c2a9f20ff..3ca3bc017 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -836,11 +836,11 @@ module econia::market { const NIL: u64 = 0; /// Custodian ID flag for no custodian. const NO_CUSTODIAN: u64 = 0; - /// Taker address flag for when taker order does not originate from - /// a market account. - const NO_MARKET_ACCOUNT: address = @0x0; /// Flag for no order restriction. const NO_RESTRICTION: u8 = 0; + /// Taker address flag for when taker order does not originate from + /// a market account or a signing swapper. + const NO_TAKER_ADDRESS: address = @0x0; /// Underwriter ID flag for no underwriter. const NO_UNDERWRITER: u64 = 0; /// Flag for passive order specified by percent advance. @@ -2047,7 +2047,7 @@ module econia::market { let (optional_base_coins, quote_coins_matched, base_traded, quote_traded, fees, _, _) = swap( &mut vector[], - NO_MARKET_ACCOUNT, + NO_TAKER_ADDRESS, market_id, NO_UNDERWRITER, integrator, @@ -2161,7 +2161,7 @@ module econia::market { let (optional_base_coins, quote_coins_matched, base_traded, quote_traded, fees, _, _) = swap( &mut vector[], - NO_MARKET_ACCOUNT, + NO_TAKER_ADDRESS, market_id, underwriter_id, integrator, @@ -2790,11 +2790,11 @@ module econia::market { /// of fills. /// * `order_book_ref_mut`: Mutable reference to market order book. /// * `taker`: Address of taker whose order is matched. Passed as - /// `NO_MARKET_ACCOUNT` when taker order originates from a swap + /// `NO_TAKER_ADDRESS` when taker order originates from a swap /// without a signature. /// * `custodian_id`: Custodian ID associated with a taker market /// account, if any. Should be passed as `NO_CUSTODIAN` if `taker` - /// is `NO_MARKET_ACCOUNT`. + /// is `NO_TAKER_ADDRESS`. /// * `integrator`: The integrator for the taker order, who collects /// a portion of taker fees at their /// `incentives::IntegratorFeeStore` for the given market. May be @@ -4063,7 +4063,7 @@ module econia::market { /// # Parameters /// /// * `signer_address`: Address of signing user if applicable, else - /// `NO_MARKET_ACCOUNT`. + /// `NO_TAKER_ADDRESS`. /// * `market_id`: Same as for `match()`. /// * `underwriter_id`: ID of underwriter to verify if `BaseType` /// is `registry::GenericAsset`, else may be passed as @@ -4152,10 +4152,7 @@ module econia::market { == order_book_ref_mut.base_type, E_INVALID_BASE); assert!(type_info::type_of() // Assert quote type. == order_book_ref_mut.quote_type, E_INVALID_QUOTE); - // Declare return assignment variables. - let (base_traded, quote_traded, fees, self_match_taker_cancel, - liquidity_gone); - ( + let ( optional_base_coins, quote_coins, base_traded, @@ -4214,10 +4211,11 @@ module econia::market { }; let handles_ref_mut = table::borrow_mut(market_event_handles_map_ref_mut, market_id); - // Emit place swap order event. - event::emit_event( - &mut handles_ref_mut.place_swap_order_events, - place_swap_order_event); + // Emit place swap order event if unable to emit for swapper. + if (signer_address == NO_TAKER_ADDRESS) { + event::emit_event(&mut handles_ref_mut.place_swap_order_events, + place_swap_order_event); + }; emit_fill_events_for_market_accounts( fill_event_queue_ref_mut, true, (NIL as u128)); let need_to_cancel_order = @@ -4237,14 +4235,16 @@ module econia::market { NO_CUSTODIAN, cancel_reason ); - event::emit_event( - &mut handles_ref_mut.cancel_order_events, - cancel_order_event); + // Emit cancel order event if unable to emit for swapper. + if (signer_address == NO_TAKER_ADDRESS) { + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + cancel_order_event); + }; option::some(cancel_order_event) } else { option::none() }; - // TODO: ensure trade events emitted to swapper/market account holder. // Return optionally modified asset inputs, trade amounts, fees, // and place swap order event. (optional_base_coins, quote_coins, base_traded, quote_traded, fees, @@ -5612,12 +5612,6 @@ module econia::market { assert!(get_NO_CUSTODIAN() == registry::get_NO_CUSTODIAN(), 0); } - #[test] - /// Verify constant is same across modules. - fun test_get_NO_MARKET_ACCOUNT() { - assert!(user::get_NO_MARKET_ACCOUNT_test() == NO_MARKET_ACCOUNT, 0) - } - #[test] /// Verify constant getter return. fun test_get_NO_RESTRICTION() { diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index a12a4030a..54a9bb8a5 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -556,9 +556,6 @@ module econia::user { const NO_CUSTODIAN: u64 = 0; /// Underwriter ID flag for no underwriter. const NO_UNDERWRITER: u64 = 0; - /// Taker address flag for when taker order does not originate from - /// a market account. - const NO_MARKET_ACCOUNT: address = @0x0; /// Number of bits market ID is shifted in market account ID. const SHIFT_MARKET_ID: u8 = 64; const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; @@ -606,7 +603,7 @@ module econia::user { &market_account_handles_ref.place_limit_order_events)), place_market_order_events_handle_creation_num: guid::creation_num(event::guid( - &market_account_handles_ref.place_market_order_events)), + &market_account_handles_ref.place_market_order_events)) }) } @@ -2623,8 +2620,7 @@ module econia::user { let (user_address, custodian_id) = if (is_maker) (event.maker, event.maker_custodian_id) else (event.taker, event.taker_custodian_id); - if ((exists(user_address)) && - (user_address != NO_MARKET_ACCOUNT)) { + if (exists(user_address)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(user_address).map; let market_account_id = @@ -3060,11 +3056,6 @@ module econia::user { /// `market.move`. public fun get_HI_PRICE_test(): u64 {HI_PRICE} - #[test_only] - /// Return `NO_MARKET_ACCOUNT`, for testing synchronization with - /// `market.move`. - public fun get_NO_MARKET_ACCOUNT_test(): address {NO_MARKET_ACCOUNT} - #[test_only] /// Like `get_collateral_value_test()`, but accepts market id and /// custodian ID. From b286ae4ffd6954de5b58baeed30196d940b9a465 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Sat, 15 Jul 2023 16:41:44 -0700 Subject: [PATCH 36/56] Optimize limit order event emission --- doc/doc-site/docs/move/changelog.md | 1 + src/move/econia/sources/market.move | 52 +++++--------- src/move/econia/sources/user.move | 101 +++++++++++++++++++++------- 3 files changed, 95 insertions(+), 59 deletions(-) diff --git a/doc/doc-site/docs/move/changelog.md b/doc/doc-site/docs/move/changelog.md index 75f08ab03..69ba4346f 100644 --- a/doc/doc-site/docs/move/changelog.md +++ b/doc/doc-site/docs/move/changelog.md @@ -15,6 +15,7 @@ Econia Move source code adheres to [Semantic Versioning] and [Keep a Changelog] - Market order size is no longer automatically adjusted based on available market account holdings ([#321]). - Default self match behavior for swaps (signing swapper self match against signing market account) changed from `ABORT` to `CANCEL_TAKER` ([#321]). - Started using `order_id` instead of `market_order_id` for new implementations ([#321]). +- Replaced `market::NO_MARKET_ACCOUNT` with `market::NO_TAKER_ADDRESS` to account for signing swappers ([#321]). ### Deprecated diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 3ca3bc017..ae57e0d93 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -626,7 +626,7 @@ module econia::market { map: Table } - /// View function return for getting event handle creation numbers. + /// View function return for getting event handle creation info. struct MarketEventHandleCreationInfo has copy, drop { resource_account_address: address, cancel_order_events_handle_creation_num: u64, @@ -650,7 +650,7 @@ module econia::market { struct SwapperEventHandleCreationNumbers has copy, drop { cancel_order_events_handle_creation_num: u64, fill_events_handle_creation_num: u64, - place_swap_order_events_handle_creation_num: u64, + place_swap_order_events_handle_creation_num: u64 } struct PlaceSwapOrderEvent has copy, drop, store { @@ -3413,12 +3413,6 @@ module econia::market { CANCEL_REASON_TOO_SMALL_AFTER_MATCHING); } }; - /* - // If matching engine halted but order still crosses spread, - // or if a self match that requires canceling the rest of - // of the order, then mark no size left to post as a maker. - size = if (still_crosses_spread || self_match_cancel) 0 else - */ } else { // If spread not crossed (matching engine not called): order_book_ref_mut.counter = order_book_ref_mut.counter + 1; if (restriction == IMMEDIATE_OR_CANCEL) { @@ -3479,35 +3473,21 @@ module econia::market { } else { remaining_size = 0; }; - // Emit a place limit order event, creating handle as needed. - user::emit_place_limit_order_event( - user::create_place_limit_order_event( - market_id, - user_address, - custodian_id, - integrator, - side, - size, - price, - restriction, - self_match_behavior, - remaining_size, - market_order_id - ) + user::emit_limit_order_events( + market_id, + user_address, + custodian_id, + integrator, + side, + size, + price, + restriction, + self_match_behavior, + remaining_size, + market_order_id, + &fill_event_queue, + &cancel_reason_option ); - emit_fill_events_for_market_accounts( - &mut fill_event_queue, false, market_order_id); - if (option::is_some(&cancel_reason_option)) { - user::emit_cancel_order_event( - user::create_cancel_order_event( - market_id, - market_order_id, - user_address, - custodian_id, - option::destroy_some(cancel_reason_option) - ) - ); - }; // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 54a9bb8a5..7c6173cc1 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -1636,7 +1636,6 @@ module econia::user { user_address, market_id, custodian_id, quote_coins); } -/* TODO: public(friend) fun emit_limit_order_events( market_id: u64, user: address, @@ -1649,34 +1648,70 @@ module econia::user { self_match_behavior: u8, remaining_size: u64, order_id: u128, - fill_event_queue_ref_mut: &mut vector, + fill_event_queue_ref: &vector, cancel_reason_option_ref: &Option ) acquires MarketEventHandles { - if (exists(user_address)) { - let market_event_handles_ref_mut_mut = - borrow_global_mut(user); + if (exists(user)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user).map; let market_account_id = get_market_account_id(market_id, custodian_id); - // Handles for market account initialized at the same time, so - // assume if one exist that all exist. - let handles_exist_for_market_account = table::contains( - &market_event_handles_ref_mut.cancel_order_events, - market_account_id); - if (handles_exist_for_market_account) { - let cancel_order_events_table_ref_mut = - &mut market_event_handles_ref_mut.cancel_order_events; - let fill_events_table_ref_mut = - &mut market_event_handles_ref_mut.fill_events; - let place_limit_order_events_table_ref_mut = - &mut market_event_handles_ref_mut.place_limit_order_events; - } - } - - // Then loop over fill events again and emit for each maker. + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + // Emit place limit order event. + event::emit_event( + &mut handles_ref_mut.place_limit_order_events, + PlaceLimitOrderEvent{ + market_id, + user, + custodian_id, + integrator, + side, + size, + price, + restriction, + self_match_behavior, + remaining_size, + order_id + } + ); + // Loop over fill events, substituting order ID in case + // order posted after fill event creation. Looping here + // minimizes borrows from the user's account, but will + // require looping again later to emit maker fill events + // because the borrow checker prohibits simultaneous + // borrowing of the same resource from two addresses. + vector::for_each_ref(fill_event_queue_ref, |event_ref| { + let event: FillEvent = *event_ref; + event.taker_order_id = order_id; + event::emit_event(&mut handles_ref_mut.fill_events, event); + }); + // Optionally emit cancel order event. + if (option::is_some(cancel_reason_option_ref)) { + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + CancelOrderEvent{ + market_id, + order_id, + user, + custodian_id, + reason: *option::borrow(cancel_reason_option_ref) + } + ); + }; + }; + }; + // Emit fill events for all makers. + vector::for_each_ref(fill_event_queue_ref, |event_ref| { + let event: FillEvent = *event_ref; + event.taker_order_id = order_id; + emit_maker_fill_event(&event); + }); } -*/ - /// Emit fill event to specified handle, if handle exists. public(friend) fun emit_fill_event_for_maker_and_taker( event: FillEvent @@ -2612,6 +2647,26 @@ module econia::user { }; } + inline fun emit_maker_fill_event( + event_ref: &FillEvent + ) acquires MarketEventHandles { + let maker = event_ref.maker; + if (exists(maker)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(maker).map; + let market_account_id = get_market_account_id( + event_ref.market_id, event_ref.maker_custodian_id); + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + event::emit_event( + &mut handles_ref_mut.fill_events, *event_ref); + }; + }; + } + /// Emit fill event for either maker or taker, if handle exists. inline fun emit_fill_event( event: FillEvent, From 2f8998b42688898913fd4e35dc5019a46d0b5538 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Sat, 15 Jul 2023 18:14:34 -0700 Subject: [PATCH 37/56] Optimize assorted event emission calls --- src/move/econia/sources/market.move | 246 ++++++++++------------- src/move/econia/sources/user.move | 291 ++++++++++++---------------- 2 files changed, 227 insertions(+), 310 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index ae57e0d93..4bdab1354 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -1878,7 +1878,7 @@ module econia::market { base_traded, quote_traded, fees, - place_swap_order_event, + place_swap_order_event_option, cancel_order_event_option ) = swap( &mut fill_event_queue, @@ -1915,17 +1915,16 @@ module econia::market { table::borrow_mut(swapper_event_handles_map_ref_mut, market_id); // Emit place swap order event. event::emit_event(&mut handles_ref_mut.place_swap_order_events, - place_swap_order_event); + option::destroy_some(place_swap_order_event_option)); // Emit fill events first-in-first-out. vector::for_each_ref(&fill_event_queue, |fill_event_ref| { let fill_event: FillEvent = *fill_event_ref; event::emit_event(&mut handles_ref_mut.fill_events, fill_event); }); // Optionally emit cancel event. - if (option::is_some(&cancel_order_event_option)) { + if (option::is_some(&cancel_order_event_option)) event::emit_event(&mut handles_ref_mut.cancel_order_events, option::destroy_some(cancel_order_event_option)); - }; // Deposit base coins back to user's coin store. coin::deposit(user_address, option::destroy_some(optional_base_coins)); // Deposit quote coins back to user's coin store. @@ -2494,14 +2493,12 @@ module econia::market { // Cancel order user-side, thus verifying market order ID. user::cancel_order_internal(user, market_id, custodian_id, side, size, price, order_access_key, market_order_id); - user::emit_cancel_order_event( - user::create_cancel_order_event( - market_id, - market_order_id, - user, - custodian_id, - CANCEL_REASON_MANUAL_CANCEL - ) + user::emit_cancel_order_event_internal( + market_id, + market_order_id, + user, + custodian_id, + CANCEL_REASON_MANUAL_CANCEL ); } @@ -2626,36 +2623,27 @@ module econia::market { assert!(new_avlq_access_key == avlq_access_key, E_SIZE_CHANGE_INSERTION_ERROR); }; - user::emit_change_order_size_event( - user::create_change_order_size_event( - market_id, - market_order_id, - user, - custodian_id, - side, - new_size - ) - ); } - fun emit_fill_events_for_market_accounts( - fill_event_queue_ref: &vector, - taker_is_swapper: bool, - new_taker_order_id: u128, - ) { - let update_taker_order_id = new_taker_order_id == (NIL as u128); - vector::for_each_ref(fill_event_queue_ref, |event_ref| { - let event: FillEvent = *event_ref; - if (update_taker_order_id) { - user::set_fill_event_taker_order_id( - &mut event, new_taker_order_id); - }; - if (taker_is_swapper) { - user::emit_fill_event_for_maker(event); + inline fun get_cancel_reason_option_for_market_order_or_swap( + self_match_taker_cancel: bool, + base_traded: u64, + max_base: u64, + liquidity_gone: bool + ): Option { + let need_to_cancel = + ((self_match_taker_cancel) || (base_traded < max_base)); + if (need_to_cancel) { + if (self_match_taker_cancel) { + option::some(CANCEL_REASON_SELF_MATCH_TAKER) + } else if (liquidity_gone) { + option::some(CANCEL_REASON_NOT_ENOUGH_LIQUIDITY) } else { - user::emit_fill_event_for_maker_and_taker(event); - }; - }); + option::some(CANCEL_REASON_MAX_QUOTE_TRADED) + } + } else { + option::none() + } } /// Get AVL queue access key encoded in `order_id`. @@ -3006,14 +2994,12 @@ module econia::market { let Order{size: _, price: _, user: _, custodian_id: _, order_access_key: _} = avl_queue::remove( orders_ref_mut, avlq_access_key); - user::emit_cancel_order_event( - user::create_cancel_order_event( - market_id, - market_order_id, - maker, - maker_custodian_id, - CANCEL_REASON_SELF_MATCH_MAKER - ) + user::emit_cancel_order_event_internal( + market_id, + market_order_id, + maker, + maker_custodian_id, + CANCEL_REASON_SELF_MATCH_MAKER ); }; // Optional maker order cancellation complete. // Break out of loop if a self match taker cancel. @@ -3039,19 +3025,20 @@ module econia::market { incentives::assess_taker_fees( market_id, integrator, taker_fee_divisor, ticks_filled * tick_size, quote_coins); - vector::push_back(event_queue_ref_mut, user::create_fill_event( - market_id, - fill_size, - price, - side, - maker, - maker_custodian_id, - market_order_id, - taker, - custodian_id, - order_id_no_post(order_book_ref_mut.counter), - fees_paid_for_fill, - fill_count + vector::push_back( + event_queue_ref_mut, user::create_fill_event_internal( + market_id, + fill_size, + price, + side, + maker, + maker_custodian_id, + market_order_id, + taker, + custodian_id, + order_id_no_post(order_book_ref_mut.counter), + fees_paid_for_fill, + fill_count )); fill_count = fill_count + 1; fees_paid = fees_paid + fees_paid_for_fill; @@ -3460,20 +3447,18 @@ module econia::market { let market_order_id_cancel = user::cancel_order_internal( user, market_id, custodian_id, side, size, price, order_access_key, (NIL as u128)); - user::emit_cancel_order_event( - user::create_cancel_order_event( - market_id, - market_order_id_cancel, - user, - custodian_id, - CANCEL_REASON_EVICTION - ) + user::emit_cancel_order_event_internal( + market_id, + market_order_id_cancel, + user, + custodian_id, + CANCEL_REASON_EVICTION ); }; } else { remaining_size = 0; }; - user::emit_limit_order_events( + user::emit_limit_order_events_internal( market_id, user_address, custodian_id, @@ -3831,38 +3816,22 @@ module econia::market { user::deposit_assets_internal( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); - user::emit_place_market_order_event( - user::create_place_market_order_event( - market_id, - user_address, - custodian_id, - integrator, - direction, - size, - self_match_behavior, - market_order_id) + let cancel_reason_option = + get_cancel_reason_option_for_market_order_or_swap( + self_match_taker_cancel, base_traded, max_base, + liquidity_gone); + user::emit_market_order_events_internal( + market_id, + user_address, + custodian_id, + integrator, + direction, + size, + self_match_behavior, + market_order_id, + &fill_event_queue, + &cancel_reason_option ); - emit_fill_events_for_market_accounts( - &mut fill_event_queue, false, (NIL as u128)); - // If order needs to be cancelled: - if ((self_match_taker_cancel) || (base_traded < max_base)) { - let cancel_reason = if (self_match_taker_cancel) { - CANCEL_REASON_SELF_MATCH_TAKER - } else if (liquidity_gone) { - CANCEL_REASON_NOT_ENOUGH_LIQUIDITY - } else { - CANCEL_REASON_MAX_QUOTE_TRADED - }; - user::emit_cancel_order_event( - user::create_cancel_order_event( - market_id, - market_order_id, - user_address, - custodian_id, - cancel_reason - ) - ); - }; // Return base and quote traded by user, fees paid. (base_traded, quote_traded, fees) } @@ -4109,7 +4078,7 @@ module econia::market { u64, u64, u64, - PlaceSwapOrderEvent, + Option, Option ) acquires MarketEventHandles, @@ -4158,18 +4127,6 @@ module econia::market { quote_coins ); let market_order_id = order_id_no_post(order_book_ref_mut.counter); - let place_swap_order_event = PlaceSwapOrderEvent{ - market_id, - signing_account: signer_address, - integrator, - direction, - min_base, - max_base, - min_quote, - max_quote, - limit_price, - order_id: market_order_id - }; // Create market event handles for market as needed. if (!exists(resource_address)) move_to(&resource_account::get_signer(), @@ -4191,44 +4148,49 @@ module econia::market { }; let handles_ref_mut = table::borrow_mut(market_event_handles_map_ref_mut, market_id); - // Emit place swap order event if unable to emit for swapper. - if (signer_address == NO_TAKER_ADDRESS) { - event::emit_event(&mut handles_ref_mut.place_swap_order_events, - place_swap_order_event); + let place_swap_order_event = PlaceSwapOrderEvent{ + market_id, + signing_account: signer_address, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + order_id: market_order_id }; - emit_fill_events_for_market_accounts( - fill_event_queue_ref_mut, true, (NIL as u128)); - let need_to_cancel_order = - (self_match_taker_cancel) || (base_traded < max_base); - let cancel_order_event_option = if (need_to_cancel_order) { - let cancel_reason = if (self_match_taker_cancel) { - CANCEL_REASON_SELF_MATCH_TAKER - } else if (liquidity_gone) { - CANCEL_REASON_NOT_ENOUGH_LIQUIDITY - } else { - CANCEL_REASON_MAX_QUOTE_TRADED - }; - let cancel_order_event = user::create_cancel_order_event( + let cancel_reason_option = + get_cancel_reason_option_for_market_order_or_swap( + self_match_taker_cancel, base_traded, max_base, + liquidity_gone); + let need_to_cancel = option::is_some(&cancel_reason_option); + let cancel_order_event_option = if (need_to_cancel) + option::some(user::create_cancel_order_event_internal( market_id, market_order_id, signer_address, NO_CUSTODIAN, - cancel_reason - ); - // Emit cancel order event if unable to emit for swapper. - if (signer_address == NO_TAKER_ADDRESS) { - event::emit_event( - &mut handles_ref_mut.cancel_order_events, - cancel_order_event); - }; - option::some(cancel_order_event) - } else { - option::none() + option::destroy_some(cancel_reason_option) + )) else option::none(); + // Get place swap order, cancel order event options to return: + let (place_swap_order_event_option, cancel_order_event_option) = + // If swap not placed by a signing swapper: + if (signer_address == NO_TAKER_ADDRESS) { + event::emit_event(&mut handles_ref_mut.place_swap_order_events, + place_swap_order_event); + if (need_to_cancel) event::emit_event( + &mut handles_ref_mut.cancel_order_events, + option::destroy_some(cancel_order_event_option)); + (option::none(), option::none()) + } else { // Otherwise swap order placed by signing swapper. + (option::some(place_swap_order_event), cancel_order_event_option) }; + user::emit_swap_maker_fill_events_internal(fill_event_queue_ref_mut); // Return optionally modified asset inputs, trade amounts, fees, // and place swap order event. (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - place_swap_order_event, cancel_order_event_option) + place_swap_order_event_option, cancel_order_event_option) } // Private functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 7c6173cc1..744ba051e 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -1568,7 +1568,10 @@ module econia::user { price: u64, order_access_key: u64, market_order_id: u128 - ) acquires MarketAccounts { + ) acquires + MarketAccounts, + MarketEventHandles + { // Mutably borrow market accounts map. let market_accounts_map_ref_mut = &mut borrow_global_mut(user_address).map; @@ -1589,6 +1592,27 @@ module econia::user { place_order_internal( // Place order with new size. user_address, market_id, custodian_id, side, new_size, price, market_order_id, order_access_key); + if (exists(user_address)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + event::emit_event( + &mut handles_ref_mut.change_order_size_events, + ChangeOrderSizeEvent{ + market_id, + order_id: market_order_id, + user: user_address, + custodian_id, + side, + new_size + } + ); + } + } } /// Deposit base asset and quote coins when matching. @@ -1636,7 +1660,7 @@ module econia::user { user_address, market_id, custodian_id, quote_coins); } - public(friend) fun emit_limit_order_events( + public(friend) fun emit_limit_order_events_internal( market_id: u64, user: address, custodian_id: u64, @@ -1712,134 +1736,128 @@ module econia::user { }); } - /// Emit fill event to specified handle, if handle exists. - public(friend) fun emit_fill_event_for_maker_and_taker( - event: FillEvent - ) acquires MarketEventHandles { - emit_fill_event(event, true); - emit_fill_event(event, false); - } - - public(friend) fun emit_fill_event_for_maker( - event: FillEvent - ) acquires MarketEventHandles { - emit_fill_event(event, true); - } - - public(friend) fun emit_cancel_order_event( - event: CancelOrderEvent - ) acquires MarketEventHandles { - let user_address = event.user; - if (!exists(user_address)) return; - let market_event_handles_map_ref_mut = - &mut borrow_global_mut(user_address).map; - let market_account_id = - get_market_account_id(event.market_id, event.custodian_id); - let has_handle = table::contains( - market_event_handles_map_ref_mut, market_account_id); - if (!has_handle) return; - let cancel_order_event_handle_ref_mut = &mut table::borrow_mut( - market_event_handles_map_ref_mut, - market_account_id - ).cancel_order_events; - event::emit_event( - cancel_order_event_handle_ref_mut, event) - } - public(friend) fun emit_change_order_size_event( - event: ChangeOrderSizeEvent - ) acquires MarketEventHandles { - let user_address = event.user; - if (!exists(user_address)) return; - let market_event_handles_map_ref_mut = - &mut borrow_global_mut(user_address).map; - let market_account_id = - get_market_account_id(event.market_id, event.custodian_id); - let has_handle = table::contains( - market_event_handles_map_ref_mut, market_account_id); - if (!has_handle) return; - let change_order_size_event_handle_ref_mut = &mut table::borrow_mut( - market_event_handles_map_ref_mut, - market_account_id - ).change_order_size_events; - event::emit_event( - change_order_size_event_handle_ref_mut, event) - } - - public(friend) fun emit_place_limit_order_event( - event: PlaceLimitOrderEvent + public(friend) fun emit_market_order_events_internal( + market_id: u64, + user: address, + custodian_id: u64, + integrator: address, + direction: bool, + size: u64, + self_match_behavior: u8, + order_id: u128, + fill_event_queue_ref: &vector, + cancel_reason_option_ref: &Option ) acquires MarketEventHandles { - let user_address = event.user; - if (!exists(user_address)) return; - let market_event_handles_map_ref_mut = - &mut borrow_global_mut(user_address).map; - let market_account_id = - get_market_account_id(event.market_id, event.custodian_id); - let has_handle = table::contains( - market_event_handles_map_ref_mut, market_account_id); - if (!has_handle) return; - let place_limit_order_event_handle_ref_mut = &mut table::borrow_mut( - market_event_handles_map_ref_mut, - market_account_id - ).place_limit_order_events; - event::emit_event( - place_limit_order_event_handle_ref_mut, event) + if (exists(user)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user).map; + let market_account_id = + get_market_account_id(market_id, custodian_id); + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + // Emit place market order event. + event::emit_event( + &mut handles_ref_mut.place_market_order_events, + PlaceMarketOrderEvent{ + market_id, + user, + custodian_id, + integrator, + direction, + size, + self_match_behavior, + order_id + } + ); + // Loop over fill events. Looping here minimizes borrows + // from the user's account, but will require looping + // again later to emit maker fill events because the + // borrow checker prohibits simultaneous borrowing of + // the same resource from two addresses. + vector::for_each_ref(fill_event_queue_ref, |event_ref| { + event::emit_event( + &mut handles_ref_mut.fill_events, *event_ref); + }); + // Optionally emit cancel order event. + if (option::is_some(cancel_reason_option_ref)) { + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + CancelOrderEvent{ + market_id, + order_id, + user, + custodian_id, + reason: *option::borrow(cancel_reason_option_ref) + } + ); + }; + }; + }; + // Emit fill events for all makers. + vector::for_each_ref(fill_event_queue_ref, |event_ref| { + emit_maker_fill_event(event_ref); + }); } - public(friend) fun emit_place_market_order_event( - event: PlaceMarketOrderEvent + public(friend) fun emit_swap_maker_fill_events_internal( + fill_event_queue_ref: &vector ) acquires MarketEventHandles { - let user_address = event.user; - if (!exists(user_address)) return; - let market_event_handles_map_ref_mut = - &mut borrow_global_mut(user_address).map; - let market_account_id = - get_market_account_id(event.market_id, event.custodian_id); - let has_handle = table::contains( - market_event_handles_map_ref_mut, market_account_id); - if (!has_handle) return; - let place_market_order_event_handle_ref_mut = &mut table::borrow_mut( - market_event_handles_map_ref_mut, - market_account_id - ).place_market_order_events; - event::emit_event( - place_market_order_event_handle_ref_mut, event) + vector::for_each_ref(fill_event_queue_ref, |event_ref| { + emit_maker_fill_event(event_ref); + }); } - public(friend) fun create_cancel_order_event( + public(friend) fun emit_cancel_order_event_internal( market_id: u64, order_id: u128, user: address, custodian_id: u64, reason: u8 - ): CancelOrderEvent { - CancelOrderEvent{ - market_id, - order_id, - user, - custodian_id, - reason + ) acquires MarketEventHandles { + if (exists(user)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user).map; + let market_account_id = + get_market_account_id(market_id, custodian_id); + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + CancelOrderEvent{ + market_id, + order_id, + user, + custodian_id, + reason + } + ); + } } } - public(friend) fun create_change_order_size_event( + public(friend) fun create_cancel_order_event_internal( market_id: u64, order_id: u128, user: address, custodian_id: u64, - side: bool, - new_size: u64 - ): ChangeOrderSizeEvent { - ChangeOrderSizeEvent{ + reason: u8 + ): CancelOrderEvent { + CancelOrderEvent{ market_id, order_id, user, custodian_id, - side, - new_size + reason } } - public(friend) fun create_fill_event( + public(friend) fun create_fill_event_internal( market_id: u64, size: u64, price: u64, @@ -1869,69 +1887,6 @@ module econia::user { } } - public(friend) fun get_fill_event_taker_order_id( - fill_event_ref: &FillEvent, - ): u128 { - fill_event_ref.taker_order_id - } - - public(friend) fun set_fill_event_taker_order_id( - fill_event_ref_mut: &mut FillEvent, - taker_order_id: u128 - ) { - fill_event_ref_mut.taker_order_id = taker_order_id - } - - public(friend) fun create_place_limit_order_event( - market_id: u64, - user: address, - custodian_id: u64, - integrator: address, - side: bool, - size: u64, - price: u64, - restriction: u8, - self_match_behavior: u8, - remaining_size: u64, - order_id: u128 - ): PlaceLimitOrderEvent { - PlaceLimitOrderEvent { - market_id, - user, - custodian_id, - integrator, - side, - size, - price, - restriction, - self_match_behavior, - remaining_size, - order_id - } - } - - public(friend) fun create_place_market_order_event( - market_id: u64, - user: address, - custodian_id: u64, - integrator: address, - direction: bool, - size: u64, - self_match_behavior: u8, - order_id: u128 - ): PlaceMarketOrderEvent { - PlaceMarketOrderEvent { - market_id, - user, - custodian_id, - integrator, - direction, - size, - self_match_behavior, - order_id - } - } - /// Fill a user's order, routing collateral appropriately. /// /// Updates asset counts in a user's market account. Transfers From af2df86d62edf91ca97aec446fb2d40a9eeeff21 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Sat, 15 Jul 2023 18:39:11 -0700 Subject: [PATCH 38/56] Consolidate order cancel event emission --- src/move/econia/sources/market.move | 39 ++++-------- src/move/econia/sources/user.move | 92 +++++++++++++++-------------- 2 files changed, 58 insertions(+), 73 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 4bdab1354..8a6fad7b3 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2491,15 +2491,9 @@ module econia::market { // Assert passed custodian ID matches that from order. assert!(custodian_id == order_custodian_id, E_INVALID_CUSTODIAN); // Cancel order user-side, thus verifying market order ID. - user::cancel_order_internal(user, market_id, custodian_id, side, size, - price, order_access_key, market_order_id); - user::emit_cancel_order_event_internal( - market_id, - market_order_id, - user, - custodian_id, - CANCEL_REASON_MANUAL_CANCEL - ); + user::cancel_order_internal( + user, market_id, custodian_id, side, size, price, order_access_key, + market_order_id, CANCEL_REASON_MANUAL_CANCEL); } /// Change maker order size on book and in user's market account. @@ -2986,21 +2980,15 @@ module econia::market { let market_order_id = user::cancel_order_internal( maker, market_id, maker_custodian_id, side, order_ref_mut.size, price, - order_ref_mut.order_access_key, (NIL as u128)); + order_ref_mut.order_access_key, (NIL as u128), + CANCEL_REASON_SELF_MATCH_MAKER); // Get AVL queue access key from market order ID. let avlq_access_key = ((market_order_id & (HI_64 as u128)) as u64); - // Remove order from AVL queue, storing size. + // Remove order from AVL queue. let Order{size: _, price: _, user: _, custodian_id: _, order_access_key: _} = avl_queue::remove( orders_ref_mut, avlq_access_key); - user::emit_cancel_order_event_internal( - market_id, - market_order_id, - maker, - maker_custodian_id, - CANCEL_REASON_SELF_MATCH_MAKER - ); }; // Optional maker order cancellation complete. // Break out of loop if a self match taker cancel. if (self_match_taker_cancel) break; @@ -3440,20 +3428,13 @@ module econia::market { // Destroy empty evictee value option. option::destroy_none(evictee_value); } else { // If had to evict order at AVL queue tail: - // Unpack evicted order, storing fields for event. + // Unpack evicted order. let Order{size, price, user, custodian_id, order_access_key} = option::destroy_some(evictee_value); - // Cancel order user-side, storing its market order ID. - let market_order_id_cancel = user::cancel_order_internal( + // Cancel order user-side. + user::cancel_order_internal( user, market_id, custodian_id, side, size, price, - order_access_key, (NIL as u128)); - user::emit_cancel_order_event_internal( - market_id, - market_order_id_cancel, - user, - custodian_id, - CANCEL_REASON_EVICTION - ); + order_access_key, (NIL as u128), CANCEL_REASON_EVICTION); }; } else { remaining_size = 0; diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 744ba051e..e97e3a2cc 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -566,6 +566,7 @@ module econia::user { const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 7; + const CANCEL_REASON_SIZE_CHANGE_INTERNAL: u8 = 8; // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @@ -1466,9 +1467,13 @@ module econia::user { start_size: u64, price: u64, order_access_key: u64, - market_order_id: u128 + market_order_id: u128, + reason: u8 ): u128 - acquires MarketAccounts { + acquires + MarketAccounts, + MarketEventHandles + { // Mutably borrow market accounts map. let market_accounts_map_ref_mut = &mut borrow_global_mut(user_address).map; @@ -1522,6 +1527,29 @@ module econia::user { let ceiling_decrement_amount = size * size_multiplier_ceiling; *in_ceiling_ref_mut = // Decrement ceiling field. *in_ceiling_ref_mut - ceiling_decrement_amount; + // Check if order is cancelled internally only so that it can + // be intenally re-placed as part of a size change. + let changing_size = reason != CANCEL_REASON_SIZE_CHANGE_INTERNAL; + if (!changing_size && exists(user_address)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user_address).map; + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + CancelOrderEvent{ + market_id, + order_id: market_order_id, + user: user_address, + custodian_id, + reason + } + ); + } + }; market_order_id // Return market order ID. } @@ -1588,7 +1616,8 @@ module econia::user { assert!(order_ref.size != new_size, E_CHANGE_ORDER_NO_CHANGE); cancel_order_internal( // Cancel order with size to be changed. user_address, market_id, custodian_id, side, start_size, price, - order_access_key, market_order_id); + order_access_key, market_order_id, + CANCEL_REASON_SIZE_CHANGE_INTERNAL); place_order_internal( // Place order with new size. user_address, market_id, custodian_id, side, new_size, price, market_order_id, order_access_key); @@ -1810,37 +1839,6 @@ module econia::user { }); } - public(friend) fun emit_cancel_order_event_internal( - market_id: u64, - order_id: u128, - user: address, - custodian_id: u64, - reason: u8 - ) acquires MarketEventHandles { - if (exists(user)) { - let market_event_handles_map_ref_mut = - &mut borrow_global_mut(user).map; - let market_account_id = - get_market_account_id(market_id, custodian_id); - let has_handles_for_market_account = table::contains( - market_event_handles_map_ref_mut, market_account_id); - if (has_handles_for_market_account) { - let handles_ref_mut = table::borrow_mut( - market_event_handles_map_ref_mut, market_account_id); - event::emit_event( - &mut handles_ref_mut.cancel_order_events, - CancelOrderEvent{ - market_id, - order_id, - user, - custodian_id, - reason - } - ); - } - } - } - public(friend) fun create_cancel_order_event_internal( market_id: u64, order_id: u128, @@ -3362,7 +3360,8 @@ module econia::user { size, price, market_order_id, 1); // Attempt invalid cancellation. cancel_order_internal(@user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, - size, price, 1, market_order_id + 1); + size, price, 1, market_order_id + 1, + CANCEL_REASON_MANUAL_CANCEL); } #[test] @@ -3390,7 +3389,8 @@ module econia::user { size, price, market_order_id, 1); // Attempt invalid cancellation. cancel_order_internal(@user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, - size + 1, price, 1, market_order_id); + size + 1, price, 1, market_order_id, + CANCEL_REASON_MANUAL_CANCEL); } #[test] @@ -3914,7 +3914,8 @@ module econia::user { size, price, market_order_id, 2); cancel_order_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size, price, - order_access_key_cancelled, market_order_id); + order_access_key_cancelled, market_order_id, + CANCEL_REASON_MANUAL_CANCEL); // Initialize external coins passing through matching engine. let optional_base_coins = option::some(coin::zero()); let quote_coins = assets::mint_test(quote_fill); @@ -4198,7 +4199,8 @@ module econia::user { place_order_internal(@user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, ASK, size, price, market_order_id_3, 3); cancel_order_internal(@user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, ASK, - size, price, 2, market_order_id_2); + size, price, 2, market_order_id_2, + CANCEL_REASON_MANUAL_CANCEL); // Get expected market order IDs vector. let expected = vector[market_order_id_1, market_order_id_3]; // Assert expected return. @@ -4214,7 +4216,8 @@ module econia::user { @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, BID) == expected, 0); // Cancel order. cancel_order_internal(@user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, BID, - size, price, 1, market_order_id_4); + size, price, 1, market_order_id_4, + CANCEL_REASON_MANUAL_CANCEL); // Assert expected return. assert!(get_active_market_order_ids_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, BID) == vector[], 0); @@ -4388,7 +4391,8 @@ module econia::user { // Cancel the first placed bid. cancel_order_internal( user, market_id, CUSTODIAN_ID, BID, size, price, - order_access_key_bid_0, market_order_id_bid_0); + order_access_key_bid_0, market_order_id_bid_0, + CANCEL_REASON_MANUAL_CANCEL); // Get all of user's market account views. market_account_views = get_market_accounts(user); // Immutably borrow first market account view element. @@ -4640,7 +4644,7 @@ module econia::user { // Evict order, storing returned market order ID. market_order_id_r = cancel_order_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size, price, - order_access_key, (NIL as u128)); + order_access_key, (NIL as u128), CANCEL_REASON_MANUAL_CANCEL); // Assert returned market order ID. assert!(market_order_id_r == market_order_id, 0); // Assert next order access key. @@ -4721,7 +4725,7 @@ module econia::user { // Cancel order, storing returned market order ID. market_order_id_r = cancel_order_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size, price, - order_access_key, market_order_id); + order_access_key, market_order_id, CANCEL_REASON_MANUAL_CANCEL); // Assert returned market order ID. assert!(market_order_id_r == market_order_id, 0); // Assert asset counts. @@ -4790,7 +4794,7 @@ module econia::user { // Cancel first order, storing market order ID. let market_order_id = cancel_order_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size, price, 1, - market_order_id_1); + market_order_id_1, CANCEL_REASON_MANUAL_CANCEL); // Assert returned market order ID. assert!(market_order_id == market_order_id_1, 0); // Assert inactive stack top on given side. @@ -4802,7 +4806,7 @@ module econia::user { // Cancel second order, storting market order ID. market_order_id = cancel_order_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size, price, 2, - market_order_id_2); + market_order_id_2, CANCEL_REASON_MANUAL_CANCEL); // Assert returned market order ID. assert!(market_order_id == market_order_id_2, 0); // Assert inactive stack top on given side. From d495754d70c4d8d4c18aa7ba9b35ade48cac1b93 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Sat, 15 Jul 2023 18:58:11 -0700 Subject: [PATCH 39/56] Optimize loopwise fee computation/assessment --- src/move/econia/sources/market.move | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 8a6fad7b3..a40f2f2e1 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2922,7 +2922,6 @@ module econia::market { order_book_ref_mut.counter = order_book_ref_mut.counter + 1; let fill_count = 0; let fees_paid = 0; - let fees_paid_for_fill; // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -3001,18 +3000,15 @@ module econia::market { ticks_until_max = ticks_until_max - ticks_filled; // Declare return assignment variable. let market_order_id; + let quote_filled = ticks_filled * tick_size; // Fill matched order user side, store market order ID. (optional_base_coins, quote_coins, market_order_id) = user::fill_order_internal( maker, market_id, maker_custodian_id, side, order_ref_mut.order_access_key, order_ref_mut.size, fill_size, complete_fill, optional_base_coins, - quote_coins, fill_size * lot_size, - ticks_filled * tick_size); - (quote_coins, fees_paid_for_fill) = - incentives::assess_taker_fees( - market_id, integrator, taker_fee_divisor, - ticks_filled * tick_size, quote_coins); + quote_coins, fill_size * lot_size, quote_filled); + let fees_paid_for_fill = quote_filled / taker_fee_divisor; vector::push_back( event_queue_ref_mut, user::create_fill_event_internal( market_id, @@ -3049,6 +3045,9 @@ module econia::market { let (base_fill, quote_fill) = // Calculate base and quote fills. (((max_lots - lots_until_max ) * lot_size), ((max_ticks - ticks_until_max) * tick_size)); + let (quote_coins, _) = incentives::assess_taker_fees( + market_id, integrator, taker_fee_divisor, + fees_paid * taker_fee_divisor, quote_coins); // If a buy, taker pays quote required for fills, and additional // fee assessed after matching. If a sell, taker receives quote // from fills, then has a portion assessed as fees. From fa3170619ba2bd4255b7cd73776a36977307a9e7 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 13:35:11 -0700 Subject: [PATCH 40/56] Manually inline runtime market ID calculations --- src/move/econia/sources/user.move | 45 +++++++++---------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index e97e3a2cc..5aebaad02 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -1257,7 +1257,8 @@ module econia::user { move_to(user, MarketEventHandles{map: table::new()}); let market_event_handles_map_ref_mut = &mut borrow_global_mut(user_address).map; - let market_account_id = get_market_account_id(market_id, custodian_id); + let market_account_id = // Get market account ID. + ((market_id as u128) << SHIFT_MARKET_ID) | (custodian_id as u128); let has_handles = table::contains( market_event_handles_map_ref_mut, market_account_id); if (!has_handles) { @@ -1707,8 +1708,9 @@ module econia::user { if (exists(user)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(user).map; - let market_account_id = - get_market_account_id(market_id, custodian_id); + // Get market account ID. + let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) | + (custodian_id as u128)); let has_handles_for_market_account = table::contains( market_event_handles_map_ref_mut, market_account_id); if (has_handles_for_market_account) { @@ -1780,8 +1782,9 @@ module econia::user { if (exists(user)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(user).map; - let market_account_id = - get_market_account_id(market_id, custodian_id); + // Get market account ID. + let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) | + (custodian_id as u128)); let has_handles_for_market_account = table::contains( market_event_handles_map_ref_mut, market_account_id); if (has_handles_for_market_account) { @@ -2607,8 +2610,11 @@ module econia::user { if (exists(maker)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(maker).map; - let market_account_id = get_market_account_id( - event_ref.market_id, event_ref.maker_custodian_id); + let market_id = event_ref.market_id; + let custodian_id = event_ref.maker_custodian_id; + // Get market account ID. + let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) | + (custodian_id as u128)); let has_handles_for_market_account = table::contains( market_event_handles_map_ref_mut, market_account_id); if (has_handles_for_market_account) { @@ -2620,31 +2626,6 @@ module econia::user { }; } - /// Emit fill event for either maker or taker, if handle exists. - inline fun emit_fill_event( - event: FillEvent, - is_maker: bool - ) acquires MarketEventHandles { - let (user_address, custodian_id) = if (is_maker) - (event.maker, event.maker_custodian_id) else - (event.taker, event.taker_custodian_id); - if (exists(user_address)) { - let market_event_handles_map_ref_mut = - &mut borrow_global_mut(user_address).map; - let market_account_id = - get_market_account_id(event.market_id, custodian_id); - let has_handle = table::contains(market_event_handles_map_ref_mut, - market_account_id); - if (has_handle) { - let fill_event_handle_ref_mut = &mut table::borrow_mut( - market_event_handles_map_ref_mut, - market_account_id - ).fill_events; - event::emit_event(fill_event_handle_ref_mut, event) - } - } - } - /// Return `registry::MarketInfo` fields stored in market account. /// /// # Parameters From 3933509289ecbc94e83dcaac88866df47d0eb2b1 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 15:11:42 -0700 Subject: [PATCH 41/56] Update doc/func comments for user module --- src/move/econia/sources/user.move | 658 +++++++++++++++++++----------- 1 file changed, 429 insertions(+), 229 deletions(-) diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 5aebaad02..7a90ef52d 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -316,6 +316,37 @@ module econia::user { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + /// Emitted when an order is cancelled. + struct CancelOrderEvent has copy, drop, store { + /// Market ID for order. + market_id: u64, + /// Unique ID for order within market. + order_id: u128, + /// User for market account that placed order. + user: address, + /// Custodian ID for market account that placed order. + custodian_id: u64, + /// Reason for the cancel, for example + /// `CANCEL_REASON_MANUAL_CANCEL`. + reason: u8 + } + + /// Emitted when the size of an open order is manually changed. + struct ChangeOrderSizeEvent has copy, drop, store { + /// Market ID for order. + market_id: u64, + /// Unique ID for order within market. + order_id: u128, + /// User for market account that placed order. + user: address, + /// Custodian ID for market account that placed order. + custodian_id: u64, + /// `ASK` or `BID`. + side: bool, + /// Order size after manual size change operation. + new_size: u64 + } + /// All of a user's collateral across all market accounts. struct Collateral has key { /// Map from market account ID to collateral for market account. @@ -325,6 +356,38 @@ module econia::user { map: Tablist> } + /// Emitted when one order fills against another. + struct FillEvent has copy, drop, store { + /// Market ID for fill. + market_id: u64, + /// Amount filled, in lots. + size: u64, + /// Fill price, in ticks per lot. + price: u64, + /// `ASK` or `BID`, the side of the maker order. + maker_side: bool, + /// User address associated with market account for maker. + maker: address, + /// Custodian ID associated with market account for maker. + maker_custodian_id: u64, + /// Order ID for maker, unique within the market. + maker_order_id: u128, + /// User address associated with market account for taker. + taker: address, + /// Custodian ID associated with market account for taker. + taker_custodian_id: u64, + /// Order ID for taker, unique within the market. + taker_order_id: u128, + /// Amount of fees paid by taker on the fill, in indivisible + /// quote subunits. + taker_quote_fees_paid: u64, + /// Sequence number (0-indexed) of fill within a single trade, + /// which may have more than one fill. For example if a market + /// order results in two fills, the first will have sequence + /// number 0 and the second will have sequence number 1. + sequence_number_for_trade: u64 + } + /// Represents a user's open orders and asset counts for a given /// market account ID. Contains `registry::MarketInfo` field /// duplicates to reduce global storage item queries against the @@ -401,91 +464,108 @@ module econia::user { custodians: Tablist> } - /// An open order, either ask or bid. - struct Order has store { - /// Market order ID. `NIL` if inactive. - market_order_id: u128, - /// Order size left to fill, in lots. When `market_order_id` is - /// `NIL`, indicates access key of next inactive order in stack. - size: u64 - } - - struct MarketEventHandlesForMarketAccount has store { - cancel_order_events: EventHandle, - change_order_size_events: EventHandle, - fill_events: EventHandle, - place_limit_order_events: EventHandle, - place_market_order_events: EventHandle - } - - /// Table keys are market account IDs. - struct MarketEventHandles has key { - map: Table - } - - /// View function return for getting event handle creation numbers. + /// View function return for getting event handle creation numbers + /// of a particular `MarketEventHandlesForMarketAccount`. struct MarketEventHandleCreationNumbers has copy, drop { + /// Creation number of `cancel_order_events` handle in a + /// `MarketEventHandlesForMarketAccount`. cancel_order_events_handle_creation_num: u64, + /// Creation number of `change_order_size_events` handle in a + /// `MarketEventHandlesForMarketAccount`. change_order_size_events_handle_creation_num: u64, + /// Creation number of `fill_events` handle in a + /// `MarketEventHandlesForMarketAccount`. fill_events_handle_creation_num: u64, + /// Creation number of `place_limit_order_events` handle in a + /// `MarketEventHandlesForMarketAccount`. place_limit_order_events_handle_creation_num: u64, + /// Creation number of `place_market_order_events` handle in a + /// `MarketEventHandlesForMarketAccount`. place_market_order_events_handle_creation_num: u64 } - struct CancelOrderEvent has copy, drop, store { - market_id: u64, - order_id: u128, - user: address, - custodian_id: u64, - reason: u8 + /// All of a user's `MarketEventHandlesForMarketAccount`. + struct MarketEventHandles has key { + /// Map from market account ID to + /// `MarketEventHandlesForMarketAccount`. + map: Table } - struct ChangeOrderSizeEvent has copy, drop, store { - market_id: u64, - order_id: u128, - user: address, - custodian_id: u64, - side: bool, - new_size: u64 + /// Event handles for market events within a unique market account. + struct MarketEventHandlesForMarketAccount has store { + /// Event handle for `CancelOrderEvent`s. + cancel_order_events: EventHandle, + /// Event handle for `ChangeOrderSizeEvent`s. + change_order_size_events: EventHandle, + /// Event handle for `FillEvent`s. + fill_events: EventHandle, + /// Event handle for `PlaceLimitOrderEvent`s. + place_limit_order_events: EventHandle, + /// Event handle for `PlaceMarketOrderEvent`s. + place_market_order_events: EventHandle } - struct FillEvent has copy, drop, store { - market_id: u64, - size: u64, - price: u64, - maker_side: bool, - maker: address, - maker_custodian_id: u64, - maker_order_id: u128, - taker: address, - taker_custodian_id: u64, - taker_order_id: u128, - taker_quote_fees_paid: u64, - sequence_number_for_trade: u64 + /// An open order, either ask or bid. + struct Order has store { + /// Market order ID. `NIL` if inactive. + market_order_id: u128, + /// Order size left to fill, in lots. When `market_order_id` is + /// `NIL`, indicates access key of next inactive order in stack. + size: u64 } + /// Emitted when a limit order is placed. struct PlaceLimitOrderEvent has copy, drop, store { + /// Market ID for order. market_id: u64, + /// User for market account that placed order. user: address, + /// Custodian ID for market account that placed order. custodian_id: u64, + /// Integrator address passed during limit order placement, + /// eligible for a portion of any generated taker fees. integrator: address, + /// `ASK` or `BID`. side: bool, + /// Size indicated during limit order placement. size: u64, + /// Order limit price. price: u64, + /// Restriction indicated during limit order placement, either + /// `market::FILL_OR_ABORT`, `market::IMMEDIATE_OR_CANCEL`, + /// `market::POST_OR_ABORT`, or `market:NO_RESTRICTION`. restriction: u8, + /// Self match behavior indicated during limit order placement, + /// either `market::ABORT`, `market::CANCEL_BOTH`, + /// `market::CANCEL_MAKER`, or `market::CANCEL_TAKER`. self_match_behavior: u8, + /// Size posted to order book after optional fills across the + /// spread. remaining_size: u64, + /// Unique ID for order within market. order_id: u128 } + /// Emitted when a limit order is placed. struct PlaceMarketOrderEvent has copy, drop, store { + /// Market ID for order. market_id: u64, + /// User for market account that placed order. user: address, + /// Custodian ID for market account that placed order. custodian_id: u64, + /// Integrator address passed during market order placement, + /// eligible for a portion of any generated taker fees. integrator: address, + /// Either `market::BUY` or `market::SELL`. direction: bool, + /// Size indicated during market order placement. size: u64, + /// Self match behavior indicated during market order placement, + /// either `market::ABORT`, `market::CANCEL_BOTH`, + /// `market::CANCEL_MAKER`, or `market::CANCEL_TAKER`. self_match_behavior: u8, + /// Unique ID for order within market. order_id: u128 } @@ -544,6 +624,33 @@ module econia::user { const ASK: bool = true; /// Flag for bid side const BID: bool = false; + /// Order cancelled because it was evicted from the price-time + /// priority queue. + const CANCEL_REASON_EVICTION: u8 = 1; + /// Order cancelled because it was an immediate-or-cancel order + /// that did not immediately fill. + const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 2; + /// Order cancelled because it was manually cancelled by either + /// signing user or custodian. + const CANCEL_REASON_MANUAL_CANCEL: u8 = 3; + /// Order cancelled because no more quote asset could be traded. + const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 4; + /// Order cancelled because there was not enough liquidity to take + /// from. + const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 5; + /// Order cancelled because it was on the maker side of an fill + /// where self match behavior indicated cancelling the maker order. + const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 6; + /// Order cancelled because it was on the taker side of an fill + /// where self match behavior indicated cancelling the taker order. + const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 7; + /// Flag to indicate that order is only temporarily cancelled from + /// market account memory because it will be subsequently re-placed + /// as part of a size change. + const CANCEL_REASON_SIZE_CHANGE_INTERNAL: u8 = 0; + /// Order cancelled because after matching across the spread the + /// remaining order size was too smal for the market. + const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8; /// `u64` bitmask with all bits set, generated in Python via /// `hex(int('1' * 64, 2))`. const HI_64: u64 = 0xffffffffffffffff; @@ -558,111 +665,107 @@ module econia::user { const NO_UNDERWRITER: u64 = 0; /// Number of bits market ID is shifted in market account ID. const SHIFT_MARKET_ID: u8 = 64; - const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; - const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 2; - const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; - const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; - const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; - const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; - const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 7; - const CANCEL_REASON_SIZE_CHANGE_INTERNAL: u8 = 8; // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> #[view] - /// Private view function to reduce runtime handle contention. - fun get_market_event_handle_creation_numbers( - user: address, - market_id: u64, - custodian_id: u64 - ): Option - acquires MarketEventHandles { - if (!exists(user)) return option::none(); - let market_event_handles_map_ref = - &borrow_global(user).map; - let market_account_id = get_market_account_id(market_id, custodian_id); - let has_handles = table::contains( - market_event_handles_map_ref, market_account_id); - if (!has_handles) return option::none(); - let market_account_handles_ref = table::borrow( - market_event_handles_map_ref, market_account_id); - option::some(MarketEventHandleCreationNumbers{ - cancel_order_events_handle_creation_num: - guid::creation_num(event::guid( - &market_account_handles_ref.cancel_order_events)), - change_order_size_events_handle_creation_num: - guid::creation_num(event::guid( - &market_account_handles_ref.change_order_size_events)), - fill_events_handle_creation_num: - guid::creation_num(event::guid( - &market_account_handles_ref.fill_events)), - place_limit_order_events_handle_creation_num: - guid::creation_num(event::guid( - &market_account_handles_ref.place_limit_order_events)), - place_market_order_events_handle_creation_num: - guid::creation_num(event::guid( - &market_account_handles_ref.place_market_order_events)) - }) - } + /// Public constant getter for `ASK`. + /// + /// # Testing + /// + /// * `test_get_ASK()` + public fun get_ASK(): bool {ASK} #[view] - public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8 { - CANCEL_REASON_MANUAL_CANCEL - } + /// Public constant getter for `BID`. + /// + /// # Testing + /// + /// * `test_get_BID()` + public fun get_BID(): bool {BID} #[view] + /// Public constant getter for `CANCEL_REASON_EVICTION`. + /// + /// # Testing + /// + /// * `test_get_cancel_reasons()` TODO public fun get_CANCEL_REASON_EVICTION(): u8 { CANCEL_REASON_EVICTION } #[view] - public fun get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY(): u8 { - CANCEL_REASON_NOT_ENOUGH_LIQUIDITY - } - - #[view] - public fun get_CANCEL_REASON_SELF_MATCH_MAKER(): u8 { - CANCEL_REASON_SELF_MATCH_MAKER + /// Public constant getter for `CANCEL_REASON_IMMEDIATE_OR_CANCEL`. + /// + /// # Testing + /// + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_IMMEDIATE_OR_CANCEL(): u8 { + CANCEL_REASON_IMMEDIATE_OR_CANCEL } #[view] - public fun get_CANCEL_REASON_SELF_MATCH_TAKER(): u8 { - CANCEL_REASON_SELF_MATCH_TAKER + /// Public constant getter for `CANCEL_REASON_MANUAL_CANCEL`. + /// + /// # Testing + /// + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8 { + CANCEL_REASON_MANUAL_CANCEL } #[view] - public fun get_CANCEL_REASON_IMMEDIATE_OR_CANCEL(): u8 { - CANCEL_REASON_IMMEDIATE_OR_CANCEL + /// Public constant getter for `CANCEL_REASON_MAX_QUOTE_TRADED`. + /// + /// # Testing + /// + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_MAX_QUOTE_TRADED(): u8 { + CANCEL_REASON_MAX_QUOTE_TRADED } #[view] - public fun get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING(): u8 { - CANCEL_REASON_TOO_SMALL_AFTER_MATCHING + /// Public constant getter for `CANCEL_REASON_NOT_ENOUGH_LIQUIDITY`. + /// + /// # Testing + /// + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY(): u8 { + CANCEL_REASON_NOT_ENOUGH_LIQUIDITY } #[view] - public fun get_CANCEL_REASON_MAX_QUOTE_TRADED(): u8 { - CANCEL_REASON_MAX_QUOTE_TRADED + /// Public constant getter for `CANCEL_REASON_SELF_MATCH_MAKER`. + /// + /// # Testing + /// + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_SELF_MATCH_MAKER(): u8 { + CANCEL_REASON_SELF_MATCH_MAKER } #[view] - /// Public constant getter for `ASK`. + /// Public constant getter for `CANCEL_REASON_SELF_MATCH_TAKER`. /// /// # Testing /// - /// * `test_get_ASK()` - public fun get_ASK(): bool {ASK} + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_SELF_MATCH_TAKER(): u8 { + CANCEL_REASON_SELF_MATCH_TAKER + } #[view] - /// Public constant getter for `BID`. + /// Public constant getter for + /// `CANCEL_REASON_TOO_SMALL_AFTER_MATCHING`. /// /// # Testing /// - /// * `test_get_BID()` - public fun get_BID(): bool {BID} + /// * `test_get_cancel_reasons()` TODO + public fun get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING(): u8 { + CANCEL_REASON_TOO_SMALL_AFTER_MATCHING + } #[view] /// Public constant getter for `NO_CUSTODIAN`. @@ -885,6 +988,46 @@ module econia::user { market_accounts // Return market account views. } + #[view] + /// Return a `MarketEventHandleCreationNumbers` for `market_id` and + /// `custodian_id`, if `user` has one for indicated market account. + fun get_market_event_handle_creation_numbers( + user: address, + market_id: u64, + custodian_id: u64 + ): Option + acquires MarketEventHandles { + // Return none if user does not have market event handles map, + if (!exists(user)) return option::none(); + // Return none if user has no handles for market account. + let market_event_handles_map_ref = + &borrow_global(user).map; + let market_account_id = get_market_account_id(market_id, custodian_id); + let has_handles = table::contains( + market_event_handles_map_ref, market_account_id); + if (!has_handles) return option::none(); + // Return option-packed creation numbers for all event handles. + let market_account_handles_ref = table::borrow( + market_event_handles_map_ref, market_account_id); + option::some(MarketEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: + guid::creation_num(event::guid( + &market_account_handles_ref.cancel_order_events)), + change_order_size_events_handle_creation_num: + guid::creation_num(event::guid( + &market_account_handles_ref.change_order_size_events)), + fill_events_handle_creation_num: + guid::creation_num(event::guid( + &market_account_handles_ref.fill_events)), + place_limit_order_events_handle_creation_num: + guid::creation_num(event::guid( + &market_account_handles_ref.place_limit_order_events)), + place_market_order_events_handle_creation_num: + guid::creation_num(event::guid( + &market_account_handles_ref.place_market_order_events)) + }) + } + #[view] /// Return market ID encoded in market account ID. /// @@ -1242,6 +1385,22 @@ module econia::user { coin::withdraw(user, amount)); } + /// Initialize market event handles for a market account if missing. + /// + /// Since market event handles were implemented as part of a + /// compatible upgrade policy, it is possible for a user to have a + /// market account without associated market event handles, if they + /// registered a market account before an on-chain upgrade. + /// + /// # Parameters + /// + /// * `user`: User for market account. + /// * `market_id`: Market ID for market account. + /// * `custodian_id`: Custodian ID for market account. + /// + /// # Aborts + /// + /// * `E_NO_MARKET_ACCOUNT`: No such specified market account. public entry fun init_market_event_handles_if_missing( user: &signer, market_id: u64, @@ -1250,14 +1409,17 @@ module econia::user { MarketAccounts, MarketEventHandles { + // Verify user has specified market account. let user_address = address_of(user); assert!(has_market_account(user_address, market_id, custodian_id), E_NO_MARKET_ACCOUNT); + // Create market event handles map if user doesn't have one, + // and fill with handles for market account as needed. if (!exists(address_of(user))) move_to(user, MarketEventHandles{map: table::new()}); let market_event_handles_map_ref_mut = &mut borrow_global_mut(user_address).map; - let market_account_id = // Get market account ID. + let market_account_id = ((market_id as u128) << SHIFT_MARKET_ID) | (custodian_id as u128); let has_handles = table::contains( market_event_handles_map_ref_mut, market_account_id); @@ -1414,6 +1576,12 @@ module econia::user { /// * `market_order_id`: `NIL` if order cancellation originates from /// an eviction or a self match cancel, otherwise the market order /// ID encoded in the user's `Order`. + /// * `cancel_reason`: The reason for the cancel. Note that + /// user-side open order size changes are processed via + /// `change_order_size_internal()` as a cancellation followed by + /// immediate re-placement, corresponding to the cancel reason + /// `CANCEL_REASON_SIZE_CHANGE_INTERNAL`. When this is the case + /// no cancel event is emitted. /// /// # Returns /// @@ -1433,6 +1601,10 @@ module econia::user { /// * `E_INVALID_MARKET_ORDER_ID`: Market order ID mismatch with /// user's open order, when market order ID not passed as `NIL`. /// + /// # Emits + /// + /// * `CancelOrderEvent`: Information about a cancelled order. + /// /// # Assumptions /// /// * Only called when also cancelling an order from the order book. @@ -1528,8 +1700,8 @@ module econia::user { let ceiling_decrement_amount = size * size_multiplier_ceiling; *in_ceiling_ref_mut = // Decrement ceiling field. *in_ceiling_ref_mut - ceiling_decrement_amount; - // Check if order is cancelled internally only so that it can - // be intenally re-placed as part of a size change. + // If order is actually being cancelled and user has market + // event handles for the market account, emit a cancel event. let changing_size = reason != CANCEL_REASON_SIZE_CHANGE_INTERNAL; if (!changing_size && exists(user_address)) { let market_event_handles_map_ref_mut = @@ -1542,13 +1714,8 @@ module econia::user { event::emit_event( &mut handles_ref_mut.cancel_order_events, CancelOrderEvent{ - market_id, - order_id: market_order_id, - user: user_address, - custodian_id, - reason - } - ); + market_id, order_id: market_order_id, + user: user_address, custodian_id, reason}); } }; market_order_id // Return market order ID. @@ -1573,6 +1740,11 @@ module econia::user { /// /// * `E_CHANGE_ORDER_NO_CHANGE`: No change in order size. /// + /// # Emits + /// + /// * `ChangeOrderSizeEvent`: Information about an order that had a + /// manual size change. + /// /// # Assumptions /// /// * Only called when also changing order size on the order book. @@ -1622,6 +1794,8 @@ module econia::user { place_order_internal( // Place order with new size. user_address, market_id, custodian_id, side, new_size, price, market_order_id, order_access_key); + // If user has market event handles for the market account, emit + // a change order size event. if (exists(user_address)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(user_address).map; @@ -1633,18 +1807,60 @@ module econia::user { event::emit_event( &mut handles_ref_mut.change_order_size_events, ChangeOrderSizeEvent{ - market_id, - order_id: market_order_id, - user: user_address, - custodian_id, - side, - new_size - } - ); + market_id, order_id: market_order_id, + user: user_address, custodian_id, side, new_size}); } } } + /// Return a `CancelOrderEvent` with the indicated fields. + public(friend) fun create_cancel_order_event_internal( + market_id: u64, + order_id: u128, + user: address, + custodian_id: u64, + reason: u8 + ): CancelOrderEvent { + CancelOrderEvent{ + market_id, + order_id, + user, + custodian_id, + reason + } + } + + /// Return a `FillEvent` with the indicated fields. + public(friend) fun create_fill_event_internal( + market_id: u64, + size: u64, + price: u64, + maker_side: bool, + maker: address, + maker_custodian_id: u64, + maker_order_id: u128, + taker: address, + taker_custodian_id: u64, + taker_order_id: u128, + taker_quote_fees_paid: u64, + sequence_number_for_trade: u64 + ): FillEvent { + FillEvent{ + market_id, + size, + price, + maker_side, + maker, + maker_custodian_id, + maker_order_id, + taker, + taker_custodian_id, + taker_order_id, + taker_quote_fees_paid, + sequence_number_for_trade + } + } + /// Deposit base asset and quote coins when matching. /// /// Should only be called by the matching engine when matching from @@ -1690,6 +1906,37 @@ module econia::user { user_address, market_id, custodian_id, quote_coins); } + /// Emit limit order events to a user's market event handles. + /// + /// # Parameters + /// + /// * `market_id`: `PlaceLimitOrderEvent.market_id`. + /// * `user`: `PlaceLimitOrderEvent.user`. + /// * `custodian_id`: `PlaceLimitOrderEvent.custodian_id`. + /// * `integrator`: `PlaceLimitOrderEvent.integrator`. + /// * `side`: `PlaceLimitOrderEvent.side`. + /// * `size`: `PlaceLimitOrderEvent.size`. + /// * `price`: `PlaceLimitOrderEvent.price`. + /// * `restriction`: `PlaceLimitOrderEvent.restriction`. + /// * `self_match_behavior`: + /// `PlaceLimitOrderEvent.self_match_behavior`. + /// * `remaining_size`: `PlaceLimitOrderEvent.remaining_size`. + /// * `order_id`: `PlaceLimitOrderEvent.order_id`. + /// * `fill_event_queue_ref`: Immutable reference to a vector of + /// `FillEvent`s to emit as part of a limit order that filled + /// across the spread, may be empty. + /// * `cancel_reason_option_ref`: Immutable reference to an optional + /// cancel reason associated with a `CancelEvent`. + /// + /// # Emits + /// + /// * `PlaceLimitOrderEvent`: Information about the limit order that + /// was placed. + /// * `FillEvent`(s): Information about fill(s) across the spread as + /// a taker. + /// * `CancelOrderEvent`: Optionally, information about why the + /// limit order may have had to be cancelled during the + /// transaction in which it was placed. public(friend) fun emit_limit_order_events_internal( market_id: u64, user: address, @@ -1705,10 +1952,11 @@ module econia::user { fill_event_queue_ref: &vector, cancel_reason_option_ref: &Option ) acquires MarketEventHandles { + // Only emit events to handles for the market account that + // placed the order if they have been initialized. if (exists(user)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(user).map; - // Get market account ID. let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) | (custodian_id as u128)); let has_handles_for_market_account = table::contains( @@ -1716,23 +1964,12 @@ module econia::user { if (has_handles_for_market_account) { let handles_ref_mut = table::borrow_mut( market_event_handles_map_ref_mut, market_account_id); - // Emit place limit order event. event::emit_event( &mut handles_ref_mut.place_limit_order_events, PlaceLimitOrderEvent{ - market_id, - user, - custodian_id, - integrator, - side, - size, - price, - restriction, - self_match_behavior, - remaining_size, - order_id - } - ); + market_id, user, custodian_id, integrator, side, size, + price, restriction, self_match_behavior, + remaining_size, order_id}); // Loop over fill events, substituting order ID in case // order posted after fill event creation. Looping here // minimizes borrows from the user's account, but will @@ -1744,22 +1981,17 @@ module econia::user { event.taker_order_id = order_id; event::emit_event(&mut handles_ref_mut.fill_events, event); }); - // Optionally emit cancel order event. if (option::is_some(cancel_reason_option_ref)) { + let event = CancelOrderEvent{ + market_id, order_id, user, custodian_id, + reason: *option::borrow(cancel_reason_option_ref)}; event::emit_event( - &mut handles_ref_mut.cancel_order_events, - CancelOrderEvent{ - market_id, - order_id, - user, - custodian_id, - reason: *option::borrow(cancel_reason_option_ref) - } - ); + &mut handles_ref_mut.cancel_order_events, event); }; }; }; - // Emit fill events for all makers. + // Emit fill events for all makers, similarly substituting + // order ID in case order posted after fill event creation. vector::for_each_ref(fill_event_queue_ref, |event_ref| { let event: FillEvent = *event_ref; event.taker_order_id = order_id; @@ -1767,6 +1999,31 @@ module econia::user { }); } + /// Emit market order events to a user's market event handles. + /// + /// # Parameters + /// + /// * `market_id`: `PlaceMarketOrderEvent.market_id`. + /// * `user`: `PlaceMarketOrderEvent.user`. + /// * `custodian_id`: `PlaceMarketOrderEvent.custodian_id`. + /// * `integrator`: `PlaceMarketOrderEvent.integrator`. + /// * `direction`: `PlaceMarketOrderEvent.direction`. + /// * `size`: `PlaceMarketOrderEvent.size`. + /// * `self_match_behavior`: + /// `PlaceMarketOrderEvent.self_match_behavior`. + /// * `order_id`: `PlaceMarketOrderEvent.order_id`. + /// * `fill_event_queue_ref`: Immutable reference to a vector of + /// `FillEvent`s to emit, may be empty. + /// * `cancel_reason_option_ref`: Immutable reference to an optional + /// cancel reason associated with a `CancelEvent`. + /// + /// # Emits + /// + /// * `PlaceMarketOrderEvent`: Information about the market order + /// that was placed. + /// * `FillEvent`(s): Information about fill(s). + /// * `CancelOrderEvent`: Optionally, information about why the + /// market order was cancelled without completely filling. public(friend) fun emit_market_order_events_internal( market_id: u64, user: address, @@ -1779,10 +2036,11 @@ module econia::user { fill_event_queue_ref: &vector, cancel_reason_option_ref: &Option ) acquires MarketEventHandles { + // Only emit events to handles for the market account that + // placed the order if they have been initialized. if (exists(user)) { let market_event_handles_map_ref_mut = &mut borrow_global_mut(user).map; - // Get market account ID. let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) | (custodian_id as u128)); let has_handles_for_market_account = table::contains( @@ -1790,20 +2048,11 @@ module econia::user { if (has_handles_for_market_account) { let handles_ref_mut = table::borrow_mut( market_event_handles_map_ref_mut, market_account_id); - // Emit place market order event. event::emit_event( &mut handles_ref_mut.place_market_order_events, PlaceMarketOrderEvent{ - market_id, - user, - custodian_id, - integrator, - direction, - size, - self_match_behavior, - order_id - } - ); + market_id, user, custodian_id, integrator, direction, + size, self_match_behavior, order_id}); // Loop over fill events. Looping here minimizes borrows // from the user's account, but will require looping // again later to emit maker fill events because the @@ -1813,18 +2062,12 @@ module econia::user { event::emit_event( &mut handles_ref_mut.fill_events, *event_ref); }); - // Optionally emit cancel order event. if (option::is_some(cancel_reason_option_ref)) { + let event = CancelOrderEvent{ + market_id, order_id, user, custodian_id, + reason: *option::borrow(cancel_reason_option_ref)}; event::emit_event( - &mut handles_ref_mut.cancel_order_events, - CancelOrderEvent{ - market_id, - order_id, - user, - custodian_id, - reason: *option::borrow(cancel_reason_option_ref) - } - ); + &mut handles_ref_mut.cancel_order_events, event); }; }; }; @@ -1834,6 +2077,7 @@ module econia::user { }); } + /// Emit a `FillEvent` for each maker associated with a swap. public(friend) fun emit_swap_maker_fill_events_internal( fill_event_queue_ref: &vector ) acquires MarketEventHandles { @@ -1842,52 +2086,6 @@ module econia::user { }); } - public(friend) fun create_cancel_order_event_internal( - market_id: u64, - order_id: u128, - user: address, - custodian_id: u64, - reason: u8 - ): CancelOrderEvent { - CancelOrderEvent{ - market_id, - order_id, - user, - custodian_id, - reason - } - } - - public(friend) fun create_fill_event_internal( - market_id: u64, - size: u64, - price: u64, - maker_side: bool, - maker: address, - maker_custodian_id: u64, - maker_order_id: u128, - taker: address, - taker_custodian_id: u64, - taker_order_id: u128, - taker_quote_fees_paid: u64, - sequence_number_for_trade: u64 - ): FillEvent { - FillEvent{ - market_id, - size, - price, - maker_side, - maker, - maker_custodian_id, - maker_order_id, - taker, - taker_custodian_id, - taker_order_id, - taker_quote_fees_paid, - sequence_number_for_trade - } - } - /// Fill a user's order, routing collateral appropriately. /// /// Updates asset counts in a user's market account. Transfers @@ -2603,6 +2801,9 @@ module econia::user { }; } + /// Emit a `FillEvent` for the market account of the maker + /// associated with a fill, if market event handles exist for the + /// indicated market account. inline fun emit_maker_fill_event( event_ref: &FillEvent ) acquires MarketEventHandles { @@ -2612,7 +2813,6 @@ module econia::user { &mut borrow_global_mut(maker).map; let market_id = event_ref.market_id; let custodian_id = event_ref.maker_custodian_id; - // Get market account ID. let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) | (custodian_id as u128)); let has_handles_for_market_account = table::contains( From 1ef956618df236a881d047822a9549d840da1da5 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 16:41:19 -0700 Subject: [PATCH 42/56] Update doc/func comments for market module --- src/move/econia/sources/market.move | 725 +++++++++++++++------------- 1 file changed, 384 insertions(+), 341 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index a40f2f2e1..3d037a66b 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -563,6 +563,37 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + /// View function return for getting event handle creation info of a + /// particular `MarkeEventHandlesForMarket`. + struct MarketEventHandleCreationInfo has copy, drop { + /// Econia resource account address, corresponding to event + /// handle creator address. + resource_account_address: address, + /// Creation number of `cancel_order_events` handle in a + /// `MarketEventHandlesForMarket`. + cancel_order_events_handle_creation_num: u64, + /// Creation number of `place_swap_order_events` handle in a + /// `MarketEventHandlesForMarket`. + place_swap_order_events_handle_creation_num: u64 + } + + /// All of the Econia resource account's + /// `MarketEventHandlesForMarket`. + struct MarketEventHandles has key { + /// Map from market ID to `MarketEventHandlesForMarket`. + map: Table + } + + /// Within a given market, event handles for market events that are + /// not emitted elsewhere when associated with a swap order placed + /// by a non-signing swapper. + struct MarketEventHandlesForMarket has store { + /// Event handle for `user::CancelOrderEvent`s. + cancel_order_events: EventHandle, + /// Event handle for `user::PlaceSwapOrderEvent`s. + place_swap_order_events: EventHandle + } + /// An order on the order book. struct Order has store { /// Number of lots to be filled. @@ -615,57 +646,6 @@ module econia::market { map: Tablist } - /// Not emitted at market account level when a swap order is placed - /// by a non-signing swapper. - struct MarketEventHandlesForMarket has store { - cancel_order_events: EventHandle, - place_swap_order_events: EventHandle - } - - struct MarketEventHandles has key { - map: Table - } - - /// View function return for getting event handle creation info. - struct MarketEventHandleCreationInfo has copy, drop { - resource_account_address: address, - cancel_order_events_handle_creation_num: u64, - place_swap_order_events_handle_creation_num: u64 - } - - /// Stored under a signing user's account (not market account), - /// since swaps are processed outside of a market account and do not - /// always require a signature. - struct SwapperEventHandlesForMarket has store { - cancel_order_events: EventHandle, - fill_events: EventHandle, - place_swap_order_events: EventHandle - } - - struct SwapperEventHandles has key { - map: Table - } - - /// View function return for getting event handle creation numbers. - struct SwapperEventHandleCreationNumbers has copy, drop { - cancel_order_events_handle_creation_num: u64, - fill_events_handle_creation_num: u64, - place_swap_order_events_handle_creation_num: u64 - } - - struct PlaceSwapOrderEvent has copy, drop, store { - market_id: u64, - signing_account: address, - integrator: address, - direction: bool, - min_base: u64, - max_base: u64, - min_quote: u64, - max_quote: u64, - limit_price: u64, - order_id: u128 - } - /// User-friendly representation of an open order on the order book. struct OrderView has copy, drop { /// Market ID for open order. @@ -696,6 +676,32 @@ module econia::market { bids: vector } + /// Emitted when a swap order is placed. + struct PlaceSwapOrderEvent has copy, drop, store { + /// Market ID for order. + market_id: u64, + /// Signing account if swap is placed by a signing swapper, else + /// `NO_TAKER_ADDRESS`. + signing_account: address, + /// Integrator address passed during swap order placement, + /// eligible for a portion of any generated taker fees. + integrator: address, + /// Either `BUY` or `SELL`. + direction: bool, + /// Inidicated minimum base subunits to trade. + min_base: u64, + /// Inidicated maximum base subunits to trade. + max_base: u64, + /// Inidicated minimum quote subunits to trade. + min_quote: u64, + /// Inidicated maximum quote subunits to trade. + max_quote: u64, + /// Indicated limit price. + limit_price: u64, + /// Unique ID for order within market. + order_id: u128 + } + /// A price level from an `OrderBook`. struct PriceLevel has copy, drop { /// Price, in ticks per lot. @@ -717,6 +723,39 @@ module econia::market { bids: vector } + /// View function return for getting event handle creation numbers + /// for a signing swapper's `SwapperEventHandlesForMarket`. + struct SwapperEventHandleCreationNumbers has copy, drop { + /// Creation number of `cancel_order_events` handle in a + /// `SwapperEventHandlesForMarket`. + cancel_order_events_handle_creation_num: u64, + /// Creation number of `fill_events` handle in a + /// `SwapperEventHandlesForMarket`. + fill_events_handle_creation_num: u64, + /// Creation number of `place_swap_order_events` handle in a + /// `SwapperEventHandlesForMarket`. + place_swap_order_events_handle_creation_num: u64 + } + + /// All of a signing swapper's `SwapperEventHandlesForMarket`. + struct SwapperEventHandles has key { + /// Map from market ID to `SwapperEventHandlesForMarket`. + map: Table + } + + /// Event handles for market events associated with a signing + /// swapper on a particular market. Stored under a signing swapper's + /// account (not market account), since swaps are processed outside + /// of an Econia-style market account. + struct SwapperEventHandlesForMarket has store { + /// Event handle for `user::CancelOrderEvent`s. + cancel_order_events: EventHandle, + /// Event handle for `user::FillEvent`s. + fill_events: EventHandle, + /// Event handle for `user::PlaceSwapOrderEvent`s. + place_swap_order_events: EventHandle + } + // Structs <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Error codes >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> @@ -807,6 +846,29 @@ module econia::market { const CANCEL_BOTH: u8 = 1; /// Flag to cancel maker order only during a self match. const CANCEL_MAKER: u8 = 2; + /// Order cancelled because it was evicted from the price-time + /// priority queue. + const CANCEL_REASON_EVICTION: u8 = 1; + /// Order cancelled because it was an immediate-or-cancel order + /// that did not immediately fill. + const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 2; + /// Order cancelled because it was manually cancelled by either + /// signing user or custodian. + const CANCEL_REASON_MANUAL_CANCEL: u8 = 3; + /// Order cancelled because no more quote asset could be traded. + const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 4; + /// Order cancelled because there was not enough liquidity to take + /// from. + const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 5; + /// Order cancelled because it was on the maker side of an fill + /// where self match behavior indicated cancelling the maker order. + const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 6; + /// Order cancelled because it was on the taker side of an fill + /// where self match behavior indicated cancelling the taker order. + const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 7; + /// Order cancelled because after matching across the spread the + /// remaining order size was too smal for the market. + const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8; /// Flag to cancel taker order only during a self match. const CANCEL_TAKER: u8 = 3; /// Flag for `MakerEvent.type` when order size is changed. @@ -858,74 +920,10 @@ module econia::market { /// Flag for passive order specified by advance in ticks. const TICKS: bool = false; - const CANCEL_REASON_MANUAL_CANCEL: u8 = 0; - const CANCEL_REASON_EVICTION: u8 = 1; - const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 2; - const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 3; - const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 4; - const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 5; - const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 6; - const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 7; - // Constants <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // View functions >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> - #[view] - /// Private view function to reduce runtime handle contention. - fun get_market_event_handle_creation_info( - market_id: u64 - ): Option - acquires MarketEventHandles { - let resource_account_address = resource_account::get_address(); - if (!exists(resource_account_address)) - return option::none(); - let market_event_handles_map_ref = - &borrow_global(resource_account_address).map; - let has_handles = table::contains( - market_event_handles_map_ref, market_id); - if (!has_handles) return option::none(); - let market_handles_ref = table::borrow( - market_event_handles_map_ref, market_id); - option::some(MarketEventHandleCreationInfo{ - resource_account_address: resource_account_address, - cancel_order_events_handle_creation_num: - guid::creation_num(event::guid( - &market_handles_ref.cancel_order_events)), - place_swap_order_events_handle_creation_num: - guid::creation_num(event::guid( - &market_handles_ref.place_swap_order_events)) - }) - } - - #[view] - /// Private view function to reduce runtime handle contention. - fun get_swapper_event_handle_creation_numbers( - swapper: address, - market_id: u64 - ): Option - acquires SwapperEventHandles { - if (!exists(swapper)) return option::none(); - let swapper_event_handles_map_ref = - &borrow_global(swapper).map; - let has_handles = table::contains( - swapper_event_handles_map_ref, market_id); - if (!has_handles) return option::none(); - let swapper_handles_ref = table::borrow( - swapper_event_handles_map_ref, market_id); - option::some(SwapperEventHandleCreationNumbers{ - cancel_order_events_handle_creation_num: - guid::creation_num(event::guid( - &swapper_handles_ref.cancel_order_events)), - fill_events_handle_creation_num: - guid::creation_num(event::guid( - &swapper_handles_ref.fill_events)), - place_swap_order_events_handle_creation_num: - guid::creation_num(event::guid( - &swapper_handles_ref.place_swap_order_events)) - }) - } - #[view] /// Return true if the order ID corresponds to an order that /// resulted in a post to the order book (including an order that @@ -1091,6 +1089,41 @@ module econia::market { /// * `test_get_TICKS()` public fun get_TICKS(): bool {TICKS} + #[view] + /// Return a `MarketEventHandleCreationInfo` for `market_id`, if + /// Econia resource account has event handles for indicated market. + /// + /// Restricted to private view function to prevent runtime handle + /// contention. + fun get_market_event_handle_creation_info( + market_id: u64 + ): Option + acquires MarketEventHandles { + // Return none if Econia resource account does not have market + // event handles map. + let resource_account_address = resource_account::get_address(); + if (!exists(resource_account_address)) + return option::none(); + // Return none if no handles exist for market. + let market_event_handles_map_ref = + &borrow_global(resource_account_address).map; + let has_handles = table::contains( + market_event_handles_map_ref, market_id); + if (!has_handles) return option::none(); + let market_handles_ref = table::borrow( + market_event_handles_map_ref, market_id); + // Return option-packed creation info for market. + option::some(MarketEventHandleCreationInfo{ + resource_account_address: resource_account_address, + cancel_order_events_handle_creation_num: + guid::creation_num(event::guid( + &market_handles_ref.cancel_order_events)), + place_swap_order_events_handle_creation_num: + guid::creation_num(event::guid( + &market_handles_ref.place_swap_order_events)) + }) + } + #[view] /// Return order counter encoded in market order ID. /// @@ -1129,33 +1162,6 @@ module econia::market { ((market_order_id & (HI_PRICE as u128)) as u64) } - #[view] - /// For an order that resulted in a post to the order book, return - /// the order side encoded in its order ID, corresponding to the - /// side that the maker portion of the order posted to the book at. - /// - /// # Aborts - /// - /// * `E_ORDER_DID_NOT_POST`: Order ID corresponds to an order that - /// did not post to the book. - /// - /// # Testing - /// - /// * `test_get_market_order_id_side_did_not_post()` - /// * `test_place_limit_order_no_cross_ask_user()` - /// * `test_place_limit_order_no_cross_bid_custodian()` - public fun get_posted_order_id_side( - order_id: u128 - ): bool { - // Assert order posted to the order book. - assert!(did_order_post(order_id), E_ORDER_DID_NOT_POST); - // Get AVL queue access key encoded in order ID. - let avlq_access_key = - get_order_id_avl_queue_access_key(order_id); - // If ascending AVL queue indicated is an ask, else a bid. - if (avl_queue::is_ascending_access_key(avlq_access_key)) ASK else BID - } - #[view] /// Return `OrderView` for `market_id` and `order_id`. /// @@ -1256,6 +1262,33 @@ module econia::market { get_open_orders(market_id, HI_64, HI_64) } + #[view] + /// For an order that resulted in a post to the order book, return + /// the order side encoded in its order ID, corresponding to the + /// side that the maker portion of the order posted to the book at. + /// + /// # Aborts + /// + /// * `E_ORDER_DID_NOT_POST`: Order ID corresponds to an order that + /// did not post to the book. + /// + /// # Testing + /// + /// * `test_get_market_order_id_side_did_not_post()` + /// * `test_place_limit_order_no_cross_ask_user()` + /// * `test_place_limit_order_no_cross_bid_custodian()` + public fun get_posted_order_id_side( + order_id: u128 + ): bool { + // Assert order posted to the order book. + assert!(did_order_post(order_id), E_ORDER_DID_NOT_POST); + // Get AVL queue access key encoded in order ID. + let avlq_access_key = + get_order_id_avl_queue_access_key(order_id); + // If ascending AVL queue indicated is an ask, else a bid. + if (avl_queue::is_ascending_access_key(avlq_access_key)) ASK else BID + } + #[view] /// Index order book for given market ID into price level vectors. /// @@ -1314,6 +1347,41 @@ module econia::market { get_price_levels(market_id, HI_64, HI_64) } + #[view] + /// Return a `SwapperEventHandleCreationNumbers` for `market_id`, if + /// signing `swapper` has event handles for indicated market. + /// + /// Restricted to private view function to prevent runtime handle + /// contention. + fun get_swapper_event_handle_creation_numbers( + swapper: address, + market_id: u64 + ): Option + acquires SwapperEventHandles { + // Return none if swapper does not have event handles map. + if (!exists(swapper)) return option::none(); + // Return none if no handles exist for market. + let swapper_event_handles_map_ref = + &borrow_global(swapper).map; + let has_handles = table::contains( + swapper_event_handles_map_ref, market_id); + if (!has_handles) return option::none(); + let swapper_handles_ref = table::borrow( + swapper_event_handles_map_ref, market_id); + // Return option-packed creation numbers for market. + option::some(SwapperEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: + guid::creation_num(event::guid( + &swapper_handles_ref.cancel_order_events)), + fill_events_handle_creation_num: + guid::creation_num(event::guid( + &swapper_handles_ref.fill_events)), + place_swap_order_events_handle_creation_num: + guid::creation_num(event::guid( + &swapper_handles_ref.place_swap_order_events)) + }) + } + #[view] /// Return `true` if `order_id` corresponds to open order for given /// `market_id`. @@ -1456,9 +1524,7 @@ module econia::market { u64, u64, u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_limit_order< BaseType, QuoteType @@ -1495,9 +1561,7 @@ module econia::market { target_advance_amount: u64, custodian_capability_ref: &CustodianCapability ): u128 - acquires - OrderBooks - { + acquires OrderBooks { place_limit_order_passive_advance< BaseType, QuoteType @@ -1538,9 +1602,7 @@ module econia::market { advance_style: bool, target_advance_amount: u64 ): u128 - acquires - OrderBooks - { + acquires OrderBooks { place_limit_order_passive_advance< BaseType, QuoteType @@ -1585,9 +1647,7 @@ module econia::market { u64, u64, u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_limit_order< BaseType, QuoteType @@ -1626,9 +1686,7 @@ module econia::market { u64, u64, u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_market_order( user_address, market_id, @@ -1660,9 +1718,7 @@ module econia::market { u64, u64, u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_market_order( address_of(user), market_id, @@ -1807,6 +1863,14 @@ module econia::market { /// * `u64`: Quote coin trade amount, same as for `match()`. /// * `u64`: Quote coin fees paid, same as for `match()`. /// + /// # Emits + /// + /// * `PlaceSwapOrderEvent`: Information about the swap order. + /// * `user::FillEvent`(s): Information about fill(s) associated + /// with the swap. + /// * `user::CancelOrderEvent`: Optionally, information about why + /// the swap was cancelled without completely filling. + /// /// # Testing /// /// * `test_swap_between_coinstores_max_possible_base_buy()` @@ -1868,10 +1932,8 @@ module econia::market { // If a sell, need max base but not quote. (option::some(coin::withdraw(user, max_base)), coin::zero()); + // Swap against the order book, saving fill events. let fill_event_queue = vector[]; - // Swap against order book, storing optionally modified coin - // inputs, base and quote trade amounts, quote fees paid, and - // place swap order event. let ( optional_base_coins, quote_coins, @@ -2041,23 +2103,30 @@ module econia::market { range_check_trade( // Range check trade amounts. direction, min_base, max_base, min_quote, max_quote, base_value, base_value, quote_value, quote_value); - // Swap against order book, storing optionally modified coin - // inputs, base and quote trade amounts, and quote fees paid. - let (optional_base_coins, quote_coins_matched, base_traded, - quote_traded, fees, _, _) = swap( - &mut vector[], - NO_TAKER_ADDRESS, - market_id, - NO_UNDERWRITER, - integrator, - direction, - min_base, - max_base, - min_quote, - max_quote, - limit_price, - optional_base_coins, - quote_coins_to_match); + // Swap against order book, discarding events. + let ( + optional_base_coins, + quote_coins_matched, + base_traded, + quote_traded, + fees, + _, + _ + ) = swap( + &mut vector[], + NO_TAKER_ADDRESS, + market_id, + NO_UNDERWRITER, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + optional_base_coins, + quote_coins_to_match + ); // Merge matched quote coins back into holdings. coin::merge(&mut quote_coins, quote_coins_matched); // Get base coins from option. @@ -2155,23 +2224,30 @@ module econia::market { range_check_trade( // Range check trade amounts. direction, min_base, max_base, min_quote, max_quote, base_value, base_value, quote_value, quote_value); - // Swap against order book, storing optionally modified quote - // coin input, base and quote trade amounts, quote fees paid. - let (optional_base_coins, quote_coins_matched, base_traded, - quote_traded, fees, _, _) = swap( - &mut vector[], - NO_TAKER_ADDRESS, - market_id, - underwriter_id, - integrator, - direction, - min_base, - max_base, - min_quote, - max_quote, - limit_price, - option::none(), - quote_coins_to_match); + // Swap against order book, discarding events. + let ( + optional_base_coins, + quote_coins_matched, + base_traded, + quote_traded, + fees, + _, + _ + ) = swap( + &mut vector[], + NO_TAKER_ADDRESS, + market_id, + underwriter_id, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + option::none(), + quote_coins_to_match + ); // Destroy empty base coin option. option::destroy_none>(optional_base_coins); // Merge matched quote coins back into holdings. @@ -2262,9 +2338,7 @@ module econia::market { size: u64, advance_style: bool, target_advance_amount: u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_limit_order_passive_advance_user< BaseType, QuoteType @@ -2295,9 +2369,7 @@ module econia::market { price: u64, restriction: u8, self_match_behavior: u8 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_limit_order_user( user, market_id, integrator, side, size, price, restriction, self_match_behavior); @@ -2318,9 +2390,7 @@ module econia::market { direction: bool, size: u64, self_match_behavior: u8 - ) acquires - OrderBooks - { + ) acquires OrderBooks { place_market_order_user( user, market_id, integrator, direction, size, self_match_behavior); } @@ -2440,10 +2510,6 @@ module econia::market { /// * `E_INVALID_CUSTODIAN`: Mismatch between `custodian_id` and /// custodian ID of order on order book having market order ID. /// - /// # Emits - /// - /// * `MakerEvent`: Information about the maker order cancelled. - /// /// # Expected value testing /// /// * `test_cancel_order_ask_custodian()` @@ -2527,10 +2593,6 @@ module econia::market { /// * `E_INVALID_CUSTODIAN`: Mismatch between `custodian_id` and /// custodian ID of order on order book having market order ID. /// - /// # Emits - /// - /// * `MakerEvent`: Information about the changed maker order. - /// /// # Expected value testing /// /// * `test_change_order_size_ask_custodian()` @@ -2619,6 +2681,22 @@ module econia::market { }; } + /// Get optional cancel reason for market order or swap. + /// + /// # Parameters + /// + /// * `self_match_taker_cancel`: If matching resulted in cancelling + /// the taker side of an order due to a self match. + /// * `base_traded`: The amount of base assets traded. + /// * `max_base`: The maximum indicated amount of base assets to + /// match. + /// * `liquidity_gone`: If the matching engine halted due to + /// insufficient liquidity. + /// + /// # Returns + /// + /// * `Option`: An optional cancel reason, if the order needs + /// to be cancelled. inline fun get_cancel_reason_option_for_market_order_or_swap( self_match_taker_cancel: bool, base_traded: u64, @@ -2640,17 +2718,6 @@ module econia::market { } } - /// Get AVL queue access key encoded in `order_id`. - /// - /// # Testing - /// - /// * `test_get_market_order_id_avl_queue_access_key()` - inline fun get_order_id_avl_queue_access_key( - order_id: u128 - ): u64 { - ((order_id & (HI_64 as u128)) as u64) - } - /// Index specified number of open orders for given side of order /// book. /// @@ -2685,6 +2752,17 @@ module econia::market { orders // Return vector of view-friendly orders. } + /// Get AVL queue access key encoded in `order_id`. + /// + /// # Testing + /// + /// * `test_get_market_order_id_avl_queue_access_key()` + inline fun get_order_id_avl_queue_access_key( + order_id: u128 + ): u64 { + ((order_id & (HI_64 as u128)) as u64) + } + /// Index specified number of price levels for given side of order /// book. /// @@ -2762,14 +2840,8 @@ module econia::market { /// # Parameters /// /// * `market_id`: Market ID of market. - /// * `resource_address`: Address of resource account where order - /// books and fill event handles are stored. - /// * `fill_event_queue_option_ref_mut`: Mutable reference to - /// optional queue for `FillEvent`s, used to defer event emission - /// for limit orders: if a limit order fills across the spread - /// before posting to the order book, the market order ID requires - /// an encoded AVL queue access key that is not known at the time - /// of fills. + /// * `fill_event_queue_ref_mut`: Mutable reference to vector for + /// enqueueing deferred `FillEvent`(s). /// * `order_book_ref_mut`: Mutable reference to market order book. /// * `taker`: Address of taker whose order is matched. Passed as /// `NO_TAKER_ADDRESS` when taker order originates from a swap @@ -2825,11 +2897,6 @@ module econia::market { /// * `bool`: `true` if liquidity is gone from order book on /// corresponding side after matching. /// - /// # Emits - /// - /// * `FillEvent`: Information about a fill, emitted for each fill, - /// when fill events are not marked for deferral. - /// /// # Aborts /// /// * `E_PRICE_TOO_HIGH`: Order price exceeds maximum allowable @@ -2873,7 +2940,7 @@ module econia::market { QuoteType >( market_id: u64, - event_queue_ref_mut: &mut vector, + fill_event_queue_ref_mut: &mut vector, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -2918,10 +2985,10 @@ module econia::market { // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; - // Increment order counter. + // Increment order book counter before any potential fills. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; - let fill_count = 0; - let fees_paid = 0; + // Initialize counters for fill iteration. + let (fill_count, fees_paid) = (0, 0); // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -2992,15 +3059,15 @@ module econia::market { // Break out of loop if a self match taker cancel. if (self_match_taker_cancel) break; } else { // If not a self match: - // Get ticks filled. + // Get ticks, quote filled. let ticks_filled = fill_size * price; + let quote_filled = ticks_filled * tick_size; // Decrement counter for lots to fill until max reached. lots_until_max = lots_until_max - fill_size; // Decrement counter for ticks to fill until max. ticks_until_max = ticks_until_max - ticks_filled; // Declare return assignment variable. let market_order_id; - let quote_filled = ticks_filled * tick_size; // Fill matched order user side, store market order ID. (optional_base_coins, quote_coins, market_order_id) = user::fill_order_internal( @@ -3008,24 +3075,18 @@ module econia::market { order_ref_mut.order_access_key, order_ref_mut.size, fill_size, complete_fill, optional_base_coins, quote_coins, fill_size * lot_size, quote_filled); + // Enqueue a fill event with the amount of fees paid. let fees_paid_for_fill = quote_filled / taker_fee_divisor; - vector::push_back( - event_queue_ref_mut, user::create_fill_event_internal( - market_id, - fill_size, - price, - side, - maker, - maker_custodian_id, - market_order_id, - taker, - custodian_id, - order_id_no_post(order_book_ref_mut.counter), - fees_paid_for_fill, - fill_count - )); + let fill_event = user::create_fill_event_internal( + market_id, fill_size, price, side, maker, + maker_custodian_id, market_order_id, taker, custodian_id, + order_id_no_post(order_book_ref_mut.counter), + fees_paid_for_fill, fill_count); + vector::push_back(fill_event_queue_ref_mut, fill_event); + // Update fill iteration counters. fill_count = fill_count + 1; fees_paid = fees_paid + fees_paid_for_fill; + // If order on book completely filled: if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -3045,6 +3106,7 @@ module econia::market { let (base_fill, quote_fill) = // Calculate base and quote fills. (((max_lots - lots_until_max ) * lot_size), ((max_ticks - ticks_until_max) * tick_size)); + // Assess taker fees. let (quote_coins, _) = incentives::assess_taker_fees( market_id, integrator, taker_fee_divisor, fees_paid * taker_fee_divisor, quote_coins); @@ -3057,8 +3119,8 @@ module econia::market { assert!(base_fill >= min_base, E_MIN_BASE_NOT_TRADED); // Assert minimum quote coin trade amount met. assert!(quote_traded >= min_quote, E_MIN_QUOTE_NOT_TRADED); - // Return optional base coin, quote coins, trade amounts, and - // self match taker cancel flag. + // Return optional base coin, quote coins, trade amounts, + // self match taker cancel flag, and if liquidity is gone. (optional_base_coins, quote_coins, base_fill, quote_traded, fees_paid, self_match_taker_cancel, avl_queue::is_empty(orders_ref_mut)) } @@ -3098,8 +3160,7 @@ module econia::market { /// /// # Returns /// - /// * `u128`: Order ID assigned if limit order took and/or posted on - /// book, else `NIL`. + /// * `u128`: Order ID assigned to order, unique within a market. /// * `u64`: Base asset trade amount as a taker, same as for /// `match()`, if order fills across the spread. /// * `u64`: Quote asset trade amount as a taker, same as for @@ -3132,16 +3193,6 @@ module econia::market { /// price-time priority if inserted to AVL queue, but AVL queue /// does not have room for any more orders. /// - /// # Emits - /// - /// * `FillEvent`: Information about the portion of the order that - /// fills as a taker, if the order fills across the spread. - /// * `MakerEvent`: Information about the user's maker order placed - /// on the order book, if one was placed. - /// * `MakerEvent`: Information about the maker order evicted from - /// the order book, if required to fit user's maker order on the - /// book. - /// /// # Restrictions /// /// * A post-or-abort order aborts if its price crosses the spread. @@ -3161,7 +3212,7 @@ module econia::market { /// # Self matching /// /// Fills up until the point of a self match, cancelling remaining - /// size without posting as a maker if: + /// size without posting if: /// /// 1. Price crosses the spread, /// 2. Cross-spread filling is permitted per the indicated @@ -3217,9 +3268,7 @@ module econia::market { u64, u64, u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { // Assert valid order restriction flag. assert!(restriction <= N_RESTRICTIONS, E_INVALID_RESTRICTION); assert!(price != 0, E_PRICE_0); // Assert nonzero price. @@ -3307,11 +3356,11 @@ module econia::market { direction, min_base, max_base, min_quote, max_quote, base_available, base_ceiling, quote_available, quote_ceiling); // Assume no assets traded as a taker. - let (base_traded, quote_traded, fees, fill_event_queue) = - (0, 0, 0, vector[]); + let (base_traded, quote_traded, fees) = (0, 0, 0); let cancel_reason_option = option::none(); + let fill_event_queue = vector[]; let remaining_size = size; - if (crosses_spread) { + if (crosses_spread) { // If order price crosses spread: // Calculate max base and quote to withdraw. If a buy: let (base_withdraw, quote_withdraw) = if (direction == BUY) // Withdraw quote to buy base, else sell base for quote. @@ -3322,19 +3371,16 @@ module econia::market { user::withdraw_assets_internal( user_address, market_id, custodian_id, base_withdraw, quote_withdraw, underwriter_id); - // Declare return assignment variables. - let self_match_taker_cancel; - // Match against order book, storing optionally modified - // asset inputs, base and quote trade amounts, quote fees - // paid, and if a self match requires canceling the rest of - // the order. (Increments order book counter). + // Declare return assignment variable. + let self_match_cancel; + // Match against order book. ( optional_base_coins, quote_coins, base_traded, quote_traded, fees, - self_match_taker_cancel, + self_match_cancel, _, ) = match( market_id, @@ -3369,9 +3415,11 @@ module econia::market { !avl_queue::would_update_head(&order_book_ref_mut.bids, price) else !avl_queue::would_update_head(&order_book_ref_mut.asks, price); + // Remaining size is amount not traded during matching. remaining_size = size - (base_traded / order_book_ref_mut.lot_size); - if (self_match_taker_cancel) { + // Get optional order cancel reason. + if (self_match_cancel) { option::fill(&mut cancel_reason_option, CANCEL_REASON_SELF_MATCH_TAKER); } else if ((remaining_size > 0) && @@ -3388,14 +3436,17 @@ module econia::market { } }; } else { // If spread not crossed (matching engine not called): + // Order book counter needs to be updated for new order ID. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + // Order neeeds to be cancelled if no fills took place. if (restriction == IMMEDIATE_OR_CANCEL) { option::fill(&mut cancel_reason_option, CANCEL_REASON_IMMEDIATE_OR_CANCEL); }; }; + // Assume that limit order will not post. let market_order_id = order_id_no_post(order_book_ref_mut.counter); - // If order still eligible to post: + // If order eligible to post: if (option::is_none(&cancel_reason_option)) { // Get next order access key for user-side order placement. let order_access_key = user::get_next_order_access_key_internal( @@ -3404,13 +3455,8 @@ module econia::market { let orders_ref_mut = if (side == ASK) &mut order_book_ref_mut.asks else &mut order_book_ref_mut.bids; // Declare order to insert to book. - let order = Order{ - size: remaining_size, - price, - user: user_address, - custodian_id, - order_access_key - }; + let order = Order{size: remaining_size, price, user: user_address, + custodian_id, order_access_key}; // Get new AVL queue access key, evictee access key, and evictee // value by attempting to insert for given critical height. let (avlq_access_key, evictee_access_key, evictee_value) = @@ -3436,23 +3482,14 @@ module econia::market { order_access_key, (NIL as u128), CANCEL_REASON_EVICTION); }; } else { + // If not eligible to post, no remaining size. remaining_size = 0; }; + // Emit relevant events to user event handles. user::emit_limit_order_events_internal( - market_id, - user_address, - custodian_id, - integrator, - side, - size, - price, - restriction, - self_match_behavior, - remaining_size, - market_order_id, - &fill_event_queue, - &cancel_reason_option - ); + market_id, user_address, custodian_id, integrator, side, size, + price, restriction, self_match_behavior, remaining_size, + market_order_id, &fill_event_queue, &cancel_reason_option); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } @@ -3554,9 +3591,7 @@ module econia::market { advance_style: bool, target_advance_amount: u64 ): u128 - acquires - OrderBooks - { + acquires OrderBooks { // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); let order_books_map_ref = // Immutably borrow order books map. @@ -3711,9 +3746,7 @@ module econia::market { u64, u64, u64 - ) acquires - OrderBooks - { + ) acquires OrderBooks { // Get user's available and ceiling asset counts. let (_, base_available, base_ceiling, _, quote_available, quote_ceiling) = user::get_asset_counts_internal( @@ -3762,6 +3795,7 @@ module econia::market { // Calculate limit price for matching engine: 0 when selling, // max price possible when buying. let limit_price = if (direction == SELL) 0 else HI_PRICE; + // Match against order book, deferring fill events. let fill_event_queue = vector[]; let ( optional_base_coins, @@ -3788,6 +3822,7 @@ module econia::market { optional_base_coins, quote_coins ); + // Get order ID from order book counter updated during matching. let market_order_id = order_id_no_post(order_book_ref_mut.counter); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else @@ -3796,22 +3831,16 @@ module econia::market { user::deposit_assets_internal( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); + // Get optional cancel reason. let cancel_reason_option = get_cancel_reason_option_for_market_order_or_swap( self_match_taker_cancel, base_traded, max_base, liquidity_gone); + // Emit relevant events to user event handles. user::emit_market_order_events_internal( - market_id, - user_address, - custodian_id, - integrator, - direction, - size, - self_match_behavior, - market_order_id, - &fill_event_queue, - &cancel_reason_option - ); + market_id, user_address, custodian_id, integrator, direction, size, + self_match_behavior, market_order_id, &fill_event_queue, + &cancel_reason_option); // Return base and quote traded by user, fees paid. (base_traded, quote_traded, fees) } @@ -3991,6 +4020,8 @@ module econia::market { /// /// # Parameters /// + /// * `fill_event_queue_ref_mut`: Mutable reference to vector for + /// enqueueing deferred `FillEvent`(s). /// * `signer_address`: Address of signing user if applicable, else /// `NO_TAKER_ADDRESS`. /// * `market_id`: Same as for `match()`. @@ -4016,6 +4047,18 @@ module econia::market { /// * `u64`: Base asset trade amount, same as for `match()`. /// * `u64`: Quote coin trade amount, same as for `match()`. /// * `u64`: Quote coin fees paid, same as for `match()`. + /// * `Option`: `PlaceSwapOrderEvent` to emit + /// if swap is from a signing swapper. + /// * `Option`: Optional `CancelOrderEvent` to + /// emit if swap is from a signing swapper. + /// + /// # Emits + /// + /// * `PlaceSwapOrderEvent`: Information about swap order, emitted + /// when swap is from a non-signing swapper. + /// * `CancelOrderEvent`: Information about order cancellation, if + /// order was cancelled without completely filling, when swap is + /// from non-signing swapper. /// /// # Aborts /// @@ -4081,6 +4124,7 @@ module econia::market { == order_book_ref_mut.base_type, E_INVALID_BASE); assert!(type_info::type_of() // Assert quote type. == order_book_ref_mut.quote_type, E_INVALID_QUOTE); + // Match against order book, deferring fill events. let ( optional_base_coins, quote_coins, @@ -4089,7 +4133,7 @@ module econia::market { fees, self_match_taker_cancel, liquidity_gone - ) = match( // Match against order book. + ) = match( market_id, fill_event_queue_ref_mut, order_book_ref_mut, @@ -4106,6 +4150,7 @@ module econia::market { optional_base_coins, quote_coins ); + // Get order ID from order book counter updated during matching. let market_order_id = order_id_no_post(order_book_ref_mut.counter); // Create market event handles for market as needed. if (!exists(resource_address)) @@ -4128,6 +4173,7 @@ module econia::market { }; let handles_ref_mut = table::borrow_mut(market_event_handles_map_ref_mut, market_id); + // Create market events as necessary. let place_swap_order_event = PlaceSwapOrderEvent{ market_id, signing_account: signer_address, @@ -4147,24 +4193,21 @@ module econia::market { let need_to_cancel = option::is_some(&cancel_reason_option); let cancel_order_event_option = if (need_to_cancel) option::some(user::create_cancel_order_event_internal( - market_id, - market_order_id, - signer_address, - NO_CUSTODIAN, - option::destroy_some(cancel_reason_option) - )) else option::none(); - // Get place swap order, cancel order event options to return: - let (place_swap_order_event_option, cancel_order_event_option) = - // If swap not placed by a signing swapper: - if (signer_address == NO_TAKER_ADDRESS) { + market_id, market_order_id, signer_address, NO_CUSTODIAN, + option::destroy_some(cancel_reason_option))) else + option::none(); + // Assume do not need to return place swap order event. + let place_swap_order_event_option = option::none(); + // If swap not placed by a signing swapper: + if (signer_address == NO_TAKER_ADDRESS) { event::emit_event(&mut handles_ref_mut.place_swap_order_events, place_swap_order_event); if (need_to_cancel) event::emit_event( &mut handles_ref_mut.cancel_order_events, - option::destroy_some(cancel_order_event_option)); - (option::none(), option::none()) + option::extract(&mut cancel_order_event_option)); } else { // Otherwise swap order placed by signing swapper. - (option::some(place_swap_order_event), cancel_order_event_option) + option::fill(&mut place_swap_order_event_option, + place_swap_order_event); }; user::emit_swap_maker_fill_events_internal(fill_event_queue_ref_mut); // Return optionally modified asset inputs, trade amounts, fees, From 35f85961ac8ea60f6bd865783bd769182a3e4e98 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:29:37 -0700 Subject: [PATCH 43/56] Remove needles acquires diffs, tweak comments --- src/move/econia/sources/market.move | 320 ++++++++-------------------- src/move/econia/sources/user.move | 8 +- 2 files changed, 89 insertions(+), 239 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 3d037a66b..f09bdde33 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -1866,10 +1866,10 @@ module econia::market { /// # Emits /// /// * `PlaceSwapOrderEvent`: Information about the swap order. - /// * `user::FillEvent`(s): Information about fill(s) associated - /// with the swap. - /// * `user::CancelOrderEvent`: Optionally, information about why - /// the swap was cancelled without completely filling. + /// * `FillEvent`(s): Information about fill(s) associated with the + /// swap. + /// * `CancelOrderEvent`: Optionally, information about why the swap + /// was cancelled without completely filling. /// /// # Testing /// @@ -1932,7 +1932,7 @@ module econia::market { // If a sell, need max base but not quote. (option::some(coin::withdraw(user, max_base)), coin::zero()); - // Swap against the order book, saving fill events. + // Swap against the order book, deferring market events. let fill_event_queue = vector[]; let ( optional_base_coins, @@ -3373,7 +3373,7 @@ module econia::market { quote_withdraw, underwriter_id); // Declare return assignment variable. let self_match_cancel; - // Match against order book. + // Match against order book, deferring fill events. ( optional_base_coins, quote_coins, @@ -4211,7 +4211,7 @@ module econia::market { }; user::emit_swap_maker_fill_events_internal(fill_event_queue_ref_mut); // Return optionally modified asset inputs, trade amounts, fees, - // and place swap order event. + // place swap order event option, and cancel order event option. (optional_base_coins, quote_coins, base_traded, quote_traded, fees, place_swap_order_event_option, cancel_order_event_option) } @@ -4299,9 +4299,7 @@ module econia::market { max_bid_price: u64, min_ask_price: u64 ): signer - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); let user_address = address_of(&user); // Get user address. @@ -4381,9 +4379,7 @@ module econia::market { public fun init_markets_users_integrator_test(): ( signer, signer - ) acquires - OrderBooks - { + ) acquires OrderBooks { init_test(); // Init for testing. // Get market registration fee. let fee = incentives::get_market_registration_fee(); @@ -4537,9 +4533,7 @@ module econia::market { /// Verify state updates for cancelling three asks under authority /// of custodian. fun test_cancel_all_orders_ask_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4599,9 +4593,7 @@ module econia::market { /// Verify state updates for cancelling three bids under authority /// of signing user. fun test_cancel_all_orders_bid_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4657,9 +4649,7 @@ module econia::market { /// Verify state updates for cancelling ask under authority of /// custodian. fun test_cancel_order_ask_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4736,9 +4726,7 @@ module econia::market { /// Verify state updates for cancelling bid under authority of /// signing user. fun test_cancel_order_bid_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4810,9 +4798,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_CUSTODIAN)] /// Verify failure for invalid custodian. fun test_cancel_order_invalid_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4853,9 +4839,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_cancel_order_invalid_market_id() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4870,9 +4854,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid bogus market order ID. fun test_cancel_order_invalid_market_order_id_bogus() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4887,9 +4869,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid market order ID passed as `NIL`. fun test_cancel_order_invalid_market_order_id_null() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -4904,9 +4884,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_USER)] /// Verify failure for invalid user. fun test_cancel_order_invalid_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, attacker) = init_markets_users_integrator_test(); // Declare order parameters. @@ -4963,9 +4941,7 @@ module econia::market { /// Verify state updates for changing ask under authority of /// custodian, for size increase at tail of price level queue. fun test_change_order_size_ask_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5110,9 +5086,7 @@ module econia::market { /// Verify state updates for changing bid under authority of signing /// user, for size decrease at tail of queue. fun test_change_order_size_bid_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5209,9 +5183,7 @@ module econia::market { /// Verify state updates for changing bid under authority of signing /// user, for size increase not at tail of queue. fun test_change_order_size_bid_user_new_tail() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5300,9 +5272,7 @@ module econia::market { /// queue access key mismatch. Based on /// `test_change_order_size_bid_user_new_tail`. fun test_change_order_size_insertion_error() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5363,9 +5333,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_CUSTODIAN)] /// Verify failure for invalid custodian. fun test_change_order_size_invalid_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5407,9 +5375,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_change_order_size_invalid_market_id() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -5425,9 +5391,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid bogus market order ID. fun test_change_order_size_invalid_market_order_id_bogus() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -5443,9 +5407,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ORDER_ID)] /// Verify failure for invalid market order ID passed as `NIL`. fun test_change_order_size_invalid_market_order_id_null() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare order change parameters. @@ -5461,9 +5423,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_USER)] /// Verify failure for invalid user. fun test_change_order_size_invalid_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, attacker) = init_markets_users_integrator_test(); // Declare order parameters. @@ -5650,10 +5610,7 @@ module econia::market { #[test] /// Verify indexing results. - fun test_get_open_orders() - acquires - OrderBooks - { + fun test_get_open_orders() acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare common order parameters. @@ -5779,10 +5736,7 @@ module econia::market { #[test] /// Verify indexing results. - fun test_get_price_levels() - acquires - OrderBooks - { + fun test_get_price_levels() acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, _) = init_markets_users_integrator_test(); // Declare common order parameters. @@ -7116,9 +7070,7 @@ module econia::market { #[expected_failure(abort_code = E_SELF_MATCH)] /// Verify failure for self match with abort behavior. fun test_match_self_match_abort() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare common market parameters. @@ -7163,9 +7115,7 @@ module econia::market { /// the order at the lower price. Here, matching halts after the /// self match. fun test_match_self_match_cancel_both() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7275,9 +7225,7 @@ module econia::market { /// the order at the lower price. Here, matching continues against /// the order at the higher price. fun test_match_self_match_cancel_maker() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7411,9 +7359,7 @@ module econia::market { /// the order at the lower price. Here, matching halts after the /// self match. fun test_match_self_match_cancel_taker() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7527,9 +7473,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_SELF_MATCH_BEHAVIOR)] /// Verify failure for self match with invalid abort behavior. fun test_match_self_match_invalid() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare common market parameters. @@ -7568,9 +7512,7 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_BASE_OVERFLOW)] /// Verify failure for base overflow. fun test_place_limit_order_base_overflow() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = HI_64 / LOT_SIZE_COIN + 1; @@ -7590,9 +7532,7 @@ module econia::market { /// completely and exactly across the spread, under authority of /// signing user. fun test_place_limit_order_crosses_ask_exact() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7697,9 +7637,7 @@ module econia::market { /// partially across the spread, under authority of signing user. /// Based on `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_ask_partial() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7811,9 +7749,7 @@ module econia::market { /// signing user. Based on /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_partial_cancel() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -7891,9 +7827,7 @@ module econia::market { /// with taker cancellation. Based on /// `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_ask_self_match_cancel() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -7964,9 +7898,7 @@ module econia::market { /// signing user. Mirror of /// `test_place_limit_order_crosses_ask_exact()`. fun test_place_limit_order_crosses_bid_exact() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -8071,9 +8003,7 @@ module econia::market { /// partially across the spread, under authority of signing user. /// Mirror of `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_crosses_bid_partial() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -8185,9 +8115,7 @@ module econia::market { /// enough remaining size to meet minimum size requirement. Based on /// `test_place_limit_order_crosses_bid_partial()`. fun test_place_limit_order_crosses_bid_partial_cancel() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -8285,9 +8213,7 @@ module econia::market { /// Verify state updates, returns, for placing limit order that /// evicts another user's order. fun test_place_limit_order_evict() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8405,9 +8331,7 @@ module econia::market { #[expected_failure(abort_code = E_FILL_OR_ABORT_NOT_CROSS_SPREAD)] /// Verify failure for not crossing spread when fill-or-abort. fun test_place_limit_order_fill_or_abort_not_cross() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -8432,9 +8356,7 @@ module econia::market { /// Verify failure for not filling completely across spread when /// fill-or-abort. fun test_place_limit_order_fill_or_abort_partial() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8466,9 +8388,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type argument. fun test_place_limit_order_invalid_base() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -8492,9 +8412,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type argument. fun test_place_limit_order_invalid_quote() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -8518,9 +8436,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_RESTRICTION)] /// Verify failure for invalid restriction. fun test_place_limit_order_invalid_restriction() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = 123; @@ -8537,9 +8453,7 @@ module econia::market { /// Verify state updates, returns, for placing ask that does not /// cross the spread, under authority of signing user. fun test_place_limit_order_no_cross_ask_user() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -8621,9 +8535,7 @@ module econia::market { /// Verify state updates, returns, for placing bid that does not /// cross the spread, under authority of custodian. fun test_place_limit_order_no_cross_bid_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = BID; let size = MIN_SIZE_COIN; @@ -8706,9 +8618,7 @@ module econia::market { #[expected_failure(abort_code = E_PRICE_0)] /// Verify failure for invalid price. fun test_place_limit_order_no_price() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = 123; @@ -8725,9 +8635,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type argument. fun test_place_limit_order_passive_advance_invalid_base() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8747,9 +8655,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_MARKET_ID)] /// Verify failure for invalid market ID. fun test_place_limit_order_passive_advance_invalid_market_id() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8769,9 +8675,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_PERCENT)] /// Verify failure for invalid percent fun test_place_limit_order_passive_advance_invalid_percent() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = 201; @@ -8793,9 +8697,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type argument. fun test_place_limit_order_passive_advance_invalid_quote() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8814,9 +8716,7 @@ module econia::market { #[test] /// Verify return for no cross price when placing an ask. fun test_place_limit_order_passive_advance_no_cross_price_ask() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = NIL; let min_ask_price = 201; @@ -8839,9 +8739,7 @@ module econia::market { #[test] /// Verify return for no cross price when placing a bid. fun test_place_limit_order_passive_advance_no_cross_price_bid() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = NIL; @@ -8864,9 +8762,7 @@ module econia::market { #[test] /// Verify returns, state updates for full advance is start price. fun test_place_limit_order_passive_advance_no_full_advance() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = 101; @@ -8894,9 +8790,7 @@ module econia::market { #[test] /// Verify returns for no start price. fun test_place_limit_order_passive_advance_no_start_price() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user, _) = init_markets_users_integrator_test(); // Declare order parameters. @@ -8923,9 +8817,7 @@ module econia::market { #[test] /// Verify returns, state updates for no target advance amount. fun test_place_limit_order_passive_advance_no_target_advance() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = 201; @@ -8952,9 +8844,7 @@ module econia::market { #[test] /// Verify returns, state updates for percent-specified asks. fun test_place_limit_order_passive_advance_percent_ask() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 99; let min_ask_price = 500; @@ -8985,9 +8875,7 @@ module econia::market { #[test] /// Verify returns, state updates for percent-specified bids. fun test_place_limit_order_passive_advance_percent_bid() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = 501; @@ -9018,9 +8906,7 @@ module econia::market { #[test] /// Verify returns, state updates for ticks-specified asks. fun test_place_limit_order_passive_advance_ticks_ask() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = 500; @@ -9069,9 +8955,7 @@ module econia::market { /// Verify returns, state updates for ticks-specified bid, for /// delegated custodian. fun test_place_limit_order_passive_advance_ticks_bid() - acquires - OrderBooks - { + acquires OrderBooks { // Configure spread. let max_bid_price = 100; let min_ask_price = 500; @@ -9122,9 +9006,7 @@ module econia::market { #[expected_failure(abort_code = E_POST_OR_ABORT_CROSSES_SPREAD)] /// Verify failure for not crossing spread as post-or-abort. fun test_place_limit_order_post_or_abort_crosses() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -9156,9 +9038,7 @@ module econia::market { #[expected_failure(abort_code = E_PRICE_TOO_HIGH)] /// Verify failure for invalid price. fun test_place_limit_order_price_hi() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = 123; @@ -9176,9 +9056,7 @@ module econia::market { /// Verify failure for unable to insert to AVL queue. Modeled off /// `test_place_limit_order_evict()`. fun test_place_limit_order_price_time_priority_low() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Declare order parameters. @@ -9225,9 +9103,7 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_PRICE_QUOTE_OVERFLOW)] /// Verify failure for quote overflow. fun test_place_limit_order_quote_overflow() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = HI_64 / LOT_SIZE_COIN; @@ -9246,9 +9122,7 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_TOO_SMALL)] /// Verify failure for invalid size. fun test_place_limit_order_size_lo() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN - 1; @@ -9273,9 +9147,7 @@ module econia::market { /// the spread after matching as a taker, under authority of signing /// user. Based on `test_place_limit_order_crosses_ask_partial()`. fun test_place_limit_order_still_crosses_ask() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, taker) = init_markets_users_integrator_test(); let (maker_address, taker_address) = // Get user addresses. @@ -9394,9 +9266,7 @@ module econia::market { /// the spread after matching as a taker, under authority of signing /// user. Based on `test_place_limit_order_still_crosses_ask()`. fun test_place_limit_order_still_crosses_bid() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (maker, taker) = init_markets_users_integrator_test(); let (maker_address, taker_address) = // Get user addresses. @@ -9511,9 +9381,7 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_PRICE_TICKS_OVERFLOW)] /// Verify failure for ticks overflow. fun test_place_limit_order_ticks_overflow() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = HI_64 / LOT_SIZE_COIN; @@ -9532,9 +9400,7 @@ module econia::market { /// Verify state updates for public entry wrapper invocation. Based /// on `test_place_limit_order_no_cross_ask_user()`. fun test_place_limit_order_user_entry() - acquires - OrderBooks - { + acquires OrderBooks { // Declare order parameters. let side = ASK; let size = MIN_SIZE_COIN; @@ -9595,9 +9461,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_BASE)] /// Verify failure for invalid base type argument. fun test_place_market_order_invalid_base() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare order arguments. @@ -9618,9 +9482,7 @@ module econia::market { #[expected_failure(abort_code = E_INVALID_QUOTE)] /// Verify failure for invalid quote type argument. fun test_place_market_order_invalid_quote() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare order arguments. @@ -9641,9 +9503,7 @@ module econia::market { #[expected_failure(abort_code = E_SIZE_TOO_SMALL)] /// Verify failure for invalid size argument. fun test_place_market_order_size_too_small() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. init_markets_users_integrator_test(); // Declare order arguments. @@ -9665,9 +9525,7 @@ module econia::market { /// base trade amount that is less than max possible, under /// authority of signing user. fun test_place_market_order_max_base_adjust_buy_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9772,9 +9630,7 @@ module econia::market { /// max possible base trade amount, under authority of signing /// user. fun test_place_market_order_max_base_buy_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9877,9 +9733,7 @@ module econia::market { /// Verify state updates, returns for market sell when max possible /// base trade amount specified, under authority of custodian. fun test_place_market_order_max_base_sell_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -9986,9 +9840,7 @@ module econia::market { /// Verify state updates, returns for market buy when max possible /// quote trade amount specified, under authority of custodian. fun test_place_market_order_max_quote_buy_custodian() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, _) = init_markets_users_integrator_test(); // Get fee divisors. @@ -10094,9 +9946,7 @@ module econia::market { /// Verify state updates, returns for market sell when max possible /// quote trade amount specified, under authority of signing user. fun test_place_market_order_max_quote_sell_user() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -10198,9 +10048,7 @@ module econia::market { /// Verify state updates for public entry wrapper invocation. Based /// on `test_place_market_order_max_base_buy_user()`. fun test_place_market_order_user_entry() - acquires - OrderBooks - { + acquires OrderBooks { // Initialize markets, users, and an integrator. let (user_0, user_1) = init_markets_users_integrator_test(); // Get fee divisors. @@ -10460,9 +10308,7 @@ module econia::market { /// 2. Registering generic market. /// 3. Registering pure coin market, not from coin store. fun test_register_markets() - acquires - OrderBooks - { + acquires OrderBooks { init_test(); // Init for testing. // Get market registration fee, denominated in utility coins. let fee = incentives::get_market_registration_fee(); diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 7a90ef52d..74684ca0e 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -546,7 +546,7 @@ module econia::user { order_id: u128 } - /// Emitted when a limit order is placed. + /// Emitted when a market order is placed. struct PlaceMarketOrderEvent has copy, drop, store { /// Market ID for order. market_id: u64, @@ -990,7 +990,11 @@ module econia::user { #[view] /// Return a `MarketEventHandleCreationNumbers` for `market_id` and - /// `custodian_id`, if `user` has one for indicated market account. + /// `custodian_id`, if `user` has event handles for indicated market + /// account. + /// + /// Restricted to private view function to prevent runtime handle + /// contention. fun get_market_event_handle_creation_numbers( user: address, market_id: u64, From 9ed03ef3a0272b0ae446e22998cad7969607e9e3 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:42:00 -0700 Subject: [PATCH 44/56] Remove MakerEvent type enum, update module doc --- src/move/econia/sources/market.move | 34 +++++++++++------------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index f09bdde33..68695d42c 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -6,31 +6,31 @@ /// ID. /// /// Once a market is registered, signing users and delegated custodians -/// can place limit orders on the book as makers and/or as takers, -/// takers can place market orders or swaps against the order book, and -/// makers can cancel or change the size of any outstanding orders they -/// have on the book. +/// can place limit orders and market orders, and cancel or change the +/// size of any open orders. Swaps can be placed permissionlessly +/// without a market account. /// -/// Econia implements an atomic matching engine for processing taker -/// fills against maker orders on the book, and emits events in response -/// to changes in order book state. Notably, Econia evicts the ask or -/// bid with the lowest price-time priority when inserting a limit order -/// to a binary search tree that exceeds a critical height. +/// Econia implements an atomic matching engine, and emits events in +/// response to changes in order book state as well as assorted market +/// operations. Notably, Econia evicts the ask or bid with the lowest +/// price-time priority when inserting a limit order to a binary search +/// tree that exceeds a critical height. /// /// Multiple API variants are supported for market registration and /// order management function, to enable diagnostic function returns, /// public entry calls, etc. /// -/// When someone places an order that result in one or more fills and/or -/// a post to the book, they are issued a "market order ID" that is -/// unique to the given market but not necessarily across different -/// markets. Each market order ID encodes a counter for the number of +/// All orders are issued an order ID upon placement, which is unique to +/// the given market. The order ID encodes a counter fo the number of /// orders that have been placed on the corresponding market. For orders /// that result in a post to the book, the market order ID additionally /// encodes an "AVL queue access key" (essentially a pointer into /// order book memory), which is required for order lookup during order /// size change and/or order cancellation operations. /// +/// Note that the terms "order ID" and "market order ID" are used +/// interchangeably. +/// /// # General overview sections /// /// [View functions](#view-functions) @@ -840,8 +840,6 @@ module econia::market { const BID: bool = false; /// Flag for buy direction. const BUY: bool = false; - /// Flag for `MakerEvent.type` when order is cancelled. - const CANCEL: u8 = 0; /// Flag to cancel maker and taker order during a self match. const CANCEL_BOTH: u8 = 1; /// Flag to cancel maker order only during a self match. @@ -871,14 +869,10 @@ module econia::market { const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8; /// Flag to cancel taker order only during a self match. const CANCEL_TAKER: u8 = 3; - /// Flag for `MakerEvent.type` when order size is changed. - const CHANGE: u8 = 1; /// Critical tree height above which evictions may take place. const CRITICAL_HEIGHT: u8 = 18; /// Descending AVL queue flag, for bids AVL queue. const DESCENDING: bool = false; - /// Flag for `MakerEvent.type` when order is evicted. - const EVICT: u8 = 2; /// Flag for fill-or-abort order restriction. const FILL_OR_ABORT: u8 = 1; /// `u64` bitmask with all bits set, generated in Python via @@ -909,8 +903,6 @@ module econia::market { const PERCENT: bool = true; /// Maximum percentage passive advance. const PERCENT_100: u64 = 100; - /// Flag for `MakerEvent.type` when order is placed. - const PLACE: u8 = 3; /// Flag for post-or-abort order restriction. const POST_OR_ABORT: u8 = 3; /// Flag for sell direction. From 2bb4663c3dc7995ab311d378f4aa8cac85fa9a6c Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 17:43:13 -0700 Subject: [PATCH 45/56] Add constant getter tests --- src/move/econia/sources/user.move | 37 ++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 74684ca0e..73fa1aa7d 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -691,7 +691,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_EVICTION(): u8 { CANCEL_REASON_EVICTION } @@ -701,7 +701,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_IMMEDIATE_OR_CANCEL(): u8 { CANCEL_REASON_IMMEDIATE_OR_CANCEL } @@ -711,7 +711,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8 { CANCEL_REASON_MANUAL_CANCEL } @@ -721,7 +721,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_MAX_QUOTE_TRADED(): u8 { CANCEL_REASON_MAX_QUOTE_TRADED } @@ -731,7 +731,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY(): u8 { CANCEL_REASON_NOT_ENOUGH_LIQUIDITY } @@ -741,7 +741,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_SELF_MATCH_MAKER(): u8 { CANCEL_REASON_SELF_MATCH_MAKER } @@ -751,7 +751,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_SELF_MATCH_TAKER(): u8 { CANCEL_REASON_SELF_MATCH_TAKER } @@ -762,7 +762,7 @@ module econia::user { /// /// # Testing /// - /// * `test_get_cancel_reasons()` TODO + /// * `test_get_cancel_reasons()` public fun get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING(): u8 { CANCEL_REASON_TOO_SMALL_AFTER_MATCHING } @@ -4466,6 +4466,27 @@ module econia::user { /// Verify constant getter return. fun test_get_BID() {assert!(get_BID() == BID, 0)} + #[test] + /// Verify constant getter returns. + fun test_get_cancel_reasons() { + assert!(get_CANCEL_REASON_EVICTION() == + CANCEL_REASON_EVICTION, 0); + assert!(get_CANCEL_REASON_IMMEDIATE_OR_CANCEL() == + CANCEL_REASON_IMMEDIATE_OR_CANCEL, 0); + assert!(get_CANCEL_REASON_MANUAL_CANCEL() == + CANCEL_REASON_MANUAL_CANCEL, 0); + assert!(get_CANCEL_REASON_MAX_QUOTE_TRADED() == + CANCEL_REASON_MAX_QUOTE_TRADED, 0); + assert!(get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY() == + CANCEL_REASON_NOT_ENOUGH_LIQUIDITY, 0); + assert!(get_CANCEL_REASON_SELF_MATCH_MAKER() == + CANCEL_REASON_SELF_MATCH_MAKER, 0); + assert!(get_CANCEL_REASON_SELF_MATCH_TAKER() == + CANCEL_REASON_SELF_MATCH_TAKER, 0); + assert!(get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING() == + CANCEL_REASON_TOO_SMALL_AFTER_MATCHING, 0); + } + #[test] #[expected_failure(abort_code = E_NO_MARKET_ACCOUNT)] /// Verify failure for no market account resource. From de22d02586e3dc6ae76b8cd6409f64ea9958a110 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Mon, 17 Jul 2023 18:15:50 -0700 Subject: [PATCH 46/56] Comment out inline directives for coverage testing --- src/move/econia/sources/market.move | 6 +++--- src/move/econia/sources/user.move | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 68695d42c..e101e2688 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2689,7 +2689,7 @@ module econia::market { /// /// * `Option`: An optional cancel reason, if the order needs /// to be cancelled. - inline fun get_cancel_reason_option_for_market_order_or_swap( + /*inline*/ fun get_cancel_reason_option_for_market_order_or_swap( self_match_taker_cancel: bool, base_traded: u64, max_base: u64, @@ -2749,7 +2749,7 @@ module econia::market { /// # Testing /// /// * `test_get_market_order_id_avl_queue_access_key()` - inline fun get_order_id_avl_queue_access_key( + /*inline*/ fun get_order_id_avl_queue_access_key( order_id: u128 ): u64 { ((order_id & (HI_64 as u128)) as u64) @@ -3119,7 +3119,7 @@ module econia::market { /// Return order ID derived solely from order book counter for an /// order that did not post. - inline fun order_id_no_post( + /*inline*/ fun order_id_no_post( counter: u64 ): u128 { (counter as u128) << SHIFT_COUNTER diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 73fa1aa7d..2420fbf1b 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -2808,7 +2808,7 @@ module econia::user { /// Emit a `FillEvent` for the market account of the maker /// associated with a fill, if market event handles exist for the /// indicated market account. - inline fun emit_maker_fill_event( + /*inline*/ fun emit_maker_fill_event( event_ref: &FillEvent ) acquires MarketEventHandles { let maker = event_ref.maker; From 3afff45ddc16462c510b55dcad259271887f2bd3 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 10:22:57 -0700 Subject: [PATCH 47/56] Adjust runtime helper func inline status --- src/move/econia/sources/market.move | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index e101e2688..d9aa38ef0 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -907,7 +907,7 @@ module econia::market { const POST_OR_ABORT: u8 = 3; /// Flag for sell direction. const SELL: bool = true; - /// Number of bits order counter is shifted in a market order ID. + /// Number of bits order counter is shifted in an order ID. const SHIFT_COUNTER: u8 = 64; /// Flag for passive order specified by advance in ticks. const TICKS: bool = false; @@ -2749,7 +2749,7 @@ module econia::market { /// # Testing /// /// * `test_get_market_order_id_avl_queue_access_key()` - /*inline*/ fun get_order_id_avl_queue_access_key( + fun get_order_id_avl_queue_access_key( order_id: u128 ): u64 { ((order_id & (HI_64 as u128)) as u64) @@ -2977,8 +2977,9 @@ module econia::market { // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; - // Increment order book counter before any potential fills. + // Get new order ID before any potential fills. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + let order_id = ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); // Initialize counters for fill iteration. let (fill_count, fees_paid) = (0, 0); // While there are orders to match against: @@ -3072,8 +3073,7 @@ module econia::market { let fill_event = user::create_fill_event_internal( market_id, fill_size, price, side, maker, maker_custodian_id, market_order_id, taker, custodian_id, - order_id_no_post(order_book_ref_mut.counter), - fees_paid_for_fill, fill_count); + order_id, fees_paid_for_fill, fill_count); vector::push_back(fill_event_queue_ref_mut, fill_event); // Update fill iteration counters. fill_count = fill_count + 1; @@ -3117,14 +3117,6 @@ module econia::market { self_match_taker_cancel, avl_queue::is_empty(orders_ref_mut)) } - /// Return order ID derived solely from order book counter for an - /// order that did not post. - /*inline*/ fun order_id_no_post( - counter: u64 - ): u128 { - (counter as u128) << SHIFT_COUNTER - } - /// Place limit order against order book from user market account. /// /// # Type Parameters @@ -3437,7 +3429,8 @@ module econia::market { }; }; // Assume that limit order will not post. - let market_order_id = order_id_no_post(order_book_ref_mut.counter); + let market_order_id = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); // If order eligible to post: if (option::is_none(&cancel_reason_option)) { // Get next order access key for user-side order placement. @@ -3815,7 +3808,8 @@ module econia::market { quote_coins ); // Get order ID from order book counter updated during matching. - let market_order_id = order_id_no_post(order_book_ref_mut.counter); + let market_order_id = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -4143,7 +4137,8 @@ module econia::market { quote_coins ); // Get order ID from order book counter updated during matching. - let market_order_id = order_id_no_post(order_book_ref_mut.counter); + let market_order_id = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); // Create market event handles for market as needed. if (!exists(resource_address)) move_to(&resource_account::get_signer(), @@ -4472,6 +4467,15 @@ module econia::market { avl_queue::is_local_tail(orders_ref, avlq_access_key) } + #[test_only] + /// Return order ID derived solely from order book counter for an + /// order that did not post. + public fun order_id_no_post( + counter: u64 + ): u128 { + (counter as u128) << SHIFT_COUNTER + } + // Test-only functions <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< // Test-only constants >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> From a32e6f4de280ac1970ad85eb3d4a7e218366f805 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 11:18:48 -0700 Subject: [PATCH 48/56] Add user tests, test helper funcs --- src/move/econia/sources/user.move | 80 +++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 2420fbf1b..01a6cdf00 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -1405,6 +1405,11 @@ module econia::user { /// # Aborts /// /// * `E_NO_MARKET_ACCOUNT`: No such specified market account. + /// + /// # Testing + /// + /// * `test_init_market_event_handles_if_missing_no_account()` + /// * `test_register_market_accounts()` public entry fun init_market_event_handles_if_missing( user: &signer, market_id: u64, @@ -3474,6 +3479,37 @@ module econia::user { market_account_id_generic_delegated) } + #[test_only] + public fun remove_market_event_handles_for_market_account_test( + user: address, + market_id: u64, + custodian_id: u64 + ) acquires MarketEventHandles { + let market_account_id = get_market_account_id(market_id, custodian_id); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut(user).map; + let MarketEventHandlesForMarketAccount{ + cancel_order_events, + change_order_size_events, + fill_events, + place_limit_order_events, + place_market_order_events + } = table::remove(market_event_handles_map_ref_mut, market_account_id); + event::destroy_handle(cancel_order_events); + event::destroy_handle(change_order_size_events); + event::destroy_handle(fill_events); + event::destroy_handle(place_limit_order_events); + event::destroy_handle(place_market_order_events); + } + + #[test_only] + public fun remove_market_event_handles_test( + user: address + ) acquires MarketEventHandles { + let MarketEventHandles{map} = move_from(user); + table::drop_unchecked(map); + } + #[test_only] /// Return `true` if order is active. public fun is_order_active_test( @@ -3606,6 +3642,9 @@ module econia::user { // Place order. place_order_internal(@user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size_old, price, market_order_id, 1); + // Remove market event handles. + remove_market_event_handles_for_market_account_test( + @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID); change_order_size_internal( // Change order size. @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size_old, size, price, order_access_key, market_order_id); @@ -4662,6 +4701,18 @@ module econia::user { assert!(get_NO_CUSTODIAN() == registry::get_NO_CUSTODIAN(), 0) } + #[test(user = @user)] + #[expected_failure(abort_code = E_NO_MARKET_ACCOUNT)] + /// Verify abort for user has no market account. + fun test_init_market_event_handles_if_missing_no_account( + user: &signer + ) acquires + MarketAccounts, + MarketEventHandles + { + init_market_event_handles_if_missing(user, 0, 0); + } + #[test] /// Verify valid returns. fun test_market_account_getters() @@ -4847,6 +4898,9 @@ module econia::user { @user, market_account_id, side, order_access_key); assert!(market_order_id_r == market_order_id, 0); assert!(size_r == size, 0); + // Remove market event handles. + remove_market_event_handles_for_market_account_test( + @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID); // Evict order, storing returned market order ID. market_order_id_r = cancel_order_internal( @user, MARKET_ID_PURE_COIN, CUSTODIAN_ID, side, size, price, @@ -5240,6 +5294,8 @@ module econia::user { /// /// Exercises all non-assert conditional branches for: /// + /// * `get_market_event_handle_creation_numbers()` + /// * `init_market_event_handles_if_missing()` /// * `register_market_account()` /// * `register_market_account_account_entries()` /// * `register_market_account_collateral_entry()` @@ -5258,13 +5314,37 @@ module econia::user { base_name_generic_generic, lot_size_generic, tick_size_generic, min_size_generic, underwriter_id_generic) = registry::register_markets_test(); + // Verify no event handle creation numbers. + assert!(get_market_event_handle_creation_numbers( + @user, market_id_pure_coin, NO_CUSTODIAN) == option::none(), 0); // Set custodian ID as registered. registry::set_registered_custodian_test(CUSTODIAN_ID); // Register pure coin market account. register_market_account( user, market_id_pure_coin, NO_CUSTODIAN); + assert!(get_market_event_handle_creation_numbers( + @user, market_id_pure_coin, NO_CUSTODIAN) == option::some( + MarketEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: 2, + change_order_size_events_handle_creation_num: 3, + fill_events_handle_creation_num: 4, + place_limit_order_events_handle_creation_num: 5, + place_market_order_events_handle_creation_num: 6}), 0); + // Invoke init call for handles already initialized. + init_market_event_handles_if_missing( + user, market_id_pure_coin, NO_CUSTODIAN); + assert!(get_market_event_handle_creation_numbers( + @user, market_id_pure_coin, CUSTODIAN_ID) == option::none(), 0); register_market_account( // Register delegated account. user, market_id_pure_coin, CUSTODIAN_ID); + assert!(get_market_event_handle_creation_numbers( + @user, market_id_pure_coin, CUSTODIAN_ID) == option::some( + MarketEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: 7, + change_order_size_events_handle_creation_num: 8, + fill_events_handle_creation_num: 9, + place_limit_order_events_handle_creation_num: 10, + place_market_order_events_handle_creation_num: 11}), 0); // Register generic asset account. register_market_account_generic_base( user, market_id_generic, NO_CUSTODIAN); From 309a87d336ce0b88c9af95e0eccba0129bcec1f4 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 14:57:47 -0700 Subject: [PATCH 49/56] Address coverage gaps in market module tests --- src/move/econia/sources/market.move | 490 +++++++++++++++++++++++++++- 1 file changed, 481 insertions(+), 9 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index d9aa38ef0..2fa648dbc 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -1087,6 +1087,10 @@ module econia::market { /// /// Restricted to private view function to prevent runtime handle /// contention. + /// + /// # Testing + /// + /// * `test_swap_between_coinstores_register_base_store()` fun get_market_event_handle_creation_info( market_id: u64 ): Option @@ -1345,6 +1349,10 @@ module econia::market { /// /// Restricted to private view function to prevent runtime handle /// contention. + /// + /// # Testing + /// + /// * `test_swap_between_coinstores_register_base_store()` fun get_swapper_event_handle_creation_numbers( swapper: address, market_id: u64 @@ -1869,8 +1877,11 @@ module econia::market { /// * `test_swap_between_coinstores_max_possible_base_sell()` /// * `test_swap_between_coinstores_max_possible_quote_buy()` /// * `test_swap_between_coinstores_max_possible_quote_sell()` + /// * `test_swap_between_coinstores_max_quote_traded()` + /// * `test_swap_between_coinstores_not_enough_liquidity()` /// * `test_swap_between_coinstores_register_base_store()` /// * `test_swap_between_coinstores_register_quote_store()` + /// * `test_swap_between_coinstores_self_match_taker_cancel()` public fun swap_between_coinstores< BaseType, QuoteType @@ -3214,6 +3225,7 @@ module econia::market { /// * `test_place_limit_order_crosses_bid_partial_cancel()` /// * `test_place_limit_order_evict()` /// * `test_place_limit_order_no_cross_ask_user()` + /// * `test_place_limit_order_no_cross_ask_user_ioc()` /// * `test_place_limit_order_no_cross_bid_custodian()` /// * `test_place_limit_order_still_crosses_ask()` /// * `test_place_limit_order_still_crosses_bid()` @@ -3715,6 +3727,7 @@ module econia::market { /// /// * `test_place_market_order_invalid_base()` /// * `test_place_market_order_invalid_quote()` + /// * `test_place_market_order_size_base_overflow()` /// * `test_place_market_order_size_too_small()` fun place_market_order< BaseType, @@ -4480,6 +4493,15 @@ module econia::market { // Test-only constants >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> + #[test_only] + /// After initializing an Aptos account (2 handles) and two order + /// books (2 handles per). + const FIRST_EVENT_HANDLE_RESOURCE_ACCOUNT: u64 = 6; + #[test_only] + /// After initializing an Aptos account (2 handles), four market + /// accounts (5 handles per), and two coin stores (2 handles per). + const FIRST_EVENT_HANDLE_SWAPPER: u64 = 26; + #[test_only] /// Custodian ID for market account with delegated custodian. const CUSTODIAN_ID_USER_0: u64 = 123; @@ -8527,6 +8549,90 @@ module econia::market { assert!(get_order_book_counter(MARKET_ID_COIN) == 2, 0); } + #[test] + /// Verify state updates, returns for placing immediate-or-cancel + /// ask that does not fill at all across the spread, under authority + /// of signing user + fun test_place_limit_order_no_cross_ask_user_ioc() + acquires OrderBooks { + // Declare order parameters. + let side = ASK; + let size = MIN_SIZE_COIN; + let price = 123; + let restriction_0 = NO_RESTRICTION; + let restriction_1 = IMMEDIATE_OR_CANCEL; + let self_match_behavior = ABORT; + // Declare change in base and quote seen by maker. + let base_delta = size * LOT_SIZE_COIN; + let quote_delta = size * price * TICK_SIZE_COIN; + // Declare min base and max quote to deposit. + let base_deposit = base_delta; + let quote_deposit = HI_64 - quote_delta; + // Initialize markets, users, and an integrator. + let (user_0, _) = init_markets_users_integrator_test(); + // Deposit base and quote coins to user's account. + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(base_deposit)); + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(quote_deposit)); + // Assert order book counter. + assert!(get_order_book_counter(MARKET_ID_COIN) == 0, 0); + let (market_order_id, base_trade, quote_trade, fees) = + place_limit_order_user( // Place limit order. + &user_0, MARKET_ID_COIN, @integrator, side, size, price, + restriction_0, self_match_behavior); + // Assert trade amount returns. + assert!(base_trade == 0, 0); + assert!(quote_trade == 0, 0); + assert!(fees == 0, 0); + // Assert counter encoded in order ID. + assert!(get_market_order_id_counter(market_order_id) == 1, 0); + // Assert market order ID marked as posting. + assert!(did_order_post(market_order_id), 0); + // Assert price encoded in order ID. + assert!(get_market_order_id_price(market_order_id) == price, 0); + // Assert side encoded in order ID. + assert!(get_posted_order_id_side(market_order_id) == side, 0); + // Assert order book counter. + assert!(get_order_book_counter(MARKET_ID_COIN) == 1, 0); + // Get order fields. + let (size_r, price_r, user_r, custodian_id_r, order_access_key) = + get_order_fields_test(MARKET_ID_COIN, side, market_order_id); + // Assert field returns except access key, used for user lookup. + assert!(size_r == size, 0); + assert!(price_r == price, 0); + assert!(user_r == @user_0, 0); + assert!(custodian_id_r == NO_CUSTODIAN, 0); + // Assert user-side order fields. + let (market_order_id_r, size_r) = user::get_order_fields_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN, side, order_access_key); + assert!(market_order_id_r == market_order_id, 0); + assert!(size_r == size, 0); + // Place another order, asserting counter in market order ID. + let (market_order_id, _, _, _) = place_limit_order_user( + &user_0, MARKET_ID_COIN, @integrator, !side, size, price - 1, + restriction_1, self_match_behavior); + assert!(get_market_order_id_counter(market_order_id) == 2, 0); + // Assert order did not post. + assert!(!did_order_post(market_order_id), 0); + // Assert user's asset counts. + let (base_total , base_available , base_ceiling, + quote_total, quote_available, quote_ceiling) = + user::get_asset_counts_internal( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN); + assert!(base_total == base_deposit , 0); + assert!(base_available == 0 , 0); + assert!(base_ceiling == base_deposit , 0); + assert!(quote_total == quote_deposit, 0); + assert!(quote_available == quote_deposit, 0); + assert!(quote_ceiling == HI_64 , 0); + // Assert collateral amounts. + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == base_deposit, 0); + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == quote_deposit, 0); + } + #[test] /// Verify state updates, returns, for placing bid that does not /// cross the spread, under authority of custodian. @@ -9495,6 +9601,27 @@ module econia::market { size, self_match_behavior); } + #[test] + #[expected_failure(abort_code = E_SIZE_BASE_OVERFLOW)] + /// Verify failure for invalid size argument. + fun test_place_market_order_size_base_overflow() + acquires OrderBooks { + // Initialize markets, users, and an integrator. + init_markets_users_integrator_test(); + // Declare order arguments. + let user_address = @user_0; + let market_id = MARKET_ID_COIN; + let custodian_id = NO_CUSTODIAN; + let integrator = @integrator; + let direction = BUY; + let size = HI_64 / LOT_SIZE_COIN + 1; + let self_match_behavior = ABORT; + // Attempt invalid invocation. + place_market_order( + user_address, market_id, custodian_id, integrator, direction, + size, self_match_behavior); + } + #[test] #[expected_failure(abort_code = E_SIZE_TOO_SMALL)] /// Verify failure for invalid size argument. @@ -10637,7 +10764,7 @@ module econia::market { let quote_trade = if (direction == BUY) quote_match + fee else quote_match - fee; let min_base = 0; - let max_base = base_taker + LOT_SIZE_COIN; + let max_base = base_taker * LOT_SIZE_COIN; let min_quote = 0; let max_quote = MAX_POSSIBLE; let self_match_behavior = ABORT; @@ -10743,7 +10870,7 @@ module econia::market { let quote_trade = if (direction == BUY) quote_match + fee else quote_match - fee; let min_base = 0; - let max_base = base_taker + LOT_SIZE_COIN; + let max_base = base_taker * LOT_SIZE_COIN; let min_quote = 0; let max_quote = MAX_POSSIBLE; let self_match_behavior = ABORT; @@ -10821,6 +10948,217 @@ module econia::market { assert!(coin::balance(@user_1) == quote_total_taker, 0); } + #[test] + /// Verify returns, state updates for specifying sell when matching + /// ends early due to quote coin constraints. + fun test_swap_between_coinstores_max_quote_traded() + acquires + MarketEventHandles, + OrderBooks, + SwapperEventHandles + { + // Initialize markets, users, and an integrator. + let (user_0, user_1) = init_markets_users_integrator_test(); + // Get taker fee divisor. + let taker_divisor = incentives::get_taker_fee_divisor(); + // Declare order setup parameters, with price set to taker fee + // divisor, to prevent truncation effects on estimates. + let direction = SELL; + let side_maker = BID; // If buy then ask, else bid. + let size_maker = MIN_SIZE_COIN * 2; + let size_taker = MIN_SIZE_COIN; + let base_maker = size_maker * LOT_SIZE_COIN; + let base_taker = size_taker * LOT_SIZE_COIN; + let price = taker_divisor; + let quote_maker = size_maker * price * TICK_SIZE_COIN; + let quote_match = size_taker * price * TICK_SIZE_COIN; + let fee = quote_match / taker_divisor; + let quote_trade = if (direction == BUY) quote_match + fee else + quote_match - fee; + let min_base = 0; + let max_base = (size_taker + MIN_SIZE_COIN) * LOT_SIZE_COIN; + let min_quote = 0; + let max_quote = quote_trade; + let self_match_behavior = ABORT; + // Declare deposit amounts so as to impinge on available/ceiling + // boundaries. + let base_deposit_maker = HI_64 - base_maker; + let quote_deposit_maker = quote_maker; + let base_deposit_taker = max_base; + let quote_deposit_taker = HI_64 - quote_trade; + // Declare expected asset amounts after the match, for maker. + let base_total_maker = base_deposit_maker + base_taker; + let base_available_maker = base_total_maker; + let base_ceiling_maker = HI_64; + let quote_total_maker = quote_deposit_maker - quote_match; + let quote_available_maker = 0; + let quote_ceiling_maker = quote_total_maker; + // Declare expected asset amounts after the match, for taker. + let base_total_taker = base_deposit_taker - base_taker; + let quote_total_taker = HI_64; + // Deposit maker coins. + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(base_deposit_maker)); + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(quote_deposit_maker)); + // Deposit taker coins. + coin::register(&user_1); + coin::register(&user_1); + coin::deposit(@user_1, assets::mint_test(base_deposit_taker)); + coin::deposit(@user_1, assets::mint_test(quote_deposit_taker)); + // Place maker order. + let (market_order_id_0, _, _, _) = place_limit_order_user( + &user_0, MARKET_ID_COIN, @integrator, side_maker, size_maker, + price, NO_RESTRICTION, self_match_behavior); + let (base_trade_r, quote_trade_r, fee_r) = // Place taker order. + swap_between_coinstores( + &user_1, MARKET_ID_COIN, @integrator, direction, min_base, + max_base, min_quote, max_quote, price); + // Assert returns. + assert!(base_trade_r == base_taker, 0); + assert!(quote_trade_r == quote_trade, 0); + assert!(fee_r == fee, 0); + // Get fields for maker order on book. + let (size_r, price_r, user_r, custodian_id_r, order_access_key) = + get_order_fields_test( + MARKET_ID_COIN, side_maker, market_order_id_0); + // Assert field returns except access key, used for user lookup. + assert!(size_r == size_maker - size_taker, 0); + assert!(price_r == price, 0); + assert!(user_r == @user_0, 0); + assert!(custodian_id_r == NO_CUSTODIAN, 0); + // Assert user-side order fields. + let (market_order_id_r, size_r) = user::get_order_fields_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN, side_maker, + order_access_key); + assert!(market_order_id_r == market_order_id_0, 0); + assert!(size_r == size_maker - size_taker, 0); + // Assert maker's asset counts. + let (base_total , base_available , base_ceiling, + quote_total, quote_available, quote_ceiling) = + user::get_asset_counts_internal( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN); + assert!(base_total == base_total_maker, 0); + assert!(base_available == base_available_maker, 0); + assert!(base_ceiling == base_ceiling_maker, 0); + assert!(quote_total == quote_total_maker, 0); + assert!(quote_available == quote_available_maker, 0); + assert!(quote_ceiling == quote_ceiling_maker, 0); + // Assert collateral amounts. + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == base_total_maker, 0); + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == quote_total_maker, 0); + // Assert taker's asset counts. + assert!(coin::balance(@user_1) == base_total_taker, 0); + assert!(coin::balance(@user_1) == quote_total_taker, 0); + } + + #[test] + /// Verify returns, state updates for specifying sell when there is + /// not enough liquidity. + fun test_swap_between_coinstores_not_enough_liquidity() + acquires + MarketEventHandles, + OrderBooks, + SwapperEventHandles + { + // Initialize markets, users, and an integrator. + let (user_0, user_1) = init_markets_users_integrator_test(); + // Get taker fee divisor. + let taker_divisor = incentives::get_taker_fee_divisor(); + // Declare order setup parameters, with price set to taker fee + // divisor, to prevent truncation effects on estimates. + let direction = SELL; + let side_maker = BID; // If buy then ask, else bid. + let size_maker = MIN_SIZE_COIN; + let size_taker = size_maker; + let base_maker = size_maker * LOT_SIZE_COIN; + let base_taker = size_taker * LOT_SIZE_COIN; + let price = taker_divisor; + let quote_maker = size_maker * price * TICK_SIZE_COIN; + let quote_match = size_taker * price * TICK_SIZE_COIN; + let fee = quote_match / taker_divisor; + let quote_trade = if (direction == BUY) quote_match + fee else + quote_match - fee; + let min_base = 0; + let max_base = (size_taker + MIN_SIZE_COIN) * LOT_SIZE_COIN; + let min_quote = 0; + let max_quote = MAX_POSSIBLE; + let self_match_behavior = ABORT; + // Declare deposit amounts so as to impinge on available/ceiling + // boundaries. + let base_deposit_maker = HI_64 - base_maker; + let quote_deposit_maker = quote_maker; + let base_deposit_taker = max_base; + let quote_deposit_taker = HI_64 - 2 * quote_trade; + // Declare expected asset amounts after the match, for maker. + let base_total_maker = base_deposit_maker + base_taker; + let base_available_maker = base_total_maker; + let base_ceiling_maker = HI_64; + let quote_total_maker = quote_deposit_maker - quote_match; + let quote_available_maker = 0; + let quote_ceiling_maker = quote_total_maker; + // Declare expected asset amounts after the match, for taker. + let base_total_taker = base_deposit_taker - base_taker; + let quote_total_taker = HI_64 - quote_trade; + // Deposit maker coins. + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(base_deposit_maker)); + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(quote_deposit_maker)); + // Deposit taker coins. + coin::register(&user_1); + coin::register(&user_1); + coin::deposit(@user_1, assets::mint_test(base_deposit_taker)); + coin::deposit(@user_1, assets::mint_test(quote_deposit_taker)); + // Place maker order. + let (market_order_id_0, _, _, _) = place_limit_order_user( + &user_0, MARKET_ID_COIN, @integrator, side_maker, size_maker, + price, NO_RESTRICTION, self_match_behavior); + // Get user-side order access key for later. + let (_, _, _, _, order_access_key) = + get_order_fields_test( + MARKET_ID_COIN, side_maker, market_order_id_0); + let (base_trade_r, quote_trade_r, fee_r) = // Place taker order. + swap_between_coinstores( + &user_1, MARKET_ID_COIN, @integrator, direction, min_base, + max_base, min_quote, max_quote, price); + // Assert returns. + assert!(base_trade_r == base_taker, 0); + assert!(quote_trade_r == quote_trade, 0); + assert!(fee_r == fee, 0); + // Assert list node order inactive. + assert!(!is_list_node_order_active( + MARKET_ID_COIN, side_maker, market_order_id_0), 0); + // Assert user-side order fields for filled order + let (market_order_id_r, size_r) = user::get_order_fields_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN, side_maker, + order_access_key); + // No market order ID. + assert!(market_order_id_r == (NIL as u128), 0); + assert!(size_r == NIL, 0); // Bottom of inactive stack. + // Assert maker's asset counts. + let (base_total , base_available , base_ceiling, + quote_total, quote_available, quote_ceiling) = + user::get_asset_counts_internal( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN); + assert!(base_total == base_total_maker, 0); + assert!(base_available == base_available_maker, 0); + assert!(base_ceiling == base_ceiling_maker, 0); + assert!(quote_total == quote_total_maker, 0); + assert!(quote_available == quote_available_maker, 0); + assert!(quote_ceiling == quote_ceiling_maker, 0); + // Assert collateral amounts. + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == base_total_maker, 0); + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == quote_total_maker, 0); + // Assert taker's asset counts. + assert!(coin::balance(@user_1) == base_total_taker, 0); + assert!(coin::balance(@user_1) == quote_total_taker, 0); + } + #[test] /// Verify returns, state updates for registering base coin store. fun test_swap_between_coinstores_register_base_store() @@ -10833,6 +11171,11 @@ module econia::market { let (user_0, user_1) = init_markets_users_integrator_test(); // Get taker fee divisor. let taker_divisor = incentives::get_taker_fee_divisor(); + // Verify no event handle info. + assert!(get_market_event_handle_creation_info(MARKET_ID_COIN) == + option::none(), 0); + assert!(get_swapper_event_handle_creation_numbers( + @user_1, MARKET_ID_COIN) == option::none(), 0); // Declare order setup parameters, with price set to taker fee // divisor, to prevent truncation effects on estimates. let direction = BUY; @@ -10916,6 +11259,31 @@ module econia::market { // Assert taker's asset counts. assert!(coin::balance(@user_1) == base_total_taker, 0); assert!(coin::balance(@user_1) == quote_total_taker, 0); + let market_handle_0 = FIRST_EVENT_HANDLE_RESOURCE_ACCOUNT; + let market_handle_1 = market_handle_0 + 1; + // Verify event handle info. + assert!(get_market_event_handle_creation_info(MARKET_ID_COIN) == + option::some(MarketEventHandleCreationInfo{ + resource_account_address: resource_account::get_address(), + cancel_order_events_handle_creation_num: market_handle_0, + place_swap_order_events_handle_creation_num: + market_handle_1 + }), 0); + let swapper_handle_0 = FIRST_EVENT_HANDLE_SWAPPER; + let swapper_handle_1 = swapper_handle_0 + 1; + let swapper_handle_2 = swapper_handle_1 + 1; + assert!(get_swapper_event_handle_creation_numbers( + @user_1, MARKET_ID_COIN) == + option::some(SwapperEventHandleCreationNumbers{ + cancel_order_events_handle_creation_num: swapper_handle_0, + fill_events_handle_creation_num: swapper_handle_1, + place_swap_order_events_handle_creation_num: + swapper_handle_2, + }), 0); + assert!(get_market_event_handle_creation_info(MARKET_ID_GENERIC) == + option::none(), 0); + assert!(get_swapper_event_handle_creation_numbers( + @user_1, MARKET_ID_GENERIC) == option::none(), 0); } #[test] @@ -10953,7 +11321,7 @@ module econia::market { // boundaries. let base_deposit_maker = HI_64 - base_maker; let quote_deposit_maker = quote_maker; - let base_deposit_taker = base_taker + LOT_SIZE_COIN; + let base_deposit_taker = base_taker * LOT_SIZE_COIN; // Declare expected asset amounts after the match, for maker. let base_total_maker = base_deposit_maker + base_taker; let base_available_maker = base_total_maker; @@ -10976,6 +11344,8 @@ module econia::market { let (market_order_id_0, _, _, _) = place_limit_order_user( &user_0, MARKET_ID_COIN, @integrator, side_maker, size_maker, price, NO_RESTRICTION, self_match_behavior); + // Create swapper event handles map, but not handles for market. + move_to(&user_1, SwapperEventHandles{map: table::new()}); swap_between_coinstores_entry( // Place taker order. &user_1, MARKET_ID_COIN, @integrator, direction, min_base, max_base, min_quote, max_quote, price); @@ -11015,6 +11385,108 @@ module econia::market { assert!(coin::balance(@user_1) == quote_total_taker, 0); } + #[test] + /// Verify returns, state updates for self match taker cancel. + fun test_swap_between_coinstores_self_match_taker_cancel() + acquires + MarketEventHandles, + OrderBooks, + SwapperEventHandles + { + // Initialize markets, users, and an integrator. + let (user_0, _) = init_markets_users_integrator_test(); + // Get taker fee divisor. + let taker_divisor = incentives::get_taker_fee_divisor(); + // Declare order setup parameters, with price set to taker fee + // divisor, to prevent truncation effects on estimates. + let direction = BUY; + let side_maker = ASK; // If buy then ask, else bid. + let size_maker = MIN_SIZE_COIN; + let size_taker = 1; + let base_maker = size_maker * LOT_SIZE_COIN; + let base_taker = size_taker * LOT_SIZE_COIN; + let price = taker_divisor; + let quote_maker = size_maker * price * TICK_SIZE_COIN; + let quote_match = size_taker * price * TICK_SIZE_COIN; + let fee = quote_match / taker_divisor; + let quote_trade = if (direction == BUY) quote_match + fee else + quote_match - fee; + let min_base = 0; + let max_base = MAX_POSSIBLE; + let min_quote = 0; + let max_quote = quote_trade + TICK_SIZE_COIN; + let self_match_behavior = ABORT; + // Declare deposit amounts so as to impinge on available/ceiling + // boundaries. + let base_deposit_maker = base_maker; + let quote_deposit_maker = HI_64 - quote_maker; + let base_deposit_taker = HI_64 - base_taker; + let quote_deposit_taker = max_quote; + // Declare expected asset amounts after the match, for maker. + let base_total_maker = base_deposit_maker; + let base_available_maker = 0; + let base_ceiling_maker = base_total_maker; + let quote_total_maker = quote_deposit_maker; + let quote_available_maker = quote_total_maker; + let quote_ceiling_maker = HI_64; + // Deposit maker coins. + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(base_deposit_maker)); + user::deposit_coins(@user_0, MARKET_ID_COIN, NO_CUSTODIAN, + assets::mint_test(quote_deposit_maker)); + // Deposit taker coins. + coin::register(&user_0); + coin::register(&user_0); + coin::deposit(@user_0, assets::mint_test(base_deposit_taker)); + coin::deposit(@user_0, assets::mint_test(quote_deposit_taker)); + // Place maker order. + let (market_order_id_0, _, _, _) = place_limit_order_user( + &user_0, MARKET_ID_COIN, @integrator, side_maker, size_maker, + price, NO_RESTRICTION, self_match_behavior); + let (base_trade_r, quote_trade_r, fee_r) = // Place taker order. + swap_between_coinstores( + &user_0, MARKET_ID_COIN, @integrator, direction, min_base, + max_base, min_quote, max_quote, price); + // Assert returns. + assert!(base_trade_r == 0, 0); + assert!(quote_trade_r == 0, 0); + assert!(fee_r == 0, 0); + // Get fields for maker order on book. + let (size_r, price_r, user_r, custodian_id_r, order_access_key) = + get_order_fields_test( + MARKET_ID_COIN, side_maker, market_order_id_0); + // Assert field returns except access key, used for user lookup. + assert!(size_r == size_maker, 0); + assert!(price_r == price, 0); + assert!(user_r == @user_0, 0); + assert!(custodian_id_r == NO_CUSTODIAN, 0); + // Assert user-side order fields. + let (market_order_id_r, size_r) = user::get_order_fields_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN, side_maker, + order_access_key); + assert!(market_order_id_r == market_order_id_0, 0); + assert!(size_r == size_maker, 0); + // Assert maker's asset counts. + let (base_total , base_available , base_ceiling, + quote_total, quote_available, quote_ceiling) = + user::get_asset_counts_internal( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN); + assert!(base_total == base_total_maker, 0); + assert!(base_available == base_available_maker, 0); + assert!(base_ceiling == base_ceiling_maker, 0); + assert!(quote_total == quote_total_maker, 0); + assert!(quote_available == quote_available_maker, 0); + assert!(quote_ceiling == quote_ceiling_maker, 0); + // Assert collateral amounts. + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == base_total_maker, 0); + assert!(user::get_collateral_value_simple_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN) == quote_total_maker, 0); + // Assert taker's asset counts. + assert!(coin::balance(@user_0) == base_deposit_taker, 0); + assert!(coin::balance(@user_0) == quote_deposit_taker, 0); + } + #[test] /// Verify returns, state updates for swap buy for max possible /// base amount specified, with base amount as limiting factor. @@ -11258,7 +11730,7 @@ module econia::market { let quote_trade = if (direction == BUY) quote_match + fee else quote_match - fee; let min_base = 0; - let max_base = base_taker + LOT_SIZE_COIN; + let max_base = base_taker * LOT_SIZE_COIN; let min_quote = 0; let max_quote = 0; let self_match_behavior = ABORT; @@ -11373,7 +11845,7 @@ module econia::market { // boundaries. let base_deposit_maker = HI_64 - base_maker; let quote_deposit_maker = quote_maker; - let base_deposit_taker = base_taker + LOT_SIZE_COIN; + let base_deposit_taker = base_taker * LOT_SIZE_COIN; let quote_deposit_taker = HI_64 - quote_trade; // Declare expected asset amounts after the match, for maker. let base_total_maker = base_deposit_maker + base_taker; @@ -11589,7 +12061,7 @@ module econia::market { // boundaries. let base_deposit_maker = HI_64 - base_maker; let quote_deposit_maker = quote_maker; - let base_deposit_taker = base_taker + LOT_SIZE_COIN; + let base_deposit_taker = base_taker * LOT_SIZE_COIN; let quote_deposit_taker = HI_64 - max_quote; // Declare expected asset amounts after the match, for maker. let base_total_maker = base_deposit_maker + base_taker; @@ -11795,7 +12267,7 @@ module econia::market { let quote_trade = if (direction == BUY) quote_match + fee else quote_match - fee; let min_base = 0; - let max_base = base_taker + LOT_SIZE_GENERIC; + let max_base = base_taker * LOT_SIZE_GENERIC; let min_quote = 0; let max_quote = 0; let self_match_behavior = ABORT; @@ -11902,7 +12374,7 @@ module econia::market { let quote_trade = if (direction == BUY) quote_match + fee else quote_match - fee; let min_base = 0; - let max_base = base_taker + LOT_SIZE_GENERIC; + let max_base = base_taker * LOT_SIZE_GENERIC; let min_quote = 0; let max_quote = MAX_POSSIBLE; let self_match_behavior = ABORT; @@ -12116,7 +12588,7 @@ module econia::market { let quote_trade = if (direction == BUY) quote_match + fee else quote_match - fee; let min_base = 0; - let max_base = base_taker + LOT_SIZE_GENERIC; + let max_base = base_taker * LOT_SIZE_GENERIC; let min_quote = 0; let max_quote = quote_trade; let self_match_behavior = ABORT; From f856b75a4e741bed828ef49e2daf31bf151a44c8 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:08:07 -0700 Subject: [PATCH 50/56] Address cross-module invocation coverage gaps --- src/move/econia/sources/market.move | 15 +++++++++++++++ src/move/econia/sources/user.move | 4 ++++ 2 files changed, 19 insertions(+) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 2fa648dbc..e96ee5d70 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -7694,12 +7694,17 @@ module econia::market { assets::mint_test(base)); user::deposit_coins(@user_1, MARKET_ID_COIN, NO_CUSTODIAN, assets::mint_test(HI_64 - quote_total)); + // Remove all event handles for user. + user::remove_market_event_handles_test(@user_0); // Place first maker order. let (market_order_id_0, _, _, _) = place_limit_order_user( &user_0, MARKET_ID_COIN, @integrator, !side, size_match, price, restriction, self_match_behavior); assert!(is_list_node_order_active( // Assert order is active. MARKET_ID_COIN, !side, market_order_id_0), 0); + // Remove only event handles for market account for user. + user::remove_market_event_handles_for_market_account_test( + @user_1, MARKET_ID_COIN, NO_CUSTODIAN); // Place partial maker, partial taker order. let (market_order_id_1, base_trade_r, quote_trade_r, fee_r) = place_limit_order_user( @@ -9689,6 +9694,10 @@ module econia::market { let (market_order_id_0, _, _, _) = place_limit_order_user( &user_0, MARKET_ID_COIN, @integrator, side, size_post, price, NO_RESTRICTION, self_match_behavior); + // Remove all event handles for maker. + user::remove_market_event_handles_test(@user_1); + // Remove all event handles for taker. + user::remove_market_event_handles_test(@user_0); // Place taker order. let (base_trade_r, quote_trade_r, fee_r) = place_market_order_user< BC, QC>(&user_1, MARKET_ID_COIN, @integrator, BUY, size_match, @@ -9794,6 +9803,12 @@ module econia::market { let (market_order_id_0, _, _, _) = place_limit_order_user( &user_0, MARKET_ID_COIN, @integrator, side, size_post, price, NO_RESTRICTION, self_match_behavior); + // Remove only event handles for market account for maker. + user::remove_market_event_handles_for_market_account_test( + @user_0, MARKET_ID_COIN, NO_CUSTODIAN); + // Remove only event handles for market account for taker. + user::remove_market_event_handles_for_market_account_test( + @user_1, MARKET_ID_COIN, NO_CUSTODIAN); // Place taker order. let (base_trade_r, quote_trade_r, fee_r) = place_market_order_user< BC, QC>(&user_1, MARKET_ID_COIN, @integrator, BUY, size_taker, diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 01a6cdf00..e5668c806 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -995,6 +995,10 @@ module econia::user { /// /// Restricted to private view function to prevent runtime handle /// contention. + /// + /// # Testing + /// + /// * `test_register_market_accounts()` fun get_market_event_handle_creation_numbers( user: address, market_id: u64, From 30e2fe1e095fb42539b341393444299aa4ab1447 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:23:17 -0700 Subject: [PATCH 51/56] Address coverage gap for swapper event handles --- src/move/econia/sources/market.move | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index e96ee5d70..849a160e1 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -11025,6 +11025,17 @@ module econia::market { let (market_order_id_0, _, _, _) = place_limit_order_user( &user_0, MARKET_ID_COIN, @integrator, side_maker, size_maker, price, NO_RESTRICTION, self_match_behavior); + // Create swapper event handles for market. + move_to(&user_1, SwapperEventHandles{map: table::new()}); + let swapper_event_handles_map_ref_mut = + &mut borrow_global_mut(@user_1).map; + let handles = SwapperEventHandlesForMarket{ + cancel_order_events: account::new_event_handle(&user_1), + fill_events: account::new_event_handle(&user_1), + place_swap_order_events: account::new_event_handle(&user_1) + }; + table::add( + swapper_event_handles_map_ref_mut, MARKET_ID_COIN, handles); let (base_trade_r, quote_trade_r, fee_r) = // Place taker order. swap_between_coinstores( &user_1, MARKET_ID_COIN, @integrator, direction, min_base, From 464a7c9b2d39172895e6e695a337a98e9745aff2 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 15:32:30 -0700 Subject: [PATCH 52/56] Uncomment inline keyword now that coverage is 100% --- src/move/econia/sources/market.move | 2 +- src/move/econia/sources/user.move | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 849a160e1..b45c437ec 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -2700,7 +2700,7 @@ module econia::market { /// /// * `Option`: An optional cancel reason, if the order needs /// to be cancelled. - /*inline*/ fun get_cancel_reason_option_for_market_order_or_swap( + inline fun get_cancel_reason_option_for_market_order_or_swap( self_match_taker_cancel: bool, base_traded: u64, max_base: u64, diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index e5668c806..4dca65be2 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -2817,7 +2817,7 @@ module econia::user { /// Emit a `FillEvent` for the market account of the maker /// associated with a fill, if market event handles exist for the /// indicated market account. - /*inline*/ fun emit_maker_fill_event( + inline fun emit_maker_fill_event( event_ref: &FillEvent ) acquires MarketEventHandles { let maker = event_ref.maker; From 83a3f0647fcb6de8f0193d5c9a548bd771e38b42 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 16:05:23 -0700 Subject: [PATCH 53/56] Update module doc func indices, dependency charts --- src/move/econia/sources/market.move | 38 ++++++++++++++++++++++++----- src/move/econia/sources/user.move | 32 +++++++++++++++++++++++- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index b45c437ec..9b90e27a3 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -91,7 +91,12 @@ /// * `did_order_post()` /// * `get_market_order_id_counter()` /// * `get_market_order_id_price()` -/// * `get_market_order_id_side()` +/// * `get_posted_order_id_side()` +/// +/// ## Event handle lookup +/// +/// * `get_market_event_handle_creation_info()` +/// * `get_swapper_event_handle_creation_numbers()` /// /// ## Order lookup /// @@ -248,6 +253,18 @@ /// /// ``` /// +/// Cancel reasons: +/// +/// ```mermaid +/// +/// flowchart LR +/// +/// place_market_order --> +/// get_cancel_reason_option_for_market_order_or_swap +/// swap --> get_cancel_reason_option_for_market_order_or_swap +/// +/// ``` +/// /// Changing order size: /// /// ```mermaid @@ -288,16 +305,15 @@ /// get_price_levels --> get_price_levels_for_side /// get_price_levels_all --> get_price_levels /// get_open_order --> has_open_order -/// get_open_order --> get_market_order_id_side +/// get_open_order --> get_posted_order_id_side /// get_open_order --> get_order_id_avl_queue_access_key -/// get_market_order_id_side --> -/// get_order_id_avl_queue_access_key -/// has_open_order --> get_market_order_id_side +/// get_posted_order_id_side --> did_order_post +/// get_posted_order_id_side --> get_order_id_avl_queue_access_key +/// has_open_order --> get_posted_order_id_side /// has_open_order --> get_order_id_avl_queue_access_key /// get_open_orders --> get_open_orders_for_side /// get_open_orders_all --> get_open_orders /// get_market_order_id_price --> did_order_post -/// get_market_order_id_side --> did_order_post /// /// ``` /// @@ -367,6 +383,7 @@ /// place_market_order --> resource_account::get_address /// /// swap --> resource_account::get_address +/// swap --> resource_account::get_signer /// /// change_order_size --> resource_account::get_address /// @@ -380,6 +397,9 @@ /// /// get_price_levels --> resource_account::get_address /// +/// get_market_event_handle_creation_info --> +/// resource_account::get_address +/// /// ``` /// /// `user`: @@ -394,12 +414,15 @@ /// place_limit_order --> user::get_next_order_access_key_internal /// place_limit_order --> user::place_order_internal /// place_limit_order --> user::cancel_order_internal +/// place_limit_order --> user::emit_limit_order_events_internal /// /// place_market_order --> user::get_asset_counts_internal /// place_market_order --> user::withdraw_assets_internal /// place_market_order --> user::deposit_assets_internal +/// place_market_order --> user::emit_market_order_events_internal /// /// match --> user::fill_order_internal +/// match --> user::create_fill_event_internal /// /// change_order_size --> user::change_order_size_internal /// @@ -411,6 +434,9 @@ /// /// get_open_orders_for_side --> user::get_open_order_id_internal /// +/// swap --> user::create_cancel_order_event_internal +/// swap --> user::emit_swap_maker_fill_events_internal +/// /// ``` /// /// # Order management testing diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 4dca65be2..b1b4ed92c 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -88,6 +88,14 @@ /// * `get_ASK()` /// * `get_BID()` /// * `get_NO_CUSTODIAN()` +/// * `get_CANCEL_REASON_EVICTION()` +/// * `get_CANCEL_REASON_IMMEDIATE_OR_CANCEL()` +/// * `get_CANCEL_REASON_MANUAL_CANCEL()` +/// * `get_CANCEL_REASON_MAX_QUOTE_TRADED()` +/// * `get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY()` +/// * `get_CANCEL_REASON_SELF_MATCH_MAKER()` +/// * `get_CANCEL_REASON_SELF_MATCH_TAKER()` +/// * `get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING()` /// /// Market account lookup: /// @@ -95,6 +103,7 @@ /// * `get_all_market_account_ids_for_user()` /// * `get_market_account()` /// * `get_market_accounts()` +/// * `get_market_event_handle_creation_numbers()` /// * `has_market_account()` /// * `has_market_account_by_market_account_id()` /// * `has_market_account_by_market_id()` @@ -132,6 +141,7 @@ /// /// Account registration: /// +/// * `init_market_event_handles_if_missing()` /// * `register_market_account()` /// * `register_market_account_generic_base()` /// @@ -156,6 +166,14 @@ /// * `get_next_order_access_key_internal()` /// * `get_active_market_order_ids_internal()` /// +/// Market events: +/// +/// * `create_cancel_order_event_internal()` +/// * `create_fill_event_internal()` +/// * `emit_limit_order_events_internal()` +/// * `emit_market_order_events_internal()` +/// * `emit_swap_maker_fill_events_internal()` +/// /// ## Dependency charts /// /// The below dependency charts use `mermaid.js` syntax, which can be @@ -239,11 +257,14 @@ /// get_market_account --> vectorize_open_orders /// /// get_open_order_id_internal --> get_market_account_id -/// get_open_order_id_internal --> has_market_account_by_market_account_id +/// get_open_order_id_internal --> +/// has_market_account_by_market_account_id /// /// has_market_account --> has_market_account_by_market_account_id /// has_market_account --> get_market_account_id /// +/// get_market_event_handle_creation_numbers --> get_market_account_id +/// /// ``` /// /// Market account registration: @@ -255,12 +276,15 @@ /// register_market_account --> registry::is_registered_custodian_id /// register_market_account --> register_market_account_account_entries /// register_market_account --> register_market_account_collateral_entry +/// register_market_account --> init_market_event_handles_if_missing /// /// register_market_account_generic_base --> register_market_account /// /// register_market_account_account_entries --> /// registry::get_market_info_for_market_account /// +/// init_market_event_handles_if_missing --> has_market_account +/// /// ``` /// /// Internal order management: @@ -274,6 +298,12 @@ /// /// ``` /// +/// Market events: +/// +/// emit_limit_order_events_internal --> emit_maker_fill_event +/// emit_market_order_events_internal --> emit_maker_fill_event +/// emit_swap_maker_fill_events_internal --> emit_maker_fill_event +/// /// # Complete DocGen index /// /// The below index is automatically generated from source code: From af94b6771f61c036a91cbd4203c5d5210a267fb1 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 16:08:43 -0700 Subject: [PATCH 54/56] Fix typos, build docs --- .../econia/doc/img/market_forward_dep.svg | 820 +++--- src/move/econia/doc/img/user_forward_dep.svg | 1046 +++---- src/move/econia/doc/market.md | 2458 ++++++++++------- src/move/econia/doc/user.md | 1971 +++++++++++-- src/move/econia/sources/market.move | 14 +- src/move/econia/sources/user.move | 2 +- 6 files changed, 4196 insertions(+), 2115 deletions(-) diff --git a/src/move/econia/doc/img/market_forward_dep.svg b/src/move/econia/doc/img/market_forward_dep.svg index f93d639ef..2bd14419c 100644 --- a/src/move/econia/doc/img/market_forward_dep.svg +++ b/src/move/econia/doc/img/market_forward_dep.svg @@ -4,934 +4,952 @@ - + G - + market - -market - - - -vector - -vector - - - -market->vector - - + +market - + option - -option + +option - + market->option - - + + - + string - -string + +string - + market->string - - + + - + signer - -signer + +signer - + market->signer - - + + - + type_info - -type_info + +type_info - + market->type_info - - + + - + table - -table + +table - + market->table - - + + + + + +guid + +guid + + + +market->guid + + event - -event + +event market->event - - + + account - -account + +account market->account - - + + coin - -coin + +coin market->coin - - + + avl_queue - -avl_queue + +avl_queue market->avl_queue - - + + tablist - -tablist + +tablist market->tablist - - + + resource_account - -resource_account + +resource_account market->resource_account - - + + incentives - -incentives + +incentives market->incentives - - + + registry - -registry + +registry market->registry - - + + user - -user + +user market->user - - + + + + + +vector + +vector option->vector - - - - - -string->vector - - + + string->option - - + + + + + +string->vector + + type_info->string - - + + - + error - -error + +error type_info->error - - + + - + features - -features + +features type_info->features - - + + - + bcs - -bcs + +bcs type_info->bcs - - - - - -event->bcs - - - - - -guid - -guid + + event->guid - - + + - - -account->vector - - + + +event->bcs + + account->option - - + + account->signer - - + + account->type_info - - + + account->table - - + + + + + +account->guid + + account->event - - + + + + + +account->vector + + account->error - - + + account->bcs - - - - - -account->guid - - + + system_addresses - -system_addresses + +system_addresses account->system_addresses - - + + hash - -hash + +hash account->hash - - + + ed25519 - -ed25519 + +ed25519 account->ed25519 - - + + multi_ed25519 - -multi_ed25519 + +multi_ed25519 account->multi_ed25519 - - + + from_bcs - -from_bcs + +from_bcs account->from_bcs - - + + create_signer - -create_signer + +create_signer account->create_signer - - + + chain_id - -chain_id + +chain_id account->chain_id - - + + coin->option - - + + coin->string - - + + coin->signer - - + + coin->type_info - - + + coin->event - - + + coin->account - - + + coin->error - - + + coin->system_addresses - - + + aggregator - -aggregator + +aggregator coin->aggregator - - + + aggregator_factory - -aggregator_factory + +aggregator_factory coin->aggregator_factory - - + + optional_aggregator - -optional_aggregator + +optional_aggregator coin->optional_aggregator - - + + avl_queue->option - - + + avl_queue->table - - + + table_with_length - -table_with_length + +table_with_length avl_queue->table_with_length - - + + tablist->option - - + + tablist->table_with_length - - + + resource_account->account - - + + resource_account->bcs - - + + timestamp - -timestamp + +timestamp resource_account->timestamp - - - - - -incentives->vector - - + + incentives->signer - - + + incentives->type_info - - + + incentives->coin - - + + incentives->tablist - - + + incentives->resource_account - - + + + + + +incentives->vector + + aptos_coin - -aptos_coin + +aptos_coin incentives->aptos_coin - - + + registry->option - - + + registry->string - - + + registry->signer - - + + registry->type_info - - + + registry->table - - + + registry->event - - + + registry->account - - + + registry->coin - - + + registry->tablist - - + + registry->incentives - - - - - -user->vector - - + + user->option - - + + user->string - - + + user->signer - - + + user->type_info - - + + user->table - - + + - + +user->guid + + + + + +user->event + + + + + +user->account + + + + + user->coin - - + + - + user->tablist - - + + - + user->registry - - + + + + + +user->vector + + - + features->signer - - + + - + features->error - - + + - + system_addresses->signer - - + + - + system_addresses->error - - + + - + ed25519->option - - + + - + ed25519->type_info - - + + - + ed25519->error - - + + - + ed25519->bcs - - + + - + ed25519->hash - - + + - + multi_ed25519->option - - + + - + multi_ed25519->error - - + + - + multi_ed25519->features - - + + - + multi_ed25519->bcs - - + + - + multi_ed25519->hash - - + + - + multi_ed25519->ed25519 - - + + - + from_bcs->string - - + + - + chain_id->system_addresses - - + + - + aggregator_factory->table - - + + - + aggregator_factory->error - - + + - + aggregator_factory->system_addresses - - + + - + aggregator_factory->aggregator - - + + - + optional_aggregator->option - - + + - + optional_aggregator->error - - + + - + optional_aggregator->aggregator - - + + - + optional_aggregator->aggregator_factory - - + + - + table_with_length->table - - + + - + table_with_length->error - - + + - + timestamp->error - - + + - + timestamp->system_addresses - - - - - -aptos_coin->vector - - + + - + aptos_coin->option - - + + - + aptos_coin->string - - + + - + aptos_coin->signer - - + + - + aptos_coin->coin - - + + + + + +aptos_coin->vector + + - + aptos_coin->error - - + + - + aptos_coin->system_addresses - - + + diff --git a/src/move/econia/doc/img/user_forward_dep.svg b/src/move/econia/doc/img/user_forward_dep.svg index 933817663..91db53d66 100644 --- a/src/move/econia/doc/img/user_forward_dep.svg +++ b/src/move/econia/doc/img/user_forward_dep.svg @@ -4,814 +4,832 @@ - + G - + user - -user + +user vector - -vector + +vector user->vector - - + + option - -option + +option user->option - - + + string - -string + +string user->string - - + + signer - -signer + +signer user->signer - - + + type_info - -type_info + +type_info user->type_info - - + + table - -table + +table user->table - - + + - + +guid + +guid + + + +user->guid + + + + + +event + +event + + + +user->event + + + + + +account + +account + + + +user->account + + + + + coin - -coin + +coin - + user->coin - - + + - + tablist - -tablist + +tablist - + user->tablist - - + + - + registry - -registry + +registry - + user->registry - - + + - + option->vector - - + + - + string->vector - - + + - + string->option - - + + - + type_info->string - - + + - + error - -error + +error - + type_info->error - - + + - + features - -features + +features - + type_info->features - - + + - + bcs - -bcs + +bcs - + type_info->bcs - - + + + + + +event->guid + + + + + +event->bcs + + + + + +account->vector + + + + + +account->option + + + + + +account->signer + + + + + +account->type_info + + + + + +account->table + + + + + +account->guid + + + + + +account->event + + + + + +account->error + + + + + +account->bcs + + + + + +system_addresses + +system_addresses + + + +account->system_addresses + + + + + +hash + +hash + + + +account->hash + + + + + +ed25519 + +ed25519 + + + +account->ed25519 + + + + + +multi_ed25519 + +multi_ed25519 + + + +account->multi_ed25519 + + + + + +from_bcs + +from_bcs + + + +account->from_bcs + + + + + +create_signer + +create_signer + + + +account->create_signer + + + + + +chain_id + +chain_id + + + +account->chain_id + + - + coin->option - - + + - + coin->string - - + + - + coin->signer - - + + - + coin->type_info - - - - - -coin->error - - - - - -system_addresses - -system_addresses - - - -coin->system_addresses - - - - - -event - -event + + - + coin->event - - - - - -account - -account + + - + coin->account - - + + + + + +coin->error + + + + + +coin->system_addresses + + - + aggregator - -aggregator + +aggregator - + coin->aggregator - - + + - + aggregator_factory - -aggregator_factory + +aggregator_factory - + coin->aggregator_factory - - + + - + optional_aggregator - -optional_aggregator + +optional_aggregator - + coin->optional_aggregator - - + + - + tablist->option - - + + - + table_with_length - -table_with_length + +table_with_length - + tablist->table_with_length - - + + - + registry->option - - + + - + registry->string - - + + - + registry->signer - - + + - + registry->type_info - - + + - + registry->table - - - - - -registry->coin - - - - - -registry->tablist - - + + - + registry->event - - + + - + registry->account - - + + + + + +registry->coin + + + + + +registry->tablist + + - + incentives - -incentives + +incentives - + registry->incentives - - + + - + features->signer - - + + - + features->error - - + + - + system_addresses->signer - - + + - + system_addresses->error - - - - - -event->bcs - - - - - -guid - -guid + + - - -event->guid - - - - - -account->vector - - - - - -account->option - - - - - -account->signer - - - - - -account->type_info - - - - - -account->table - - - - - -account->error - - - - - -account->bcs - - - - - -account->system_addresses - - - - - -account->event - - - - - -account->guid - - + + +ed25519->option + + - - -hash - -hash + + +ed25519->type_info + + - - -account->hash - - + + +ed25519->error + + - - -ed25519 - -ed25519 + + +ed25519->bcs + + - - -account->ed25519 - - + + +ed25519->hash + + - - -multi_ed25519 - -multi_ed25519 + + +multi_ed25519->option + + - - -account->multi_ed25519 - - + + +multi_ed25519->error + + - - -from_bcs - -from_bcs + + +multi_ed25519->features + + - - -account->from_bcs - - + + +multi_ed25519->bcs + + - - -create_signer - -create_signer + + +multi_ed25519->hash + + - - -account->create_signer - - + + +multi_ed25519->ed25519 + + - - -chain_id - -chain_id + + +from_bcs->string + + - - -account->chain_id - - + + +chain_id->system_addresses + + - + aggregator_factory->table - - + + - + aggregator_factory->error - - + + - + aggregator_factory->system_addresses - - + + - + aggregator_factory->aggregator - - + + - + optional_aggregator->option - - + + - + optional_aggregator->error - - + + - + optional_aggregator->aggregator - - + + - + optional_aggregator->aggregator_factory - - + + - + table_with_length->table - - + + - + table_with_length->error - - + + - + incentives->vector - - + + - + incentives->signer - - + + - + incentives->type_info - - + + - + incentives->coin - - + + - + incentives->tablist - - + + aptos_coin - -aptos_coin + +aptos_coin - + incentives->aptos_coin - - + + resource_account - -resource_account + +resource_account - + incentives->resource_account - - - - - -ed25519->option - - - - - -ed25519->type_info - - - - - -ed25519->error - - - - - -ed25519->bcs - - - - - -ed25519->hash - - - - - -multi_ed25519->option - - - - - -multi_ed25519->error - - - - - -multi_ed25519->features - - - - - -multi_ed25519->bcs - - - - - -multi_ed25519->hash - - - - - -multi_ed25519->ed25519 - - - - - -from_bcs->string - - - - - -chain_id->system_addresses - - + + - + aptos_coin->vector - - + + - + aptos_coin->option - - + + - + aptos_coin->string - - + + - + aptos_coin->signer - - + + - + aptos_coin->coin - - + + - + aptos_coin->error - - + + - + aptos_coin->system_addresses - - - - - -resource_account->bcs - - + + - + resource_account->account - - + + + + + +resource_account->bcs + + timestamp - -timestamp + +timestamp - + resource_account->timestamp - - + + - + timestamp->error - - + + - + timestamp->system_addresses - - + + diff --git a/src/move/econia/doc/market.md b/src/move/econia/doc/market.md index 78267a2a4..30407c0ee 100644 --- a/src/move/econia/doc/market.md +++ b/src/move/econia/doc/market.md @@ -11,31 +11,31 @@ order book entry is added under the resource account at a new market ID. Once a market is registered, signing users and delegated custodians -can place limit orders on the book as makers and/or as takers, -takers can place market orders or swaps against the order book, and -makers can cancel or change the size of any outstanding orders they -have on the book. +can place limit orders and market orders, and cancel or change the +size of any open orders. Swaps can be placed permissionlessly +without a market account. -Econia implements an atomic matching engine for processing taker -fills against maker orders on the book, and emits events in response -to changes in order book state. Notably, Econia evicts the ask or -bid with the lowest price-time priority when inserting a limit order -to a binary search tree that exceeds a critical height. +Econia implements an atomic matching engine, and emits events in +response to changes in order book state as well as assorted market +operations. Notably, Econia evicts the ask or bid with the lowest +price-time priority when inserting a limit order to a binary search +tree that exceeds a critical height. Multiple API variants are supported for market registration and order management function, to enable diagnostic function returns, public entry calls, etc. -When someone places an order that result in one or more fills and/or -a post to the book, they are issued a "market order ID" that is -unique to the given market but not necessarily across different -markets. Each market order ID encodes a counter for the number of +All orders are issued an order ID upon placement, which is unique to +the given market. The order ID encodes a counter fo the number of orders that have been placed on the corresponding market. For orders that result in a post to the book, the market order ID additionally encodes an "AVL queue access key" (essentially a pointer into order book memory), which is required for order lookup during order size change and/or order cancellation operations. +Note that the terms "order ID" and "market order ID" are used +interchangeably. + @@ -112,10 +112,19 @@ size change and/or order cancellation operations. * did_order_post() * get_market_order_id_counter() * get_market_order_id_price() -* get_market_order_id_side() +* get_posted_order_id_side() + + + + +### Event handle lookup + + +* get_market_event_handle_creation_info() +* get_swapper_event_handle_creation_numbers() - + ### Order lookup @@ -128,7 +137,7 @@ size change and/or order cancellation operations. * has_open_order() - + ## Public function index @@ -137,7 +146,7 @@ See the [dependency charts](#dependency-charts) for a visual map of associated function wrappers. - + ### Market registration @@ -147,7 +156,7 @@ associated function wrappers. * register_market_base_generic() - + ### Limit orders @@ -157,7 +166,7 @@ associated function wrappers. * place_limit_order_user_entry() - + ### Passive advance limit orders @@ -167,7 +176,7 @@ associated function wrappers. * place_limit_order_passive_advance_user_entry() - + ### Market orders @@ -177,7 +186,7 @@ associated function wrappers. * place_market_order_user_entry() - + ### Swaps @@ -188,7 +197,7 @@ associated function wrappers. * swap_generic() - + ### Change order size @@ -197,7 +206,7 @@ associated function wrappers. * change_order_size_user() - + ### Cancel orders @@ -208,7 +217,7 @@ associated function wrappers. * cancel_all_orders_user() - + ## Dependency charts @@ -220,7 +229,7 @@ a browser renders the diagrams with coloring that makes it difficult to read, try a different browser. - + ### Internal dependencies @@ -313,6 +322,18 @@ end ``` +Cancel reasons: + +```mermaid + +flowchart LR + +place_market_order --> +get_cancel_reason_option_for_market_order_or_swap +swap --> get_cancel_reason_option_for_market_order_or_swap + +``` + Changing order size: ```mermaid @@ -353,21 +374,20 @@ get_price_levels --> get_open_orders get_price_levels --> get_price_levels_for_side get_price_levels_all --> get_price_levels get_open_order --> has_open_order -get_open_order --> get_market_order_id_side -get_open_order --> get_market_order_id_avl_queue_access_key -get_market_order_id_side --> -get_market_order_id_avl_queue_access_key -has_open_order --> get_market_order_id_side -has_open_order --> get_market_order_id_avl_queue_access_key +get_open_order --> get_posted_order_id_side +get_open_order --> get_order_id_avl_queue_access_key +get_posted_order_id_side --> did_order_post +get_posted_order_id_side --> get_order_id_avl_queue_access_key +has_open_order --> get_posted_order_id_side +has_open_order --> get_order_id_avl_queue_access_key get_open_orders --> get_open_orders_for_side get_open_orders_all --> get_open_orders get_market_order_id_price --> did_order_post -get_market_order_id_side --> did_order_post ``` - + ### External module dependencies @@ -436,6 +456,7 @@ place_limit_order --> resource_account::get_address place_market_order --> resource_account::get_address swap --> resource_account::get_address +swap --> resource_account::get_signer change_order_size --> resource_account::get_address @@ -449,6 +470,9 @@ has_open_order --> resource_account::get_address get_price_levels --> resource_account::get_address +get_market_event_handle_creation_info --> +resource_account::get_address + ``` user: @@ -463,12 +487,15 @@ place_limit_order --> user::deposit_assets_internal place_limit_order --> user::get_next_order_access_key_internal place_limit_order --> user::place_order_internal place_limit_order --> user::cancel_order_internal +place_limit_order --> user::emit_limit_order_events_internal place_market_order --> user::get_asset_counts_internal place_market_order --> user::withdraw_assets_internal place_market_order --> user::deposit_assets_internal +place_market_order --> user::emit_market_order_events_internal match --> user::fill_order_internal +match --> user::create_fill_event_internal change_order_size --> user::change_order_size_internal @@ -480,10 +507,13 @@ has_open_order --> user::get_open_order_id_internal get_open_orders_for_side --> user::get_open_order_id_internal +swap --> user::create_cancel_order_event_internal +swap --> user::emit_swap_maker_fill_events_internal + ``` - + ## Order management testing @@ -495,7 +525,7 @@ logical branches, returns, and state updates. Aborts are tested individually for each function. - + ### Functions with aborts @@ -512,7 +542,7 @@ Function aborts to test: * [x] swap() - + ### Return proxies @@ -563,7 +593,7 @@ Function returns to test: * [x] swap_generic() - + ### Invocation proxies @@ -594,7 +624,7 @@ Function invocations to test: * [x] swap_generic() - + ### Branching functions @@ -617,7 +647,7 @@ Functions with logical branches to test: See each function for its logical branches. - + ## Complete DocGen index @@ -629,245 +659,255 @@ The below index is automatically generated from source code: - [View functions](#@View_functions_1) - [Constant getters](#@Constant_getters_2) - [Market order ID decoders](#@Market_order_ID_decoders_3) - - [Order lookup](#@Order_lookup_4) -- [Public function index](#@Public_function_index_5) - - [Market registration](#@Market_registration_6) - - [Limit orders](#@Limit_orders_7) - - [Passive advance limit orders](#@Passive_advance_limit_orders_8) - - [Market orders](#@Market_orders_9) - - [Swaps](#@Swaps_10) - - [Change order size](#@Change_order_size_11) - - [Cancel orders](#@Cancel_orders_12) -- [Dependency charts](#@Dependency_charts_13) - - [Internal dependencies](#@Internal_dependencies_14) - - [External module dependencies](#@External_module_dependencies_15) -- [Order management testing](#@Order_management_testing_16) - - [Functions with aborts](#@Functions_with_aborts_17) - - [Return proxies](#@Return_proxies_18) - - [Invocation proxies](#@Invocation_proxies_19) - - [Branching functions](#@Branching_functions_20) -- [Complete DocGen index](#@Complete_DocGen_index_21) -- [Struct `FillEvent`](#0xc0deb00c_market_FillEvent) -- [Resource `FillEventHandles`](#0xc0deb00c_market_FillEventHandles) -- [Struct `MakerEvent`](#0xc0deb00c_market_MakerEvent) + - [Event handle lookup](#@Event_handle_lookup_4) + - [Order lookup](#@Order_lookup_5) +- [Public function index](#@Public_function_index_6) + - [Market registration](#@Market_registration_7) + - [Limit orders](#@Limit_orders_8) + - [Passive advance limit orders](#@Passive_advance_limit_orders_9) + - [Market orders](#@Market_orders_10) + - [Swaps](#@Swaps_11) + - [Change order size](#@Change_order_size_12) + - [Cancel orders](#@Cancel_orders_13) +- [Dependency charts](#@Dependency_charts_14) + - [Internal dependencies](#@Internal_dependencies_15) + - [External module dependencies](#@External_module_dependencies_16) +- [Order management testing](#@Order_management_testing_17) + - [Functions with aborts](#@Functions_with_aborts_18) + - [Return proxies](#@Return_proxies_19) + - [Invocation proxies](#@Invocation_proxies_20) + - [Branching functions](#@Branching_functions_21) +- [Complete DocGen index](#@Complete_DocGen_index_22) +- [Struct `MarketEventHandleCreationInfo`](#0xc0deb00c_market_MarketEventHandleCreationInfo) +- [Resource `MarketEventHandles`](#0xc0deb00c_market_MarketEventHandles) +- [Struct `MarketEventHandlesForMarket`](#0xc0deb00c_market_MarketEventHandlesForMarket) - [Struct `Order`](#0xc0deb00c_market_Order) - [Struct `OrderBook`](#0xc0deb00c_market_OrderBook) - [Resource `OrderBooks`](#0xc0deb00c_market_OrderBooks) - [Struct `OrderView`](#0xc0deb00c_market_OrderView) - [Struct `OrdersView`](#0xc0deb00c_market_OrdersView) +- [Struct `PlaceSwapOrderEvent`](#0xc0deb00c_market_PlaceSwapOrderEvent) - [Struct `PriceLevel`](#0xc0deb00c_market_PriceLevel) - [Struct `PriceLevels`](#0xc0deb00c_market_PriceLevels) +- [Struct `SwapperEventHandleCreationNumbers`](#0xc0deb00c_market_SwapperEventHandleCreationNumbers) +- [Resource `SwapperEventHandles`](#0xc0deb00c_market_SwapperEventHandles) +- [Struct `SwapperEventHandlesForMarket`](#0xc0deb00c_market_SwapperEventHandlesForMarket) +- [Struct `MakerEvent`](#0xc0deb00c_market_MakerEvent) - [Resource `Orders`](#0xc0deb00c_market_Orders) - [Struct `TakerEvent`](#0xc0deb00c_market_TakerEvent) -- [Constants](#@Constants_22) +- [Constants](#@Constants_23) - [Function `did_order_post`](#0xc0deb00c_market_did_order_post) - - [Testing](#@Testing_23) -- [Function `get_ABORT`](#0xc0deb00c_market_get_ABORT) - [Testing](#@Testing_24) -- [Function `get_ASK`](#0xc0deb00c_market_get_ASK) +- [Function `get_ABORT`](#0xc0deb00c_market_get_ABORT) - [Testing](#@Testing_25) -- [Function `get_BID`](#0xc0deb00c_market_get_BID) +- [Function `get_ASK`](#0xc0deb00c_market_get_ASK) - [Testing](#@Testing_26) -- [Function `get_BUY`](#0xc0deb00c_market_get_BUY) +- [Function `get_BID`](#0xc0deb00c_market_get_BID) - [Testing](#@Testing_27) -- [Function `get_CANCEL_BOTH`](#0xc0deb00c_market_get_CANCEL_BOTH) +- [Function `get_BUY`](#0xc0deb00c_market_get_BUY) - [Testing](#@Testing_28) -- [Function `get_CANCEL_MAKER`](#0xc0deb00c_market_get_CANCEL_MAKER) +- [Function `get_CANCEL_BOTH`](#0xc0deb00c_market_get_CANCEL_BOTH) - [Testing](#@Testing_29) -- [Function `get_CANCEL_TAKER`](#0xc0deb00c_market_get_CANCEL_TAKER) +- [Function `get_CANCEL_MAKER`](#0xc0deb00c_market_get_CANCEL_MAKER) - [Testing](#@Testing_30) -- [Function `get_FILL_OR_ABORT`](#0xc0deb00c_market_get_FILL_OR_ABORT) +- [Function `get_CANCEL_TAKER`](#0xc0deb00c_market_get_CANCEL_TAKER) - [Testing](#@Testing_31) -- [Function `get_HI_PRICE`](#0xc0deb00c_market_get_HI_PRICE) +- [Function `get_FILL_OR_ABORT`](#0xc0deb00c_market_get_FILL_OR_ABORT) - [Testing](#@Testing_32) -- [Function `get_IMMEDIATE_OR_CANCEL`](#0xc0deb00c_market_get_IMMEDIATE_OR_CANCEL) +- [Function `get_HI_PRICE`](#0xc0deb00c_market_get_HI_PRICE) - [Testing](#@Testing_33) -- [Function `get_MAX_POSSIBLE`](#0xc0deb00c_market_get_MAX_POSSIBLE) +- [Function `get_IMMEDIATE_OR_CANCEL`](#0xc0deb00c_market_get_IMMEDIATE_OR_CANCEL) - [Testing](#@Testing_34) -- [Function `get_NO_CUSTODIAN`](#0xc0deb00c_market_get_NO_CUSTODIAN) +- [Function `get_MAX_POSSIBLE`](#0xc0deb00c_market_get_MAX_POSSIBLE) - [Testing](#@Testing_35) -- [Function `get_NO_RESTRICTION`](#0xc0deb00c_market_get_NO_RESTRICTION) +- [Function `get_NO_CUSTODIAN`](#0xc0deb00c_market_get_NO_CUSTODIAN) - [Testing](#@Testing_36) -- [Function `get_NO_UNDERWRITER`](#0xc0deb00c_market_get_NO_UNDERWRITER) +- [Function `get_NO_RESTRICTION`](#0xc0deb00c_market_get_NO_RESTRICTION) - [Testing](#@Testing_37) -- [Function `get_POST_OR_ABORT`](#0xc0deb00c_market_get_POST_OR_ABORT) +- [Function `get_NO_UNDERWRITER`](#0xc0deb00c_market_get_NO_UNDERWRITER) - [Testing](#@Testing_38) -- [Function `get_PERCENT`](#0xc0deb00c_market_get_PERCENT) +- [Function `get_POST_OR_ABORT`](#0xc0deb00c_market_get_POST_OR_ABORT) - [Testing](#@Testing_39) -- [Function `get_SELL`](#0xc0deb00c_market_get_SELL) +- [Function `get_PERCENT`](#0xc0deb00c_market_get_PERCENT) - [Testing](#@Testing_40) -- [Function `get_TICKS`](#0xc0deb00c_market_get_TICKS) +- [Function `get_SELL`](#0xc0deb00c_market_get_SELL) - [Testing](#@Testing_41) -- [Function `get_market_order_id_counter`](#0xc0deb00c_market_get_market_order_id_counter) +- [Function `get_TICKS`](#0xc0deb00c_market_get_TICKS) - [Testing](#@Testing_42) -- [Function `get_market_order_id_price`](#0xc0deb00c_market_get_market_order_id_price) - - [Aborts](#@Aborts_43) +- [Function `get_market_event_handle_creation_info`](#0xc0deb00c_market_get_market_event_handle_creation_info) + - [Testing](#@Testing_43) +- [Function `get_market_order_id_counter`](#0xc0deb00c_market_get_market_order_id_counter) - [Testing](#@Testing_44) -- [Function `get_market_order_id_side`](#0xc0deb00c_market_get_market_order_id_side) +- [Function `get_market_order_id_price`](#0xc0deb00c_market_get_market_order_id_price) - [Aborts](#@Aborts_45) - [Testing](#@Testing_46) - [Function `get_open_order`](#0xc0deb00c_market_get_open_order) - - [Aborts](#@Aborts_47) - - [Testing](#@Testing_48) + - [Testing](#@Testing_47) - [Function `get_open_orders`](#0xc0deb00c_market_get_open_orders) - - [Parameters](#@Parameters_49) - - [Aborts](#@Aborts_50) - - [Testing](#@Testing_51) + - [Parameters](#@Parameters_48) + - [Aborts](#@Aborts_49) + - [Testing](#@Testing_50) - [Function `get_open_orders_all`](#0xc0deb00c_market_get_open_orders_all) - - [Testing](#@Testing_52) + - [Testing](#@Testing_51) +- [Function `get_posted_order_id_side`](#0xc0deb00c_market_get_posted_order_id_side) + - [Aborts](#@Aborts_52) + - [Testing](#@Testing_53) - [Function `get_price_levels`](#0xc0deb00c_market_get_price_levels) - - [Parameters](#@Parameters_53) - - [Testing](#@Testing_54) -- [Function `get_price_levels_all`](#0xc0deb00c_market_get_price_levels_all) + - [Parameters](#@Parameters_54) - [Testing](#@Testing_55) -- [Function `has_open_order`](#0xc0deb00c_market_has_open_order) +- [Function `get_price_levels_all`](#0xc0deb00c_market_get_price_levels_all) - [Testing](#@Testing_56) +- [Function `get_swapper_event_handle_creation_numbers`](#0xc0deb00c_market_get_swapper_event_handle_creation_numbers) + - [Testing](#@Testing_57) +- [Function `has_open_order`](#0xc0deb00c_market_has_open_order) + - [Testing](#@Testing_58) - [Function `cancel_all_orders_custodian`](#0xc0deb00c_market_cancel_all_orders_custodian) - - [Invocation testing](#@Invocation_testing_57) + - [Invocation testing](#@Invocation_testing_59) - [Function `cancel_order_custodian`](#0xc0deb00c_market_cancel_order_custodian) - - [Invocation testing](#@Invocation_testing_58) + - [Invocation testing](#@Invocation_testing_60) - [Function `change_order_size_custodian`](#0xc0deb00c_market_change_order_size_custodian) - - [Invocation testing](#@Invocation_testing_59) + - [Invocation testing](#@Invocation_testing_61) - [Function `place_limit_order_custodian`](#0xc0deb00c_market_place_limit_order_custodian) - - [Invocation and return testing](#@Invocation_and_return_testing_60) + - [Invocation and return testing](#@Invocation_and_return_testing_62) - [Function `place_limit_order_passive_advance_custodian`](#0xc0deb00c_market_place_limit_order_passive_advance_custodian) - - [Invocation and return testing](#@Invocation_and_return_testing_61) + - [Invocation and return testing](#@Invocation_and_return_testing_63) - [Function `place_limit_order_passive_advance_user`](#0xc0deb00c_market_place_limit_order_passive_advance_user) - - [Invocation and return testing](#@Invocation_and_return_testing_62) + - [Invocation and return testing](#@Invocation_and_return_testing_64) - [Function `place_limit_order_user`](#0xc0deb00c_market_place_limit_order_user) - - [Invocation and return testing](#@Invocation_and_return_testing_63) + - [Invocation and return testing](#@Invocation_and_return_testing_65) - [Function `place_market_order_custodian`](#0xc0deb00c_market_place_market_order_custodian) - - [Invocation and return testing](#@Invocation_and_return_testing_64) + - [Invocation and return testing](#@Invocation_and_return_testing_66) - [Function `place_market_order_user`](#0xc0deb00c_market_place_market_order_user) - - [Invocation and return testing](#@Invocation_and_return_testing_65) + - [Invocation and return testing](#@Invocation_and_return_testing_67) - [Function `register_market_base_coin`](#0xc0deb00c_market_register_market_base_coin) - - [Type parameters](#@Type_parameters_66) - - [Parameters](#@Parameters_67) - - [Returns](#@Returns_68) - - [Testing](#@Testing_69) + - [Type parameters](#@Type_parameters_68) + - [Parameters](#@Parameters_69) + - [Returns](#@Returns_70) + - [Testing](#@Testing_71) - [Function `register_market_base_generic`](#0xc0deb00c_market_register_market_base_generic) - - [Type parameters](#@Type_parameters_70) - - [Parameters](#@Parameters_71) - - [Returns](#@Returns_72) - - [Testing](#@Testing_73) + - [Type parameters](#@Type_parameters_72) + - [Parameters](#@Parameters_73) + - [Returns](#@Returns_74) + - [Testing](#@Testing_75) - [Function `swap_between_coinstores`](#0xc0deb00c_market_swap_between_coinstores) - - [Type Parameters](#@Type_Parameters_74) - - [Parameters](#@Parameters_75) - - [Returns](#@Returns_76) - - [Testing](#@Testing_77) + - [Type Parameters](#@Type_Parameters_76) + - [Parameters](#@Parameters_77) + - [Returns](#@Returns_78) + - [Emits](#@Emits_79) + - [Testing](#@Testing_80) - [Function `swap_coins`](#0xc0deb00c_market_swap_coins) - - [Type Parameters](#@Type_Parameters_78) - - [Parameters](#@Parameters_79) - - [Returns](#@Returns_80) - - [Terminology](#@Terminology_81) - - [Testing](#@Testing_82) + - [Type Parameters](#@Type_Parameters_81) + - [Parameters](#@Parameters_82) + - [Returns](#@Returns_83) + - [Terminology](#@Terminology_84) + - [Testing](#@Testing_85) - [Function `swap_generic`](#0xc0deb00c_market_swap_generic) - - [Type Parameters](#@Type_Parameters_83) - - [Parameters](#@Parameters_84) - - [Returns](#@Returns_85) - - [Testing](#@Testing_86) + - [Type Parameters](#@Type_Parameters_86) + - [Parameters](#@Parameters_87) + - [Returns](#@Returns_88) + - [Testing](#@Testing_89) - [Function `cancel_all_orders_user`](#0xc0deb00c_market_cancel_all_orders_user) - - [Invocation testing](#@Invocation_testing_87) + - [Invocation testing](#@Invocation_testing_90) - [Function `cancel_order_user`](#0xc0deb00c_market_cancel_order_user) - - [Invocation testing](#@Invocation_testing_88) + - [Invocation testing](#@Invocation_testing_91) - [Function `change_order_size_user`](#0xc0deb00c_market_change_order_size_user) - - [Invocation testing](#@Invocation_testing_89) + - [Invocation testing](#@Invocation_testing_92) - [Function `place_limit_order_passive_advance_user_entry`](#0xc0deb00c_market_place_limit_order_passive_advance_user_entry) - - [Invocation testing](#@Invocation_testing_90) + - [Invocation testing](#@Invocation_testing_93) - [Function `place_limit_order_user_entry`](#0xc0deb00c_market_place_limit_order_user_entry) - - [Invocation testing](#@Invocation_testing_91) + - [Invocation testing](#@Invocation_testing_94) - [Function `place_market_order_user_entry`](#0xc0deb00c_market_place_market_order_user_entry) - - [Invocation testing](#@Invocation_testing_92) + - [Invocation testing](#@Invocation_testing_95) - [Function `register_market_base_coin_from_coinstore`](#0xc0deb00c_market_register_market_base_coin_from_coinstore) - - [Testing](#@Testing_93) + - [Testing](#@Testing_96) - [Function `swap_between_coinstores_entry`](#0xc0deb00c_market_swap_between_coinstores_entry) - - [Invocation testing](#@Invocation_testing_94) + - [Invocation testing](#@Invocation_testing_97) - [Function `cancel_all_orders`](#0xc0deb00c_market_cancel_all_orders) - - [Parameters](#@Parameters_95) - - [Expected value testing](#@Expected_value_testing_96) + - [Parameters](#@Parameters_98) + - [Expected value testing](#@Expected_value_testing_99) - [Function `cancel_order`](#0xc0deb00c_market_cancel_order) - - [Parameters](#@Parameters_97) - - [Aborts](#@Aborts_98) - - [Emits](#@Emits_99) - - [Expected value testing](#@Expected_value_testing_100) - - [Failure testing](#@Failure_testing_101) + - [Parameters](#@Parameters_100) + - [Aborts](#@Aborts_101) + - [Expected value testing](#@Expected_value_testing_102) + - [Failure testing](#@Failure_testing_103) - [Function `change_order_size`](#0xc0deb00c_market_change_order_size) - - [Parameters](#@Parameters_102) - - [Aborts](#@Aborts_103) - - [Emits](#@Emits_104) - - [Expected value testing](#@Expected_value_testing_105) - - [Failure testing](#@Failure_testing_106) -- [Function `get_market_order_id_avl_queue_access_key`](#0xc0deb00c_market_get_market_order_id_avl_queue_access_key) - - [Testing](#@Testing_107) + - [Parameters](#@Parameters_104) + - [Aborts](#@Aborts_105) + - [Expected value testing](#@Expected_value_testing_106) + - [Failure testing](#@Failure_testing_107) +- [Function `get_cancel_reason_option_for_market_order_or_swap`](#0xc0deb00c_market_get_cancel_reason_option_for_market_order_or_swap) + - [Parameters](#@Parameters_108) + - [Returns](#@Returns_109) - [Function `get_open_orders_for_side`](#0xc0deb00c_market_get_open_orders_for_side) - - [Testing](#@Testing_108) + - [Testing](#@Testing_110) +- [Function `get_order_id_avl_queue_access_key`](#0xc0deb00c_market_get_order_id_avl_queue_access_key) + - [Testing](#@Testing_111) - [Function `get_price_levels_for_side`](#0xc0deb00c_market_get_price_levels_for_side) - - [Testing](#@Testing_109) + - [Testing](#@Testing_112) - [Function `init_module`](#0xc0deb00c_market_init_module) - [Function `match`](#0xc0deb00c_market_match) - - [Type Parameters](#@Type_Parameters_110) - - [Parameters](#@Parameters_111) - - [Returns](#@Returns_112) - - [Emits](#@Emits_113) - - [Aborts](#@Aborts_114) - - [Expected value testing](#@Expected_value_testing_115) - - [Failure testing](#@Failure_testing_116) + - [Type Parameters](#@Type_Parameters_113) + - [Parameters](#@Parameters_114) + - [Returns](#@Returns_115) + - [Aborts](#@Aborts_116) + - [Expected value testing](#@Expected_value_testing_117) + - [Failure testing](#@Failure_testing_118) - [Function `place_limit_order`](#0xc0deb00c_market_place_limit_order) - - [Type Parameters](#@Type_Parameters_117) - - [Parameters](#@Parameters_118) - - [Returns](#@Returns_119) - - [Aborts](#@Aborts_120) - - [Emits](#@Emits_121) - - [Restrictions](#@Restrictions_122) - - [Minimum size](#@Minimum_size_123) - - [Self matching](#@Self_matching_124) - - [Expected value testing](#@Expected_value_testing_125) - - [Failure testing](#@Failure_testing_126) + - [Type Parameters](#@Type_Parameters_119) + - [Parameters](#@Parameters_120) + - [Returns](#@Returns_121) + - [Aborts](#@Aborts_122) + - [Restrictions](#@Restrictions_123) + - [Minimum size](#@Minimum_size_124) + - [Self matching](#@Self_matching_125) + - [Expected value testing](#@Expected_value_testing_126) + - [Failure testing](#@Failure_testing_127) - [Function `place_limit_order_passive_advance`](#0xc0deb00c_market_place_limit_order_passive_advance) - - [Price calculations](#@Price_calculations_127) - - [Type Parameters](#@Type_Parameters_128) - - [Parameters](#@Parameters_129) - - [Returns](#@Returns_130) - - [Aborts](#@Aborts_131) - - [Expected value testing](#@Expected_value_testing_132) - - [Failure testing](#@Failure_testing_133) + - [Price calculations](#@Price_calculations_128) + - [Type Parameters](#@Type_Parameters_129) + - [Parameters](#@Parameters_130) + - [Returns](#@Returns_131) + - [Aborts](#@Aborts_132) + - [Expected value testing](#@Expected_value_testing_133) + - [Failure testing](#@Failure_testing_134) - [Function `place_market_order`](#0xc0deb00c_market_place_market_order) - - [Type Parameters](#@Type_Parameters_134) - - [Parameters](#@Parameters_135) - - [Returns](#@Returns_136) - - [Aborts](#@Aborts_137) - - [Expected value testing](#@Expected_value_testing_138) - - [Failure testing](#@Failure_testing_139) + - [Type Parameters](#@Type_Parameters_135) + - [Parameters](#@Parameters_136) + - [Returns](#@Returns_137) + - [Aborts](#@Aborts_138) + - [Expected value testing](#@Expected_value_testing_139) + - [Failure testing](#@Failure_testing_140) - [Function `range_check_trade`](#0xc0deb00c_market_range_check_trade) - - [Terminology](#@Terminology_140) - - [Parameters](#@Parameters_141) - - [Aborts](#@Aborts_142) - - [Failure testing](#@Failure_testing_143) + - [Terminology](#@Terminology_141) + - [Parameters](#@Parameters_142) + - [Aborts](#@Aborts_143) + - [Failure testing](#@Failure_testing_144) - [Function `register_market`](#0xc0deb00c_market_register_market) - - [Type parameters](#@Type_parameters_144) - - [Parameters](#@Parameters_145) - - [Returns](#@Returns_146) - - [Testing](#@Testing_147) + - [Type parameters](#@Type_parameters_145) + - [Parameters](#@Parameters_146) + - [Returns](#@Returns_147) + - [Testing](#@Testing_148) - [Function `swap`](#0xc0deb00c_market_swap) - - [Type Parameters](#@Type_Parameters_148) - - [Parameters](#@Parameters_149) - - [Returns](#@Returns_150) - - [Aborts](#@Aborts_151) - - [Expected value testing](#@Expected_value_testing_152) - - [Failure testing](#@Failure_testing_153) + - [Type Parameters](#@Type_Parameters_149) + - [Parameters](#@Parameters_150) + - [Returns](#@Returns_151) + - [Emits](#@Emits_152) + - [Aborts](#@Aborts_153) + - [Expected value testing](#@Expected_value_testing_154) + - [Failure testing](#@Failure_testing_155) - [Function `index_orders_sdk`](#0xc0deb00c_market_index_orders_sdk) - - [Coverage testing](#@Coverage_testing_154) + - [Coverage testing](#@Coverage_testing_156)
use 0x1::account;
 use 0x1::coin;
 use 0x1::event;
+use 0x1::guid;
 use 0x1::option;
 use 0x1::signer;
 use 0x1::string;
 use 0x1::table;
 use 0x1::type_info;
-use 0x1::vector;
 use 0xc0deb00c::avl_queue;
 use 0xc0deb00c::incentives;
 use 0xc0deb00c::registry;
@@ -890,15 +930,15 @@ The below index is automatically generated from source code:
 ![](img/market_backward_dep.svg)
 
 
-
+
 
-## Struct `FillEvent`
+## Struct `MarketEventHandleCreationInfo`
 
-Emitted for each order fill. If an order results in multiple
-fills, a separate event is emitted for each one.
+View function return for getting event handle creation info of a
+particular MarketEventHandlesForMarket.
 
 
-
struct FillEvent has copy, drop, store
+
struct MarketEventHandleCreationInfo has copy, drop
 
@@ -908,73 +948,38 @@ fills, a separate event is emitted for each one.
-market_id: u64 -
-
- Market ID of corresponding market. -
-
-size: u64 -
-
- The size filled, in lots. -
-
-price: u64 -
-
- Fill price, in ticks per lot. -
-
-maker_side: bool +resource_account_address: address
- ASK or BID, the side of the maker order filled against. + Econia resource account address, corresponding to event + handle creator address.
-maker_market_order_id: u128 +cancel_order_events_handle_creation_num: u64
- Market order ID of for maker order just filled against. + Creation number of cancel_order_events handle in a + MarketEventHandlesForMarket.
-maker: address +place_swap_order_events_handle_creation_num: u64
- Address of user holding maker order. -
-
-maker_custodian_id: u64 -
-
- For given maker, ID of custodian required to approve order - operations and withdrawals on given market account. -
-
-taker_market_order_id: u128 -
-
- Market order ID for taker side of fill. If multiple - FillEvents are emitted for a single order, they all have - the same FillEvent.taker_order_id. If a limit order that - crosses the spread partially fills as a taker then posts as - a maker, FillEvent.taker_market_order_id for the taker - portion is identical to MakerEvent.market_order_id emitted - for the maker portion. + Creation number of place_swap_order_events handle in a + MarketEventHandlesForMarket.
- + -## Resource `FillEventHandles` +## Resource `MarketEventHandles` -Map of FillEvent handles, implemented as a replacement for -OrderBook.taker_events through a backwards-compatible package -upgrade. +All of the Econia resource account's +MarketEventHandlesForMarket. -
struct FillEventHandles has key
+
struct MarketEventHandles has key
 
@@ -984,24 +989,24 @@ upgrade.
-map: table::Table<u64, event::EventHandle<market::FillEvent>> +map: table::Table<u64, market::MarketEventHandlesForMarket>
- Map from market ID to FillEvent event handle. + Map from market ID to MarketEventHandlesForMarket.
- + -## Struct `MakerEvent` +## Struct `MarketEventHandlesForMarket` -Emitted when a maker order (treated as the portion of an order -that posts to the book) is placed, cancelled, evicted, or its -size is manually changed. +Within a given market, event handles for market events that are +not emitted elsewhere when associated with a swap order placed +by a non-signing swapper. -
struct MakerEvent has drop, store
+
struct MarketEventHandlesForMarket has store
 
@@ -1011,56 +1016,16 @@ size is manually changed.
-market_id: u64 +cancel_order_events: event::EventHandle<user::CancelOrderEvent>
- Market ID of corresponding market. + Event handle for user::CancelOrderEvents.
-side: bool +place_swap_order_events: event::EventHandle<market::PlaceSwapOrderEvent>
- ASK or BID, the side of the maker order. -
-
-market_order_id: u128 -
-
- Market order ID, unique within a given market but not - necessarily across markets. -
-
-user: address -
-
- Address of user holding maker order. -
-
-custodian_id: u64 -
-
- For given maker, ID of custodian required to approve order - operations and withdrawals on given market account. -
-
-type: u8 -
-
- CANCEL, CHANGE, EVICT, or PLACE, the event type. -
-
-size: u64 -
-
- The size, in lots, on the book after an order has been - placed or its size has been manually changed. Else the size - on the book before the order was cancelled or evicted. -
-
-price: u64 -
-
- Order price, in ticks per lot. + Event handle for user::PlaceSwapOrderEvents.
@@ -1197,13 +1162,13 @@ item queries against the registry. maker_events: event::EventHandle<market::MakerEvent>
- Event handle for maker events. + Deprecated field retained for compatible upgrade policy.
taker_events: event::EventHandle<market::TakerEvent>
- Deprecated field retained for backwards compatibility. + Deprecated field retained for compatible upgrade policy.
@@ -1238,9 +1203,7 @@ Order book map for all Econia order books. ## Struct `OrderView` -User-friendly representation of an open order on the order book, -combining fields from Order and the corresponding -MakerEvent emitted when order was first placed. +User-friendly representation of an open order on the order book.
struct OrderView has copy, drop
@@ -1256,43 +1219,44 @@ combining fields from Ordermarket_id: u64
 
 
- MakerEvent.market_id. + Market ID for open order.
side: bool
- MakerEvent.side. + ASK or BID.
-market_order_id: u128 +order_id: u128
- MakerEvent.market_order_id. + The order ID for the posted order.
-size: u64 +remaining_size: u64
- Order.size. + Remaining number of lots to be filled.
price: u64
- Order.price. + Order price, in ticks per lot.
user: address
- Order.user. + Address of user holding order.
custodian_id: u64
- Order.custodian_id. + For given user, ID of custodian required to approve order + operations and withdrawals on given market account.
@@ -1331,6 +1295,87 @@ sorted by price-time priority. + + +## Struct `PlaceSwapOrderEvent` + +Emitted when a swap order is placed. + + +
struct PlaceSwapOrderEvent has copy, drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID for order. +
+
+signing_account: address +
+
+ Signing account if swap is placed by a signing swapper, else + NO_TAKER_ADDRESS. +
+
+integrator: address +
+
+ Integrator address passed during swap order placement, + eligible for a portion of any generated taker fees. +
+
+direction: bool +
+
+ Either BUY or SELL. +
+
+min_base: u64 +
+
+ Indicated minimum base subunits to trade. +
+
+max_base: u64 +
+
+ Indicated maximum base subunits to trade. +
+
+min_quote: u64 +
+
+ Indicated minimum quote subunits to trade. +
+
+max_quote: u64 +
+
+ Indicated maximum quote subunits to trade. +
+
+limit_price: u64 +
+
+ Indicated limit price. +
+
+order_id: u128 +
+
+ Unique ID for order within market. +
+
+ + ## Struct `PriceLevel` @@ -1375,29 +1420,202 @@ sorted by price-time priority. -##### Fields +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID of corresponding market. +
+
+asks: vector<market::PriceLevel> +
+
+ Ask price levels sorted by price-time priority: lowest price + level first in vector. +
+
+bids: vector<market::PriceLevel> +
+
+ Ask price levels sorted by price-time priority: highest + price level first in vector. +
+
+ + + + +## Struct `SwapperEventHandleCreationNumbers` + +View function return for getting event handle creation numbers +for a signing swapper's SwapperEventHandlesForMarket. + + +
struct SwapperEventHandleCreationNumbers has copy, drop
+
+ + + +##### Fields + + +
+
+cancel_order_events_handle_creation_num: u64 +
+
+ Creation number of cancel_order_events handle in a + SwapperEventHandlesForMarket. +
+
+fill_events_handle_creation_num: u64 +
+
+ Creation number of fill_events handle in a + SwapperEventHandlesForMarket. +
+
+place_swap_order_events_handle_creation_num: u64 +
+
+ Creation number of place_swap_order_events handle in a + SwapperEventHandlesForMarket. +
+
+ + + + +## Resource `SwapperEventHandles` + +All of a signing swapper's SwapperEventHandlesForMarket. + + +
struct SwapperEventHandles has key
+
+ + + +##### Fields + + +
+
+map: table::Table<u64, market::SwapperEventHandlesForMarket> +
+
+ Map from market ID to SwapperEventHandlesForMarket. +
+
+ + + + +## Struct `SwapperEventHandlesForMarket` + +Event handles for market events associated with a signing +swapper on a particular market. Stored under a signing swapper's +account (not market account), since swaps are processed outside +of an Econia-style market account. + + +
struct SwapperEventHandlesForMarket has store
+
+ + + +##### Fields + + +
+
+cancel_order_events: event::EventHandle<user::CancelOrderEvent> +
+
+ Event handle for user::CancelOrderEvents. +
+
+fill_events: event::EventHandle<user::FillEvent> +
+
+ Event handle for user::FillEvents. +
+
+place_swap_order_events: event::EventHandle<market::PlaceSwapOrderEvent> +
+
+ Event handle for user::PlaceSwapOrderEvents. +
+
+ + + + +## Struct `MakerEvent` + +Deprecated struct retained for compatible upgrade policy. + + +
struct MakerEvent has drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ +
+
+side: bool +
+
+ +
+
+market_order_id: u128 +
+
+ +
+
+user: address +
+
+
+
+custodian_id: u64 +
+
-
+
-market_id: u64 +type: u8
- Market ID of corresponding market. +
-asks: vector<market::PriceLevel> +size: u64
- Ask price levels sorted by price-time priority: lowest price - level first in vector. +
-bids: vector<market::PriceLevel> +price: u64
- Ask price levels sorted by price-time priority: highest - price level first in vector. +
@@ -1406,7 +1624,7 @@ sorted by price-time priority. ## Resource `Orders` -Deprecated struct retained for backwards compatibility. +Deprecated struct retained for compatible upgrade policy.
struct Orders has key
@@ -1437,7 +1655,7 @@ Deprecated struct retained for backwards compatibility.
 
 ## Struct `TakerEvent`
 
-Deprecated struct retained for backwards compatibility.
+Deprecated struct retained for compatible upgrade policy.
 
 
 
struct TakerEvent has drop, store
@@ -1494,7 +1712,7 @@ Deprecated struct retained for backwards compatibility.
 
 
 
-
+
 
 ## Constants
 
@@ -1630,6 +1848,93 @@ Flag for bid side.
 
 
 
+
+
+Order cancelled because it was evicted from the price-time
+priority queue.
+
+
+
const CANCEL_REASON_EVICTION: u8 = 1;
+
+ + + + + +Order cancelled because it was an immediate-or-cancel order +that did not immediately fill. + + +
const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 2;
+
+ + + + + +Order cancelled because it was manually cancelled by either +signing user or custodian. + + +
const CANCEL_REASON_MANUAL_CANCEL: u8 = 3;
+
+ + + + + +Order cancelled because no more quote asset could be traded. + + +
const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 4;
+
+ + + + + +Order cancelled because there was not enough liquidity to take +from. + + +
const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 5;
+
+ + + + + +Order cancelled because it was on the maker side of an fill +where self match behavior indicated cancelling the maker order. + + +
const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 6;
+
+ + + + + +Order cancelled because it was on the taker side of an fill +where self match behavior indicated cancelling the taker order. + + +
const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 7;
+
+ + + + + +Order cancelled because after matching across the spread the +remaining order size was too small for the market. + + +
const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8;
+
+ + + Market order ID invalid. @@ -1711,16 +2016,6 @@ Flag to abort during a self match. - - -Flag for MakerEvent.type when order is cancelled. - - -
const CANCEL: u8 = 0;
-
- - - Flag to cancel maker and taker order during a self match. @@ -1751,16 +2046,6 @@ Flag to cancel taker order only during a self match. - - -Flag for MakerEvent.type when order size is changed. - - -
const CHANGE: u8 = 1;
-
- - - Critical tree height above which evictions may take place. @@ -1771,16 +2056,6 @@ Critical tree height above which evictions may take place. - - -Flag for MakerEvent.type when order is evicted. - - -
const EVICT: u8 = 2;
-
- - - Fill-or-abort price does not cross the spread. @@ -1923,7 +2198,7 @@ Simulation query called by invalid account. -Market order ID corresponds to an order that did not post. +Order ID corresponds to an order that did not post.
const E_ORDER_DID_NOT_POST: u64 = 31;
@@ -2043,23 +2318,23 @@ bits set, generated in Python via hex(int('1' * 64, 2)).
 
 
 
-
+
 
-Taker address flag for when taker order does not originate from
-a market account.
+Flag for no order restriction.
 
 
-
const NO_MARKET_ACCOUNT: address = 0x0;
+
const NO_RESTRICTION: u8 = 0;
 
- + -Flag for no order restriction. +Taker address flag for when taker order does not originate from +a market account or a signing swapper. -
const NO_RESTRICTION: u8 = 0;
+
const NO_TAKER_ADDRESS: address = 0x0;
 
@@ -2094,16 +2369,6 @@ Maximum percentage passive advance. - - -Flag for MakerEvent.type when order is placed. - - -
const PLACE: u8 = 3;
-
- - - Flag for post-or-abort order restriction. @@ -2116,7 +2381,7 @@ Flag for post-or-abort order restriction. -Number of bits order counter is shifted in a market order ID. +Number of bits order counter is shifted in an order ID.
const SHIFT_COUNTER: u8 = 64;
@@ -2138,12 +2403,12 @@ Flag for passive order specified by advance in ticks.
 
 ## Function `did_order_post`
 
-Return true if the market order ID corresponds to an order that
+Return true if the order ID corresponds to an order that
 resulted in a post to the order book (including an order that
 filled across the spread as a taker before posting as a maker).
 
 
-
+
 
 ### Testing
 
@@ -2154,7 +2419,7 @@ filled across the spread as a taker before posting as a maker).
 * test_place_limit_order_no_cross_bid_custodian()
 
 
-
public fun did_order_post(market_order_id: u128): bool
+
public fun did_order_post(order_id: u128): bool
 
@@ -2163,9 +2428,9 @@ filled across the spread as a taker before posting as a maker).
public fun did_order_post(
-    market_order_id: u128
+    order_id: u128
 ): bool {
-    (market_order_id & (HI_64 as u128)) != (NIL as u128)
+    (order_id & (HI_64 as u128)) != (NIL as u128)
 }
 
@@ -2178,7 +2443,7 @@ filled across the spread as a taker before posting as a maker). Public constant getter for ABORT. - + ### Testing @@ -2206,7 +2471,7 @@ Public constant getter for ABO Public constant getter for ASK. - + ### Testing @@ -2235,7 +2500,7 @@ Public constant getter for ASKBID. - + ### Testing @@ -2264,7 +2529,7 @@ Public constant getter for BIDBUY. - + ### Testing @@ -2293,7 +2558,7 @@ Public constant getter for BUYCANCEL_BOTH. - + ### Testing @@ -2321,7 +2586,7 @@ Public constant getter for CANCEL_MAKER. - + ### Testing @@ -2349,7 +2614,7 @@ Public constant getter for CANCEL_TAKER. - + ### Testing @@ -2377,7 +2642,7 @@ Public constant getter for FILL_OR_ABORT. - + ### Testing @@ -2405,7 +2670,7 @@ Public constant getter for HI_PRICE. - + ### Testing @@ -2433,7 +2698,7 @@ Public constant getter for Public constant getter for IMMEDIATE_OR_CANCEL. - + ### Testing @@ -2461,7 +2726,7 @@ Public constant getter for MAX_POSSIBLE. - + ### Testing @@ -2489,7 +2754,7 @@ Public constant getter for NO_CUSTODIAN. - + ### Testing @@ -2517,7 +2782,7 @@ Public constant getter for NO_RESTRICTION. - + ### Testing @@ -2545,7 +2810,7 @@ Public constant getter for NO_UNDERWRITER. - + ### Testing @@ -2573,7 +2838,7 @@ Public constant getter for POST_OR_ABORT. - + ### Testing @@ -2601,7 +2866,7 @@ Public constant getter for PERCENT. - + ### Testing @@ -2629,7 +2894,7 @@ Public constant getter for P Public constant getter for SELL. - + ### Testing @@ -2658,7 +2923,7 @@ Public constant getter for SELL Public constant getter for TICKS. - + ### Testing @@ -2679,23 +2944,26 @@ Public constant getter for TIC - + -## Function `get_market_order_id_counter` +## Function `get_market_event_handle_creation_info` -Return order counter encoded in market order ID. +Return a MarketEventHandleCreationInfo for market_id, if +Econia resource account has event handles for indicated market. +Restricted to private view function to prevent runtime handle +contention. - + + ### Testing -* test_place_limit_order_no_cross_ask_user() -* test_place_limit_order_no_cross_bid_custodian() +* test_swap_between_coinstores_register_base_store() -
public fun get_market_order_id_counter(market_order_id: u128): u64
+
fun get_market_event_handle_creation_info(market_id: u64): option::Option<market::MarketEventHandleCreationInfo>
 
@@ -2703,32 +2971,43 @@ Return order counter encoded in market order ID. ##### Implementation -
public fun get_market_order_id_counter(
-    market_order_id: u128
-): u64 {
-    (((market_order_id >> SHIFT_COUNTER) & (HI_64 as u128)) as u64)
+
fun get_market_event_handle_creation_info(
+    market_id: u64
+): Option<MarketEventHandleCreationInfo>
+acquires MarketEventHandles {
+    // Return none if Econia resource account does not have market
+    // event handles map.
+    let resource_account_address = resource_account::get_address();
+    if (!exists<MarketEventHandles>(resource_account_address))
+        return option::none();
+    // Return none if no handles exist for market.
+    let market_event_handles_map_ref =
+        &borrow_global<MarketEventHandles>(resource_account_address).map;
+    let has_handles = table::contains(
+        market_event_handles_map_ref, market_id);
+    if (!has_handles) return option::none();
+    let market_handles_ref = table::borrow(
+        market_event_handles_map_ref, market_id);
+    // Return option-packed creation info for market.
+    option::some(MarketEventHandleCreationInfo{
+        resource_account_address: resource_account_address,
+        cancel_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_handles_ref.cancel_order_events)),
+        place_swap_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_handles_ref.place_swap_order_events))
+    })
 }
 
- - -## Function `get_market_order_id_price` - -For an order that resulted in a post to the order book, return -the order price encoded in its market order ID, corresponding to -the price that the maker portion of the order posted to the book -at. - - - - -### Aborts + +## Function `get_market_order_id_counter` -* E_ORDER_DID_NOT_POST: market order ID corresponds to an -order that did not post to the book. +Return order counter encoded in market order ID. @@ -2736,12 +3015,11 @@ order that did not post to the book. ### Testing -* test_get_market_order_id_price_did_not_post() * test_place_limit_order_no_cross_ask_user() * test_place_limit_order_no_cross_bid_custodian() -
public fun get_market_order_id_price(market_order_id: u128): u64
+
public fun get_market_order_id_counter(market_order_id: u128): u64
 
@@ -2749,25 +3027,22 @@ order that did not post to the book. ##### Implementation -
public fun get_market_order_id_price(
+
public fun get_market_order_id_counter(
     market_order_id: u128
 ): u64 {
-    // Assert order posted to the order book.
-    assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST);
-    // Extract encoded price.
-    ((market_order_id & (HI_PRICE as u128)) as u64)
+    (((market_order_id >> SHIFT_COUNTER) & (HI_64 as u128)) as u64)
 }
 
- + -## Function `get_market_order_id_side` +## Function `get_market_order_id_price` For an order that resulted in a post to the order book, return -the order side encoded in its market order ID, corresponding to -the side that the maker portion of the order posted to the book +the order price encoded in its market order ID, corresponding to +the price that the maker portion of the order posted to the book at. @@ -2776,8 +3051,8 @@ at. ### Aborts -* E_ORDER_DID_NOT_POST: market order ID corresponds to an -order that did not post to the book. +* E_ORDER_DID_NOT_POST: Order ID corresponds to an order that +did not post to the book. @@ -2785,12 +3060,12 @@ order that did not post to the book. ### Testing -* test_get_market_order_id_side_did_not_post() +* test_get_market_order_id_price_did_not_post() * test_place_limit_order_no_cross_ask_user() * test_place_limit_order_no_cross_bid_custodian() -
public fun get_market_order_id_side(market_order_id: u128): bool
+
public fun get_market_order_id_price(market_order_id: u128): u64
 
@@ -2798,16 +3073,13 @@ order that did not post to the book. ##### Implementation -
public fun get_market_order_id_side(
+
public fun get_market_order_id_price(
     market_order_id: u128
-): bool {
+): u64 {
     // Assert order posted to the order book.
     assert!(did_order_post(market_order_id), E_ORDER_DID_NOT_POST);
-    // Get AVL queue access key encoded in market order ID.
-    let avlq_access_key =
-        get_market_order_id_avl_queue_access_key(market_order_id);
-    // If ascending AVL queue indicated is an ask, else a bid.
-    if (avl_queue::is_ascending_access_key(avlq_access_key)) ASK else BID
+    // Extract encoded price.
+    ((market_order_id & (HI_PRICE as u128)) as u64)
 }
 
@@ -2817,31 +3089,22 @@ order that did not post to the book. ## Function `get_open_order` -Return OrderView for market_id and market_order_id. +Return OrderView for market_id and order_id. Mutates state, so kept as a private view function. - - -### Aborts - - -* E_INVALID_MARKET_ORDER_ID: No market order with given ID for -indicated market. - - - + ### Testing * test_change_order_size_ask_custodian() * test_change_order_size_bid_user() -* test_get_open_order_invalid_market_order_id() +* test_get_open_order_no_such_order() -
fun get_open_order(market_id: u64, market_order_id: u128): market::OrderView
+
fun get_open_order(market_id: u64, order_id: u128): option::Option<market::OrderView>
 
@@ -2851,12 +3114,11 @@ indicated market.
fun get_open_order(
     market_id: u64,
-    market_order_id: u128
-): OrderView
+    order_id: u128
+): Option<OrderView>
 acquires OrderBooks {
-    // Assert market has an open order with given market order ID.
-    assert!(has_open_order(market_id, market_order_id),
-            E_INVALID_MARKET_ORDER_ID);
+    // Return empty option if no such order.
+    if (!has_open_order(market_id, order_id)) return option::none();
     // Get address of resource account where order books are stored.
     let resource_address = resource_account::get_address();
     // Mutably borrow order books map.
@@ -2865,19 +3127,20 @@ indicated market.
     // Mutably borrow market order book.
     let order_book_ref_mut = tablist::borrow_mut(
         order_books_map_ref_mut, market_id);
-    // Get market order ID side.
-    let side = get_market_order_id_side(market_order_id);
+    // Get order ID side.
+    let side = get_posted_order_id_side(order_id);
     // Get open orders for given side.
     let orders_ref_mut = if (side == ASK) &mut order_book_ref_mut.asks else
         &mut order_book_ref_mut.bids;
     let avlq_access_key = // Get AVL queue access key.
-        get_market_order_id_avl_queue_access_key(market_order_id);
+        get_order_id_avl_queue_access_key(order_id);
     // Remove and unpack order with given access key, discarding
     // order access key.
     let Order{size, price, user, custodian_id, order_access_key: _} =
         avl_queue::remove(orders_ref_mut, avlq_access_key);
-    OrderView{market_id, side, market_order_id, size, price, user,
-              custodian_id} // Pack and return an order view.
+    // Pack and return an order view in an option.
+    option::some(OrderView{market_id, side, order_id, remaining_size: size,
+                           price, user, custodian_id})
 }
 
@@ -2894,7 +3157,7 @@ Vectors sorted by price-time priority per + ### Parameters @@ -2904,7 +3167,7 @@ Mutates state, so kept as a private view function. * n_bids_max: Maximum number of bids to index. - + ### Aborts @@ -2912,7 +3175,7 @@ Mutates state, so kept as a private view function. * E_INVALID_MARKET_ID: No market with given ID. - + ### Testing @@ -2964,15 +3227,61 @@ Wrapped call to get_ on both sides. - + + +### Testing + + +* test_get_open_orders() + + +
fun get_open_orders_all(market_id: u64): market::OrdersView
+
+ + + +##### Implementation + + +
fun get_open_orders_all(
+    market_id: u64
+): OrdersView
+acquires OrderBooks {
+    get_open_orders(market_id, HI_64, HI_64)
+}
+
+ + + + + +## Function `get_posted_order_id_side` + +For an order that resulted in a post to the order book, return +the order side encoded in its order ID, corresponding to the +side that the maker portion of the order posted to the book at. + + + + +### Aborts + + +* E_ORDER_DID_NOT_POST: Order ID corresponds to an order that +did not post to the book. + + + ### Testing -* test_get_open_orders() +* test_get_market_order_id_side_did_not_post() +* test_place_limit_order_no_cross_ask_user() +* test_place_limit_order_no_cross_bid_custodian() -
fun get_open_orders_all(market_id: u64): market::OrdersView
+
public fun get_posted_order_id_side(order_id: u128): bool
 
@@ -2980,11 +3289,16 @@ on both sides. ##### Implementation -
fun get_open_orders_all(
-    market_id: u64
-): OrdersView
-acquires OrderBooks {
-    get_open_orders(market_id, HI_64, HI_64)
+
public fun get_posted_order_id_side(
+    order_id: u128
+): bool {
+    // Assert order posted to the order book.
+    assert!(did_order_post(order_id), E_ORDER_DID_NOT_POST);
+    // Get AVL queue access key encoded in order ID.
+    let avlq_access_key =
+        get_order_id_avl_queue_access_key(order_id);
+    // If ascending AVL queue indicated is an ask, else a bid.
+    if (avl_queue::is_ascending_access_key(avlq_access_key)) ASK else BID
 }
 
@@ -3001,7 +3315,7 @@ Vectors sorted by price priority per + ### Parameters @@ -3013,7 +3327,7 @@ index. index. - + ### Testing @@ -3066,7 +3380,7 @@ Wrapped call to get levels on both sides. - + ### Testing @@ -3092,27 +3406,86 @@ levels on both sides. + + +## Function `get_swapper_event_handle_creation_numbers` + +Return a SwapperEventHandleCreationNumbers for market_id, if +signing swapper has event handles for indicated market. + +Restricted to private view function to prevent runtime handle +contention. + + + + +### Testing + + +* test_swap_between_coinstores_register_base_store() + + +
fun get_swapper_event_handle_creation_numbers(swapper: address, market_id: u64): option::Option<market::SwapperEventHandleCreationNumbers>
+
+ + + +##### Implementation + + +
fun get_swapper_event_handle_creation_numbers(
+    swapper: address,
+    market_id: u64
+): Option<SwapperEventHandleCreationNumbers>
+acquires SwapperEventHandles {
+    // Return none if swapper does not have event handles map.
+    if (!exists<SwapperEventHandles>(swapper)) return option::none();
+    // Return none if no handles exist for market.
+    let swapper_event_handles_map_ref =
+        &borrow_global<SwapperEventHandles>(swapper).map;
+    let has_handles = table::contains(
+        swapper_event_handles_map_ref, market_id);
+    if (!has_handles) return option::none();
+    let swapper_handles_ref = table::borrow(
+        swapper_event_handles_map_ref, market_id);
+    // Return option-packed creation numbers for market.
+    option::some(SwapperEventHandleCreationNumbers{
+        cancel_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &swapper_handles_ref.cancel_order_events)),
+        fill_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &swapper_handles_ref.fill_events)),
+        place_swap_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &swapper_handles_ref.place_swap_order_events))
+    })
+}
+
+ + + ## Function `has_open_order` -Return true if market_order_id corresponds to open order for -given market_id. +Return true if order_id corresponds to open order for given +market_id. Kept private to prevent runtime order book state contention. - + ### Testing -* test_has_open_order_no_market() * test_change_order_size_ask_custodian() * test_change_order_size_bid_user() +* test_has_open_order_no_market() -
fun has_open_order(market_id: u64, market_order_id: u128): bool
+
fun has_open_order(market_id: u64, order_id: u128): bool
 
@@ -3122,7 +3495,7 @@ Kept private to prevent runtime order book state contention.
fun has_open_order(
     market_id: u64,
-    market_order_id: u128
+    order_id: u128
 ): bool
 acquires OrderBooks {
     // Get address of resource account where order books are stored.
@@ -3133,14 +3506,14 @@ Kept private to prevent runtime order book state contention.
         return false; // Return false if no market with market ID.
     // Immutably borrow order book for given market ID.
     let order_book_ref = tablist::borrow(order_books_map_ref, market_id);
-    // Determine side indicated by market order ID.
-    let side = get_market_order_id_side(market_order_id);
+    // Determine side indicated by order ID.
+    let side = get_posted_order_id_side(order_id);
     // Get open orders for given side.
     let orders_ref = if (side == ASK) &order_book_ref.asks
         else &order_book_ref.bids;
-    // Get AVL queue access key from market order ID.
+    // Get AVL queue access key from order ID.
     let avlq_access_key =
-        get_market_order_id_avl_queue_access_key(market_order_id);
+        get_order_id_avl_queue_access_key(order_id);
     // Check if borrowing from the AVL queue is even possible.
     let borrow_possible = avl_queue::contains_active_list_node_id(
         orders_ref, avlq_access_key);
@@ -3148,16 +3521,16 @@ Kept private to prevent runtime order book state contention.
     if (!borrow_possible) return false;
     // Immutably borrow order having list node ID.
     let order_ref = avl_queue::borrow(orders_ref, avlq_access_key);
-    // Check if user has corresponding open order market order ID.
-    let optional_market_order_id = user::get_open_order_id_internal(
+    // Check if user has corresponding open order order ID.
+    let optional_order_id = user::get_open_order_id_internal(
         order_ref.user, market_id, order_ref.custodian_id, side,
         order_ref.order_access_key);
-    // If user has no corresponding market order ID return false.
-    if (option::is_none(&optional_market_order_id)) return false;
-    let user_market_order_id = // Get user's market order ID.
-        option::destroy_some(optional_market_order_id);
-    // Return if user-indicated market order ID matches passed one.
-    user_market_order_id == market_order_id
+    // If user has no corresponding order ID return false.
+    if (option::is_none(&optional_order_id)) return false;
+    let user_order_id = // Get user's order ID.
+        option::destroy_some(optional_order_id);
+    // Return if user-indicated order ID matches passed one.
+    user_order_id == order_id
 }
 
@@ -3171,7 +3544,7 @@ Public function wrapper for + ### Invocation testing @@ -3211,7 +3584,7 @@ Public function wrapper for + ### Invocation testing @@ -3253,7 +3626,7 @@ Public function wrapper for + ### Invocation testing @@ -3297,7 +3670,7 @@ Public function wrapper for + ### Invocation and return testing @@ -3331,10 +3704,7 @@ order under authority of delegated custodian. u64, u64, u64 -) acquires - FillEventHandles, - OrderBooks -{ +) acquires OrderBooks { place_limit_order< BaseType, QuoteType @@ -3363,7 +3733,7 @@ Public function wrapper for authority of delegated custodian. - + ### Invocation and return testing @@ -3392,10 +3762,7 @@ authority of delegated custodian. target_advance_amount: u64, custodian_capability_ref: &CustodianCapability ): u128 -acquires - FillEventHandles, - OrderBooks -{ +acquires OrderBooks { place_limit_order_passive_advance< BaseType, QuoteType @@ -3422,7 +3789,7 @@ Public function wrapper for authority of signing user. - + ### Invocation and return testing @@ -3457,10 +3824,7 @@ authority of signing user. advance_style: bool, target_advance_amount: u64 ): u128 -acquires - FillEventHandles, - OrderBooks -{ +acquires OrderBooks { place_limit_order_passive_advance< BaseType, QuoteType @@ -3486,7 +3850,7 @@ Public function wrapper for + ### Invocation and return testing @@ -3526,10 +3890,7 @@ order under authority of signing user. u64, u64, u64 -) acquires - FillEventHandles, - OrderBooks -{ +) acquires OrderBooks { place_limit_order< BaseType, QuoteType @@ -3557,7 +3918,7 @@ Public function wrapper for + ### Invocation and return testing @@ -3589,10 +3950,7 @@ order under authority of delegated custodian. u64, u64, u64 -) acquires - FillEventHandles, - OrderBooks -{ +) acquires OrderBooks { place_market_order<BaseType, QuoteType>( user_address, market_id, @@ -3614,7 +3972,7 @@ Public function wrapper for + ### Invocation and return testing @@ -3645,10 +4003,7 @@ order under authority of signing user. u64, u64, u64 -) acquires - FillEventHandles, - OrderBooks -{ +) acquires OrderBooks { place_market_order<BaseType, QuoteType>( address_of(user), market_id, @@ -3671,7 +4026,7 @@ Register pure coin market, return resultant market ID. See inner function register_market(). - + ### Type parameters @@ -3682,7 +4037,7 @@ See inner function r incentives::IncentiveParameters.utility_coin_type_info. - + ### Parameters @@ -3694,7 +4049,7 @@ See inner function r incentives::IncentiveParameters.market_registration_fee. - + ### Returns @@ -3702,7 +4057,7 @@ See inner function r * u64: Market ID for new market. - + ### Testing @@ -3728,10 +4083,7 @@ See inner function r min_size: u64, utility_coins: Coin<UtilityType> ): u64 -acquires - FillEventHandles, - OrderBooks -{ +acquires OrderBooks { // Register market in global registry, storing market ID. let market_id = registry::register_market_base_coin_internal< BaseType, QuoteType, UtilityType>(lot_size, tick_size, min_size, @@ -3758,7 +4110,7 @@ Generic base name restrictions described at registry::register_market_base_generic_internal(). - + ### Type parameters @@ -3768,7 +4120,7 @@ Generic base name restrictions described at incentives::IncentiveParameters.utility_coin_type_info. - + ### Parameters @@ -3784,7 +4136,7 @@ for market. underwriter capability. - + ### Returns @@ -3792,7 +4144,7 @@ underwriter capability. * u64: Market ID for new market. - + ### Testing @@ -3819,10 +4171,7 @@ underwriter capability. utility_coins: Coin<UtilityType>, underwriter_capability_ref: &UnderwriterCapability ): u64 -acquires - FillEventHandles, - OrderBooks -{ +acquires OrderBooks { // Register market in global registry, storing market ID. let market_id = registry::register_market_base_generic_internal< QuoteType, UtilityType>(base_name_generic, lot_size, tick_size, @@ -3847,7 +4196,7 @@ Initializes an aptos_framework::coin::CoinStore for each coin type that does not yet have one. - + ### Type Parameters @@ -3856,7 +4205,7 @@ type that does not yet have one. * QuoteType: Same as for match(). - + ### Parameters @@ -3875,7 +4224,7 @@ for coin store. * limit_price: Same as for match(). - + ### Returns @@ -3885,7 +4234,19 @@ for coin store. * u64: Quote coin fees paid, same as for match(). - + + +### Emits + + +* PlaceSwapOrderEvent: Information about the swap order. +* FillEvent(s): Information about fill(s) associated with the +swap. +* CancelOrderEvent: Optionally, information about why the swap +was cancelled without completely filling. + + + ### Testing @@ -3894,8 +4255,11 @@ for coin store. * test_swap_between_coinstores_max_possible_base_sell() * test_swap_between_coinstores_max_possible_quote_buy() * test_swap_between_coinstores_max_possible_quote_sell() +* test_swap_between_coinstores_max_quote_traded() +* test_swap_between_coinstores_not_enough_liquidity() * test_swap_between_coinstores_register_base_store() * test_swap_between_coinstores_register_quote_store() +* test_swap_between_coinstores_self_match_taker_cancel()
public fun swap_between_coinstores<BaseType, QuoteType>(user: &signer, market_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64): (u64, u64, u64)
@@ -3924,8 +4288,9 @@ for coin store.
     u64,
     u64
 ) acquires
-    FillEventHandles,
-    OrderBooks
+    MarketEventHandles,
+    OrderBooks,
+    SwapperEventHandles
 {
     let user_address = address_of(user); // Get user address.
     // Register base coin store if user does not have one.
@@ -3958,12 +4323,61 @@ for coin store.
         // If a sell, need max base but not quote.
         (option::some(coin::withdraw<BaseType>(user, max_base)),
          coin::zero<QuoteType>());
-    // Swap against order book, storing optionally modified coin
-    // inputs, base and quote trade amounts, and quote fees paid.
-    let (optional_base_coins, quote_coins, base_traded, quote_traded, fees)
-        = swap(market_id, NO_UNDERWRITER, integrator, direction, min_base,
-               max_base, min_quote, max_quote, limit_price,
-               optional_base_coins, quote_coins);
+    // Swap against the order book, deferring market events.
+    let fill_event_queue = vector[];
+    let (
+        optional_base_coins,
+        quote_coins,
+        base_traded,
+        quote_traded,
+        fees,
+        place_swap_order_event_option,
+        cancel_order_event_option
+    ) = swap(
+        &mut fill_event_queue,
+        user_address,
+        market_id,
+        NO_UNDERWRITER,
+        integrator,
+        direction,
+        min_base,
+        max_base,
+        min_quote,
+        max_quote,
+        limit_price,
+        optional_base_coins,
+        quote_coins
+    );
+    // Create swapper event handles for market as needed.
+    if (!exists<SwapperEventHandles>(user_address))
+        move_to(user, SwapperEventHandles{map: table::new()});
+    let swapper_event_handles_map_ref_mut =
+        &mut borrow_global_mut<SwapperEventHandles>(user_address).map;
+    let has_handles =
+        table::contains(swapper_event_handles_map_ref_mut, market_id);
+    if (!has_handles) {
+        let handles = SwapperEventHandlesForMarket{
+            cancel_order_events: account::new_event_handle(user),
+            fill_events: account::new_event_handle(user),
+            place_swap_order_events: account::new_event_handle(user)
+        };
+        table::add(
+            swapper_event_handles_map_ref_mut, market_id, handles);
+    };
+    let handles_ref_mut =
+        table::borrow_mut(swapper_event_handles_map_ref_mut, market_id);
+    // Emit place swap order event.
+    event::emit_event(&mut handles_ref_mut.place_swap_order_events,
+                      option::destroy_some(place_swap_order_event_option));
+    // Emit fill events first-in-first-out.
+    vector::for_each_ref(&fill_event_queue, |fill_event_ref| {
+        let fill_event: FillEvent = *fill_event_ref;
+        event::emit_event(&mut handles_ref_mut.fill_events, fill_event);
+    });
+    // Optionally emit cancel event.
+    if (option::is_some(&cancel_order_event_option))
+        event::emit_event(&mut handles_ref_mut.cancel_order_events,
+                          option::destroy_some(cancel_order_event_option));
     // Deposit base coins back to user's coin store.
     coin::deposit(user_address, option::destroy_some(optional_base_coins));
     // Deposit quote coins back to user's coin store.
@@ -3990,7 +4404,7 @@ intermediate quote match overflow that could occur prior to fee
 assessment.
 
 
-
+
 
 ### Type Parameters
 
@@ -3999,7 +4413,7 @@ assessment.
 * QuoteType: Same as for match().
 
 
-
+
 
 ### Parameters
 
@@ -4021,7 +4435,7 @@ unpacked.
 * quote_coins: Same as for match().
 
 
-
+
 
 ### Returns
 
@@ -4035,7 +4449,7 @@ unpacked.
 * u64: Quote coin fees paid, same as for match().
 
 
-
+
 
 ### Terminology
 
@@ -4046,7 +4460,7 @@ coins in the case of a buy, quote coins in the case of a sell.
 the case of a buy, base coins in the case of a sell.
 
 
-
+
 
 ### Testing
 
@@ -4088,7 +4502,7 @@ the case of a buy, base coins in the case of a sell.
     u64,
     u64
 ) acquires
-    FillEventHandles,
+    MarketEventHandles,
     OrderBooks
 {
     let (base_value, quote_value) = // Get coin value amounts.
@@ -4117,13 +4531,30 @@ the case of a buy, base coins in the case of a sell.
     range_check_trade( // Range check trade amounts.
         direction, min_base, max_base, min_quote, max_quote,
         base_value, base_value, quote_value, quote_value);
-    // Swap against order book, storing optionally modified coin
-    // inputs, base and quote trade amounts, and quote fees paid.
-    let (optional_base_coins, quote_coins_matched, base_traded,
-         quote_traded, fees) = swap(
-            market_id, NO_UNDERWRITER, integrator, direction, min_base,
-            max_base, min_quote, max_quote, limit_price,
-            optional_base_coins, quote_coins_to_match);
+    // Swap against order book, discarding events.
+    let (
+        optional_base_coins,
+        quote_coins_matched,
+        base_traded,
+        quote_traded,
+        fees,
+        _,
+        _
+    ) = swap(
+        &mut vector[],
+        NO_TAKER_ADDRESS,
+        market_id,
+        NO_UNDERWRITER,
+        integrator,
+        direction,
+        min_base,
+        max_base,
+        min_quote,
+        max_quote,
+        limit_price,
+        optional_base_coins,
+        quote_coins_to_match
+    );
     // Merge matched quote coins back into holdings.
     coin::merge(&mut quote_coins, quote_coins_matched);
     // Get base coins from option.
@@ -4148,7 +4579,7 @@ intermediate quote match overflow that could occur prior to fee
 assessment.
 
 
-
+
 
 ### Type Parameters
 
@@ -4156,7 +4587,7 @@ assessment.
 * QuoteType: Same as for match().
 
 
-
+
 
 ### Parameters
 
@@ -4176,7 +4607,7 @@ possible amount for passed coin holdings.
 underwriter capability for given market.
 
 
-
+
 
 ### Returns
 
@@ -4188,7 +4619,7 @@ underwriter capability for given market.
 * u64: Quote coin fees paid, same as for match().
 
 
-
+
 
 ### Testing
 
@@ -4227,7 +4658,7 @@ underwriter capability for given market.
     u64,
     u64
 ) acquires
-    FillEventHandles,
+    MarketEventHandles,
     OrderBooks
 {
     let underwriter_id = // Get underwriter ID.
@@ -4254,13 +4685,30 @@ underwriter capability for given market.
     range_check_trade( // Range check trade amounts.
         direction, min_base, max_base, min_quote, max_quote,
         base_value, base_value, quote_value, quote_value);
-    // Swap against order book, storing optionally modified quote
-    // coin input, base and quote trade amounts, quote fees paid.
-    let (optional_base_coins, quote_coins_matched, base_traded,
-         quote_traded, fees) = swap(
-            market_id, underwriter_id, integrator, direction, min_base,
-            max_base, min_quote, max_quote, limit_price, option::none(),
-            quote_coins_to_match);
+    // Swap against order book, discarding events.
+    let (
+        optional_base_coins,
+        quote_coins_matched,
+        base_traded,
+        quote_traded,
+        fees,
+        _,
+        _
+    ) = swap(
+        &mut vector[],
+        NO_TAKER_ADDRESS,
+        market_id,
+        underwriter_id,
+        integrator,
+        direction,
+        min_base,
+        max_base,
+        min_quote,
+        max_quote,
+        limit_price,
+        option::none(),
+        quote_coins_to_match
+    );
     // Destroy empty base coin option.
     option::destroy_none<Coin<GenericAsset>>(optional_base_coins);
     // Merge matched quote coins back into holdings.
@@ -4281,7 +4729,7 @@ Public entry function wrapper for 
+
 
 ### Invocation testing
 
@@ -4320,7 +4768,7 @@ Public entry function wrapper for 
+
 
 ### Invocation testing
 
@@ -4361,7 +4809,7 @@ Public entry function wrapper for 
+
 
 ### Invocation testing
 
@@ -4404,7 +4852,7 @@ Public entry function wrapper for
 place_limit_order_passive_advance_user().
 
 
-
+
 
 ### Invocation testing
 
@@ -4431,10 +4879,7 @@ Public entry function wrapper for
     size: u64,
     advance_style: bool,
     target_advance_amount: u64
-) acquires
-    FillEventHandles,
-    OrderBooks
-{
+) acquires OrderBooks {
     place_limit_order_passive_advance_user<
         BaseType,
         QuoteType
@@ -4458,7 +4903,7 @@ Public entry function wrapper for
 Public entry function wrapper for place_limit_order_user().
 
 
-
+
 
 ### Invocation testing
 
@@ -4486,10 +4931,7 @@ Public entry function wrapper for FillEventHandles,
-    OrderBooks
-{
+) acquires OrderBooks {
     place_limit_order_user<BaseType, QuoteType>(
         user, market_id, integrator, side, size, price, restriction,
         self_match_behavior);
@@ -4505,7 +4947,7 @@ Public entry function wrapper for place_market_order_user().
 
 
-
+
 
 ### Invocation testing
 
@@ -4531,10 +4973,7 @@ Public entry function wrapper for FillEventHandles,
-    OrderBooks
-{
+) acquires OrderBooks {
     place_market_order_user<BaseType, QuoteType>(
         user, market_id, integrator, direction, size, self_match_behavior);
 }
@@ -4550,7 +4989,7 @@ Wrapped call to 
+
 
 ### Testing
 
@@ -4575,10 +5014,7 @@ coins from an aptos_framework::coin::CoinStore.
     lot_size: u64,
     tick_size: u64,
     min_size: u64
-) acquires
-    FillEventHandles,
-    OrderBooks
-{
+) acquires OrderBooks {
     // Get market registration fee, denominated in utility coins.
     let fee = incentives::get_market_registration_fee();
     // Register market with base coin, paying fees from coin store.
@@ -4596,7 +5032,7 @@ coins from an aptos_framework::coin::CoinStore.
 Public entry function wrapper for swap_between_coinstores().
 
 
-
+
 
 ### Invocation testing
 
@@ -4627,8 +5063,9 @@ Public entry function wrapper for FillEventHandles,
-    OrderBooks
+    MarketEventHandles,
+    OrderBooks,
+    SwapperEventHandles
 {
     swap_between_coinstores<BaseType, QuoteType>(
         user, market_id, integrator, direction, min_base, max_base,
@@ -4645,7 +5082,7 @@ Public entry function wrapper for 
+
 
 ### Parameters
 
@@ -4656,7 +5093,7 @@ Cancel all of a user's open maker orders.
 * side: Same as for cancel_order().
 
 
-
+
 
 ### Expected value testing
 
@@ -4709,7 +5146,7 @@ verified against the order access key derived from the AVL queue
 removal operation.
 
 
-
+
 
 ### Parameters
 
@@ -4721,7 +5158,7 @@ removal operation.
 * market_order_id: Market order ID of order on order book.
 
 
-
+
 
 ### Aborts
 
@@ -4735,15 +5172,7 @@ on book having given market order ID.
 custodian ID of order on order book having market order ID.
 
 
-
-
-### Emits
-
-
-* MakerEvent: Information about the maker order cancelled.
-
-
-
+
 
 ### Expected value testing
 
@@ -4752,7 +5181,7 @@ custodian ID of order on order book having market order ID.
 * test_cancel_order_bid_user()
 
 
-
+
 
 ### Failure testing
 
@@ -4807,12 +5236,9 @@ custodian ID of order on order book having market order ID.
     // Assert passed custodian ID matches that from order.
     assert!(custodian_id == order_custodian_id, E_INVALID_CUSTODIAN);
     // Cancel order user-side, thus verifying market order ID.
-    user::cancel_order_internal(user, market_id, custodian_id, side, size,
-                                price, order_access_key, market_order_id);
-    // Emit a maker cancel event.
-    event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{
-        market_id, side, market_order_id, user, custodian_id,
-        type: CANCEL, size, price});
+    user::cancel_order_internal(
+        user, market_id, custodian_id, side, size, price, order_access_key,
+        market_order_id, CANCEL_REASON_MANUAL_CANCEL);
 }
 
@@ -4835,7 +5261,7 @@ again verified against the order access key derived from the AVL queue borrow operation. - + ### Parameters @@ -4848,7 +5274,7 @@ queue borrow operation. * new_size: The new order size to change to. - + ### Aborts @@ -4862,15 +5288,7 @@ on book having given market order ID. custodian ID of order on order book having market order ID. - - -### Emits - - -* MakerEvent: Information about the changed maker order. - - - + ### Expected value testing @@ -4880,7 +5298,7 @@ custodian ID of order on order book having market order ID. * test_change_order_size_bid_user_new_tail() - + ### Failure testing @@ -4973,31 +5391,42 @@ custodian ID of order on order book having market order ID. assert!(new_avlq_access_key == avlq_access_key, E_SIZE_CHANGE_INSERTION_ERROR); }; - // Emit a maker change event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id, user, custodian_id, type: CHANGE, - size: new_size, price}); }
- + -## Function `get_market_order_id_avl_queue_access_key` +## Function `get_cancel_reason_option_for_market_order_or_swap` -Get AVL queue access key encoded in market_order_id. +Get optional cancel reason for market order or swap. - + -### Testing +### Parameters -* test_get_market_order_id_avl_queue_access_key() +* self_match_taker_cancel: If matching resulted in cancelling +the taker side of an order due to a self match. +* base_traded: The amount of base assets traded. +* max_base: The maximum indicated amount of base assets to +match. +* liquidity_gone: If the matching engine halted due to +insufficient liquidity. + + + + +### Returns + + +* Option<u8>: An optional cancel reason, if the order needs +to be cancelled. -
fun get_market_order_id_avl_queue_access_key(market_order_id: u128): u64
+
fun get_cancel_reason_option_for_market_order_or_swap(self_match_taker_cancel: bool, base_traded: u64, max_base: u64, liquidity_gone: bool): option::Option<u8>
 
@@ -5005,10 +5434,25 @@ Get AVL queue access key encoded in market_order_id. ##### Implementation -
inline fun get_market_order_id_avl_queue_access_key(
-    market_order_id: u128
-): u64 {
-    ((market_order_id & (HI_64 as u128)) as u64)
+
inline fun get_cancel_reason_option_for_market_order_or_swap(
+    self_match_taker_cancel: bool,
+    base_traded: u64,
+    max_base: u64,
+    liquidity_gone: bool
+): Option<u8> {
+    let need_to_cancel =
+        ((self_match_taker_cancel) || (base_traded < max_base));
+    if (need_to_cancel) {
+        if (self_match_taker_cancel) {
+            option::some(CANCEL_REASON_SELF_MATCH_TAKER)
+        } else if (liquidity_gone) {
+            option::some(CANCEL_REASON_NOT_ENOUGH_LIQUIDITY)
+        } else {
+            option::some(CANCEL_REASON_MAX_QUOTE_TRADED)
+        }
+    } else {
+        option::none()
+    }
 }
 
@@ -5022,7 +5466,7 @@ Index specified number of open orders for given side of order book. - + ### Testing @@ -5054,13 +5498,13 @@ book. // Remove and unpack order at head of queue. let Order{size, price, user, custodian_id, order_access_key} = avl_queue::pop_head(avlq_ref_mut); - // Get market order ID from user-side order memory. - let market_order_id = option::destroy_some( + // Get order ID from user-side order memory. + let order_id = option::destroy_some( user::get_open_order_id_internal(user, market_id, custodian_id, side, order_access_key)); // Push back an order view to orders view vector. vector::push_back(&mut orders, OrderView{ - market_id, side, market_order_id, size, price, user, + market_id, side, order_id, remaining_size: size, price, user, custodian_id}); }; orders // Return vector of view-friendly orders. @@ -5069,6 +5513,38 @@ book. + + +## Function `get_order_id_avl_queue_access_key` + +Get AVL queue access key encoded in order_id. + + + + +### Testing + + +* test_get_market_order_id_avl_queue_access_key() + + +
fun get_order_id_avl_queue_access_key(order_id: u128): u64
+
+ + + +##### Implementation + + +
fun get_order_id_avl_queue_access_key(
+    order_id: u128
+): u64 {
+    ((order_id & (HI_64 as u128)) as u64)
+}
+
+ + + ## Function `get_price_levels_for_side` @@ -5077,7 +5553,7 @@ Index specified number of price levels for given side of order book. - + ### Testing @@ -5180,7 +5656,7 @@ assesses taker fees. Matches up until the point of a self match, then proceeds according to specified self match behavior. - + ### Type Parameters @@ -5190,26 +5666,21 @@ then proceeds according to specified self match behavior. * QuoteType: Quote coin type for market. - + ### Parameters * market_id: Market ID of market. -* resource_address: Address of resource account where order -books and fill event handles are stored. -* fill_event_queue_option_ref_mut: Mutable reference to -optional queue for FillEvents, used to defer event emission -for limit orders: if a limit order fills across the spread -before posting to the order book, the market order ID requires -an encoded AVL queue access key that is not known at the time -of fills. +* fill_event_queue_ref_mut: Mutable reference to vector for +enqueueing deferred FillEvent(s). * order_book_ref_mut: Mutable reference to market order book. * taker: Address of taker whose order is matched. Passed as -NO_MARKET_ACCOUNT when taker order originates from a swap. +NO_TAKER_ADDRESS when taker order originates from a swap +without a signature. * custodian_id: Custodian ID associated with a taker market account, if any. Should be passed as NO_CUSTODIAN if taker -is NO_MARKET_ACCOUNT. +is NO_TAKER_ADDRESS. * integrator: The integrator for the taker order, who collects a portion of taker fees at their incentives::IntegratorFeeStore for the given market. May be @@ -5243,7 +5714,7 @@ decremented if direction is SELL. - + ### Returns @@ -5259,18 +5730,11 @@ taker's base holdings. net change in taker's quote coin holdings. * u64: Amount of quote coin fees paid. * bool: true if a self match that results in a taker cancel. +* bool: true if liquidity is gone from order book on +corresponding side after matching. - - -### Emits - - -* FillEvent: Information about a fill, emitted for each fill, -when fill events are not marked for deferral. - - - + ### Aborts @@ -5289,7 +5753,7 @@ requirement not met. requirement not met. - + ### Expected value testing @@ -5308,7 +5772,7 @@ requirement not met. * test_match_self_match_cancel_taker() - + ### Failure testing @@ -5321,7 +5785,7 @@ requirement not met. * test_match_self_match_invalid() -
fun match<BaseType, QuoteType>(market_id: u64, resource_address: address, fill_event_queue_option_ref_mut: &mut option::Option<vector<market::FillEvent>>, order_book_ref_mut: &mut market::OrderBook, taker: address, custodian_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, self_match_behavior: u8, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, bool)
+
fun match<BaseType, QuoteType>(market_id: u64, fill_event_queue_ref_mut: &mut vector<user::FillEvent>, order_book_ref_mut: &mut market::OrderBook, taker: address, custodian_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, self_match_behavior: u8, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, bool, bool)
 
@@ -5334,8 +5798,7 @@ requirement not met. QuoteType >( market_id: u64, - resource_address: address, - fill_event_queue_option_ref_mut: &mut Option<vector<FillEvent>>, + fill_event_queue_ref_mut: &mut vector<FillEvent>, order_book_ref_mut: &mut OrderBook, taker: address, custodian_id: u64, @@ -5355,8 +5818,9 @@ requirement not met. u64, u64, u64, + bool, bool -) acquires FillEventHandles { +) { // Assert price is not too high. assert!(limit_price <= HI_PRICE, E_PRICE_TOO_HIGH); // Taker buy fills against asks, sell against bids. @@ -5379,18 +5843,11 @@ requirement not met. // Assume it is not the case that a self match led to a taker // order cancellation. let self_match_taker_cancel = false; - // Determine if fill events should be deferred into a queue. - let defer_events = option::is_some(fill_event_queue_option_ref_mut); - // If should defer events, mutably borrow event queue: - let event_queue_ref_mut = if (defer_events) - option::borrow_mut(fill_event_queue_option_ref_mut) else - &mut vector[]; // Otherwise mutably borrow null vector. - // Mutably borrow fill event handle: - let fill_event_handle_ref_mut = table::borrow_mut( - &mut borrow_global_mut<FillEventHandles>(resource_address).map, - market_id); - // Increment order counter. + // Get new order ID before any potential fills. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; + let order_id = ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + // Initialize counters for fill iteration. + let (fill_count, fees_paid) = (0, 0); // While there are orders to match against: while (!avl_queue::is_empty(orders_ref_mut)) { let price = // Get price of order at head of AVL queue. @@ -5448,27 +5905,22 @@ requirement not met. let market_order_id = user::cancel_order_internal( maker, market_id, maker_custodian_id, side, order_ref_mut.size, price, - order_ref_mut.order_access_key, (NIL as u128)); + order_ref_mut.order_access_key, (NIL as u128), + CANCEL_REASON_SELF_MATCH_MAKER); // Get AVL queue access key from market order ID. let avlq_access_key = ((market_order_id & (HI_64 as u128)) as u64); - // Remove order from AVL queue, storing size. - let Order{size, price: _, user: _, custodian_id: _, + // Remove order from AVL queue. + let Order{size: _, price: _, user: _, custodian_id: _, order_access_key: _} = avl_queue::remove( orders_ref_mut, avlq_access_key); - // Get maker events handle. - let maker_handle = &mut order_book_ref_mut.maker_events; - // Emit a maker cancel event. - event::emit_event(maker_handle, MakerEvent{ - market_id, side, market_order_id, user: maker, - custodian_id: maker_custodian_id, type: CANCEL, - size, price}); }; // Optional maker order cancellation complete. // Break out of loop if a self match taker cancel. if (self_match_taker_cancel) break; } else { // If not a self match: - // Get ticks filled. + // Get ticks, quote filled. let ticks_filled = fill_size * price; + let quote_filled = ticks_filled * tick_size; // Decrement counter for lots to fill until max reached. lots_until_max = lots_until_max - fill_size; // Decrement counter for ticks to fill until max. @@ -5481,18 +5933,18 @@ requirement not met. maker, market_id, maker_custodian_id, side, order_ref_mut.order_access_key, order_ref_mut.size, fill_size, complete_fill, optional_base_coins, - quote_coins, fill_size * lot_size, - ticks_filled * tick_size); - let fill_event = FillEvent{ // Create fill event. - market_id, size: fill_size, price, maker_side: side, - maker_market_order_id: market_order_id, maker, - maker_custodian_id: custodian_id, taker_market_order_id: - ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER)}; - // If should defer events, push pack event onto queue: - if (defer_events) - vector::push_back(event_queue_ref_mut, fill_event) else - // Otherwise emit event. - event::emit_event(fill_event_handle_ref_mut, fill_event); + quote_coins, fill_size * lot_size, quote_filled); + // Enqueue a fill event with the amount of fees paid. + let fees_paid_for_fill = quote_filled / taker_fee_divisor; + let fill_event = user::create_fill_event_internal( + market_id, fill_size, price, side, maker, + maker_custodian_id, market_order_id, taker, custodian_id, + order_id, fees_paid_for_fill, fill_count); + vector::push_back(fill_event_queue_ref_mut, fill_event); + // Update fill iteration counters. + fill_count = fill_count + 1; + fees_paid = fees_paid + fees_paid_for_fill; + // If order on book completely filled: if (complete_fill) { let avlq_access_key = // Get AVL queue access key. ((market_order_id & (HI_64 as u128)) as u64); @@ -5512,10 +5964,10 @@ requirement not met. let (base_fill, quote_fill) = // Calculate base and quote fills. (((max_lots - lots_until_max ) * lot_size), ((max_ticks - ticks_until_max) * tick_size)); - // Assess taker fees, storing taker fees paid. - let (quote_coins, fees_paid) = incentives::assess_taker_fees< - QuoteType>(market_id, integrator, taker_fee_divisor, quote_fill, - quote_coins); + // Assess taker fees. + let (quote_coins, _) = incentives::assess_taker_fees<QuoteType>( + market_id, integrator, taker_fee_divisor, + fees_paid * taker_fee_divisor, quote_coins); // If a buy, taker pays quote required for fills, and additional // fee assessed after matching. If a sell, taker receives quote // from fills, then has a portion assessed as fees. @@ -5525,10 +5977,10 @@ requirement not met. assert!(base_fill >= min_base, E_MIN_BASE_NOT_TRADED); // Assert minimum quote coin trade amount met. assert!(quote_traded >= min_quote, E_MIN_QUOTE_NOT_TRADED); - // Return optional base coin, quote coins, trade amounts, and - // self match taker cancel flag. + // Return optional base coin, quote coins, trade amounts, + // self match taker cancel flag, and if liquidity is gone. (optional_base_coins, quote_coins, base_fill, quote_traded, fees_paid, - self_match_taker_cancel) + self_match_taker_cancel, avl_queue::is_empty(orders_ref_mut)) }
@@ -5541,7 +5993,7 @@ requirement not met. Place limit order against order book from user market account. - + ### Type Parameters @@ -5550,7 +6002,7 @@ Place limit order against order book from user market account. * QuoteType: Same as for match(). - + ### Parameters @@ -5572,13 +6024,12 @@ may take place. Should only be passed as + ### Returns -* u128: Market order ID of limit order placed on book, if one -was placed. Else NIL. +* u128: Order ID assigned to order, unique within a market. * u64: Base asset trade amount as a taker, same as for match(), if order fills across the spread. * u64: Quote asset trade amount as a taker, same as for @@ -5587,7 +6038,7 @@ was placed. Else NIL. if order fills across the spread. - + ### Aborts @@ -5616,21 +6067,7 @@ price-time priority if inserted to AVL queue, but AVL queue does not have room for any more orders. - - -### Emits - - -* FillEvent: Information about the portion of the order that -fills as a taker, if the order fills across the spread. -* MakerEvent: Information about the user's maker order placed -on the order book, if one was placed. -* MakerEvent: Information about the maker order evicted from -the order book, if required to fit user's maker order on the -book. - - - + ### Restrictions @@ -5644,7 +6081,7 @@ amount is not filled. then returns. - + ### Minimum size @@ -5654,13 +6091,13 @@ left as a maker, minimum order size condition must be met again for the maker portion. - + ### Self matching Fills up until the point of a self match, cancelling remaining -size without posting as a maker if: +size without posting if: 1. Price crosses the spread, 2. Cross-spread filling is permitted per the indicated @@ -5668,7 +6105,7 @@ restriction, and 3. Self match behavior indicates taker cancellation. - + ### Expected value testing @@ -5682,12 +6119,13 @@ restriction, and * test_place_limit_order_crosses_bid_partial_cancel() * test_place_limit_order_evict() * test_place_limit_order_no_cross_ask_user() +* test_place_limit_order_no_cross_ask_user_ioc() * test_place_limit_order_no_cross_bid_custodian() * test_place_limit_order_still_crosses_ask() * test_place_limit_order_still_crosses_bid() - + ### Failure testing @@ -5734,10 +6172,7 @@ restriction, and u64, u64, u64 -) acquires - FillEventHandles, - OrderBooks -{ +) acquires OrderBooks { // Assert valid order restriction flag. assert!(restriction <= N_RESTRICTIONS, E_INVALID_RESTRICTION); assert!(price != 0, E_PRICE_0); // Assert nonzero price. @@ -5826,9 +6261,10 @@ restriction, and base_available, base_ceiling, quote_available, quote_ceiling); // Assume no assets traded as a taker. let (base_traded, quote_traded, fees) = (0, 0, 0); - // Evaluate any potential fills across the spread, which may - // result in deferred fill events: - let fill_event_queue = if (crosses_spread) { + let cancel_reason_option = option::none(); + let fill_event_queue = vector[]; + let remaining_size = size; + if (crosses_spread) { // If order price crosses spread: // Calculate max base and quote to withdraw. If a buy: let (base_withdraw, quote_withdraw) = if (direction == BUY) // Withdraw quote to buy base, else sell base for quote. @@ -5841,18 +6277,32 @@ restriction, and quote_withdraw, underwriter_id); // Declare return assignment variable. let self_match_cancel; - // Declare empty fill event queue inside of an option. - let fill_event_queue_option = option::some(vector[]); - // Match against order book, storing optionally modified - // asset inputs, base and quote trade amounts, quote fees - // paid, and if a self match requires canceling the rest of - // the order. (Increments order book counter). - (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - self_match_cancel) = match( - market_id, resource_address, &mut fill_event_queue_option, - order_book_ref_mut, user_address, custodian_id, integrator, - direction, min_base, max_base, min_quote, max_quote, price, - self_match_behavior, optional_base_coins, quote_coins); + // Match against order book, deferring fill events. + ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + self_match_cancel, + _, + ) = match( + market_id, + &mut fill_event_queue, + order_book_ref_mut, + user_address, + custodian_id, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + price, + self_match_behavior, + optional_base_coins, + quote_coins + ); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else base_withdraw - base_traded; @@ -5869,92 +6319,82 @@ restriction, and !avl_queue::would_update_head(&order_book_ref_mut.bids, price) else !avl_queue::would_update_head(&order_book_ref_mut.asks, price); - // If matching engine halted but order still crosses spread, - // or if a self match that requires canceling the rest of - // of the order, then mark no size left to post as a maker. - size = if (still_crosses_spread || self_match_cancel) 0 else - // Else update size to amount left to fill post-match. + // Remaining size is amount not traded during matching. + remaining_size = size - (base_traded / order_book_ref_mut.lot_size); - // Extract fill event queue packed by matching engine. - option::extract(&mut fill_event_queue_option) + // Get optional order cancel reason. + if (self_match_cancel) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_SELF_MATCH_TAKER); + } else if ((remaining_size > 0) && + (restriction == IMMEDIATE_OR_CANCEL)) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_IMMEDIATE_OR_CANCEL); + } else if (still_crosses_spread) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_MAX_QUOTE_TRADED); + } else { + if (remaining_size < order_book_ref_mut.min_size) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_TOO_SMALL_AFTER_MATCHING); + } + }; } else { // If spread not crossed (matching engine not called): - // Increment order counter. + // Order book counter needs to be updated for new order ID. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; - vector[] // There are no fill events to defer. - }; - // Determine if there are fill events to emit. - let fill_events_to_emit = !vector::is_empty(&fill_event_queue); - // Mutably borrow fill event handle: - let fill_event_handle_ref_mut = table::borrow_mut( - &mut borrow_global_mut<FillEventHandles>(resource_address).map, - market_id); - // If immediate-or-cancel or if remaining size to fill after - // matching does not meet minimum size requirement for market: - if ((restriction == IMMEDIATE_OR_CANCEL) || - (size < order_book_ref_mut.min_size)) { - if (fill_events_to_emit) // If fill events are enqueued: - vector::for_each_ref(&fill_event_queue, |fill_event_ref| { - event::emit_event(fill_event_handle_ref_mut, - *fill_event_ref); - }); // Emit each fill event (first-in-first-out): - // Return without posting. - return ((NIL as u128), base_traded, quote_traded, fees) + // Order needs to be cancelled if no fills took place. + if (restriction == IMMEDIATE_OR_CANCEL) { + option::fill(&mut cancel_reason_option, + CANCEL_REASON_IMMEDIATE_OR_CANCEL); + }; }; - // Get next order access key for user-side order placement. - let order_access_key = user::get_next_order_access_key_internal( - user_address, market_id, custodian_id, side); - // Get orders AVL queue for maker side. - let orders_ref_mut = if (side == ASK) &mut order_book_ref_mut.asks else - &mut order_book_ref_mut.bids; - // Declare order to insert to book. - let order = Order{size, price, user: user_address, custodian_id, - order_access_key}; - // Get new AVL queue access key, evictee access key, and evictee - // value by attempting to insert for given critical height. - let (avlq_access_key, evictee_access_key, evictee_value) = - avl_queue::insert_check_eviction( - orders_ref_mut, price, order, critical_height); - // Assert that order could be inserted to AVL queue. - assert!(avlq_access_key != NIL, E_PRICE_TIME_PRIORITY_TOO_LOW); - // Get market order ID from AVL queue access key, counter. - let market_order_id = (avlq_access_key as u128) | + // Assume that limit order will not post. + let market_order_id = ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); - // If fill events have been deferred: - if (fill_events_to_emit) { - // For each fill event (first-in-first-out): - vector::for_each_ref(&fill_event_queue, |fill_event_ref| { - // Get a copy of the fill event. - let fill_event: FillEvent = *fill_event_ref; - // Re-assign common market order ID generated from - // portion of order that posts as a maker. - fill_event.taker_market_order_id = market_order_id; - // Emit event. - event::emit_event(fill_event_handle_ref_mut, fill_event); - }) - }; - user::place_order_internal( // Place order user-side. - user_address, market_id, custodian_id, side, size, price, - market_order_id, order_access_key); - // Emit a maker place event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id, user: user_address, - custodian_id, type: PLACE, size, price}); - if (evictee_access_key == NIL) { // If no eviction required: - // Destroy empty evictee value option. - option::destroy_none(evictee_value); - } else { // If had to evict order at AVL queue tail: - // Unpack evicted order, storing fields for event. - let Order{size, price, user, custodian_id, order_access_key} = - option::destroy_some(evictee_value); - // Cancel order user-side, storing its market order ID. - let market_order_id_cancel = user::cancel_order_internal( - user, market_id, custodian_id, side, size, price, - order_access_key, (NIL as u128)); - // Emit a maker evict event. - event::emit_event(&mut order_book_ref_mut.maker_events, MakerEvent{ - market_id, side, market_order_id: market_order_id_cancel, user, - custodian_id, type: EVICT, size, price}); + // If order eligible to post: + if (option::is_none(&cancel_reason_option)) { + // Get next order access key for user-side order placement. + let order_access_key = user::get_next_order_access_key_internal( + user_address, market_id, custodian_id, side); + // Get orders AVL queue for maker side. + let orders_ref_mut = if (side == ASK) + &mut order_book_ref_mut.asks else &mut order_book_ref_mut.bids; + // Declare order to insert to book. + let order = Order{size: remaining_size, price, user: user_address, + custodian_id, order_access_key}; + // Get new AVL queue access key, evictee access key, and evictee + // value by attempting to insert for given critical height. + let (avlq_access_key, evictee_access_key, evictee_value) = + avl_queue::insert_check_eviction( + orders_ref_mut, price, order, critical_height); + // Assert that order could be inserted to AVL queue. + assert!(avlq_access_key != NIL, E_PRICE_TIME_PRIORITY_TOO_LOW); + // Encode AVL queue access key in market order ID. + market_order_id = market_order_id | (avlq_access_key as u128); + user::place_order_internal( // Place order user-side. + user_address, market_id, custodian_id, side, remaining_size, + price, market_order_id, order_access_key); + if (evictee_access_key == NIL) { // If no eviction required: + // Destroy empty evictee value option. + option::destroy_none(evictee_value); + } else { // If had to evict order at AVL queue tail: + // Unpack evicted order. + let Order{size, price, user, custodian_id, order_access_key} = + option::destroy_some(evictee_value); + // Cancel order user-side. + user::cancel_order_internal( + user, market_id, custodian_id, side, size, price, + order_access_key, (NIL as u128), CANCEL_REASON_EVICTION); + }; + } else { + // If not eligible to post, no remaining size. + remaining_size = 0; }; + // Emit relevant events to user event handles. + user::emit_limit_order_events_internal( + market_id, user_address, custodian_id, integrator, side, size, + price, restriction, self_match_behavior, remaining_size, + market_order_id, &fill_event_queue, &cancel_reason_option); // Return market order ID and taker trade amounts. return (market_order_id, base_traded, quote_traded, fees) } @@ -5993,7 +6433,7 @@ order that aborts for a self match. Advance price is then range-checked by place_limit_order(). - + ### Price calculations @@ -6005,7 +6445,7 @@ operation during the advance amount calculation for the percent case. - + ### Type Parameters @@ -6014,7 +6454,7 @@ case. * QuoteType: Same as for match(). - + ### Parameters @@ -6033,7 +6473,7 @@ percent of the spread to advance, else the number of ticks to advance. - + ### Returns @@ -6041,7 +6481,7 @@ advance. * u128: Market order ID, same as for place_limit_order(). - + ### Aborts @@ -6053,7 +6493,7 @@ advance. target_advance_amount is not less than or equal to 100. - + ### Expected value testing @@ -6069,7 +6509,7 @@ advance. * test_place_limit_order_passive_advance_ticks_bid() - + ### Failure testing @@ -6101,10 +6541,7 @@ advance. advance_style: bool, target_advance_amount: u64 ): u128 -acquires - FillEventHandles, - OrderBooks -{ +acquires OrderBooks { // Get address of resource account where order books are stored. let resource_address = resource_account::get_address(); let order_books_map_ref = // Immutably borrow order books map. @@ -6209,7 +6646,7 @@ advance. Place market order against order book from user market account. - + ### Type Parameters @@ -6218,7 +6655,7 @@ Place market order against order book from user market account. * QuoteType: Same as for match(). - + ### Parameters @@ -6228,11 +6665,11 @@ Place market order against order book from user market account. * custodian_id: Same as for match(). * integrator: Same as for match(). * direction: Same as for match(). -* size: The maximum size, in lots, to fill. +* size: Size, in lots, to fill. * self_match_behavior: Same as for match(). - + ### Returns @@ -6242,7 +6679,7 @@ Place market order against order book from user market account. * u64: Quote coin fees paid, same as for match(). - + ### Aborts @@ -6251,9 +6688,11 @@ Place market order against order book from user market account. * E_INVALID_QUOTE: Quote asset type is invalid. * E_SIZE_TOO_SMALL: Market order size does not meet minimum size for market. +* E_SIZE_BASE_OVERFLOW: The product of order size and market +lot size results in a base asset unit overflow. - + ### Expected value testing @@ -6265,13 +6704,14 @@ size for market. * test_place_market_order_max_quote_sell_user() - + ### Failure testing * test_place_market_order_invalid_base() * test_place_market_order_invalid_quote() +* test_place_market_order_size_base_overflow() * test_place_market_order_size_too_small() @@ -6298,10 +6738,7 @@ size for market. u64, u64, u64 -) acquires - FillEventHandles, - OrderBooks -{ +) acquires OrderBooks { // Get user's available and ceiling asset counts. let (_, base_available, base_ceiling, _, quote_available, quote_ceiling) = user::get_asset_counts_internal( @@ -6319,29 +6756,20 @@ size for market. == order_book_ref_mut.quote_type, E_INVALID_QUOTE); // Assert order size is at least minimum size for market. assert!(size >= order_book_ref_mut.min_size, E_SIZE_TOO_SMALL); + // Calculate base asset amount corresponding to size in lots. + let base = (size as u128) * (order_book_ref_mut.lot_size as u128); + // Assert corresponding base asset amount fits in a u64. + assert!(base <= (HI_64 as u128), E_SIZE_BASE_OVERFLOW); // Get market underwriter ID. let underwriter_id = order_book_ref_mut.underwriter_id; - // Calculate max base that can be traded: if a buy, max base - // that can fit in market account. If a sell, base available in - // market account. - let max_base = if (direction == BUY) - (HI_64 - base_ceiling) else base_available; - // Get max lots that can be traded by user. - let max_lots_user_can_trade = max_base / order_book_ref_mut.lot_size; - // If market order size is less than number of lots user can - // trade based on account limits, adjust the max base trade - // amount to correspond with the market order size. - if (size < max_lots_user_can_trade) - max_base = size * order_book_ref_mut.lot_size; + // Max base to trade is amount calculated from size, lot size. + let max_base = (base as u64); // Calculate max quote that can be traded: if a buy, quote // available in market account. If a sell, max quote that can // fit in market account. let max_quote = if (direction == BUY) quote_available else (HI_64 - quote_ceiling); - // Declare min base and quote trade amounts 0, enabling silent - // return without fills if there is no depth on the book, and - // silent return with max possible fills if order takes all - // liquidity before filling user-indicated size. + // Set min base/quote to match as 0. let (min_base, min_quote) = (0, 0); range_check_trade( // Range check trade amounts. direction, min_base, max_base, min_quote, max_quote, @@ -6359,14 +6787,36 @@ size for market. // Calculate limit price for matching engine: 0 when selling, // max price possible when buying. let limit_price = if (direction == SELL) 0 else HI_PRICE; - // Match against order book, storing optionally modified asset - // inputs, base and quote trade amounts, and quote fees paid. - let (optional_base_coins, quote_coins, base_traded, quote_traded, fees, - _) = match( - market_id, resource_address, &mut option::none(), - order_book_ref_mut, user_address, custodian_id, integrator, - direction, min_base, max_base, min_quote, max_quote, limit_price, - self_match_behavior, optional_base_coins, quote_coins); + // Match against order book, deferring fill events. + let fill_event_queue = vector[]; + let ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + self_match_taker_cancel, + liquidity_gone + ) = match( + market_id, + &mut fill_event_queue, + order_book_ref_mut, + user_address, + custodian_id, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + self_match_behavior, + optional_base_coins, + quote_coins + ); + // Get order ID from order book counter updated during matching. + let market_order_id = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); // Calculate amount of base deposited back to market account. let base_deposit = if (direction == BUY) base_traded else (base_withdraw - base_traded); @@ -6374,6 +6824,16 @@ size for market. user::deposit_assets_internal<BaseType, QuoteType>( user_address, market_id, custodian_id, base_deposit, optional_base_coins, quote_coins, underwriter_id); + // Get optional cancel reason. + let cancel_reason_option = + get_cancel_reason_option_for_market_order_or_swap( + self_match_taker_cancel, base_traded, max_base, + liquidity_gone); + // Emit relevant events to user event handles. + user::emit_market_order_events_internal( + market_id, user_address, custodian_id, integrator, direction, size, + self_match_behavior, market_order_id, &fill_event_queue, + &cancel_reason_option); // Return base and quote traded by user, fees paid. (base_traded, quote_traded, fees) } @@ -6390,7 +6850,7 @@ Range check minimum and maximum asset trade amounts. Should be called before match(). - + ### Terminology @@ -6413,7 +6873,7 @@ user's aptos_framework::coin::CoinStore or from standalone coins, is the same as available amount. - + ### Parameters @@ -6434,7 +6894,7 @@ trade. SELL. - + ### Aborts @@ -6450,7 +6910,7 @@ received from trade. * E_NOT_ENOUGH_ASSET_OUT: Not enough asset to trade away. - + ### Failure testing @@ -6524,7 +6984,7 @@ See registry::MarketI size, minimum size, and 32-bit prices. - + ### Type parameters @@ -6533,7 +6993,7 @@ size, minimum size, and 32-bit prices. * QuoteType: Quote coin type for market. - + ### Parameters @@ -6547,7 +7007,7 @@ for market. * underwriter_id: registry::MarketInfo.min_size for market. - + ### Returns @@ -6555,7 +7015,7 @@ for market. * u64: Market ID for new market. - + ### Testing @@ -6582,10 +7042,7 @@ for market. min_size: u64, underwriter_id: u64 ): u64 -acquires - FillEventHandles, - OrderBooks -{ +acquires OrderBooks { // Get Econia resource account signer. let resource_account = resource_account::get_signer(); // Get resource account address. @@ -6608,21 +7065,6 @@ for market. account::new_event_handle<MakerEvent>(&resource_account), taker_events: account::new_event_handle<TakerEvent>(&resource_account)}); - // If a fill event handles map has not yet been moved to the - // resource account: - if (!exists<FillEventHandles>(resource_address)) { - // Initialize fill event handles map under resource account. - // This is done here rather than in `init_module()` since - // the fill event handles map was implemented in a - // backwards-compatible package upgrade. - move_to(&resource_account, FillEventHandles{map: table::new()}); - }; - // Mutably borrow fill event handles map. - let fill_event_handles_map_ref_mut = - &mut borrow_global_mut<FillEventHandles>(resource_address).map; - table::add( // Add fill event handle to fill event handles map. - fill_event_handles_map_ref_mut, market_id, - account::new_event_handle<FillEvent>(&resource_account)); // Register an Econia fee store entry for market quote coin. incentives::register_econia_fee_store_entry<QuoteType>(market_id); market_id // Return market ID. @@ -6638,7 +7080,7 @@ for market. Match a taker's swap order against order book for given market. - + ### Type Parameters @@ -6647,11 +7089,15 @@ Match a taker's swap order against order book for given market. * QuoteType: Same as for match(). - + ### Parameters +* fill_event_queue_ref_mut: Mutable reference to vector for +enqueueing deferred FillEvent(s). +* signer_address: Address of signing user if applicable, else +NO_TAKER_ADDRESS. * market_id: Same as for match(). * underwriter_id: ID of underwriter to verify if BaseType is registry::GenericAsset, else may be passed as @@ -6667,7 +7113,7 @@ is registry::Generi * quote_coins: Same as for match(). - + ### Returns @@ -6679,9 +7125,25 @@ same as for match() * u64: Base asset trade amount, same as for match(). * u64: Quote coin trade amount, same as for match(). * u64: Quote coin fees paid, same as for match(). +* Option<PlaceSwapOrderEvent>: PlaceSwapOrderEvent to emit +if swap is from a signing swapper. +* Option<CancelOrderEvent>: Optional CancelOrderEvent to +emit if swap is from a signing swapper. + + + + +### Emits - +* PlaceSwapOrderEvent: Information about swap order, emitted +when swap is from a non-signing swapper. +* CancelOrderEvent: Information about order cancellation, if +order was cancelled without completely filling, when swap is +from non-signing swapper. + + + ### Aborts @@ -6692,7 +7154,7 @@ same as for match() * E_INVALID_QUOTE: Quote asset type is invalid. - + ### Expected value testing @@ -6701,7 +7163,7 @@ same as for match() swap_generic() testing. - + ### Failure testing @@ -6712,7 +7174,7 @@ same as for match() * test_swap_invalid_underwriter() -
fun swap<BaseType, QuoteType>(market_id: u64, underwriter_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64)
+
fun swap<BaseType, QuoteType>(fill_event_queue_ref_mut: &mut vector<user::FillEvent>, signer_address: address, market_id: u64, underwriter_id: u64, integrator: address, direction: bool, min_base: u64, max_base: u64, min_quote: u64, max_quote: u64, limit_price: u64, optional_base_coins: option::Option<coin::Coin<BaseType>>, quote_coins: coin::Coin<QuoteType>): (option::Option<coin::Coin<BaseType>>, coin::Coin<QuoteType>, u64, u64, u64, option::Option<market::PlaceSwapOrderEvent>, option::Option<user::CancelOrderEvent>)
 
@@ -6724,6 +7186,8 @@ same as for match() BaseType, QuoteType >( + fill_event_queue_ref_mut: &mut vector<FillEvent>, + signer_address: address, market_id: u64, underwriter_id: u64, integrator: address, @@ -6740,9 +7204,11 @@ same as for match() Coin<QuoteType>, u64, u64, - u64 + u64, + Option<PlaceSwapOrderEvent>, + Option<CancelOrderEvent> ) acquires - FillEventHandles, + MarketEventHandles, OrderBooks { // Get address of resource account where order books are stored. @@ -6762,17 +7228,97 @@ same as for match() == order_book_ref_mut.base_type, E_INVALID_BASE); assert!(type_info::type_of<QuoteType>() // Assert quote type. == order_book_ref_mut.quote_type, E_INVALID_QUOTE); - // Declare return assignment variables. - let (base_traded, quote_traded, fees); - (optional_base_coins, quote_coins, base_traded, quote_traded, fees, _) - = match( // Match against order book. - market_id, resource_address, &mut option::none(), - order_book_ref_mut, NO_MARKET_ACCOUNT, NO_CUSTODIAN, - integrator, direction, min_base, max_base, min_quote, - max_quote, limit_price, ABORT, optional_base_coins, - quote_coins); - // Return optionally modified asset inputs, trade amounts, fees. - (optional_base_coins, quote_coins, base_traded, quote_traded, fees) + // Match against order book, deferring fill events. + let ( + optional_base_coins, + quote_coins, + base_traded, + quote_traded, + fees, + self_match_taker_cancel, + liquidity_gone + ) = match( + market_id, + fill_event_queue_ref_mut, + order_book_ref_mut, + signer_address, + NO_CUSTODIAN, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + CANCEL_TAKER, + optional_base_coins, + quote_coins + ); + // Get order ID from order book counter updated during matching. + let market_order_id = + ((order_book_ref_mut.counter as u128) << SHIFT_COUNTER); + // Create market event handles for market as needed. + if (!exists<MarketEventHandles>(resource_address)) + move_to(&resource_account::get_signer(), + MarketEventHandles{map: table::new()}); + let market_event_handles_map_ref_mut = + &mut borrow_global_mut<MarketEventHandles>(resource_address).map; + let has_handles = + table::contains(market_event_handles_map_ref_mut, market_id); + if (!has_handles) { + let resource_signer = resource_account::get_signer(); + let handles = MarketEventHandlesForMarket{ + cancel_order_events: + account::new_event_handle(&resource_signer), + place_swap_order_events: + account::new_event_handle(&resource_signer) + }; + table::add( + market_event_handles_map_ref_mut, market_id, handles); + }; + let handles_ref_mut = + table::borrow_mut(market_event_handles_map_ref_mut, market_id); + // Create market events as necessary. + let place_swap_order_event = PlaceSwapOrderEvent{ + market_id, + signing_account: signer_address, + integrator, + direction, + min_base, + max_base, + min_quote, + max_quote, + limit_price, + order_id: market_order_id + }; + let cancel_reason_option = + get_cancel_reason_option_for_market_order_or_swap( + self_match_taker_cancel, base_traded, max_base, + liquidity_gone); + let need_to_cancel = option::is_some(&cancel_reason_option); + let cancel_order_event_option = if (need_to_cancel) + option::some(user::create_cancel_order_event_internal( + market_id, market_order_id, signer_address, NO_CUSTODIAN, + option::destroy_some(cancel_reason_option))) else + option::none(); + // Assume do not need to return place swap order event. + let place_swap_order_event_option = option::none(); + // If swap not placed by a signing swapper: + if (signer_address == NO_TAKER_ADDRESS) { + event::emit_event(&mut handles_ref_mut.place_swap_order_events, + place_swap_order_event); + if (need_to_cancel) event::emit_event( + &mut handles_ref_mut.cancel_order_events, + option::extract(&mut cancel_order_event_option)); + } else { // Otherwise swap order placed by signing swapper. + option::fill(&mut place_swap_order_event_option, + place_swap_order_event); + }; + user::emit_swap_maker_fill_events_internal(fill_event_queue_ref_mut); + // Return optionally modified asset inputs, trade amounts, fees, + // place swap order event option, and cancel order event option. + (optional_base_coins, quote_coins, base_traded, quote_traded, fees, + place_swap_order_event_option, cancel_order_event_option) }
@@ -6782,10 +7328,10 @@ same as for match() ## Function `index_orders_sdk` -Deprecated function retained for backwards compatibility. +Deprecated function retained for compatible upgrade policy. - + ### Coverage testing diff --git a/src/move/econia/doc/user.md b/src/move/econia/doc/user.md index 23e45c055..a7cb8f9cf 100644 --- a/src/move/econia/doc/user.md +++ b/src/move/econia/doc/user.md @@ -125,6 +125,14 @@ Constant getters: * get_ASK() * get_BID() * get_NO_CUSTODIAN() +* get_CANCEL_REASON_EVICTION() +* get_CANCEL_REASON_IMMEDIATE_OR_CANCEL() +* get_CANCEL_REASON_MANUAL_CANCEL() +* get_CANCEL_REASON_MAX_QUOTE_TRADED() +* get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY() +* get_CANCEL_REASON_SELF_MATCH_MAKER() +* get_CANCEL_REASON_SELF_MATCH_TAKER() +* get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING() Market account lookup: @@ -132,6 +140,7 @@ Market account lookup: * get_all_market_account_ids_for_user() * get_market_account() * get_market_accounts() +* get_market_event_handle_creation_numbers() * has_market_account() * has_market_account_by_market_account_id() * has_market_account_by_market_id() @@ -177,6 +186,7 @@ Asset transfer: Account registration: +* init_market_event_handles_if_missing() * register_market_account() * register_market_account_generic_base() @@ -205,6 +215,14 @@ Order identifiers: * get_next_order_access_key_internal() * get_active_market_order_ids_internal() +Market events: + +* create_cancel_order_event_internal() +* create_fill_event_internal() +* emit_limit_order_events_internal() +* emit_market_order_events_internal() +* emit_swap_maker_fill_events_internal() + @@ -292,11 +310,14 @@ get_market_account --> has_market_account_by_market_account_id get_market_account --> vectorize_open_orders get_open_order_id_internal --> get_market_account_id -get_open_order_id_internal --> has_market_account_by_market_account_id +get_open_order_id_internal --> +has_market_account_by_market_account_id has_market_account --> has_market_account_by_market_account_id has_market_account --> get_market_account_id +get_market_event_handle_creation_numbers --> get_market_account_id + ``` Market account registration: @@ -308,12 +329,15 @@ flowchart LR register_market_account --> registry::is_registered_custodian_id register_market_account --> register_market_account_account_entries register_market_account --> register_market_account_collateral_entry +register_market_account --> init_market_event_handles_if_missing register_market_account_generic_base --> register_market_account register_market_account_account_entries --> registry::get_market_info_for_market_account +init_market_event_handles_if_missing --> has_market_account + ``` Internal order management: @@ -327,6 +351,12 @@ change_order_size_internal --> place_order_internal ``` +Market events: + +emit_limit_order_events_internal --> emit_maker_fill_event +emit_market_order_events_internal --> emit_maker_fill_event +emit_swap_maker_fill_events_internal --> emit_maker_fill_event + @@ -349,165 +379,210 @@ The below index is automatically generated from source code: - [Public friend functions](#@Public_friend_functions_10) - [Dependency charts](#@Dependency_charts_11) - [Complete DocGen index](#@Complete_DocGen_index_12) +- [Struct `CancelOrderEvent`](#0xc0deb00c_user_CancelOrderEvent) +- [Struct `ChangeOrderSizeEvent`](#0xc0deb00c_user_ChangeOrderSizeEvent) - [Resource `Collateral`](#0xc0deb00c_user_Collateral) +- [Struct `FillEvent`](#0xc0deb00c_user_FillEvent) - [Struct `MarketAccount`](#0xc0deb00c_user_MarketAccount) - [Struct `MarketAccountView`](#0xc0deb00c_user_MarketAccountView) - [Resource `MarketAccounts`](#0xc0deb00c_user_MarketAccounts) +- [Struct `MarketEventHandleCreationNumbers`](#0xc0deb00c_user_MarketEventHandleCreationNumbers) +- [Resource `MarketEventHandles`](#0xc0deb00c_user_MarketEventHandles) +- [Struct `MarketEventHandlesForMarketAccount`](#0xc0deb00c_user_MarketEventHandlesForMarketAccount) - [Struct `Order`](#0xc0deb00c_user_Order) +- [Struct `PlaceLimitOrderEvent`](#0xc0deb00c_user_PlaceLimitOrderEvent) +- [Struct `PlaceMarketOrderEvent`](#0xc0deb00c_user_PlaceMarketOrderEvent) - [Constants](#@Constants_13) - [Function `get_ASK`](#0xc0deb00c_user_get_ASK) - [Testing](#@Testing_14) - [Function `get_BID`](#0xc0deb00c_user_get_BID) - [Testing](#@Testing_15) -- [Function `get_NO_CUSTODIAN`](#0xc0deb00c_user_get_NO_CUSTODIAN) +- [Function `get_CANCEL_REASON_EVICTION`](#0xc0deb00c_user_get_CANCEL_REASON_EVICTION) - [Testing](#@Testing_16) -- [Function `get_all_market_account_ids_for_market_id`](#0xc0deb00c_user_get_all_market_account_ids_for_market_id) - - [Parameters](#@Parameters_17) - - [Returns](#@Returns_18) - - [Gas considerations](#@Gas_considerations_19) +- [Function `get_CANCEL_REASON_IMMEDIATE_OR_CANCEL`](#0xc0deb00c_user_get_CANCEL_REASON_IMMEDIATE_OR_CANCEL) + - [Testing](#@Testing_17) +- [Function `get_CANCEL_REASON_MANUAL_CANCEL`](#0xc0deb00c_user_get_CANCEL_REASON_MANUAL_CANCEL) + - [Testing](#@Testing_18) +- [Function `get_CANCEL_REASON_MAX_QUOTE_TRADED`](#0xc0deb00c_user_get_CANCEL_REASON_MAX_QUOTE_TRADED) + - [Testing](#@Testing_19) +- [Function `get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY`](#0xc0deb00c_user_get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY) - [Testing](#@Testing_20) -- [Function `get_all_market_account_ids_for_user`](#0xc0deb00c_user_get_all_market_account_ids_for_user) - - [Parameters](#@Parameters_21) - - [Returns](#@Returns_22) - - [Gas considerations](#@Gas_considerations_23) +- [Function `get_CANCEL_REASON_SELF_MATCH_MAKER`](#0xc0deb00c_user_get_CANCEL_REASON_SELF_MATCH_MAKER) + - [Testing](#@Testing_21) +- [Function `get_CANCEL_REASON_SELF_MATCH_TAKER`](#0xc0deb00c_user_get_CANCEL_REASON_SELF_MATCH_TAKER) + - [Testing](#@Testing_22) +- [Function `get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING`](#0xc0deb00c_user_get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING) + - [Testing](#@Testing_23) +- [Function `get_NO_CUSTODIAN`](#0xc0deb00c_user_get_NO_CUSTODIAN) - [Testing](#@Testing_24) +- [Function `get_all_market_account_ids_for_market_id`](#0xc0deb00c_user_get_all_market_account_ids_for_market_id) + - [Parameters](#@Parameters_25) + - [Returns](#@Returns_26) + - [Gas considerations](#@Gas_considerations_27) + - [Testing](#@Testing_28) +- [Function `get_all_market_account_ids_for_user`](#0xc0deb00c_user_get_all_market_account_ids_for_user) + - [Parameters](#@Parameters_29) + - [Returns](#@Returns_30) + - [Gas considerations](#@Gas_considerations_31) + - [Testing](#@Testing_32) - [Function `get_custodian_id`](#0xc0deb00c_user_get_custodian_id) - - [Testing](#@Testing_25) + - [Testing](#@Testing_33) - [Function `get_market_account`](#0xc0deb00c_user_get_market_account) - - [Aborts](#@Aborts_26) - - [Testing](#@Testing_27) + - [Aborts](#@Aborts_34) + - [Testing](#@Testing_35) - [Function `get_market_account_id`](#0xc0deb00c_user_get_market_account_id) - - [Testing](#@Testing_28) + - [Testing](#@Testing_36) - [Function `get_market_accounts`](#0xc0deb00c_user_get_market_accounts) - - [Testing](#@Testing_29) + - [Testing](#@Testing_37) +- [Function `get_market_event_handle_creation_numbers`](#0xc0deb00c_user_get_market_event_handle_creation_numbers) + - [Testing](#@Testing_38) - [Function `get_market_id`](#0xc0deb00c_user_get_market_id) - - [Testing](#@Testing_30) + - [Testing](#@Testing_39) - [Function `has_market_account`](#0xc0deb00c_user_has_market_account) - - [Testing](#@Testing_31) + - [Testing](#@Testing_40) - [Function `has_market_account_by_market_account_id`](#0xc0deb00c_user_has_market_account_by_market_account_id) - - [Testing](#@Testing_32) + - [Testing](#@Testing_41) - [Function `has_market_account_by_market_id`](#0xc0deb00c_user_has_market_account_by_market_id) - - [Testing](#@Testing_33) + - [Testing](#@Testing_42) - [Function `deposit_coins`](#0xc0deb00c_user_deposit_coins) - - [Aborts](#@Aborts_34) - - [Testing](#@Testing_35) + - [Aborts](#@Aborts_43) + - [Testing](#@Testing_44) - [Function `deposit_generic_asset`](#0xc0deb00c_user_deposit_generic_asset) - - [Testing](#@Testing_36) + - [Testing](#@Testing_45) - [Function `get_asset_counts_custodian`](#0xc0deb00c_user_get_asset_counts_custodian) - - [Testing](#@Testing_37) + - [Testing](#@Testing_46) - [Function `get_asset_counts_user`](#0xc0deb00c_user_get_asset_counts_user) - - [Testing](#@Testing_38) + - [Testing](#@Testing_47) - [Function `get_market_account_market_info_custodian`](#0xc0deb00c_user_get_market_account_market_info_custodian) - - [Testing](#@Testing_39) + - [Testing](#@Testing_48) - [Function `get_market_account_market_info_user`](#0xc0deb00c_user_get_market_account_market_info_user) - - [Testing](#@Testing_40) + - [Testing](#@Testing_49) - [Function `withdraw_coins_custodian`](#0xc0deb00c_user_withdraw_coins_custodian) - - [Testing](#@Testing_41) + - [Testing](#@Testing_50) - [Function `withdraw_coins_user`](#0xc0deb00c_user_withdraw_coins_user) - - [Testing](#@Testing_42) + - [Testing](#@Testing_51) - [Function `withdraw_generic_asset_custodian`](#0xc0deb00c_user_withdraw_generic_asset_custodian) - - [Testing](#@Testing_43) + - [Testing](#@Testing_52) - [Function `withdraw_generic_asset_user`](#0xc0deb00c_user_withdraw_generic_asset_user) - - [Testing](#@Testing_44) + - [Testing](#@Testing_53) - [Function `deposit_from_coinstore`](#0xc0deb00c_user_deposit_from_coinstore) - - [Testing](#@Testing_45) + - [Testing](#@Testing_54) +- [Function `init_market_event_handles_if_missing`](#0xc0deb00c_user_init_market_event_handles_if_missing) + - [Parameters](#@Parameters_55) + - [Aborts](#@Aborts_56) + - [Testing](#@Testing_57) - [Function `register_market_account`](#0xc0deb00c_user_register_market_account) - - [Type parameters](#@Type_parameters_46) - - [Parameters](#@Parameters_47) - - [Aborts](#@Aborts_48) - - [Testing](#@Testing_49) + - [Type parameters](#@Type_parameters_58) + - [Parameters](#@Parameters_59) + - [Aborts](#@Aborts_60) + - [Testing](#@Testing_61) - [Function `register_market_account_generic_base`](#0xc0deb00c_user_register_market_account_generic_base) - - [Testing](#@Testing_50) + - [Testing](#@Testing_62) - [Function `withdraw_to_coinstore`](#0xc0deb00c_user_withdraw_to_coinstore) - - [Testing](#@Testing_51) + - [Testing](#@Testing_63) - [Function `cancel_order_internal`](#0xc0deb00c_user_cancel_order_internal) - - [Parameters](#@Parameters_52) - - [Returns](#@Returns_53) - - [Terminology](#@Terminology_54) - - [Aborts](#@Aborts_55) - - [Assumptions](#@Assumptions_56) - - [Expected value testing](#@Expected_value_testing_57) - - [Failure testing](#@Failure_testing_58) + - [Parameters](#@Parameters_64) + - [Returns](#@Returns_65) + - [Terminology](#@Terminology_66) + - [Aborts](#@Aborts_67) + - [Emits](#@Emits_68) + - [Assumptions](#@Assumptions_69) + - [Expected value testing](#@Expected_value_testing_70) + - [Failure testing](#@Failure_testing_71) - [Function `change_order_size_internal`](#0xc0deb00c_user_change_order_size_internal) - - [Parameters](#@Parameters_59) - - [Aborts](#@Aborts_60) - - [Assumptions](#@Assumptions_61) - - [Testing](#@Testing_62) + - [Parameters](#@Parameters_72) + - [Aborts](#@Aborts_73) + - [Emits](#@Emits_74) + - [Assumptions](#@Assumptions_75) + - [Testing](#@Testing_76) +- [Function `create_cancel_order_event_internal`](#0xc0deb00c_user_create_cancel_order_event_internal) +- [Function `create_fill_event_internal`](#0xc0deb00c_user_create_fill_event_internal) - [Function `deposit_assets_internal`](#0xc0deb00c_user_deposit_assets_internal) - - [Type parameters](#@Type_parameters_63) - - [Parameters](#@Parameters_64) - - [Testing](#@Testing_65) + - [Type parameters](#@Type_parameters_77) + - [Parameters](#@Parameters_78) + - [Testing](#@Testing_79) +- [Function `emit_limit_order_events_internal`](#0xc0deb00c_user_emit_limit_order_events_internal) + - [Parameters](#@Parameters_80) + - [Emits](#@Emits_81) +- [Function `emit_market_order_events_internal`](#0xc0deb00c_user_emit_market_order_events_internal) + - [Parameters](#@Parameters_82) + - [Emits](#@Emits_83) +- [Function `emit_swap_maker_fill_events_internal`](#0xc0deb00c_user_emit_swap_maker_fill_events_internal) - [Function `fill_order_internal`](#0xc0deb00c_user_fill_order_internal) - - [Type parameters](#@Type_parameters_66) - - [Parameters](#@Parameters_67) - - [Returns](#@Returns_68) - - [Aborts](#@Aborts_69) - - [Assumptions](#@Assumptions_70) - - [Testing](#@Testing_71) + - [Type parameters](#@Type_parameters_84) + - [Parameters](#@Parameters_85) + - [Returns](#@Returns_86) + - [Aborts](#@Aborts_87) + - [Assumptions](#@Assumptions_88) + - [Testing](#@Testing_89) - [Function `get_asset_counts_internal`](#0xc0deb00c_user_get_asset_counts_internal) - - [Parameters](#@Parameters_72) - - [Returns](#@Returns_73) - - [Aborts](#@Aborts_74) - - [Testing](#@Testing_75) + - [Parameters](#@Parameters_90) + - [Returns](#@Returns_91) + - [Aborts](#@Aborts_92) + - [Testing](#@Testing_93) - [Function `get_active_market_order_ids_internal`](#0xc0deb00c_user_get_active_market_order_ids_internal) - - [Parameters](#@Parameters_76) - - [Returns](#@Returns_77) - - [Aborts](#@Aborts_78) - - [Testing](#@Testing_79) + - [Parameters](#@Parameters_94) + - [Returns](#@Returns_95) + - [Aborts](#@Aborts_96) + - [Testing](#@Testing_97) - [Function `get_next_order_access_key_internal`](#0xc0deb00c_user_get_next_order_access_key_internal) - - [Parameters](#@Parameters_80) - - [Returns](#@Returns_81) - - [Aborts](#@Aborts_82) - - [Testing](#@Testing_83) + - [Parameters](#@Parameters_98) + - [Returns](#@Returns_99) + - [Aborts](#@Aborts_100) + - [Testing](#@Testing_101) - [Function `get_open_order_id_internal`](#0xc0deb00c_user_get_open_order_id_internal) - - [Testing](#@Testing_84) + - [Testing](#@Testing_102) - [Function `place_order_internal`](#0xc0deb00c_user_place_order_internal) - - [Parameters](#@Parameters_85) - - [Terminology](#@Terminology_86) - - [Assumptions](#@Assumptions_87) - - [Aborts](#@Aborts_88) - - [Expected value testing](#@Expected_value_testing_89) - - [Failure testing](#@Failure_testing_90) + - [Parameters](#@Parameters_103) + - [Terminology](#@Terminology_104) + - [Assumptions](#@Assumptions_105) + - [Aborts](#@Aborts_106) + - [Expected value testing](#@Expected_value_testing_107) + - [Failure testing](#@Failure_testing_108) - [Function `withdraw_assets_internal`](#0xc0deb00c_user_withdraw_assets_internal) - - [Type parameters](#@Type_parameters_91) - - [Parameters](#@Parameters_92) - - [Returns](#@Returns_93) - - [Testing](#@Testing_94) + - [Type parameters](#@Type_parameters_109) + - [Parameters](#@Parameters_110) + - [Returns](#@Returns_111) + - [Testing](#@Testing_112) - [Function `deposit_asset`](#0xc0deb00c_user_deposit_asset) - - [Type parameters](#@Type_parameters_95) - - [Parameters](#@Parameters_96) - - [Aborts](#@Aborts_97) - - [Assumptions](#@Assumptions_98) - - [Testing](#@Testing_99) + - [Type parameters](#@Type_parameters_113) + - [Parameters](#@Parameters_114) + - [Aborts](#@Aborts_115) + - [Assumptions](#@Assumptions_116) + - [Testing](#@Testing_117) +- [Function `emit_maker_fill_event`](#0xc0deb00c_user_emit_maker_fill_event) - [Function `get_market_account_market_info`](#0xc0deb00c_user_get_market_account_market_info) - - [Parameters](#@Parameters_100) - - [Returns](#@Returns_101) - - [Aborts](#@Aborts_102) - - [Testing](#@Testing_103) + - [Parameters](#@Parameters_118) + - [Returns](#@Returns_119) + - [Aborts](#@Aborts_120) + - [Testing](#@Testing_121) - [Function `register_market_account_account_entries`](#0xc0deb00c_user_register_market_account_account_entries) - - [Type parameters](#@Type_parameters_104) - - [Parameters](#@Parameters_105) - - [Aborts](#@Aborts_106) - - [Testing](#@Testing_107) + - [Type parameters](#@Type_parameters_122) + - [Parameters](#@Parameters_123) + - [Aborts](#@Aborts_124) + - [Testing](#@Testing_125) - [Function `register_market_account_collateral_entry`](#0xc0deb00c_user_register_market_account_collateral_entry) - - [Type parameters](#@Type_parameters_108) - - [Parameters](#@Parameters_109) - - [Testing](#@Testing_110) + - [Type parameters](#@Type_parameters_126) + - [Parameters](#@Parameters_127) + - [Testing](#@Testing_128) - [Function `vectorize_open_orders`](#0xc0deb00c_user_vectorize_open_orders) - - [Testing](#@Testing_111) + - [Testing](#@Testing_129) - [Function `withdraw_asset`](#0xc0deb00c_user_withdraw_asset) - - [Type parameters](#@Type_parameters_112) - - [Parameters](#@Parameters_113) - - [Returns](#@Returns_114) - - [Aborts](#@Aborts_115) - - [Testing](#@Testing_116) + - [Type parameters](#@Type_parameters_130) + - [Parameters](#@Parameters_131) + - [Returns](#@Returns_132) + - [Aborts](#@Aborts_133) + - [Testing](#@Testing_134) - [Function `withdraw_coins`](#0xc0deb00c_user_withdraw_coins) - - [Testing](#@Testing_117) + - [Testing](#@Testing_135) - [Function `withdraw_generic_asset`](#0xc0deb00c_user_withdraw_generic_asset) - - [Testing](#@Testing_118) + - [Testing](#@Testing_136) -
use 0x1::coin;
+
use 0x1::account;
+use 0x1::coin;
+use 0x1::event;
+use 0x1::guid;
 use 0x1::option;
 use 0x1::signer;
 use 0x1::string;
@@ -532,6 +607,111 @@ The below index is automatically generated from source code:
 ![](img/user_backward_dep.svg)
 
 
+
+
+## Struct `CancelOrderEvent`
+
+Emitted when an order is cancelled.
+
+
+
struct CancelOrderEvent has copy, drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID for order. +
+
+order_id: u128 +
+
+ Unique ID for order within market. +
+
+user: address +
+
+ User for market account that placed order. +
+
+custodian_id: u64 +
+
+ Custodian ID for market account that placed order. +
+
+reason: u8 +
+
+ Reason for the cancel, for example + CANCEL_REASON_MANUAL_CANCEL. +
+
+ + + + +## Struct `ChangeOrderSizeEvent` + +Emitted when the size of an open order is manually changed. + + +
struct ChangeOrderSizeEvent has copy, drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID for order. +
+
+order_id: u128 +
+
+ Unique ID for order within market. +
+
+user: address +
+
+ User for market account that placed order. +
+
+custodian_id: u64 +
+
+ Custodian ID for market account that placed order. +
+
+side: bool +
+
+ ASK or BID. +
+
+new_size: u64 +
+
+ Order size after manual size change operation. +
+
+ + ## Resource `Collateral` @@ -560,6 +740,101 @@ All of a user's collateral across all market accounts. + + +## Struct `FillEvent` + +Emitted when one order fills against another. + + +
struct FillEvent has copy, drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID for fill. +
+
+size: u64 +
+
+ Amount filled, in lots. +
+
+price: u64 +
+
+ Fill price, in ticks per lot. +
+
+maker_side: bool +
+
+ ASK or BID, the side of the maker order. +
+
+maker: address +
+
+ User address associated with market account for maker. +
+
+maker_custodian_id: u64 +
+
+ Custodian ID associated with market account for maker. +
+
+maker_order_id: u128 +
+
+ Order ID for maker, unique within the market. +
+
+taker: address +
+
+ User address associated with market account for taker. +
+
+taker_custodian_id: u64 +
+
+ Custodian ID associated with market account for taker. +
+
+taker_order_id: u128 +
+
+ Order ID for taker, unique within the market. +
+
+taker_quote_fees_paid: u64 +
+
+ Amount of fees paid by taker on the fill, in indivisible + quote subunits. +
+
+sequence_number_for_trade: u64 +
+
+ Sequence number (0-indexed) of fill within a single trade, + which may have more than one fill. For example if a market + order results in two fills, the first will have sequence + number 0 and the second will have sequence number 1. +
+
+ + ## Struct `MarketAccount` @@ -797,6 +1072,136 @@ All of a user's market accounts. + + +## Struct `MarketEventHandleCreationNumbers` + +View function return for getting event handle creation numbers +of a particular MarketEventHandlesForMarketAccount. + + +
struct MarketEventHandleCreationNumbers has copy, drop
+
+ + + +##### Fields + + +
+
+cancel_order_events_handle_creation_num: u64 +
+
+ Creation number of cancel_order_events handle in a + MarketEventHandlesForMarketAccount. +
+
+change_order_size_events_handle_creation_num: u64 +
+
+ Creation number of change_order_size_events handle in a + MarketEventHandlesForMarketAccount. +
+
+fill_events_handle_creation_num: u64 +
+
+ Creation number of fill_events handle in a + MarketEventHandlesForMarketAccount. +
+
+place_limit_order_events_handle_creation_num: u64 +
+
+ Creation number of place_limit_order_events handle in a + MarketEventHandlesForMarketAccount. +
+
+place_market_order_events_handle_creation_num: u64 +
+
+ Creation number of place_market_order_events handle in a + MarketEventHandlesForMarketAccount. +
+
+ + + + +## Resource `MarketEventHandles` + +All of a user's MarketEventHandlesForMarketAccount. + + +
struct MarketEventHandles has key
+
+ + + +##### Fields + + +
+
+map: table::Table<u128, user::MarketEventHandlesForMarketAccount> +
+
+ Map from market account ID to + MarketEventHandlesForMarketAccount. +
+
+ + + + +## Struct `MarketEventHandlesForMarketAccount` + +Event handles for market events within a unique market account. + + +
struct MarketEventHandlesForMarketAccount has store
+
+ + + +##### Fields + + +
+
+cancel_order_events: event::EventHandle<user::CancelOrderEvent> +
+
+ Event handle for CancelOrderEvents. +
+
+change_order_size_events: event::EventHandle<user::ChangeOrderSizeEvent> +
+
+ Event handle for ChangeOrderSizeEvents. +
+
+fill_events: event::EventHandle<user::FillEvent> +
+
+ Event handle for FillEvents. +
+
+place_limit_order_events: event::EventHandle<user::PlaceLimitOrderEvent> +
+
+ Event handle for PlaceLimitOrderEvents. +
+
+place_market_order_events: event::EventHandle<user::PlaceMarketOrderEvent> +
+
+ Event handle for PlaceMarketOrderEvents. +
+
+ + ## Struct `Order` @@ -829,68 +1234,328 @@ An open order, either ask or bid. - + + +## Struct `PlaceLimitOrderEvent` + +Emitted when a limit order is placed. + + +
struct PlaceLimitOrderEvent has copy, drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID for order. +
+
+user: address +
+
+ User for market account that placed order. +
+
+custodian_id: u64 +
+
+ Custodian ID for market account that placed order. +
+
+integrator: address +
+
+ Integrator address passed during limit order placement, + eligible for a portion of any generated taker fees. +
+
+side: bool +
+
+ ASK or BID. +
+
+size: u64 +
+
+ Size indicated during limit order placement. +
+
+price: u64 +
+
+ Order limit price. +
+
+restriction: u8 +
+
+ Restriction indicated during limit order placement, either + market::FILL_OR_ABORT, market::IMMEDIATE_OR_CANCEL, + market::POST_OR_ABORT, or market:NO_RESTRICTION. +
+
+self_match_behavior: u8 +
+
+ Self match behavior indicated during limit order placement, + either market::ABORT, market::CANCEL_BOTH, + market::CANCEL_MAKER, or market::CANCEL_TAKER. +
+
+remaining_size: u64 +
+
+ Size posted to order book after optional fills across the + spread. +
+
+order_id: u128 +
+
+ Unique ID for order within market. +
+
+ + + + +## Struct `PlaceMarketOrderEvent` + +Emitted when a market order is placed. + + +
struct PlaceMarketOrderEvent has copy, drop, store
+
+ + + +##### Fields + + +
+
+market_id: u64 +
+
+ Market ID for order. +
+
+user: address +
+
+ User for market account that placed order. +
+
+custodian_id: u64 +
+
+ Custodian ID for market account that placed order. +
+
+integrator: address +
+
+ Integrator address passed during market order placement, + eligible for a portion of any generated taker fees. +
+
+direction: bool +
+
+ Either market::BUY or market::SELL. +
+
+size: u64 +
+
+ Size indicated during market order placement. +
+
+self_match_behavior: u8 +
+
+ Self match behavior indicated during market order placement, + either market::ABORT, market::CANCEL_BOTH, + market::CANCEL_MAKER, or market::CANCEL_TAKER. +
+
+order_id: u128 +
+
+ Unique ID for order within market. +
+
+ + + + +## Constants + + + + +u64 bitmask with all bits set, generated in Python via +hex(int('1' * 64, 2)). + + +
const HI_64: u64 = 18446744073709551615;
+
+ + + + + +Flag for null value when null defined as 0. + + +
const NIL: u64 = 0;
+
+ + + + + +Custodian ID flag for no custodian. + + +
const NO_CUSTODIAN: u64 = 0;
+
+ + + + + +Underwriter ID flag for no underwriter. + + +
const NO_UNDERWRITER: u64 = 0;
+
+ + + + + +Flag for ask side + + +
const ASK: bool = true;
+
+ + + + + +Flag for bid side + + +
const BID: bool = false;
+
+ + + + + +Order cancelled because it was evicted from the price-time +priority queue. + + +
const CANCEL_REASON_EVICTION: u8 = 1;
+
+ + + + + +Order cancelled because it was an immediate-or-cancel order +that did not immediately fill. + + +
const CANCEL_REASON_IMMEDIATE_OR_CANCEL: u8 = 2;
+
+ + -## Constants + +Order cancelled because it was manually cancelled by either +signing user or custodian. - -u64 bitmask with all bits set, generated in Python via -hex(int('1' * 64, 2)). +
const CANCEL_REASON_MANUAL_CANCEL: u8 = 3;
+
-
const HI_64: u64 = 18446744073709551615;
+
+
+
+Order cancelled because no more quote asset could be traded.
+
+
+
const CANCEL_REASON_MAX_QUOTE_TRADED: u8 = 4;
 
- + -Flag for null value when null defined as 0. +Order cancelled because there was not enough liquidity to take +from. -
const NIL: u64 = 0;
+
const CANCEL_REASON_NOT_ENOUGH_LIQUIDITY: u8 = 5;
 
- + -Custodian ID flag for no custodian. +Order cancelled because it was on the maker side of an fill +where self match behavior indicated cancelling the maker order. -
const NO_CUSTODIAN: u64 = 0;
+
const CANCEL_REASON_SELF_MATCH_MAKER: u8 = 6;
 
- + -Underwriter ID flag for no underwriter. +Order cancelled because it was on the taker side of an fill +where self match behavior indicated cancelling the taker order. -
const NO_UNDERWRITER: u64 = 0;
+
const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 7;
 
- + -Flag for ask side +Flag to indicate that order is only temporarily cancelled from +market account memory because it will be subsequently re-placed +as part of a size change. -
const ASK: bool = true;
+
const CANCEL_REASON_SIZE_CHANGE_INTERNAL: u8 = 0;
 
- + -Flag for bid side +Order cancelled because after matching across the spread the +remaining order size was too small for the market. -
const BID: bool = false;
+
const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8;
 
@@ -1174,6 +1839,247 @@ Public constant getter for BID + +## Function `get_CANCEL_REASON_EVICTION` + +Public constant getter for CANCEL_REASON_EVICTION. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_EVICTION(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_EVICTION(): u8 {
+    CANCEL_REASON_EVICTION
+}
+
+ + + + + +## Function `get_CANCEL_REASON_IMMEDIATE_OR_CANCEL` + +Public constant getter for CANCEL_REASON_IMMEDIATE_OR_CANCEL. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_IMMEDIATE_OR_CANCEL(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_IMMEDIATE_OR_CANCEL(): u8 {
+    CANCEL_REASON_IMMEDIATE_OR_CANCEL
+}
+
+ + + + + +## Function `get_CANCEL_REASON_MANUAL_CANCEL` + +Public constant getter for CANCEL_REASON_MANUAL_CANCEL. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_MANUAL_CANCEL(): u8 {
+    CANCEL_REASON_MANUAL_CANCEL
+}
+
+ + + + + +## Function `get_CANCEL_REASON_MAX_QUOTE_TRADED` + +Public constant getter for CANCEL_REASON_MAX_QUOTE_TRADED. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_MAX_QUOTE_TRADED(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_MAX_QUOTE_TRADED(): u8 {
+    CANCEL_REASON_MAX_QUOTE_TRADED
+}
+
+ + + + + +## Function `get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY` + +Public constant getter for CANCEL_REASON_NOT_ENOUGH_LIQUIDITY. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_NOT_ENOUGH_LIQUIDITY(): u8 {
+    CANCEL_REASON_NOT_ENOUGH_LIQUIDITY
+}
+
+ + + + + +## Function `get_CANCEL_REASON_SELF_MATCH_MAKER` + +Public constant getter for CANCEL_REASON_SELF_MATCH_MAKER. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_SELF_MATCH_MAKER(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_SELF_MATCH_MAKER(): u8 {
+    CANCEL_REASON_SELF_MATCH_MAKER
+}
+
+ + + + + +## Function `get_CANCEL_REASON_SELF_MATCH_TAKER` + +Public constant getter for CANCEL_REASON_SELF_MATCH_TAKER. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_SELF_MATCH_TAKER(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_SELF_MATCH_TAKER(): u8 {
+    CANCEL_REASON_SELF_MATCH_TAKER
+}
+
+ + + + + +## Function `get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING` + +Public constant getter for +CANCEL_REASON_TOO_SMALL_AFTER_MATCHING. + + + + +### Testing + + +* test_get_cancel_reasons() + + +
public fun get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING(): u8
+
+ + + +##### Implementation + + +
public fun get_CANCEL_REASON_TOO_SMALL_AFTER_MATCHING(): u8 {
+    CANCEL_REASON_TOO_SMALL_AFTER_MATCHING
+}
+
+ + + ## Function `get_NO_CUSTODIAN` @@ -1181,7 +2087,7 @@ Public constant getter for BIDNO_CUSTODIAN. - + ### Testing @@ -1209,7 +2115,7 @@ Public constant getter for Return all market account IDs associated with market ID. - + ### Parameters @@ -1218,7 +2124,7 @@ Return all market account IDs associated with market ID. * market_id: Market ID to check market accounts for. - + ### Returns @@ -1227,7 +2133,7 @@ Return all market account IDs associated with market ID. market, empty if no market accounts. - + ### Gas considerations @@ -1236,7 +2142,7 @@ Loops over all elements within a vector that is itself a single item in global storage, and returns a vector via pass-by-value. - + ### Testing @@ -1292,7 +2198,7 @@ item in global storage, and returns a vector via pass-by-value. Return all of a user's market account IDs. - + ### Parameters @@ -1300,7 +2206,7 @@ Return all of a user's market account IDs. * user: Address of user to check market account IDs for. - + ### Returns @@ -1309,7 +2215,7 @@ Return all of a user's market account IDs. no market accounts. - + ### Gas considerations @@ -1321,7 +2227,7 @@ read, incurring linearly-scaled vector operation costs. Returns a vector via pass-by-value. - + ### Testing @@ -1384,7 +2290,7 @@ a vector via pass-by-value. Return custodian ID encoded in market account ID. - + ### Testing @@ -1418,7 +2324,7 @@ Return human-readable Mutates state, so kept as a private view function. - + ### Aborts @@ -1426,7 +2332,7 @@ Mutates state, so kept as a private view function. * E_NO_MARKET_ACCOUNT: No such specified market account. - + ### Testing @@ -1486,7 +2392,7 @@ Mutates state, so kept as a private view function. Return market account ID with encoded market and custodian IDs. - + ### Testing @@ -1521,7 +2427,7 @@ Get user-friendly views of all of a user Mutates state, so kept as a private view function. - + ### Testing @@ -1563,6 +2469,74 @@ Mutates state, so kept as a private view function. + + +## Function `get_market_event_handle_creation_numbers` + +Return a MarketEventHandleCreationNumbers for market_id and +custodian_id, if user has event handles for indicated market +account. + +Restricted to private view function to prevent runtime handle +contention. + + + + +### Testing + + +* test_register_market_accounts() + + +
fun get_market_event_handle_creation_numbers(user: address, market_id: u64, custodian_id: u64): option::Option<user::MarketEventHandleCreationNumbers>
+
+ + + +##### Implementation + + +
fun get_market_event_handle_creation_numbers(
+    user: address,
+    market_id: u64,
+    custodian_id: u64
+): Option<MarketEventHandleCreationNumbers>
+acquires MarketEventHandles {
+    // Return none if user does not have market event handles map,
+    if (!exists<MarketEventHandles>(user)) return option::none();
+    // Return none if user has no handles for market account.
+    let market_event_handles_map_ref =
+        &borrow_global<MarketEventHandles>(user).map;
+    let market_account_id = get_market_account_id(market_id, custodian_id);
+    let has_handles = table::contains(
+        market_event_handles_map_ref, market_account_id);
+    if (!has_handles) return option::none();
+    // Return option-packed creation numbers for all event handles.
+    let market_account_handles_ref = table::borrow(
+        market_event_handles_map_ref, market_account_id);
+    option::some(MarketEventHandleCreationNumbers{
+        cancel_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_account_handles_ref.cancel_order_events)),
+        change_order_size_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_account_handles_ref.change_order_size_events)),
+        fill_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_account_handles_ref.fill_events)),
+        place_limit_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_account_handles_ref.place_limit_order_events)),
+        place_market_order_events_handle_creation_num:
+            guid::creation_num(event::guid(
+                &market_account_handles_ref.place_market_order_events))
+    })
+}
+
+ + + ## Function `get_market_id` @@ -1570,7 +2544,7 @@ Mutates state, so kept as a private view function. Return market ID encoded in market account ID. - + ### Testing @@ -1603,7 +2577,7 @@ Return true if user< given market_id and custodian_id. - + ### Testing @@ -1640,7 +2614,7 @@ Return true if user< given market_account_id. - + ### Testing @@ -1680,7 +2654,7 @@ Return true if user< registered with given market_id. - + ### Testing @@ -1719,7 +2693,7 @@ registered with given market_id. Wrapped call to deposit_asset() for depositing coins. - + ### Aborts @@ -1729,7 +2703,7 @@ corresponding to the Econia account having initialized a coin of type GenericAsset. - + ### Testing @@ -1781,7 +2755,7 @@ of type GenericAsset. Wrapped call to deposit_asset() for depositing generic asset. - + ### Testing @@ -1829,7 +2803,7 @@ Restricted to custodian for given market account to prevent excessive public queries and thus transaction collisions. - + ### Testing @@ -1875,7 +2849,7 @@ Restricted to signing user for given market account to prevent excessive public queries and thus transaction collisions. - + ### Testing @@ -1919,7 +2893,7 @@ Restricted to custodian for given market account to prevent excessive public queries and thus transaction collisions. - + ### Testing @@ -1967,7 +2941,7 @@ Restricted to signing user for given market account to prevent excessive public queries and thus transaction collisions. - + ### Testing @@ -2010,7 +2984,7 @@ Wrapped call to withdraw_ authority of delegated custodian. - + ### Testing @@ -2056,7 +3030,7 @@ Wrapped call to withdraw_ authority of signing user. - + ### Testing @@ -2101,7 +3075,7 @@ Wrapped call to w authority of delegated custodian. - + ### Testing @@ -2146,7 +3120,7 @@ Wrapped call to w authority of signing user. - + ### Testing @@ -2190,7 +3164,7 @@ Wrapped call to deposit_co aptos_framework::coin::CoinStore. - + ### Testing @@ -2227,6 +3201,91 @@ Wrapped call to deposit_co + + +## Function `init_market_event_handles_if_missing` + +Initialize market event handles for a market account if missing. + +Since market event handles were implemented as part of a +compatible upgrade policy, it is possible for a user to have a +market account without associated market event handles, if they +registered a market account before an on-chain upgrade. + + + + +### Parameters + + +* user: User for market account. +* market_id: Market ID for market account. +* custodian_id: Custodian ID for market account. + + + + +### Aborts + + +* E_NO_MARKET_ACCOUNT: No such specified market account. + + + + +### Testing + + +* test_init_market_event_handles_if_missing_no_account() +* test_register_market_accounts() + + +
public entry fun init_market_event_handles_if_missing(user: &signer, market_id: u64, custodian_id: u64)
+
+ + + +##### Implementation + + +
public entry fun init_market_event_handles_if_missing(
+    user: &signer,
+    market_id: u64,
+    custodian_id: u64
+) acquires
+    MarketAccounts,
+    MarketEventHandles
+{
+    // Verify user has specified market account.
+    let user_address = address_of(user);
+    assert!(has_market_account(user_address, market_id, custodian_id),
+            E_NO_MARKET_ACCOUNT);
+    // Create market event handles map if user doesn't have one,
+    // and fill with handles for market account as needed.
+    if (!exists<MarketEventHandles>(address_of(user)))
+        move_to(user, MarketEventHandles{map: table::new()});
+    let market_event_handles_map_ref_mut =
+        &mut borrow_global_mut<MarketEventHandles>(user_address).map;
+    let market_account_id =
+        ((market_id as u128) << SHIFT_MARKET_ID) | (custodian_id as u128);
+    let has_handles = table::contains(
+        market_event_handles_map_ref_mut, market_account_id);
+    if (!has_handles) {
+        let handles = MarketEventHandlesForMarketAccount{
+            cancel_order_events: account::new_event_handle(user),
+            change_order_size_events: account::new_event_handle(user),
+            fill_events: account::new_event_handle(user),
+            place_limit_order_events: account::new_event_handle(user),
+            place_market_order_events: account::new_event_handle(user)
+        };
+        table::add(
+            market_event_handles_map_ref_mut, market_account_id, handles);
+    };
+}
+
+ + + ## Function `register_market_account` @@ -2237,7 +3296,7 @@ Verifies market ID and asset types via internal call to register_market_account_account_entries(). - + ### Type parameters @@ -2248,7 +3307,7 @@ a generic asset, must be passed as + ### Parameters @@ -2259,7 +3318,7 @@ a generic asset, must be passed as NO_CUSTODIAN. - + ### Aborts @@ -2268,7 +3327,7 @@ a generic asset, must be passed as + ### Testing @@ -2294,7 +3353,8 @@ registered. custodian_id: u64 ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { // If custodian ID indicated, assert it is registered. if (custodian_id != NO_CUSTODIAN) assert!( @@ -2315,6 +3375,7 @@ registered. // (quote type for a verified market must be a coin). register_market_account_collateral_entry<QuoteType>( user, market_account_id); + init_market_event_handles_if_missing(user, market_id, custodian_id); }
@@ -2327,7 +3388,7 @@ registered. Wrapped register_market_account() call for generic base asset. - + ### Testing @@ -2351,7 +3412,8 @@ Wrapped register custodian_id: u64 ) acquires Collateral, - MarketAccounts + MarketAccounts, + MarketEventHandles { register_market_account<GenericAsset, QuoteType>( user, market_id, custodian_id); @@ -2368,7 +3430,7 @@ Wrapped call to with market account to user's aptos_framework::coin::CoinStore. - + ### Testing @@ -2428,7 +3490,7 @@ malicious market order ID (portions of which essentially function as pointers into AVL queue state). - + ### Parameters @@ -2443,9 +3505,15 @@ function as pointers into AVL queue state). * market_order_id: NIL if order cancellation originates from an eviction or a self match cancel, otherwise the market order ID encoded in the user's Order. +* cancel_reason: The reason for the cancel. Note that +user-side open order size changes are processed via +change_order_size_internal() as a cancellation followed by +immediate re-placement, corresponding to the cancel reason +CANCEL_REASON_SIZE_CHANGE_INTERNAL. When this is the case +no cancel event is emitted. - + ### Returns @@ -2453,7 +3521,7 @@ ID encoded in the user's Order * u128: Market order ID for corresponding order. - + ### Terminology @@ -2464,7 +3532,7 @@ from a trade if the cancelled order had been filled. away if the cancelled order had been filled. - + ### Aborts @@ -2475,7 +3543,15 @@ operation and actual size before operation. user's open order, when market order ID not passed as NIL. - + + +### Emits + + +* CancelOrderEvent: Information about a cancelled order. + + + ### Assumptions @@ -2496,7 +3572,7 @@ or a self match cancel. order if market order ID is not NIL. - + ### Expected value testing @@ -2506,7 +3582,7 @@ order if market order ID is not NIL< * test_place_cancel_order_stack() - + ### Failure testing @@ -2515,7 +3591,7 @@ order if market order ID is not NIL< * test_cancel_order_internal_start_size_mismatch() -
public(friend) fun cancel_order_internal(user_address: address, market_id: u64, custodian_id: u64, side: bool, start_size: u64, price: u64, order_access_key: u64, market_order_id: u128): u128
+
public(friend) fun cancel_order_internal(user_address: address, market_id: u64, custodian_id: u64, side: bool, start_size: u64, price: u64, order_access_key: u64, market_order_id: u128, reason: u8): u128
 
@@ -2531,9 +3607,13 @@ order if market order ID is not NIL< start_size: u64, price: u64, order_access_key: u64, - market_order_id: u128 + market_order_id: u128, + reason: u8 ): u128 -acquires MarketAccounts { +acquires + MarketAccounts, + MarketEventHandles +{ // Mutably borrow market accounts map. let market_accounts_map_ref_mut = &mut borrow_global_mut<MarketAccounts>(user_address).map; @@ -2587,6 +3667,24 @@ order if market order ID is not NIL< let ceiling_decrement_amount = size * size_multiplier_ceiling; *in_ceiling_ref_mut = // Decrement ceiling field. *in_ceiling_ref_mut - ceiling_decrement_amount; + // If order is actually being cancelled and user has market + // event handles for the market account, emit a cancel event. + let changing_size = reason != CANCEL_REASON_SIZE_CHANGE_INTERNAL; + if (!changing_size && exists<MarketEventHandles>(user_address)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut<MarketEventHandles>(user_address).map; + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + event::emit_event( + &mut handles_ref_mut.cancel_order_events, + CancelOrderEvent{ + market_id, order_id: market_order_id, + user: user_address, custodian_id, reason}); + } + }; market_order_id // Return market order ID. }
@@ -2600,7 +3698,7 @@ order if market order ID is not NIL< Change the size of a user's open order on given side. - + ### Parameters @@ -2617,7 +3715,7 @@ to place_order_inte * market_order_id: Market order ID for order book lookup. - + ### Aborts @@ -2625,7 +3723,16 @@ to place_order_inte * E_CHANGE_ORDER_NO_CHANGE: No change in order size. - + + +### Emits + + +* ChangeOrderSizeEvent: Information about an order that had a +manual size change. + + + ### Assumptions @@ -2638,7 +3745,7 @@ order ID, which is checked in + ### Testing @@ -2666,7 +3773,10 @@ order. price: u64, order_access_key: u64, market_order_id: u128 -) acquires MarketAccounts { +) acquires + MarketAccounts, + MarketEventHandles +{ // Mutably borrow market accounts map. let market_accounts_map_ref_mut = &mut borrow_global_mut<MarketAccounts>(user_address).map; @@ -2683,10 +3793,110 @@ order. assert!(order_ref.size != new_size, E_CHANGE_ORDER_NO_CHANGE); cancel_order_internal( // Cancel order with size to be changed. user_address, market_id, custodian_id, side, start_size, price, - order_access_key, market_order_id); + order_access_key, market_order_id, + CANCEL_REASON_SIZE_CHANGE_INTERNAL); place_order_internal( // Place order with new size. user_address, market_id, custodian_id, side, new_size, price, market_order_id, order_access_key); + // If user has market event handles for the market account, emit + // a change order size event. + if (exists<MarketEventHandles>(user_address)) { + let market_event_handles_map_ref_mut = + &mut borrow_global_mut<MarketEventHandles>(user_address).map; + let has_handles_for_market_account = table::contains( + market_event_handles_map_ref_mut, market_account_id); + if (has_handles_for_market_account) { + let handles_ref_mut = table::borrow_mut( + market_event_handles_map_ref_mut, market_account_id); + event::emit_event( + &mut handles_ref_mut.change_order_size_events, + ChangeOrderSizeEvent{ + market_id, order_id: market_order_id, + user: user_address, custodian_id, side, new_size}); + } + } +} +
+ + + + + +## Function `create_cancel_order_event_internal` + +Return a CancelOrderEvent with the indicated fields. + + +
public(friend) fun create_cancel_order_event_internal(market_id: u64, order_id: u128, user: address, custodian_id: u64, reason: u8): user::CancelOrderEvent
+
+ + + +##### Implementation + + +
public(friend) fun create_cancel_order_event_internal(
+    market_id: u64,
+    order_id: u128,
+    user: address,
+    custodian_id: u64,
+    reason: u8
+): CancelOrderEvent {
+    CancelOrderEvent{
+        market_id,
+        order_id,
+        user,
+        custodian_id,
+        reason
+    }
+}
+
+ + + + + +## Function `create_fill_event_internal` + +Return a FillEvent with the indicated fields. + + +
public(friend) fun create_fill_event_internal(market_id: u64, size: u64, price: u64, maker_side: bool, maker: address, maker_custodian_id: u64, maker_order_id: u128, taker: address, taker_custodian_id: u64, taker_order_id: u128, taker_quote_fees_paid: u64, sequence_number_for_trade: u64): user::FillEvent
+
+ + + +##### Implementation + + +
public(friend) fun create_fill_event_internal(
+    market_id: u64,
+    size: u64,
+    price: u64,
+    maker_side: bool,
+    maker: address,
+    maker_custodian_id: u64,
+    maker_order_id: u128,
+    taker: address,
+    taker_custodian_id: u64,
+    taker_order_id: u128,
+    taker_quote_fees_paid: u64,
+    sequence_number_for_trade: u64
+): FillEvent {
+    FillEvent{
+        market_id,
+        size,
+        price,
+        maker_side,
+        maker,
+        maker_custodian_id,
+        maker_order_id,
+        taker,
+        taker_custodian_id,
+        taker_order_id,
+        taker_quote_fees_paid,
+        sequence_number_for_trade
+    }
 }
 
@@ -2702,7 +3912,7 @@ Should only be called by the matching engine when matching from a user's market account. - + ### Type parameters @@ -2711,7 +3921,7 @@ a user's market account. * QuoteType: Quote type for market. - + ### Parameters @@ -2725,7 +3935,7 @@ a user's market account. * underwriter_id: Underwriter ID for market. - + ### Testing @@ -2766,6 +3976,253 @@ a user's market account. + + +## Function `emit_limit_order_events_internal` + +Emit limit order events to a user's market event handles. + + + + +### Parameters + + +* market_id: PlaceLimitOrderEvent.market_id. +* user: PlaceLimitOrderEvent.user. +* custodian_id: PlaceLimitOrderEvent.custodian_id. +* integrator: PlaceLimitOrderEvent.integrator. +* side: PlaceLimitOrderEvent.side. +* size: PlaceLimitOrderEvent.size. +* price: PlaceLimitOrderEvent.price. +* restriction: PlaceLimitOrderEvent.restriction. +* self_match_behavior: +PlaceLimitOrderEvent.self_match_behavior. +* remaining_size: PlaceLimitOrderEvent.remaining_size. +* order_id: PlaceLimitOrderEvent.order_id. +* fill_event_queue_ref: Immutable reference to a vector of +FillEvents to emit as part of a limit order that filled +across the spread, may be empty. +* cancel_reason_option_ref: Immutable reference to an optional +cancel reason associated with a CancelEvent. + + + + +### Emits + + +* PlaceLimitOrderEvent: Information about the limit order that +was placed. +* FillEvent(s): Information about fill(s) across the spread as +a taker. +* CancelOrderEvent: Optionally, information about why the +limit order may have had to be cancelled during the +transaction in which it was placed. + + +
public(friend) fun emit_limit_order_events_internal(market_id: u64, user: address, custodian_id: u64, integrator: address, side: bool, size: u64, price: u64, restriction: u8, self_match_behavior: u8, remaining_size: u64, order_id: u128, fill_event_queue_ref: &vector<user::FillEvent>, cancel_reason_option_ref: &option::Option<u8>)
+
+ + + +##### Implementation + + +
public(friend) fun emit_limit_order_events_internal(
+    market_id: u64,
+    user: address,
+    custodian_id: u64,
+    integrator: address,
+    side: bool,
+    size: u64,
+    price: u64,
+    restriction: u8,
+    self_match_behavior: u8,
+    remaining_size: u64,
+    order_id: u128,
+    fill_event_queue_ref: &vector<FillEvent>,
+    cancel_reason_option_ref: &Option<u8>
+) acquires MarketEventHandles {
+    // Only emit events to handles for the market account that
+    // placed the order if they have been initialized.
+    if (exists<MarketEventHandles>(user)) {
+        let market_event_handles_map_ref_mut =
+            &mut borrow_global_mut<MarketEventHandles>(user).map;
+        let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) |
+                                 (custodian_id as u128));
+        let has_handles_for_market_account = table::contains(
+            market_event_handles_map_ref_mut, market_account_id);
+        if (has_handles_for_market_account) {
+            let handles_ref_mut = table::borrow_mut(
+                market_event_handles_map_ref_mut, market_account_id);
+            event::emit_event(
+                &mut handles_ref_mut.place_limit_order_events,
+                PlaceLimitOrderEvent{
+                    market_id, user, custodian_id, integrator, side, size,
+                    price, restriction, self_match_behavior,
+                    remaining_size, order_id});
+            // Loop over fill events, substituting order ID in case
+            // order posted after fill event creation. Looping here
+            // minimizes borrows from the user's account, but will
+            // require looping again later to emit maker fill events
+            // because the borrow checker prohibits simultaneous
+            // borrowing of the same resource from two addresses.
+            vector::for_each_ref(fill_event_queue_ref, |event_ref| {
+                let event: FillEvent = *event_ref;
+                event.taker_order_id = order_id;
+                event::emit_event(&mut handles_ref_mut.fill_events, event);
+            });
+            if (option::is_some(cancel_reason_option_ref)) {
+                let event = CancelOrderEvent{
+                    market_id, order_id, user, custodian_id,
+                    reason: *option::borrow(cancel_reason_option_ref)};
+                event::emit_event(
+                    &mut handles_ref_mut.cancel_order_events, event);
+            };
+        };
+    };
+    // Emit fill events for all makers, similarly substituting
+    // order ID in case order posted after fill event creation.
+    vector::for_each_ref(fill_event_queue_ref, |event_ref| {
+        let event: FillEvent = *event_ref;
+        event.taker_order_id = order_id;
+        emit_maker_fill_event(&event);
+    });
+}
+
+ + + + + +## Function `emit_market_order_events_internal` + +Emit market order events to a user's market event handles. + + + + +### Parameters + + +* market_id: PlaceMarketOrderEvent.market_id. +* user: PlaceMarketOrderEvent.user. +* custodian_id: PlaceMarketOrderEvent.custodian_id. +* integrator: PlaceMarketOrderEvent.integrator. +* direction: PlaceMarketOrderEvent.direction. +* size: PlaceMarketOrderEvent.size. +* self_match_behavior: +PlaceMarketOrderEvent.self_match_behavior. +* order_id: PlaceMarketOrderEvent.order_id. +* fill_event_queue_ref: Immutable reference to a vector of +FillEvents to emit, may be empty. +* cancel_reason_option_ref: Immutable reference to an optional +cancel reason associated with a CancelEvent. + + + + +### Emits + + +* PlaceMarketOrderEvent: Information about the market order +that was placed. +* FillEvent(s): Information about fill(s). +* CancelOrderEvent: Optionally, information about why the +market order was cancelled without completely filling. + + +
public(friend) fun emit_market_order_events_internal(market_id: u64, user: address, custodian_id: u64, integrator: address, direction: bool, size: u64, self_match_behavior: u8, order_id: u128, fill_event_queue_ref: &vector<user::FillEvent>, cancel_reason_option_ref: &option::Option<u8>)
+
+ + + +##### Implementation + + +
public(friend) fun emit_market_order_events_internal(
+    market_id: u64,
+    user: address,
+    custodian_id: u64,
+    integrator: address,
+    direction: bool,
+    size: u64,
+    self_match_behavior: u8,
+    order_id: u128,
+    fill_event_queue_ref: &vector<FillEvent>,
+    cancel_reason_option_ref: &Option<u8>
+) acquires MarketEventHandles {
+    // Only emit events to handles for the market account that
+    // placed the order if they have been initialized.
+    if (exists<MarketEventHandles>(user)) {
+        let market_event_handles_map_ref_mut =
+            &mut borrow_global_mut<MarketEventHandles>(user).map;
+        let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) |
+                                 (custodian_id as u128));
+        let has_handles_for_market_account = table::contains(
+            market_event_handles_map_ref_mut, market_account_id);
+        if (has_handles_for_market_account) {
+            let handles_ref_mut = table::borrow_mut(
+                market_event_handles_map_ref_mut, market_account_id);
+            event::emit_event(
+                &mut handles_ref_mut.place_market_order_events,
+                PlaceMarketOrderEvent{
+                    market_id, user, custodian_id, integrator, direction,
+                    size, self_match_behavior, order_id});
+            // Loop over fill events. Looping here minimizes borrows
+            // from the user's account, but will require looping
+            // again later to emit maker fill events because the
+            // borrow checker prohibits simultaneous borrowing of
+            // the same resource from two addresses.
+            vector::for_each_ref(fill_event_queue_ref, |event_ref| {
+                event::emit_event(
+                    &mut handles_ref_mut.fill_events, *event_ref);
+            });
+            if (option::is_some(cancel_reason_option_ref)) {
+                let event = CancelOrderEvent{
+                    market_id, order_id, user, custodian_id,
+                    reason: *option::borrow(cancel_reason_option_ref)};
+                event::emit_event(
+                    &mut handles_ref_mut.cancel_order_events, event);
+            };
+        };
+    };
+    // Emit fill events for all makers.
+    vector::for_each_ref(fill_event_queue_ref, |event_ref| {
+        emit_maker_fill_event(event_ref);
+    });
+}
+
+ + + + + +## Function `emit_swap_maker_fill_events_internal` + +Emit a FillEvent for each maker associated with a swap. + + +
public(friend) fun emit_swap_maker_fill_events_internal(fill_event_queue_ref: &vector<user::FillEvent>)
+
+ + + +##### Implementation + + +
public(friend) fun emit_swap_maker_fill_events_internal(
+    fill_event_queue_ref: &vector<FillEvent>
+) acquires MarketEventHandles {
+    vector::for_each_ref(fill_event_queue_ref, |event_ref| {
+        emit_maker_fill_event(event_ref);
+    });
+}
+
+ + + ## Function `fill_order_internal` @@ -2785,7 +4242,7 @@ order as indicated with sufficient assets to fill it. Hence no error checking. - + ### Type parameters @@ -2794,7 +4251,7 @@ error checking. * QuoteType: Quote type for indicated market. - + ### Parameters @@ -2815,7 +4272,7 @@ matching engine. * quote_to_route: Amount of quote asset filled. - + ### Returns @@ -2827,7 +4284,7 @@ matching engine. * u128: Market order ID just filled against. - + ### Aborts @@ -2836,7 +4293,7 @@ matching engine. operation and actual size before operation. - + ### Assumptions @@ -2844,7 +4301,7 @@ operation and actual size before operation. * Only called by the matching engine as described above. - + ### Testing @@ -2992,7 +4449,7 @@ operation and actual size before operation. Return asset counts for specified market account. - + ### Parameters @@ -3002,7 +4459,7 @@ Return asset counts for specified market account. * custodian_id: Custodian ID for market account. - + ### Returns @@ -3015,7 +4472,7 @@ Return asset counts for specified market account. * MarketAccount.quote_ceiling - + ### Aborts @@ -3024,7 +4481,7 @@ Return asset counts for specified market account. * E_NO_MARKET_ACCOUNT: No market account resource found. - + ### Testing @@ -3084,7 +4541,7 @@ Return asset counts for specified market account. Return all active market order IDs for given market account. - + ### Parameters @@ -3095,7 +4552,7 @@ Return all active market order IDs for given market account. * side: ASK or BID, the side on which to check. - + ### Returns @@ -3104,7 +4561,7 @@ Return all active market order IDs for given market account. given market account and side, empty if none. - + ### Aborts @@ -3113,7 +4570,7 @@ given market account and side, empty if none. * E_NO_MARKET_ACCOUNT: No market account resource found. - + ### Testing @@ -3182,7 +4639,7 @@ order access key to be allocated. Otherwise is order access key at top of inactive order stack. - + ### Parameters @@ -3194,7 +4651,7 @@ at top of inactive order stack. placed. - + ### Returns @@ -3202,7 +4659,7 @@ placed. * u64: Order access key of next order to be placed. - + ### Aborts @@ -3211,7 +4668,7 @@ placed. * E_NO_MARKET_ACCOUNT: No market account resource found. - + ### Testing @@ -3275,7 +4732,7 @@ Restricted to public friend to prevent runtime user state contention. - + ### Testing @@ -3345,7 +4802,7 @@ required. Once an order book entry has been created, a market order ID will then be made available. - + ### Parameters @@ -3361,7 +4818,7 @@ order ID will then be made available. assigned to order. - + ### Terminology @@ -3370,7 +4827,7 @@ assigned to order. * The "outbound" asset is the asset traded away. - + ### Assumptions @@ -3381,7 +4838,7 @@ assigned to order. verified by get_next_order_access_key_internal(). - + ### Aborts @@ -3397,7 +4854,7 @@ received from trade. match assigned order access key. - + ### Expected value testing @@ -3407,7 +4864,7 @@ match assigned order access key. * test_place_cancel_order_stack() - + ### Failure testing @@ -3524,7 +4981,7 @@ Should only be called by the matching engine when matching from a user's market account. - + ### Type parameters @@ -3533,7 +4990,7 @@ a user's market account. * QuoteType: Quote type for market. - + ### Parameters @@ -3546,7 +5003,7 @@ a user's market account. * underwriter_id: Underwriter ID for market. - + ### Returns @@ -3556,7 +5013,7 @@ market account. * <Coin<QuoteType>: Quote coins from user's market account. - + ### Testing @@ -3609,7 +5066,7 @@ Deposit an asset to a user's market account. Update asset counts, deposit optional coins as collateral. - + ### Type parameters @@ -3618,7 +5075,7 @@ Update asset counts, deposit optional coins as collateral. if a generic asset. - + ### Parameters @@ -3632,7 +5089,7 @@ if a generic asset. depositing coins. - + ### Aborts @@ -3647,7 +5104,7 @@ asset ceiling. indicated market, in the case of a generic asset deposit. - + ### Assumptions @@ -3656,7 +5113,7 @@ indicated market, in the case of a generic asset deposit. does a corresponding collateral map entry. - + ### Testing @@ -3749,6 +5206,48 @@ does a corresponding collateral map entry. + + +## Function `emit_maker_fill_event` + +Emit a FillEvent for the market account of the maker +associated with a fill, if market event handles exist for the +indicated market account. + + +
fun emit_maker_fill_event(event_ref: &user::FillEvent)
+
+ + + +##### Implementation + + +
inline fun emit_maker_fill_event(
+    event_ref: &FillEvent
+) acquires MarketEventHandles {
+    let maker = event_ref.maker;
+    if (exists<MarketEventHandles>(maker)) {
+        let market_event_handles_map_ref_mut =
+            &mut borrow_global_mut<MarketEventHandles>(maker).map;
+        let market_id = event_ref.market_id;
+        let custodian_id = event_ref.maker_custodian_id;
+        let market_account_id = (((market_id as u128) << SHIFT_MARKET_ID) |
+                                 (custodian_id as u128));
+        let has_handles_for_market_account = table::contains(
+            market_event_handles_map_ref_mut, market_account_id);
+        if (has_handles_for_market_account) {
+            let handles_ref_mut = table::borrow_mut(
+                market_event_handles_map_ref_mut, market_account_id);
+            event::emit_event(
+                &mut handles_ref_mut.fill_events, *event_ref);
+        };
+    };
+}
+
+ + + ## Function `get_market_account_market_info` @@ -3756,7 +5255,7 @@ does a corresponding collateral map entry. Return registry::MarketInfo fields stored in market account. - + ### Parameters @@ -3766,7 +5265,7 @@ Return registry::Mark * custodian_id: Custodian ID for market account. - + ### Returns @@ -3780,7 +5279,7 @@ Return registry::Mark * MarketAccount.underwriter_id - + ### Aborts @@ -3789,7 +5288,7 @@ Return registry::Mark * E_NO_MARKET_ACCOUNT: No market account resource found. - + ### Testing @@ -3858,7 +5357,7 @@ registered market, via call to registry::get_market_info_for_market_account(). - + ### Type parameters @@ -3867,7 +5366,7 @@ registered market, via call to * QuoteType: Quote type for indicated market. - + ### Parameters @@ -3879,7 +5378,7 @@ registered market, via call to NO_CUSTODIAN. - + ### Aborts @@ -3887,7 +5386,7 @@ registered market, via call to * E_EXISTS_MARKET_ACCOUNT: Market account already exists. - + ### Testing @@ -3971,7 +5470,7 @@ performed by register_market_account_accounts_entries() in register_market_account(). - + ### Type parameters @@ -3979,7 +5478,7 @@ performed by register_market_account_accounts_entries() in * CoinType: Phantom coin type for indicated market. - + ### Parameters @@ -3988,7 +5487,7 @@ performed by register_market_account_accounts_entries() in * market_account_id: Market account ID for given market. - + ### Testing @@ -4033,7 +5532,7 @@ performed by register_market_account_accounts_entries() in Convert a tablist of Order into a vector of only open orders. - + ### Testing @@ -4086,7 +5585,7 @@ Withdraw an asset from a user's market account. Update asset counts, withdraw optional collateral coins. - + ### Type parameters @@ -4095,7 +5594,7 @@ Update asset counts, withdraw optional collateral coins. if a generic asset. - + ### Parameters @@ -4108,7 +5607,7 @@ if a generic asset. withdrawing coins. - + ### Returns @@ -4116,7 +5615,7 @@ withdrawing coins. * Option<Coin<AssetType>>: Optional collateral coins. - + ### Aborts @@ -4131,7 +5630,7 @@ withdrawal. indicated market, in the case of a generic asset withdrawal. - + ### Testing @@ -4226,7 +5725,7 @@ indicated market, in the case of a generic asset withdrawal. Wrapped call to withdraw_asset() for withdrawing coins. - + ### Testing @@ -4273,7 +5772,7 @@ Wrapped call to withdraw_ asset. - + ### Testing diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 9b90e27a3..5df456f83 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -590,7 +590,7 @@ module econia::market { // Structs >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> /// View function return for getting event handle creation info of a - /// particular `MarkeEventHandlesForMarket`. + /// particular `MarketEventHandlesForMarket`. struct MarketEventHandleCreationInfo has copy, drop { /// Econia resource account address, corresponding to event /// handle creator address. @@ -714,13 +714,13 @@ module econia::market { integrator: address, /// Either `BUY` or `SELL`. direction: bool, - /// Inidicated minimum base subunits to trade. + /// Indicated minimum base subunits to trade. min_base: u64, - /// Inidicated maximum base subunits to trade. + /// Indicated maximum base subunits to trade. max_base: u64, - /// Inidicated minimum quote subunits to trade. + /// Indicated minimum quote subunits to trade. min_quote: u64, - /// Inidicated maximum quote subunits to trade. + /// Indicated maximum quote subunits to trade. max_quote: u64, /// Indicated limit price. limit_price: u64, @@ -891,7 +891,7 @@ module econia::market { /// where self match behavior indicated cancelling the taker order. const CANCEL_REASON_SELF_MATCH_TAKER: u8 = 7; /// Order cancelled because after matching across the spread the - /// remaining order size was too smal for the market. + /// remaining order size was too small for the market. const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8; /// Flag to cancel taker order only during a self match. const CANCEL_TAKER: u8 = 3; @@ -3460,7 +3460,7 @@ module econia::market { } else { // If spread not crossed (matching engine not called): // Order book counter needs to be updated for new order ID. order_book_ref_mut.counter = order_book_ref_mut.counter + 1; - // Order neeeds to be cancelled if no fills took place. + // Order needs to be cancelled if no fills took place. if (restriction == IMMEDIATE_OR_CANCEL) { option::fill(&mut cancel_reason_option, CANCEL_REASON_IMMEDIATE_OR_CANCEL); diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index b1b4ed92c..90c4a0958 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -679,7 +679,7 @@ module econia::user { /// as part of a size change. const CANCEL_REASON_SIZE_CHANGE_INTERNAL: u8 = 0; /// Order cancelled because after matching across the spread the - /// remaining order size was too smal for the market. + /// remaining order size was too small for the market. const CANCEL_REASON_TOO_SMALL_AFTER_MATCHING: u8 = 8; /// `u64` bitmask with all bits set, generated in Python via /// `hex(int('1' * 64, 2))`. From 4237cb79667ba7b6686db36aadf2a95ea2418b8d Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 16:27:12 -0700 Subject: [PATCH 55/56] Fix doc linking, dep chart --- src/move/econia/sources/market.move | 27 ++++++++++++++------------- src/move/econia/sources/user.move | 12 +++++++++--- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/move/econia/sources/market.move b/src/move/econia/sources/market.move index 5df456f83..9ab00c9ee 100644 --- a/src/move/econia/sources/market.move +++ b/src/move/econia/sources/market.move @@ -616,7 +616,7 @@ module econia::market { struct MarketEventHandlesForMarket has store { /// Event handle for `user::CancelOrderEvent`s. cancel_order_events: EventHandle, - /// Event handle for `user::PlaceSwapOrderEvent`s. + /// Event handle for `PlaceSwapOrderEvent`s. place_swap_order_events: EventHandle } @@ -778,7 +778,7 @@ module econia::market { cancel_order_events: EventHandle, /// Event handle for `user::FillEvent`s. fill_events: EventHandle, - /// Event handle for `user::PlaceSwapOrderEvent`s. + /// Event handle for `PlaceSwapOrderEvent`s. place_swap_order_events: EventHandle } @@ -1892,10 +1892,10 @@ module econia::market { /// # Emits /// /// * `PlaceSwapOrderEvent`: Information about the swap order. - /// * `FillEvent`(s): Information about fill(s) associated with the - /// swap. - /// * `CancelOrderEvent`: Optionally, information about why the swap - /// was cancelled without completely filling. + /// * `user::FillEvent`(s): Information about fill(s) associated + /// with the swap. + /// * `user::CancelOrderEvent`: Optionally, information about why + /// the swap was cancelled without completely filling. /// /// # Testing /// @@ -2870,7 +2870,7 @@ module econia::market { /// /// * `market_id`: Market ID of market. /// * `fill_event_queue_ref_mut`: Mutable reference to vector for - /// enqueueing deferred `FillEvent`(s). + /// enqueueing deferred `user::FillEvent`(s). /// * `order_book_ref_mut`: Mutable reference to market order book. /// * `taker`: Address of taker whose order is matched. Passed as /// `NO_TAKER_ADDRESS` when taker order originates from a swap @@ -4046,7 +4046,7 @@ module econia::market { /// # Parameters /// /// * `fill_event_queue_ref_mut`: Mutable reference to vector for - /// enqueueing deferred `FillEvent`(s). + /// enqueueing deferred `user::FillEvent`(s). /// * `signer_address`: Address of signing user if applicable, else /// `NO_TAKER_ADDRESS`. /// * `market_id`: Same as for `match()`. @@ -4074,16 +4074,17 @@ module econia::market { /// * `u64`: Quote coin fees paid, same as for `match()`. /// * `Option`: `PlaceSwapOrderEvent` to emit /// if swap is from a signing swapper. - /// * `Option`: Optional `CancelOrderEvent` to - /// emit if swap is from a signing swapper. + /// * `Option`: Optional + /// `user::CancelOrderEvent` to emit if swap is from a signing + /// swapper. /// /// # Emits /// /// * `PlaceSwapOrderEvent`: Information about swap order, emitted /// when swap is from a non-signing swapper. - /// * `CancelOrderEvent`: Information about order cancellation, if - /// order was cancelled without completely filling, when swap is - /// from non-signing swapper. + /// * `user::CancelOrderEvent`: Information about order + /// cancellation, if order was cancelled without completely + /// filling, when swap is from non-signing swapper. /// /// # Aborts /// diff --git a/src/move/econia/sources/user.move b/src/move/econia/sources/user.move index 90c4a0958..e1a10ce09 100644 --- a/src/move/econia/sources/user.move +++ b/src/move/econia/sources/user.move @@ -300,10 +300,16 @@ /// /// Market events: /// +/// ```mermaid +/// +/// flowchart LR +/// /// emit_limit_order_events_internal --> emit_maker_fill_event /// emit_market_order_events_internal --> emit_maker_fill_event /// emit_swap_maker_fill_events_internal --> emit_maker_fill_event /// +/// ``` +/// /// # Complete DocGen index /// /// The below index is automatically generated from source code: @@ -563,7 +569,7 @@ module econia::user { price: u64, /// Restriction indicated during limit order placement, either /// `market::FILL_OR_ABORT`, `market::IMMEDIATE_OR_CANCEL`, - /// `market::POST_OR_ABORT`, or `market:NO_RESTRICTION`. + /// `market::POST_OR_ABORT`, or `market::NO_RESTRICTION`. restriction: u8, /// Self match behavior indicated during limit order placement, /// either `market::ABORT`, `market::CANCEL_BOTH`, @@ -1969,7 +1975,7 @@ module econia::user { /// `FillEvent`s to emit as part of a limit order that filled /// across the spread, may be empty. /// * `cancel_reason_option_ref`: Immutable reference to an optional - /// cancel reason associated with a `CancelEvent`. + /// cancel reason associated with a `CancelOrderEvent`. /// /// # Emits /// @@ -2058,7 +2064,7 @@ module econia::user { /// * `fill_event_queue_ref`: Immutable reference to a vector of /// `FillEvent`s to emit, may be empty. /// * `cancel_reason_option_ref`: Immutable reference to an optional - /// cancel reason associated with a `CancelEvent`. + /// cancel reason associated with a `CancelOrderEvent`. /// /// # Emits /// From d24160200094d9da7f8db9a293023cfa4658af54 Mon Sep 17 00:00:00 2001 From: alnoki <43892045+alnoki@users.noreply.github.com> Date: Tue, 18 Jul 2023 16:29:51 -0700 Subject: [PATCH 56/56] Re-build docs for typo fixes --- src/move/econia/doc/market.md | 27 ++++++++++++++------------- src/move/econia/doc/user.md | 12 +++++++++--- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/move/econia/doc/market.md b/src/move/econia/doc/market.md index 30407c0ee..f3ef93aa5 100644 --- a/src/move/econia/doc/market.md +++ b/src/move/econia/doc/market.md @@ -1025,7 +1025,7 @@ by a non-signing swapper. place_swap_order_events: event::EventHandle<market::PlaceSwapOrderEvent>
- Event handle for user::PlaceSwapOrderEvents. + Event handle for PlaceSwapOrderEvents.
@@ -1548,7 +1548,7 @@ of an Econia-style market account. place_swap_order_events: event::EventHandle<market::PlaceSwapOrderEvent>
- Event handle for user::PlaceSwapOrderEvents. + Event handle for PlaceSwapOrderEvents.
@@ -4240,10 +4240,10 @@ for coin store. * PlaceSwapOrderEvent: Information about the swap order. -* FillEvent(s): Information about fill(s) associated with the -swap. -* CancelOrderEvent: Optionally, information about why the swap -was cancelled without completely filling. +* user::FillEvent(s): Information about fill(s) associated +with the swap. +* user::CancelOrderEvent: Optionally, information about why +the swap was cancelled without completely filling. @@ -5673,7 +5673,7 @@ then proceeds according to specified self match behavior. * market_id: Market ID of market. * fill_event_queue_ref_mut: Mutable reference to vector for -enqueueing deferred FillEvent(s). +enqueueing deferred user::FillEvent(s). * order_book_ref_mut: Mutable reference to market order book. * taker: Address of taker whose order is matched. Passed as NO_TAKER_ADDRESS when taker order originates from a swap @@ -7095,7 +7095,7 @@ Match a taker's swap order against order book for given market. * fill_event_queue_ref_mut: Mutable reference to vector for -enqueueing deferred FillEvent(s). +enqueueing deferred user::FillEvent(s). * signer_address: Address of signing user if applicable, else NO_TAKER_ADDRESS. * market_id: Same as for match(). @@ -7127,8 +7127,9 @@ same as for match() * u64: Quote coin fees paid, same as for match(). * Option<PlaceSwapOrderEvent>: PlaceSwapOrderEvent to emit if swap is from a signing swapper. -* Option<CancelOrderEvent>: Optional CancelOrderEvent to -emit if swap is from a signing swapper. +* Option<user::CancelOrderEvent>: Optional +user::CancelOrderEvent to emit if swap is from a signing +swapper. @@ -7138,9 +7139,9 @@ emit if swap is from a signing swapper. * PlaceSwapOrderEvent: Information about swap order, emitted when swap is from a non-signing swapper. -* CancelOrderEvent: Information about order cancellation, if -order was cancelled without completely filling, when swap is -from non-signing swapper. +* user::CancelOrderEvent: Information about order +cancellation, if order was cancelled without completely +filling, when swap is from non-signing swapper. diff --git a/src/move/econia/doc/user.md b/src/move/econia/doc/user.md index a7cb8f9cf..3b09cd6a9 100644 --- a/src/move/econia/doc/user.md +++ b/src/move/econia/doc/user.md @@ -353,10 +353,16 @@ change_order_size_internal --> place_order_internal Market events: +```mermaid + +flowchart LR + emit_limit_order_events_internal --> emit_maker_fill_event emit_market_order_events_internal --> emit_maker_fill_event emit_swap_maker_fill_events_internal --> emit_maker_fill_event +``` + @@ -1299,7 +1305,7 @@ Emitted when a limit order is placed.
Restriction indicated during limit order placement, either market::FILL_OR_ABORT, market::IMMEDIATE_OR_CANCEL, - market::POST_OR_ABORT, or market:NO_RESTRICTION. + market::POST_OR_ABORT, or market::NO_RESTRICTION.
self_match_behavior: u8 @@ -4004,7 +4010,7 @@ Emit limit order events to a user's market event handles. FillEvents to emit as part of a limit order that filled across the spread, may be empty. * cancel_reason_option_ref: Immutable reference to an optional -cancel reason associated with a CancelEvent. +cancel reason associated with a CancelOrderEvent. @@ -4118,7 +4124,7 @@ Emit market order events to a user's market event handles. * fill_event_queue_ref: Immutable reference to a vector of FillEvents to emit, may be empty. * cancel_reason_option_ref: Immutable reference to an optional -cancel reason associated with a CancelEvent. +cancel reason associated with a CancelOrderEvent.