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
accountControl: Full control.
Constraints: Should be
msg.senderitself or an approved operator for theaccount.Impact: The account on whose behalf the order is being filled.
argsControl: Full control.
Constraints: The
cancelTimestampshould be more than theblock.timestamp. TheamountInBaseLotsshould be more thansettings.minLimitOrderAmountInBase. Also,price % tickSize == 0 && args.price != 0.Impact: Contains the information about the order —
amountInBase,price,cancelTimestamp,side,limitOrderType, andsettlement.
Branches and code coverage
Intended branches
The
BUYorder was fully executed and was not posted.The
BUYorder was partly executed and was posted.The
SELLorder was fully executed and was not posted.The
SELLorder was partly executed and was posted.
Negative behavior
The caller is not an
accountoroperatorof the account.cancelTimestamp < block.timestamp.price % tickSize != 0.args.price == 0.If there is a
BUYorder andsettlementisACCOUNT— the quote internal-account balance in CLOBManager is insufficient.If there is a
SELLorder andsettlementisACCOUNT— the base internal-account balance in CLOBManager is insufficient.If there is a
BUYorder andsettlementisINSTANT— the quote account balance is insufficient.If there is a
SELLorder andsettlementisINSTANT— 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
priceLimitis zero orprice % 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
amountInBaseis less thanminLimitOrderAmountInBase.
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
maxLimitsPerTxor if the limit is exceeded for thecaller.
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, andargs.priceLimit.If the return value is controllable, how is it used and how can it go wrong? Returns the new
Orderobject.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
cancelTimestampis not null and is less than the currentblock.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
totalQuoteTokenSentand zerototalBaseTokenReceived.What happens if it reverts, reenters or does other unusual control flow? Reverts if only one of
totalQuoteTokenSentortotalBaseTokenReceivedis 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
cancelTimestampis not null and is less than the currentblock.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
baseAmountwill be saved for the owner of the expired order in theTransientMakerDatamemory.
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.quoteTokenOpenInterestandmetadata.baseTokenOpenInterestwill be decremented — depends on the side of the order, andorder.idwill be deleted from theorderslist. Also,bidTreeandaskTreewill be updated in addition toorders.nextOrderIdandorders.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
matchedBaseandincomingOrder.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.amountis less thanmatchedBase, thematchData.baseDeltawill be equal to theincomingOrder.amountand 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
matchedPriceandmatchData.baseDeltaamount. The result can be rounded down to zero ifmatchData.baseDelta * matchedPriceis less thanconfig.baseSize.What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during
matchData.baseDelta * matchedPricecalculation ifmatchedPriceormatchData.baseDeltais 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
matchedBaseand the result of thegetBaseTokenAmountfunction execution, which calculates the base-token amount using the provided-by-the-callerincomingOrder.amountand thematchedPrice.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.amountand thematchedPrice. Can return zero ifquoteAmount * self.config.baseSizeis less thanprice.What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during
quoteAmount * self.config.baseSizecalculation ifquoteAmountis 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
matchedPriceandmatchData.baseDeltaamount. The result can be rounded down to zero ifmatchData.baseDelta * matchedPriceis less thanconfig.baseSize.What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during
matchData.baseDelta * matchedPricecalculation ifmatchedPriceormatchData.baseDeltais 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.quoteDeltawill be saved for the owner of the matched order in theTransientMakerDatamemory.
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.baseDeltacan be controlled by the caller, if this amount is less than thematchedOrder.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.baseDeltawill be saved for the owner of the matched order in theTransientMakerDatamemory.
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.quoteTokenOpenInterestandmetadata.baseTokenOpenInterestwill be decremented — depends on the side of the order, andorder.idwill be deleted from theorderslist. Also,bidTreeandaskTreewill be updated in addition toorders.nextOrderIdandorders.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
quoteRefundedamount. 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.quoteTokenOpenInterestandmetadata.baseTokenOpenInterestwill be decremented — depends on the side of the order, andorder.idwill be deleted from theorderslist. Also,bidTreeandaskTreewill be updated in addition toorders.nextOrderIdandorders.prevOrderId.
this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> ds.addOrderToBook(newOrder);What is controllable?
newOrderis 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
quoteTokenOpenInterestwith the order amount since the side isBUY.
this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> ds.getQuoteTokenAmount(newOrder.price, newOrder.amount);What is controllable?
newOrder.priceandnewOrder.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
matchedPriceandmatchData.baseDeltaamount. The result can be rounded down to zero ifmatchData.baseDelta * matchedPriceis less thanconfig.baseSize.What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during
matchData.baseDelta * matchedPricecalculation ifmatchedPriceormatchData.baseDeltais 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.settlementis controlled by the caller.If the return value is controllable, how is it used and how can it go wrong? Returns the
takerFeeamount, which is used for events and as a part of the returnedPostFillOrderResult.What happens if it reverts, reenters or does other unusual control flow? If
settlementis set toINSTANT, the function might revert duringsafeTransferFromif 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. Ifsettlementis set toACCOUNT, the function might revert during thedebitAccountfunction 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
quoteTokenamount should be received by the account andbaseTokenshould 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_ONLYbut the specified orderpriceis 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
cancelTimestampis not null and is less than the currentblock.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.priceandorder.amount. The result can be rounded down to zero iforder.amount * order.priceis less thanconfig.baseSize.What happens if it reverts, reenters or does other unusual control flow? Can revert as a result of overflow during
order.amount * order.pricecalculation iforder.priceororder.amountis 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
quoteTokenAmountwill be saved for the owner of the expired order in theTransientMakerDatamemory.
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.quoteTokenOpenInterestandmetadata.baseTokenOpenInterestwill be decremented — depends on the side of the order, andorder.idwill be deleted from theorderslist. Also,bidTreeandaskTreewill be updated in addition toorders.nextOrderIdandorders.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
baseRefundedamount. 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.quoteTokenOpenInterestandmetadata.baseTokenOpenInterestwill be decremented — depends on the side of the order, andorder.idwill be deleted from theorderslist. Also,bidTreeandaskTreewill be updated in addition toorders.nextOrderIdandorders.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?
newOrderis 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
baseTokenOpenInterestwith the order amount since the side isSELL.