axelar-cgp-sui

Module 0x0::order_info

Order module defines the order struct and its methods. All order matching happens in this module.

use 0x0::balances;
use 0x0::constants;
use 0x0::deep_price;
use 0x0::fill;
use 0x0::math;
use 0x0::order;
use 0x2::event;
use 0x2::object;

Struct OrderInfo

OrderInfo struct represents all order information. This objects gets created at the beginning of the order lifecycle and gets updated until it is completed or placed in the book. It is returned at the end of the order lifecycle.

struct OrderInfo has copy, drop, store
Fields
pool_id: object::ID
order_id: u128
balance_manager_id: object::ID
client_order_id: u64
trader: address
order_type: u8
self_matching_option: u8
price: u64
is_bid: bool
original_quantity: u64
order_deep_price: deep_price::OrderDeepPrice
expire_timestamp: u64
executed_quantity: u64
cumulative_quote_quantity: u64
fills: vector<fill::Fill>
fee_is_deep: bool
paid_fees: u64
maker_fees: u64
epoch: u64
status: u8
market_order: bool
fill_limit_reached: bool
order_inserted: bool

Struct OrderFilled

Emitted when a maker order is filled.

struct OrderFilled has copy, drop, store
Fields
pool_id: object::ID
maker_order_id: u128
taker_order_id: u128
maker_client_order_id: u64
taker_client_order_id: u64
price: u64
taker_is_bid: bool
taker_fee: u64
maker_fee: u64
base_quantity: u64
quote_quantity: u64
maker_balance_manager_id: object::ID
taker_balance_manager_id: object::ID
timestamp: u64

Struct OrderPlaced

Emitted when a maker order is injected into the order book.

struct OrderPlaced has copy, drop, store
Fields
balance_manager_id: object::ID
pool_id: object::ID
order_id: u128
client_order_id: u64
trader: address
price: u64
is_bid: bool
placed_quantity: u64
expire_timestamp: u64

Constants

const EFOKOrderCannotBeFullyFilled: u64 = 6;

const EInvalidExpireTimestamp: u64 = 3;

const EInvalidOrderType: u64 = 4;

const EMarketOrderCannotBePostOnly: u64 = 7;

const EOrderBelowMinimumSize: u64 = 1;

const EOrderInvalidLotSize: u64 = 2;

const EOrderInvalidPrice: u64 = 0;

const EPOSTOrderCrossesOrderbook: u64 = 5;

const ESelfMatchingCancelTaker: u64 = 8;

Function pool_id

public fun pool_id(self: &order_info::OrderInfo): object::ID
Implementation
public fun pool_id(self: &OrderInfo): ID {
    self.pool_id
}

Function order_id

public fun order_id(self: &order_info::OrderInfo): u128
Implementation
public fun order_id(self: &OrderInfo): u128 {
    self.order_id
}

Function balance_manager_id

public fun balance_manager_id(self: &order_info::OrderInfo): object::ID
Implementation
public fun balance_manager_id(self: &OrderInfo): ID {
    self.balance_manager_id
}

Function client_order_id

public fun client_order_id(self: &order_info::OrderInfo): u64
Implementation
public fun client_order_id(self: &OrderInfo): u64 {
    self.client_order_id
}

Function trader

public fun trader(self: &order_info::OrderInfo): address
Implementation
public fun trader(self: &OrderInfo): address {
    self.trader
}

Function order_type

public fun order_type(self: &order_info::OrderInfo): u8
Implementation
public fun order_type(self: &OrderInfo): u8 {
    self.order_type
}

Function self_matching_option

public fun self_matching_option(self: &order_info::OrderInfo): u8
Implementation
public fun self_matching_option(self: &OrderInfo): u8 {
    self.self_matching_option
}

Function price

public fun price(self: &order_info::OrderInfo): u64
Implementation
public fun price(self: &OrderInfo): u64 {
    self.price
}

Function is_bid

