Skip to main content

Trading

Overview

The trading module provides a place to asynchronously swap fungible tokens with other users. It means users can swap or trade their fungible assets now, but settle them in an agreed-upon future time. This module uses forwards contracts as its infrastructure to ensure the swap settlement. Obviously, other third parties can implement some other trading platforms using forward contracts.

Concepts

Order

In the context of a trading platform, an order is a buy or sell request that has a predetermined price, quantity, and delivery time period initiated by the maker. Some of these predetermined properties can also be defined or changed dynamically based on different circumstances. The orders can only be defined on fungible assets.

There are two primary types of orders: Limit orders and Market orders. The key distinction lies in how the price is determined. For Limit orders, the price is set at the time of creation and remains unaffected by the asset's current market price. In contrast, the price of Market orders is tied to the asset's live market price and may fluctuate during the matching process.

Trading Types

There are two main types of trading:

  1. Simple Trading: Placing a simple order (any of market or limit types) which is simply one single isolated order.
  2. Bundled Trading: Placing a group of orders with a specified relationship between them. For instance, match-or-kill orders represent a transactional approach to executing multiple trades simultaneously.

Specified Order Terms

When a user wants to submit an order, they should specify the following terms:

  • Assets To Exchange: Assets they provide and assets they request in response.
  • Settlement Period: A user-defined time range during which they are happy to have their trade settled that is independent of when the order was created or matched.
  • Minimum Accepted Escrow: Minimum escrow required from the other counterpart. Can be a percentage of the underlying asset or a fixed amount of stablecoins. Can specify only one
  • Maximum Deposited Escrow: The maximum escrow order creator is willing to deposit. Can be a percentage of the underlying asset or a fixed amount of stablecoins. Can specify only one
  • Partial fill allowed: If the order creator is happy to allow partial matching of their order or not. i.e. I want to buy 1 BTC but happy to accept 0.1 BTC
  • Enable Buy-in: If the order creator wants to enable the buy-in option or not. Where if one party defaults another can step in and fulfil the order and keep the escrow

Specified Trading Terms

  • Auction Terms - more
    • Enable Auction: If the order creator wants to put their order as an auction and wait for the best bid or not. This is like an RFQ (Request For Quote)
    • Reserve Price: The reserve price of auction which is kind of starting price for bidders (only set when enable auction was enabled).
    • Auction Duration: The duration allocated for conducting the auction and accommodating bidder participation (only set when enable auction was enabled).
    • Bidders Must Hold Badges: List of badges that bidders must have. Only holders of these badges are allowed to put bids on this auction (only set when enable auction was enabled).
  • Orderbook Terms - more
    • **Enable Putting In Order-book:**If the order creator wants to put their order in order-book and automatically find the best match or not.
    • Limit Price: The limit price of the order which is the asset to asked by the order creator (only set when enable putting in order-book enabled).
    • Matches Must Have Badges: List of required badges that order owners must possess. Only orders from individuals holding these badges can be matched with this order. (only set when enable putting in order-book enabled).
  • Discounted Price: The configurations for discounted price orders. more
    • **Percentage:** The discount percentage on market price (pair must have oracle price).
    • Stop Price: The minimum acceptable price. The order will be skipped if discounted price is lower (for sell orders) or higher (for buy orders) than this amount.
    • Settlement Period Start Time After Match: Allows to set the settlement period dynamically based on matching time.
    • Settlement Period Duration: Time frame for delivery of provided and requested assets by both sides.

Capital Efficiency

As a seller, it can often be inefficient and impractical to tie up all of your selling assets while waiting for bids. Instead of keeping all your assets in limbo, you have the option to put a portion of them in escrow, allowing you to retain access to the rest of your assets. By doing so, you can maintain flexibility and keep your assets readily available for potential opportunities that may arise during the selling process.

Placing a portion of your assets in escrow enables you to only transfer them at the time of settlement, providing you with the freedom to explore various selling options without being restricted by the need to have all assets tied up. This approach allows you to keep your options open while we diligently search for the best buyers offering the most competitive prices.

Moreover, by utilizing escrow, you can ensure that your assets remain accessible throughout the selling process, giving you peace of mind and the ability to respond swiftly to potential buyers' offers. This strategy maximizes your flexibility and empowers you to make informed decisions based on the current market conditions, ultimately leading to a more efficient and successful selling experience.

Governance Token

