Place Limit Order

Explanation of the PlaceLimitOrder transaction


Limit orders provide the primary mechanism for trading on Duality. Limit orders can provide liquidity to the Dex (“Maker LimitOrders”) and/or can be used to trade against preexisting liquidity (“Taker Limit Orders”). All limit orders provide a TickIndexwhich serves as a limit price for which the order will be executed at.

Maker limit orders provide new liquidity to the dex that can be swapped through by other traders (either via Multihop Swap or a Taker Limit Order.) The liquidity supplied by a maker limit order is stored in a LimitOrderTranche at a specific tick. Once the tranche has been fully or partially filled via another order the user can withdraw the proceeds from that tranche. Maker limit orders can also be cancelled at any time. Maker only limit order’s are created with the following order types: GOOD_TIL_CANCELLED (will first try to satisfy the order via a taker limit order and only create an maker order if there is insufficient liquidity available above the provided TickIndex) JUST_IN_TIME GOOD_TIL_TIME

Taker limit orders do not add liquidity to the dex, instead they trade against existing TickLiquidity. Taker orders will either fail at the time of transaction or be completed immediately. Successful taker orders will deposit the proceeds directly back into the receiever’s address.

Rather than supplying a limit price, limit orders take a TickIndex as an argument. For maker limit orders this is the tick that the LimitOrderTranche will be placed at. For taker limit order will only trade through liquidity at or above the TickIndex. A specific price can be converted to a TickIndex using the following formula:

TickIndex=log1.0001(price)TickIndex = log_{1.0001}(price)

Order types


Fill-or-Kill limit orders are maker limit orders that either successfully swap 100% of the supplied AmountIn or return an error. If there is insufficient liquidity to complete the trade at or above the supplied TickIndex a Fill-or-Kill order will return an error of ErrFoKLimitOrderNotFilled.


Immediate-or-Cancel limit orders are maker orders that will swap as much as of the AmountIn as possible given available liquidity above the supplied TickIndex. Unlike Fill-or-Kill orders they will still successfully complete even if they are only able to partially trade through the AmountIn at the TickIndex or better.


Good-til-Cancelled limit orders are hybrid maker and taker limit orders. They will attempt to trade the supplied AmountIn at the TickIndex or better. However, if the total AmountIn cannot be traded at the limit price they remaining amount will be placed as a maker limit order. The proceeds from the taker portion are deposited into the user’s account immediately, however, the proceeds from the maker portion must be explicitly withdrawn via WithdrawLimitOrder.


Good-til-Time limit order function exactly the same as Good-til-Cancelled limit orders first trying to trade as a taker limit order and then placing any remaining amount as a maker limit order. However, the maker portion of the limit order has a specified ExpirationTime. After the ExpirationTime the order will be cancelled and can no longer be traded against. When withdrawing a Good-til-Time limit order the user will receive both the successfully traded portion of the limit order (TokenOut) as well as any remaining untraded amount (TokenIn).


Just-in-Time limit orders are an advanced maker limit order order that provides tradeable liquidity for exactly one block. At the end of the same block in which the Just-in-Time order was submitted the order is canceled and any untraded portion will no longer be usable as active liquidity.

PlaceLimitOrder Message

message MsgPlaceLimitOrder {
    string creator = 1;
    string receiver = 2;
    string token_in = 3;
    string token_out = 4;
    int64 tick_index_in_to_out = 5;
    string amount_in = 7 [
        (gogoproto.moretags) = "yaml:\"amount_in\"",
        (gogoproto.customtype) = "",
        (gogoproto.nullable) = false,
        (gogoproto.jsontag) = "amount_in"
    LimitOrderType order_type = 8;
    // expirationTime is only valid iff orderType == GOOD_TIL_TIME.
    google.protobuf.Timestamp expiration_time = 9 [
        (gogoproto.stdtime) = true,
        (gogoproto.nullable) = true
    string max_amount_out = 10 [
        (gogoproto.moretags) = "yaml:\"max_amount_out\"",
        (gogoproto.customtype) = "",
        (gogoproto.nullable) = true,
        (gogoproto.jsontag) = "max_amount_out"



Creator string (sdk.AccAddress)

Account from which TokenIn is debited

Receiver string (sdk.AccAddress)

Account to which TokenOut is credited or that will be allowed to withdraw or cancel a maker order

TokenIn string

Token being “sold”


Token being “bought”

TickIndex int64

Limit tick for a limit order, specified in terms of TokenIn to TokenOut

AmountIn sdk.Int

Amount of TokenIn to be traded

OrderType orderType

Type of limit order to be used. Must be one of: GOOD_TIL_CANCELLED, FILL_OR_KILL, IMMEDIATE_OR_CANCEL, JUST_IN_TIME, or GOOD_TIL_TIME

ExpirationTime time.Time

Expiration time for order. Only valid for GOOD_TIL_TIME limit orders

Last updated