public fun is_bid(self: &order_info::OrderInfo): bool
Implementation
public fun is_bid(self: &OrderInfo): bool {
    self.is_bid
}

Function original_quantity

public fun original_quantity(self: &order_info::OrderInfo): u64
Implementation
public fun original_quantity(self: &OrderInfo): u64 {
    self.original_quantity
}

Function order_deep_price

public fun order_deep_price(self: &order_info::OrderInfo): deep_price::OrderDeepPrice
Implementation
public fun order_deep_price(self: &OrderInfo): OrderDeepPrice {
    self.order_deep_price
}

Function expire_timestamp

public fun expire_timestamp(self: &order_info::OrderInfo): u64
Implementation
public fun expire_timestamp(self: &OrderInfo): u64 {
    self.expire_timestamp
}

Function executed_quantity

public fun executed_quantity(self: &order_info::OrderInfo): u64
Implementation
public fun executed_quantity(self: &OrderInfo): u64 {
    self.executed_quantity
}

Function cumulative_quote_quantity

public fun cumulative_quote_quantity(self: &order_info::OrderInfo): u64
Implementation
public fun cumulative_quote_quantity(self: &OrderInfo): u64 {
    self.cumulative_quote_quantity
}

Function fills

public fun fills(self: &order_info::OrderInfo): vector<fill::Fill>
Implementation
public fun fills(self: &OrderInfo): vector<Fill> {
    self.fills
}

Function fee_is_deep

public fun fee_is_deep(self: &order_info::OrderInfo): bool
Implementation
public fun fee_is_deep(self: &OrderInfo): bool {
    self.fee_is_deep
}

Function paid_fees

public fun paid_fees(self: &order_info::OrderInfo): u64
Implementation
public fun paid_fees(self: &OrderInfo): u64 {
    self.paid_fees
}

Function maker_fees

public fun maker_fees(self: &order_info::OrderInfo): u64
Implementation
public fun maker_fees(self: &OrderInfo): u64 {
    self.maker_fees
}

Function epoch

public fun epoch(self: &order_info::OrderInfo): u64
Implementation
public fun epoch(self: &OrderInfo): u64 {
    self.epoch
}

Function status

public fun status(self: &order_info::OrderInfo): u8
Implementation
public fun status(self: &OrderInfo): u8 {
    self.status
}

Function fill_limit_reached

public fun fill_limit_reached(self: &order_info::OrderInfo): bool
Implementation
public fun fill_limit_reached(self: &OrderInfo): bool {
    self.fill_limit_reached
}

Function order_inserted

public fun order_inserted(self: &order_info::OrderInfo): bool
Implementation
public fun order_inserted(self: &OrderInfo): bool {
    self.order_inserted
}

Function new

public(friend) fun new(pool_id: object::ID, balance_manager_id: object::ID, client_order_id: u64, trader: address, order_type: u8, self_matching_option: u8, price: u64, quantity: u64, is_bid: bool, fee_is_deep: bool, epoch: u64, expire_timestamp: u64, order_deep_price: deep_price::OrderDeepPrice, market_order: bool): order_info::OrderInfo
Implementation
public(package) fun new(
    pool_id: ID,
    balance_manager_id: ID,
    client_order_id: u64,
    trader: address,
    order_type: u8,
    self_matching_option: u8,
    price: u64,
    quantity: u64,
    is_bid: bool,
    fee_is_deep: bool,
    epoch: u64,
    expire_timestamp: u64,
    order_deep_price: OrderDeepPrice,
    market_order: bool,
): OrderInfo {
    OrderInfo {
        pool_id,
        order_id: 0,
        balance_manager_id,
        client_order_id,
        trader,
        order_type,
        self_matching_option,
        price,
        is_bid,
        original_quantity: quantity,
        order_deep_price,
        expire_timestamp,
        executed_quantity: 0,
        cumulative_quote_quantity: 0,
        fills: vector[],
        fee_is_deep,
        epoch,
        paid_fees: 0,
        maker_fees: 0,
        status: constants::live(),
        market_order,
        fill_limit_reached: false,
        order_inserted: false,
    }
}