Forwards governance token ($FWD) is essential for creating new orders. Makers are only allowed to create an order if they have staked an adequate amount of FWD beforehand. These tokens can be obtained by utilizing assets within the blockchain ecosystem or trading them on external exchanges.

To determine the number of allowed limit orders based on the number of tokens staked, we use the following formula:

$$ orderAllowance = round(baseRatio * log10(stakedTokens + 1)) + freeAllowanceCount $$

In this formula, the +1 term is added to avoid the logarithm returning undefined or causing errors when the stakedTokens value is zero. Also, the variable freeAllowanceCount determines the number of creation order allowances without any staked FWD.

Here’s a table illustrating the above formula for different levels of staking (baseRatio = 5):

staked tokensorder allowance
00
10010
100015
1000020

Initially, the increase is relatively steep, but it gradually tapers off as the number of tokens staked increases. This logarithmic scaling approach ensures that users with larger token stakes have a higher number of limit orders available to them, but the rate of increase becomes slower over time, discouraging excessive spamming.

The formula can be fine-tuned to better meet the chain's requirements by adjusting the baseRatio.

Escrow Conditions

Forward Chain enables users to sell their assets while deferring settlement to a future date. This functionality is achieved through the use of forward contracts, which serve as a mechanism to manage the deal over time.

When two orders are matched, a forward contract is created between both parties. To mitigate settlement risks, both parties are required to deposit funds into the contract’s escrow account. Each order owner must define their desired escrow terms, including the maximum amount they are willing to deposit and the minimum amount they expect from the counterparty.

The escrow deposit can either consist of a portion of the selling asset or a specified amount of stable coin. To proceed, each order owner must specify at least one of the following condition pairs:

{
// portion of selling asset
"min_expected_escrow_percent": 0.15,
"max_accepted_escrow_percent": 0.1,

// a fixed amount of stable coin
"min_expected_escrow": "250usdc",
"max_accepted_escrow": "300usdc",
}

Reputational Badges

One effective method for mitigating counterparty risks is to engage in trading activities exclusively with well-established and reputable traders. When a user or market maker has consistently demonstrated integrity and reliability in their trading history, they are generally considered to be more trustworthy compared to other market participants. Trust is a valuable asset that is cultivated over time through ethical and transparent conduct, rather than being acquired through monetary means. Users are motivated to uphold and safeguard this invaluable asset.

In the realm of forward contracts, users can be awarded with reputational badges based on their trading activities, which serves as a tool for counterparties to gauge the level of risk associated with entering into a contract with a particular individual. As the renowned entrepreneur Dhar Mann aptly stated,

Trust takes years to build, seconds to break, and forever to repair.

01.png

Limit Orders

Limit orders are orders with a predefined price. The price is not changing dynamically based on price fluctuations of the market. When working with limit orders, there are three ways that the order owner can select how they prefer to fill their order.

1. Order Book Matching

Matching orders with another order is one of the ways to fill orders. When a user specifies to put their order in the order-book, the chain will actively try to find the best match to fill that order. Matching orders must meet the following criteria:

  1. Price: The seller’s price must be lower than or equal to the buyer’s price.
  2. Settlement Period: The orders’ settlement period must have overlaps, even for a second.
  3. Escrow Conditions: The escrow conditions must overlap. This means that if one order requires the other party to place at least X percent in escrow, the second order’s escrow condition must satisfy this requirement.
  4. Reputational Badges: The Order owner specifies that the matching order’s owner must have specific badges.

In each end block, the chain finds all matching candidates and sorts them to match the best candidates first. The sorting is based on the following (with the same priority):

  1. Price: Candidate with a better price (higher for the buyer, lower for the seller) is better.
  2. Settlement Period: Candidate with an earlier end of the settlement period is better.
  3. Amount: Candidate with a higher amount is better.

2. Token Auctions

Placing an order in an auction to be filled by other users’ bids is another way to fill an order. When a user selects a token auction, their order is listed as an auction with a specified reserve price and a set time frame.

During the auction period, anyone is permitted to place bids to fulfill the order. By placing a bid, participants agree to the settlement period and escrow conditions set by the auction owner, without the option to propose changes. The sole factor of competition is the price.

At the end of the auction period, the best bid will win the auction, and this will result in a contract between the auction order and the winning bidder. If no bids are placed, the auction order will be declined, and the escrow amount will be released.

