Function: postFillOrder(address account, PostFillOrderArgs args)
This function allows to fill a 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 with existing orders. It provides the execution result to the CLOBManager contract for token settlement and applies fees. The postFillOrder
function reverts if the type of the order is FILL_OR_KILL
and the order was not fully filled during matching. If the fillOrderType
is IMMEDIATE_OR_CANCEL
, the order may be partially filled.
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:
args.priceLimit % tickSize == 0 && args.priceLimit != 0
.Impact: Contains
amount
,priceLimit
,side
,amountIsBase
,fillOrderType
, andsettlement
.
Branches and code coverage
Intended branches
The order type is
FILL_OR_KILL
, the order was fully filled, and theargs.amountIsBase
istrue
.The order type is
FILL_OR_KILL
, the order was fully filled, and theargs.amountIsBase
isfalse
.The order type is
IMMEDIATE_OR_CANCEL
, the order was partly filled, and theargs.amountIsBase
istrue
.The order type is
IMMEDIATE_OR_CANCEL
, the order was partly filled, and theargs.amountIsBase
isfalse
.The order type is
IMMEDIATE_OR_CANCEL
, the order was fully filled, and theargs.amountIsBase
istrue
.The order type is
IMMEDIATE_OR_CANCEL
, the order was fully filled, and theargs.amountIsBase
isfalse
.The
takerFee
is equal to the expected amount.The multiple expired orders have been closed and fee was not charged from them.
There were multiple matches, and the maker fee is equal to the expected amount.
Negative behavior
The order type is
FILL_OR_KILL
, the order was not fully filled, and theargs.amountIsBase
istrue
.The order type is
FILL_OR_KILL
, the order was not fully filled, and theargs.amountIsBase
isfalse
.The caller is not an
account
oroperator
of the account.
Function call analysis
BookLib.assertLimitPriceInBounds(ds, args.priceLimit)
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.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.amount
, andargs.price
.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.
this._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._matchIncomingBid(ds, newOrder, args.amountIsBase) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._settleIncomingOrder(ds, account, Side.BUY, args.settlement, result.totalQuoteTokenSent, result.totalBaseTokenReceived) -> 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._processFillBidOrder(ds, account, newOrder, args) -> this._settleIncomingOrder(ds, account, Side.BUY, args.settlement, result.totalQuoteTokenSent, result.totalBaseTokenReceived) -> factory.settleIncomingOrder(settleParams)
What is controllable?
settleParams.taker
,settleParams.side
, andsettleParams.settlement
are 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._processFillAskOrder(ds, account, newOrder, args) -> this._matchIncomingAsk(ds, newOrder, args.amountIsBase) -> 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._processFillAskOrder(ds, account, newOrder, args) -> this._matchIncomingAsk(ds, newOrder, args.amountIsBase) -> 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._processFillAskOrder(ds, account, newOrder, args) -> this._matchIncomingAsk(ds, newOrder, args.amountIsBase) -> 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._processFillAskOrder(ds, account, newOrder, args) -> this._matchIncomingAsk(ds, newOrder, args.amountIsBase) -> 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? There are no problems here.
this._processFillAskOrder(ds, account, newOrder, args) -> this._matchIncomingAsk(ds, newOrder, args.amountIsBase) -> 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
.