Function market_order

public(friend) fun market_order(self: &order_info::OrderInfo): bool
Implementation
public(package) fun market_order(self: &OrderInfo): bool {
    self.market_order
}

Function set_order_id

public(friend) fun set_order_id(self: &mut order_info::OrderInfo, order_id: u128)
Implementation
public(package) fun set_order_id(self: &mut OrderInfo, order_id: u128) {
    self.order_id = order_id;
}

Function set_paid_fees

public(friend) fun set_paid_fees(self: &mut order_info::OrderInfo, paid_fees: u64)
Implementation
public(package) fun set_paid_fees(self: &mut OrderInfo, paid_fees: u64) {
    self.paid_fees = paid_fees;
}

Function add_fill

public(friend) fun add_fill(self: &mut order_info::OrderInfo, fill: fill::Fill)
Implementation
public(package) fun add_fill(self: &mut OrderInfo, fill: Fill) {
    self.fills.push_back(fill);
}

Function fills_ref

public(friend) fun fills_ref(self: &mut order_info::OrderInfo): &mut vector<fill::Fill>
Implementation
public(package) fun fills_ref(self: &mut OrderInfo): &mut vector<Fill> {
    &mut self.fills
}

Function calculate_partial_fill_balances

Given a partially filled OrderInfo, the taker fee and maker fee, for the user placing the order, calculate all of the balances that need to be settled and the balances that are owed. The executed quantity is multiplied by the taker_fee and the remaining quantity is multiplied by the maker_fee to get the DEEP fee.

public(friend) fun calculate_partial_fill_balances(self: &mut order_info::OrderInfo, taker_fee: u64, maker_fee: u64): (balances::Balances, balances::Balances)
Implementation
public(package) fun calculate_partial_fill_balances(
    self: &mut OrderInfo,
    taker_fee: u64,
    maker_fee: u64,
): (Balances, Balances) {
    let taker_deep_in = math::mul(
        taker_fee,
        self
            .order_deep_price
            .deep_quantity(
                self.executed_quantity,
                self.cumulative_quote_quantity,
            ),
    );
    self.paid_fees = taker_deep_in;
    let fills = &mut self.fills;

    let mut i = 0;
    while (i < fills.length()) {
        let fill = &mut fills[i];
        if (!fill.expired()) {
            let base_quantity = fill.base_quantity();
            let quote_quantity = fill.quote_quantity();
            let fill_taker_fee = math::mul(
                taker_fee,
                self
                    .order_deep_price
                    .deep_quantity(
                        base_quantity,
                        quote_quantity,
                    ),
            );
            if (fill_taker_fee > 0) {
                fill.set_fill_taker_fee(fill_taker_fee);
            };
        };

        i = i + 1;
    };

    let mut settled_balances = balances::new(0, 0, 0);
    let mut owed_balances = balances::new(0, 0, 0);
    owed_balances.add_deep(taker_deep_in);

    if (self.is_bid) {
        settled_balances.add_base(self.executed_quantity);
        owed_balances.add_quote(self.cumulative_quote_quantity);
    } else {
        settled_balances.add_quote(self.cumulative_quote_quantity);
        owed_balances.add_base(self.executed_quantity);
    };

    let remaining_quantity = self.remaining_quantity();
    if (self.order_inserted()) {
        let maker_deep_in = math::mul(
            maker_fee,
            self
                .order_deep_price
                .deep_quantity(
                    remaining_quantity,
                    math::mul(remaining_quantity, self.price()),
                ),
        );
        self.maker_fees = maker_deep_in;
        owed_balances.add_deep(maker_deep_in);
        if (self.is_bid) {
            owed_balances.add_quote(
                math::mul(remaining_quantity, self.price()),
            );
        } else {
            owed_balances.add_base(remaining_quantity);
        };
    };

    (settled_balances, owed_balances)
}

