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 theaccount
.Impact: The account on whose behalf the order is being filled.
args
Control: Full control.
Constraints: The
cancelTimestamp
should be more than theblock.timestamp
. TheamountInBaseLots
should 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
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
oroperator
of the account.cancelTimestamp < block.timestamp
.price % tickSize != 0
.args.price == 0
.If there is a
BUY
order andsettlement
isACCOUNT
— the quote internal-account balance in CLOBManager is insufficient.If there is a
SELL
order andsettlement
isACCOUNT
— the base internal-account balance in CLOBManager is insufficient.If there is a
BUY
order andsettlement
isINSTANT
— the quote account balance is insufficient.If there is a
SELL
order andsettlement
isINSTANT
— 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 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
amountInBase
is 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
maxLimitsPerTx
or 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
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 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
totalQuoteTokenSent
and zerototalBaseTokenReceived
.What happens if it reverts, reenters or does other unusual control flow? Reverts if only one of
totalQuoteTokenSent
ortotalBaseTokenReceived
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 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
baseAmount
will be saved for the owner of the expired order in theTransientMakerData
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
andmetadata.baseTokenOpenInterest
will be decremented — depends on the side of the order, andorder.id
will be deleted from theorders
list. Also,bidTree
andaskTree
will be updated in addition toorders.nextOrderId
andorders.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
andincomingOrder.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 thanmatchedBase
, thematchData.baseDelta
will be equal to theincomingOrder.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
andmatchData.baseDelta
amount. The result can be rounded down to zero ifmatchData.baseDelta * matchedPrice
is 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 * matchedPrice
calculation ifmatchedPrice
ormatchData.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 thegetBaseTokenAmount
function execution, which calculates the base-token amount using the provided-by-the-callerincomingOrder.amount
and 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.amount
and thematchedPrice
. Can return zero ifquoteAmount * self.config.baseSize
is 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.baseSize
calculation ifquoteAmount
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
andmatchData.baseDelta
amount. The result can be rounded down to zero ifmatchData.baseDelta * matchedPrice
is 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 * matchedPrice
calculation ifmatchedPrice
ormatchData.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 theTransientMakerData
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 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.baseDelta
will be saved for the owner of the matched order in theTransientMakerData
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
andmetadata.baseTokenOpenInterest
will be decremented — depends on the side of the order, andorder.id
will be deleted from theorders
list. Also,bidTree
andaskTree
will be updated in addition toorders.nextOrderId
andorders.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
andmetadata.baseTokenOpenInterest
will be decremented — depends on the side of the order, andorder.id
will be deleted from theorders
list. Also,bidTree
andaskTree
will be updated in addition toorders.nextOrderId
andorders.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 isBUY
.
this._processLimitBidOrder(ds, account, newOrder, args) -> this._executeBidLimitOrder(ds, newOrder, args.limitOrderType) -> ds.getQuoteTokenAmount(newOrder.price, newOrder.amount);
What is controllable?
newOrder.price
andnewOrder.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
andmatchData.baseDelta
amount. The result can be rounded down to zero ifmatchData.baseDelta * matchedPrice
is 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 * matchedPrice
calculation ifmatchedPrice
ormatchData.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 returnedPostFillOrderResult
.What happens if it reverts, reenters or does other unusual control flow? If
settlement
is set toINSTANT
, the function might revert duringsafeTransferFrom
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. Ifsettlement
is set toACCOUNT
, the function might revert during thedebitAccount
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 andbaseToken
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 orderprice
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 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.price
andorder.amount
. The result can be rounded down to zero iforder.amount * order.price
is 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.price
calculation iforder.price
ororder.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 theTransientMakerData
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
andmetadata.baseTokenOpenInterest
will be decremented — depends on the side of the order, andorder.id
will be deleted from theorders
list. Also,bidTree
andaskTree
will be updated in addition toorders.nextOrderId
andorders.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
andmetadata.baseTokenOpenInterest
will be decremented — depends on the side of the order, andorder.id
will be deleted from theorders
list. Also,bidTree
andaskTree
will be updated in addition toorders.nextOrderId
andorders.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 isSELL
.