Assessment reports>GTE>Threat Model>postLimitOrder

Function: postLimitOrder(address account, PostLimitOrderArgs args)

This function allows to post a limit buy and sell order for the account. It can be called by the account itself or an operator authorized for this account. Also, this function is designed to handle matching and settling new orders with existing orders in the order book. It provides the execution result to the CLOBManager contract for token settlement and applies fees.

Inputs

  • account

    • Control: Full control.

    • Constraints: Should be msg.sender itself or an approved operator for the account.

    • Impact: The account on whose behalf the order is being filled.

  • args

    • Control: Full control.

    • Constraints: The cancelTimestamp should be more than the block.timestamp. The amountInBaseLots should be more than settings.minLimitOrderAmountInBase. Also, price % tickSize == 0 && args.price != 0.

    • Impact: Contains the information about the order — amountInBase, price, cancelTimestamp, side, limitOrderType, and settlement.

Branches and code coverage

Intended branches

  • The BUY order was fully executed and was not posted.

  • The BUY order was partly executed and was posted.

  • The SELL order was fully executed and was not posted.

  • The SELL order was partly executed and was posted.

Negative behavior

  • The caller is not an account or operator of the account.

  • cancelTimestamp < block.timestamp.

  • price % tickSize != 0.

  • args.price == 0.

  • If there is a BUY order and settlement is ACCOUNT — the quote internal-account balance in CLOBManager is insufficient.

  • If there is a SELL order and settlement is ACCOUNT — the base internal-account balance in CLOBManager is insufficient.

  • If there is a BUY order and settlement is INSTANT — the quote account balance is insufficient.

  • If there is a SELL order and settlement is INSTANT — the base account balance is insufficient.