Function to_order

OrderInfo is converted to an Order before being injected into the order book. This is done to save space in the order book. Order contains the minimum information required to match orders.

public(friend) fun to_order(self: &order_info::OrderInfo): order::Order
Implementation
public(package) fun to_order(self: &OrderInfo): Order {
    order::new(
        self.order_id,
        self.balance_manager_id,
        self.client_order_id,
        self.remaining_quantity(),
        self.fee_is_deep,
        self.order_deep_price,
        self.epoch,
        self.status,
        self.expire_timestamp,
    )
}

Function validate_inputs

Validates that the initial order created meets the pool requirements.

public(friend) fun validate_inputs(order_info: &order_info::OrderInfo, tick_size: u64, min_size: u64, lot_size: u64, timestamp: u64)
Implementation
public(package) fun validate_inputs(
    order_info: &OrderInfo,
    tick_size: u64,
    min_size: u64,
    lot_size: u64,
    timestamp: u64,
) {
    assert!(order_info.original_quantity >= min_size, EOrderBelowMinimumSize);
    assert!(order_info.original_quantity % lot_size == 0, EOrderInvalidLotSize);
    assert!(timestamp <= order_info.expire_timestamp, EInvalidExpireTimestamp);
    assert!(
        order_info.order_type >= constants::no_restriction() &&
        order_info.order_type <= constants::max_restriction(),
        EInvalidOrderType,
    );
    if (order_info.market_order) {
        assert!(
            order_info.order_type != constants::post_only(),
            EMarketOrderCannotBePostOnly,
        );
        return
    };
    assert!(
        order_info.price >= constants::min_price() &&
        order_info.price <= constants::max_price(),
        EOrderInvalidPrice,
    );
    assert!(order_info.price % tick_size == 0, EOrderInvalidPrice);
}

Function assert_execution

Assert order types after partial fill against the order book.

public(friend) fun assert_execution(self: &mut order_info::OrderInfo): bool
Implementation
public(package) fun assert_execution(self: &mut OrderInfo): bool {
    if (self.order_type == constants::post_only()) {
        assert!(self.executed_quantity == 0, EPOSTOrderCrossesOrderbook)
    };
    if (self.order_type == constants::fill_or_kill()) {
        assert!(
            self.executed_quantity == self.original_quantity,
            EFOKOrderCannotBeFullyFilled,
        )
    };
    if (self.order_type == constants::immediate_or_cancel()) {
        if (self.remaining_quantity() > 0) {
            self.status = constants::canceled();
        } else {
            self.status = constants::filled();
        };

        return true
    };

    if (self.remaining_quantity() == 0) {
        self.status = constants::filled();

        return true
    };

    if (self.fill_limit_reached) {
        return true
    };

    false
}

Function remaining_quantity

Returns the remaining quantity for the order.

public(friend) fun remaining_quantity(self: &order_info::OrderInfo): u64
Implementation
public(package) fun remaining_quantity(self: &OrderInfo): u64 {
    self.original_quantity - self.executed_quantity
}

Function can_match

Returns true if two opposite orders are overlapping in price.

public(friend) fun can_match(self: &order_info::OrderInfo, order: &order::Order): bool
Implementation
public(package) fun can_match(self: &OrderInfo, order: &Order): bool {
    let maker_price = order.price();

    (
        self.original_quantity - self.executed_quantity > 0 && (
            self.is_bid && self.price >= maker_price ||
            !self.is_bid && self.price <= maker_price,
        ),
    )
}

Function match_maker

Matches an OrderInfo with an Order from the book. Appends a Fill to fills. If the book order is expired, the Fill will have the expired flag set to true. Funds for the match or an expired order are returned to the maker as settled.