3. Hybrid Approach

Users can also opt for a hybrid approach that combines both previous methods. In this approach, the order is initially listed as an auction for a specified time frame. If no bids are placed during the auction period, the order is automatically moved to the order book, where it remains until a match is found and filled.

02.png

Market Orders

Market orders are orders without a predefined price, with their value fluctuating dynamically based on market price changes. Currently, the Forwards chain supports only one type of market order.

1. Simple Market Order

In this type of market order, users can place orders to find the best price for selling or buying their assets, with specified settlement periods, escrow conditions, requested badges, and partial matching flags. The market order will be matched immediately in the current block or rejected if no suitable matching candidate is available.

Since the price is determined by the state of orders in the order book, the final matched order may have a different price than the current market price. For instance, if a market order aims to buy BTC and the current market price is 100K, the best matching candidate's selling price in the order book might be 85K.

Discounted Price Orders

In this type of market order, users can place buy or sell orders at a discounted percentage relative to the current market price. By specifying the discount percentage, the order price will automatically adjust with each block based on the asset's market price. Placing a sell order at a discount means selling at a price lower than the market price, while placing a buy order at a discount indicates an attempt to fill orders at a price lower than the market price.

The order owner can set a stop price to limit discounts during significant market fluctuations. If the applied discount causes the market price to drop below the stop price, the order will be temporarily deactivated until the market returns to an acceptable level.

Match Or Kill Orders

A match-or-kill order is a powerful tool that allows traders to address multiple positions simultaneously, ensuring that either all of the sub-orders are filled or none of them apply. This order type is commonly used by market makers to facilitate a concept known as coincidence of wants (CoW), where multiple positions can be matched with one another based on specific criteria. By utilizing a match-or-kill order, traders can specify the exact wiring of the positions to guarantee that they are all filled according to their preferences.

03.png

In the context of trading, the ability to execute a match-or-kill order provides a level of control and precision that is essential for optimizing trading strategies and managing risk. This order type allows traders to orchestrate complex multi-leg transactions with confidence, knowing that the outcome will align with their desired objectives.

Furthermore, the use of match-or-kill orders can streamline the trading process by reducing the need for manual intervention and oversight. Instead of monitoring each individual sub-order separately, traders can rely on the match-or-kill order to automatically coordinate the execution of multiple positions in a seamless and efficient manner.

In addition, the concept of coincidence of wants (CoW) facilitated by match-or-kill orders highlights the interconnected nature of trading activities. By leveraging this order type, market participants can capitalize on the potential for synergistic transactions where the fulfillment of one position complements or offsets another, leading to a more balanced and optimized portfolio.

04.png

Messages

MsgCreateOrder

This message creates an order. The response includes the ID of the created order.

message MsgCreateOrder {
option (cosmos.msg.v1.signer) = "creator";

string creator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string deposit_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
cosmos.base.v1beta1.Coin provided_asset = 3;
contracts.v1.Period settlement_period = 4;
bool partial_fill_allowed = 5;
bool enable_buy_in = 6;
string min_expected_escrow_percent = 7 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
string max_accepted_escrow_percent = 8 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
cosmos.base.v1beta1.Coin min_expected_escrow = 9;
cosmos.base.v1beta1.Coin max_accepted_escrow = 10;
string preferred_fee_denom = 11;

bool enable_auction = 12;
cosmos.base.v1beta1.Coin reserve_price = 13;
google.protobuf.Duration auction_duration = 14 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];
repeated string bidders_must_hold_badges = 15;

bool put_in_order_book = 16;
cosmos.base.v1beta1.Coin limit_price = 17;
repeated string matching_buyers_must_hold_badges = 18;

DiscountedPrice discounted_price = 19;
}

message Period {
option (gogoproto.equal) = true;

google.protobuf.Timestamp start = 1 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false
];
google.protobuf.Timestamp end = 2 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false
];
}

message DiscountedPrice {
//must be between 0 and 1
string percentage = 1 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
string stop_price = 2 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = true
];
string requested_denom = 3;
google.protobuf.Duration settlement_period_start_time_after_match = 4 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];
google.protobuf.Duration settlement_period_duration = 5 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];
}
message MsgCreateOrderResponse {
uint64 id = 1;
uint64 auction_id = 2;
}

MsgCancelOrder

This message is used to cancel an order.