Function call analysis

  • BookLib.assertLimitPriceInBounds(ds, args.price)

    • What is controllable? args.priceLimit.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? Reverts if priceLimit is zero or price % tickSize != 0.

  • BookLib.assertLimitOrderAmountInBounds(ds, args.amountInBase)

    • What is controllable? args.amountInBase.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? Reverts if the amountInBase is less than minLimitOrderAmountInBase.

  • BookLib.incrementLimitsPlaced(ds, msg.sender)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? Reverts if the number of orders placed in this transaction exceeds the maxLimitsPerTx or if the limit is exceeded for the caller.

  • BookLib.incrementNextOrderId(ds)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the next order ID.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • OrderLib.toOrder(args, orderId, account)

    • What is controllable? args.side, args.amountInBase, and args.priceLimit.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the new Order object.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • OrderLib.isExpired(newOrder)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns true when the cancelTimestamp is not null and is less than the current block.timestamp; otherwise, it returns false.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true)

    • What is controllable? newOrder.

    • If the return value is controllable, how is it used and how can it go wrong? If there are not any matches, this function returns zero totalQuoteTokenSent and zero totalBaseTokenReceived.

    • What happens if it reverts, reenters or does other unusual control flow? Reverts if only one of totalQuoteTokenSent or totalBaseTokenReceived is zero.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> BookLib.getBestAsk(ds)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the best minimum price askTree.minimum().

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> OrderLib.isExpired(bestAskOrder)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns true when the cancelTimestamp is not null and is less than the current block.timestamp; otherwise, it returns false.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._removeExpiredAsk(ds, bestAskOrder) -> TransientMakerData.addBaseToken(order.owner, baseTokenAmount)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here. The baseAmount will be saved for the owner of the expired order in the TransientMakerData memory.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._removeExpiredAsk(ds, bestAskOrder) -> BookLib.removeOrderFromBook(ds, order)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? The metadata.quoteTokenOpenInterest and metadata.baseTokenOpenInterest will be decremented — depends on the side of the order, and order.id will be deleted from the orders list. Also, bidTree and askTree will be updated in addition to orders.nextOrderId and orders.prevOrderId.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> FixedPointMathLib.min(matchedBase, incomingOrder.amount)

    • What is controllable? incomingOrder.amount.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the minimum value between matchedBase and incomingOrder.amount.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> BookLib.getQuoteTokenAmount(ds, matchedPrice, matchData.baseDelta)

    • What is controllable? If the provided incomingOrder.amount is less than matchedBase, the matchData.baseDelta will be equal to the incomingOrder.amount and fully controlled by the caller.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the quote-tokens amount calculated using the provided matchedPrice and matchData.baseDelta amount. The result can be rounded down to zero if matchData.baseDelta * matchedPrice is less than config.baseSize.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during matchData.baseDelta * matchedPrice calculation if matchedPrice or matchData.baseDelta is too large.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> FixedPointMathLib.min(matchedBase, BookLib.getBaseTokenAmount(ds, matchedPrice, incomingOrder.amount))

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the minimum amount between the matchedBase and the result of the getBaseTokenAmount function execution, which calculates the base-token amount using the provided-by-the-caller incomingOrder.amount and the matchedPrice.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> BookLib.getBaseTokenAmount(ds, matchedPrice, incomingOrder.amount)

    • What is controllable? incomingOrder.amount.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the base-token amount, which is calculated using the provided-by-the-caller incomingOrder.amount and the matchedPrice. Can return zero if quoteAmount * self.config.baseSize is less than price.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during quoteAmount * self.config.baseSize calculation if quoteAmount is too large.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> BookLib.getQuoteTokenAmount(ds, matchedPrice, matchData.baseDelta)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the quote-tokens amount calculated using the provided matchedPrice and matchData.baseDelta amount. The result can be rounded down to zero if matchData.baseDelta * matchedPrice is less than config.baseSize.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during matchData.baseDelta * matchedPrice calculation if matchedPrice or matchData.baseDelta is too large.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> TransientMakerData.addQuoteToken(matchedOrder.owner, matchData.quoteDelta)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here. The matchData.quoteDelta will be saved for the owner of the matched order in the TransientMakerData memory.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> TransientMakerData.addBaseToken(matchedOrder.owner, matchData.baseDelta)

    • What is controllable? matchData.baseDelta can be controlled by the caller, if this amount is less than the matchedOrder.amount.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here. The matchData.baseDelta will be saved for the owner of the matched order in the TransientMakerData memory.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._matchIncomingBid(ds, newOrder, true) -> this._matchIncomingOrder(ds, bestAskOrder, incomingOrder, incomingOrder.amount, amountIsBase) -> BookLib.removeOrderFromBook(ds, matchedOrder)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? The metadata.quoteTokenOpenInterest and metadata.baseTokenOpenInterest will be decremented — depends on the side of the order, and order.id will be deleted from the orders list. Also, bidTree and askTree will be updated in addition to orders.nextOrderId and orders.prevOrderId.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._removeNonCompetitiveOrder(ds, ds.orders[ds.bidLimits[minBidPrice].tailOrder]) -> factory.creditAccount(order.owner, address(ds.config.quoteToken), quoteRefunded)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? This function increases the internal account balance using the specified quoteRefunded amount. But there is no verification that the actual factory balance is sufficient to replenish the account for this amount.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> this._removeNonCompetitiveOrder(ds, ds.orders[ds.bidLimits[minBidPrice].tailOrder]) -> ds.removeOrderFromBook(order)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? The metadata.quoteTokenOpenInterest and metadata.baseTokenOpenInterest will be decremented — depends on the side of the order, and order.id will be deleted from the orders list. Also, bidTree and askTree will be updated in addition to orders.nextOrderId and orders.prevOrderId.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> ds.addOrderToBook(newOrder);

    • What is controllable? newOrder is partly controlled by the caller.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? Updates the book with a new order. Increases the quoteTokenOpenInterest with the order amount since the side is BUY.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> ds.getQuoteTokenAmount(newOrder.price, newOrder.amount);

    • What is controllable? newOrder.price and newOrder.amount.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the quote-tokens amount calculated using the provided matchedPrice and matchData.baseDelta amount. The result can be rounded down to zero if matchData.baseDelta * matchedPrice is less than config.baseSize.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during matchData.baseDelta * matchedPrice calculation if matchedPrice or matchData.baseDelta is too large.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._settleIncomingOrder(ds, account, Side.BUY, args.settlement, quoteTokenAmountSent + postAmount,baseTokenAmountReceived) -> TransientMakerData.getMakerCreditsAndClearStorage()

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the current state of the maker's credits including the expired orders and matched orders.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._settleIncomingOrder(ds, account, Side.BUY, args.settlement, quoteTokenAmountSent + postAmount,baseTokenAmountReceived) -> factory.settleIncomingOrder(settleParams)

    • What is controllable? settleParams.settlement is controlled by the caller.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the takerFee amount, which is used for events and as a part of the returned PostFillOrderResult.

    • What happens if it reverts, reenters or does other unusual control flow? If settlement is set to INSTANT, the function might revert during safeTransferFrom if the taker does not have enough balance or has not approved a sufficient allowance. Also, it reverts if the balance of the factory contract is not enough to transfer tokens to the taker. If settlement is set to ACCOUNT, the function might revert during the debitAccount function call if the taker does not have enough internal token balance.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType)

    • What is controllable? newOrder.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the final posted amount for the new order — also, the quoteToken amount should be received by the account and baseToken should be provided by the account.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert if the order type is POST_ONLY but the specified order price is less than the best price.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> _matchIncomingAsk(ds, newOrder, true) -> BookLib.getBestBid(ds)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the best maximum price bidTree.minimum().

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> _matchIncomingAsk(ds, newOrder, true) -> OrderLib.isExpired(bestBidOrder)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns true when the cancelTimestamp is not null and is less than the current block.timestamp; otherwise, it returns false.

    • What happens if it reverts, reenters or does other unusual control flow? There are no problems here.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> _matchIncomingAsk(ds, newOrder, true) -> this._removeExpiredBid(ds, bestBidOrder) -> BookLib.getQuoteTokenAmount(ds, order.price, order.amount)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? Returns the quote-tokens amount calculated using the expired order.price and order.amount. The result can be rounded down to zero if order.amount * order.price is less than config.baseSize.

    • What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during order.amount * order.price calculation if order.price or order.amount is too large.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> _matchIncomingAsk(ds, newOrder, true) -> this._removeExpiredBid(ds, bestBidOrder) -> TransientMakerData.addQuoteToken(order.owner, quoteTokenAmount)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? The quoteTokenAmount will be saved for the owner of the expired order in the TransientMakerData memory.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> _matchIncomingAsk(ds, newOrder, true) -> this._removeExpiredBid(ds, bestBidOrder) -> BookLib.removeOrderFromBook(ds, order)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? The metadata.quoteTokenOpenInterest and metadata.baseTokenOpenInterest will be decremented — depends on the side of the order, and order.id will be deleted from the orders list. Also, bidTree and askTree will be updated in addition to orders.nextOrderId and orders.prevOrderId.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> _removeNonCompetitiveOrder(ds, ds.orders[ds.askLimits[maxAskPrice].tailOrder]) -> factory.creditAccount(order.owner, address(ds.config.baseToken), baseRefunded)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? This function increases the internal account balance using the specified baseRefunded amount. But there is no verification that the actual factory balance is sufficient to replenish the account for this amount.

  • this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> _removeNonCompetitiveOrder(ds, ds.orders[ds.askLimits[maxAskPrice].tailOrder]) -> ds.removeOrderFromBook(order)

    • What is controllable? N/A.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? The metadata.quoteTokenOpenInterest and metadata.baseTokenOpenInterest will be decremented — depends on the side of the order, and order.id will be deleted from the orders list. Also, bidTree and askTree will be updated in addition to orders.nextOrderId and orders.prevOrderId.

  • this._processLimitAskOrder(ds, account, newOrder, args) -> this._executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> CLOB._executeAskLimitOrder(ds, account, newOrder, args) -> _executeAskLimitOrder(ds, newOrder, args.limitOrderType) -> ds.addOrderToBook(newOrder)

    • What is controllable? newOrder is partly controlled by the caller.

    • If the return value is controllable, how is it used and how can it go wrong? This function does not return a value.

    • What happens if it reverts, reenters or does other unusual control flow? Updates the book with a new order. Increases the baseTokenOpenInterest with the order amount since the side is SELL.

Zellic © 2025Back to top ↑