public(friend) fun match_maker(self: &mut order_info::OrderInfo, maker: &mut order::Order, timestamp: u64): bool
Implementation
public(package) fun match_maker(
    self: &mut OrderInfo,
    maker: &mut Order,
    timestamp: u64,
): bool {
    if (!self.can_match(maker)) return false;

    if (self.self_matching_option() == constants::cancel_taker()) {
        assert!(
            maker.balance_manager_id() != self.balance_manager_id(),
            ESelfMatchingCancelTaker,
        );
    };
    let expire_maker =
        self.self_matching_option() == constants::cancel_maker() &&
        maker.balance_manager_id() == self.balance_manager_id();
    let fill = maker.generate_fill(
        timestamp,
        self.remaining_quantity(),
        self.is_bid,
        expire_maker,
    );
    self.fills.push_back(fill);
    if (fill.expired()) return true;

    self.executed_quantity = self.executed_quantity + fill.base_quantity();
    self.cumulative_quote_quantity =
        self.cumulative_quote_quantity + fill.quote_quantity();
    self.status = constants::partially_filled();
    if (self.remaining_quantity() == 0) self.status = constants::filled();

    true
}

Function emit_orders_filled

Emit all fills for this order in a vector of OrderFilled events. To avoid DOS attacks, 100 fills are emitted at a time. Up to 10,000 fills can be emitted in a single call.

public(friend) fun emit_orders_filled(self: &order_info::OrderInfo, timestamp: u64)
Implementation
public(package) fun emit_orders_filled(self: &OrderInfo, timestamp: u64) {
    let mut i = 0;
    while (i < self.fills.length()) {
        let fill = &self.fills[i];
        if (!fill.expired()) {
            event::emit(self.order_filled_from_fill(fill, timestamp));
        };
        i = i + 1;
    };
}

Function emit_order_placed

public(friend) fun emit_order_placed(self: &order_info::OrderInfo)
Implementation
public(package) fun emit_order_placed(self: &OrderInfo) {
    event::emit(OrderPlaced {
        balance_manager_id: self.balance_manager_id,
        pool_id: self.pool_id,
        order_id: self.order_id,
        client_order_id: self.client_order_id,
        is_bid: self.is_bid,
        trader: self.trader,
        placed_quantity: self.remaining_quantity(),
        price: self.price,
        expire_timestamp: self.expire_timestamp,
    });
}

Function emit_order_info

public(friend) fun emit_order_info(self: &order_info::OrderInfo)
Implementation
public(package) fun emit_order_info(self: &OrderInfo) {
    event::emit(*self);
}

Function set_fill_limit_reached

public(friend) fun set_fill_limit_reached(self: &mut order_info::OrderInfo)
Implementation
public(package) fun set_fill_limit_reached(self: &mut OrderInfo) {
    self.fill_limit_reached = true;
}

Function set_order_inserted

public(friend) fun set_order_inserted(self: &mut order_info::OrderInfo)
Implementation
public(package) fun set_order_inserted(self: &mut OrderInfo) {
    self.order_inserted = true;
}

Function order_filled_from_fill

fun order_filled_from_fill(self: &order_info::OrderInfo, fill: &fill::Fill, timestamp: u64): order_info::OrderFilled
Implementation
fun order_filled_from_fill(
    self: &OrderInfo,
    fill: &Fill,
    timestamp: u64,
): OrderFilled {
    OrderFilled {
        pool_id: self.pool_id,
        maker_order_id: fill.maker_order_id(),
        taker_order_id: self.order_id,
        maker_client_order_id: fill.maker_client_order_id(),
        taker_client_order_id: self.client_order_id,
        price: fill.execution_price(),
        taker_is_bid: self.is_bid,
        taker_fee: fill.taker_fee(),
        maker_fee: fill.maker_fee(),
        base_quantity: fill.base_quantity(),
        quote_quantity: fill.quote_quantity(),
        maker_balance_manager_id: fill.balance_manager_id(),
        taker_balance_manager_id: self.balance_manager_id,
        timestamp,
    }
}