message MsgCancelOrder {
option (cosmos.msg.v1.signer) = "creator";

string creator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
uint64 order_id = 2;
string preferred_fee_denom = 3;
}
message MsgCancelOrderResponse {}

MsgCreateMatchOrKillOrder

This message is used to create a match-or-kill order. The response includes the ID of created match-or-kill order.

message MsgCreateMatchOrKillOrder {
option (cosmos.msg.v1.signer) = "creator";

string creator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string deposit_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
repeated OrderCreationData orders = 3 [(gogoproto.nullable) = false];
string preferred_fee_denom = 4;
}

message OrderCreationData {
cosmos.base.v1beta1.Coin provided_asset = 1;
cosmos.base.v1beta1.Coin requested_asset = 2;
contracts.v1.Period settlement_period = 3;
string min_expected_escrow_percent = 4 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
string max_accepted_escrow_percent = 5 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
cosmos.base.v1beta1.Coin min_expected_escrow = 6;
cosmos.base.v1beta1.Coin max_accepted_escrow = 7;
repeated string buyer_must_hold_badges = 8;
}
message MsgCreateMatchOrKillOrderResponse {
uint64 id = 1;
repeated uint64 order_ids = 2;
}

MsgCancelMatchOrKillOrder

This message is used to cancel a match-or-kill order.

message MsgCancelMatchOrKillOrder {
option (cosmos.msg.v1.signer) = "creator";

string creator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
uint64 order_id = 2;
string preferred_fee_denom = 3;
}
message MsgCancelMatchOrKillOrderResponse {}

MsgBidOnTokenAuction

This message is used by other users to place bid on token auctions.

message MsgBidOnTokenAuction {
option (cosmos.msg.v1.signer) = "creator";

string creator = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
uint64 auction_id = 2;
string bidder_recipient_address = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
bool enable_buy_in = 4;
cosmos.base.v1beta1.Coin bid = 5;
string preferred_fee_denom = 6;
}
message MsgBidOnTokenAuctionResponse {}

MsgUpdateModuleParams

This message updates the module parameters. Only the governance can execute this message.

message MsgUpdateModuleParams {
option (cosmos.msg.v1.signer) = "authority";

string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
Params params = 2 [(gogoproto.nullable) = false];
}

message Params {
string stake_base_ratio = 1 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
int64 free_allowance_count = 2;
int64 max_open_orders_per_block = 3;

// order_expiration_duration specifies how long an order can be live in order to find a match
google.protobuf.Duration order_expiration_duration = 4 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];
// price_expiration_duration specifies how long a price can be valid
google.protobuf.Duration price_expiration_duration = 5 [
(gogoproto.stdduration) = true,
(gogoproto.nullable) = false
];
}

message MsgUpdateModuleParamsResponse {}

MsgUpdateFeeConfig

This message updates the module’s fee configurations. Only the governance can execute this message.

message MsgUpdateFeeConfig {
option (cosmos.msg.v1.signer) = "authority";

string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
FeeConfigs fee_config = 2 [(gogoproto.nullable) = false];
}

message FeeConfigs {
FeeConfig order_creation = 1 [(gogoproto.nullable) = false];
FeeConfig order_cancellation = 2 [(gogoproto.nullable) = false];
FeeConfig match_or_kill_order_creation = 3 [(gogoproto.nullable) = false];
FeeConfig match_or_kill_order_cancellation = 4 [(gogoproto.nullable) = false];
FeeConfig token_auction_bidding = 5 [(gogoproto.nullable) = false];
}

message FeeConfig {
bool enabled = 1;
repeated cosmos.base.v1beta1.Coin fixed = 2;
string percentage_of_underlying_asset = 3 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
}

message MsgUpdateFeeConfigResponse {}

MsgSetDenomMappingForDiscountedPrice

This message sets new denom mappings for the module. Only the governance can execute this message.

message MsgSetDenomMappingForDiscountedPrice {
option (cosmos.msg.v1.signer) = "authority";

string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
DenomMapping denom_mapping = 2;
}

message DenomMapping {
string oracle_denom = 1;
string base_denom = 2;
uint64 decimals = 3;
bool enabled = 4;
}

Queries

Params

This query fetches the parameters of the module.

message QueryParamsRequest {}
message QueryParamsResponse {
// params holds all the parameters of this module.
Params params = 1 [(gogoproto.nullable) = false];
}

FeeConfigs

This query fetches the fee configurations of the module.

message QueryFeeConfigsRequest {}
message QueryFeeConfigsResponse {
// fee config holds all the fee configurations of this module.
FeeConfigs fee_configs = 1 [(gogoproto.nullable) = false];
}

Order

This query retrieves an order using its id.

message QueryGetOrderRequest {
uint64 id = 1;
}
message QueryGetOrderResponse {
Order order = 1 [(gogoproto.nullable) = false];
}

OrderAll

This query fetches all orders.

message QueryAllOrderRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryAllOrderResponse {
repeated Order orders = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

MatchOrKillOrder

This query retrieves a match-or-kill order using its id.

message QueryGetMatchOrKillOrderRequest {
uint64 id = 1;
}
message QueryGetMatchOrKillOrderResponse {
MatchOrKillOrder match_or_kill_order = 1 [(gogoproto.nullable) = false];
}

MatchOrKillOrderAll

This query fetches all match-or-kill orders.

message QueryAllMatchOrKillOrderRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryAllMatchOrKillOrderResponse {
repeated MatchOrKillOrder match_or_kill_orders = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

TokenAuction

This query retrieves a token auction using its id.

message QueryGetTokenAuctionRequest {
uint64 id = 1;
}
message QueryGetTokenAuctionResponse {
TokenAuction token_auction = 1 [(gogoproto.nullable) = false];
}

TokenAuctionAll

This query fetches all token auctions.

message QueryAllTokenAuctionRequest {
cosmos.base.query.v1beta1.PageRequest pagination = 1;
}
message QueryAllTokenAuctionResponse {
repeated TokenAuction token_auctions = 1 [(gogoproto.nullable) = false];
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

Price

This query retrieves the price of an asset using its base and quote denom.

message QueryPriceRequest {
string base_denom = 1;
string quote_denom = 2;
}
message QueryPriceResponse {
string price = 1 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = true
];
uint64 decimals = 2;
google.protobuf.Timestamp price_time = 3 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false
];
bool deprecated = 4;
}

Events

OrderCreatedEvent

Emitted when an order is created. It includes the order information.

message OrderCreatedEvent {
uint64 order_id = 1;
string owner_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string owner_deposit_address = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
cosmos.base.v1beta1.Coin provided_asset = 4;
contracts.v1.Period settlement_period = 5;
bool partial_fill_allowed = 6;
bool buy_in_enabled = 7;
string min_expected_escrow_percent = 8 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
string max_accepted_escrow_percent = 9 [
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = true
];
cosmos.base.v1beta1.Coin min_expected_escrow = 10;
cosmos.base.v1beta1.Coin max_accepted_escrow = 11;
uint64 match_or_kill_order_id = 12;
google.protobuf.Timestamp creation_time = 13 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false
];

bool auction_enabled = 14;
cosmos.base.v1beta1.Coin reserve_price = 15;
contracts.v1.Period auction_period = 16;
string bidders_must_hold_badges = 17;

bool put_in_order_book = 18;
cosmos.base.v1beta1.Coin limit_price = 19;
string matching_buyers_must_hold_badges = 20;

DiscountedPrice discounted_price = 21;
string requested_denom = 22;
}

OrderCancelledEvent

Emitted when an order is cancelled. It includes the order ID.

message OrderCancelledEvent {
uint64 order_id = 1;
}

OrderMatchEvent

Emitted when two orders are matched. It includes the changes of both orders .

message OrderMatchEvent {
OrderChanges first_order_changes = 1;
OrderChanges second_order_changes = 2;
}

message OrderChanges {
uint64 order_id = 1;
cosmos.base.v1beta1.Coin filled = 2;
bool totally_filled = 3;
}

MatchOrKillOrderCreatedEvent

Emitted when a match-or-kill order is created. It includes the match-or-kill order ID and it’s sub-order IDs.

message MatchOrKillOrderCreatedEvent {
uint64 id = 1;
repeated uint64 order_ids = 2;
google.protobuf.Timestamp creation_time = 3 [
(gogoproto.stdtime) = true,
(gogoproto.nullable) = false
];
}

MatchOrKillOrderCancelledEvent

Emitted when a match-or-kill order is cancelled. It includes the match-or-kill order ID.

message MatchOrKillOrderCancelledEvent {
uint64 order_id = 1;
}

MatchOrKillOrderMatchedEvent

Emitted when all sub-orders of a match-or-kill order get matched. It includes the match-or-kill order ID.

message MatchOrKillOrderMatchedEvent {
uint64 id = 1;
}

TokenAuctionFinishedEvent

Emmited when a token auction’s time period is finished.

message TokenAuctionFinishedEvent {
uint64 id = 1;
string winner_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
cosmos.base.v1beta1.Coin winner_price = 3;
}

State

Order

Orders are stored using their IDs as store keys:

(
[]byte("/Orders/value/") |
[]byte(id)
) -> ProtoBuf(Order)

Orders are also indexed with their owner, state, price:

type OrderIndexes struct {
// Owner is a multi index that indexes orders by their owner address.
Owner *indexes.Multi[string, uint64, types.Order]

// State is a multi index that indexes orders by their state.
State *indexes.Multi[string, uint64, types.Order]

// Price is a multi index that indexes orders by their Price.
Price *indexes.Multi[math.LegacyDec, uint64, types.Order]
}

Match-Or-Kill Order

Match-or-kill orders are stored using their IDs as store keys:

(
[]byte("/MatchOrKillOrders/value/") |
[]byte(id)
) -> ProtoBuf(MatchOrKillOrder)

Match-or-kill orders are also indexed with their owner:

type MatchOrKillOrderIndexes struct {
// Owner is a multi index that indexes match-or-kill orders by their owner address.
Owner *indexes.Multi[string, uint64, types.MatchOrKillOrder]
}

Token Auction

Token auctions are stored using their IDs as store keys:

(
[]byte("/TokenAuctions/value/") |
[]byte(id)
) -> ProtoBuf(TokenAucion)

Token auctions are also indexed with their owner, related order id:

type TokenAuctionIndexes struct {
// Owner is a multi index that indexes token-auctions by their owner address.
Owner *indexes.Multi[string, uint64, types.TokenAuction]

// Order is a unique index that indexes token-auctions by their related order
Order *indexes.Unique[uint64, uint64, types.TokenAuction]
}

Params

Module parameters are stored under the following store key:

([]byte("Params/")) -> ProtoBuf(Params)

FeeConfigs

Module fee configs are stored under the following store key:

([]byte("FeeConfigs/")) -> ProtoBuf(FeeConfigs)

Denom mapping

Denom mappings are stored using their oracle denom as store keys:

(
[]byte("/DenomMappings/value/") |
[]byte(oracle_denom)
) -> ProtoBuf(DenomMapping)

Denom mappings are also indexed with their base denom:

type DenomMappingIndexes struct {
// baseDenom is a unique index that indexes denom-mappings by their base-denom.
baseDenom *indexes.Unique[string, string, types.DenomMapping]
}

Parameters

Order Params

  • stake_base_ratio: This parameter is used in calculating the allowed open orders for a user. more
    • Type: cosmossdk.io/math.LegacyDec
    • Range: (0, inf]
    • Default Value: 5
  • free_allowance_count: This parameter determines the number of free open orders that a user can create without needing to stake any governance token. more
    • Type: int64
    • Range: [0, inf]
    • Default Value: 1
  • max_open_orders_per_block: This parameter limits the number of open orders that can be processed in each block.
    • Type: int64
    • Range: (0, inf]
    • Default Value: 100000
  • order_expiration_duration: This parameter determines the duration an order can be valid. If an order stays more than this duration in the orderbook, it will be expired and removed.
    • Type: google.protobuf.Duration
    • Range: (0, inf]
    • Default Value: 5184000000000000 (60 days)

Price Params

  • price_expiration_duration: This parameter determines how long a price can be valid.
    • Type: google.protobuf.Duration
    • Range: (0, inf]
    • Default Value: 60000000000 (1 minute)

Genesis

The genesis state of this module includes:

  • params: Parameters for the trading module.
  • fee_configs: Fee configurations of the trading module.
  • denom_mappings: denom-mappings of the trading module.
  • orders_list: List of all orders.
  • orders_starting_id: Next order id that can be generated.
  • orders_count: Number of orders.
  • match_or_kill_orders_list: List of all match-or-kill orders.
  • match_or_kill_orders_starting_id: Next match-or-kill order id that can be generated.
  • match_or_kill_orders_count: Number of match-or-kill orders.
  • token_auctions_list: List of all token auctions.
  • token_auctions_starting_id: Next token auction id that can be generated.