AsyncFiller
Title: AsyncFiller
Author: @msakiart
Stores open async orders and settles fills against them.
Authorization model: the maker authorizes a Router/executor at order-creation time
(setExecutor[owner][executor] = true). All subsequent fill / cancel / updatePrice
calls on the hook must come from that registered executor. The hook forwards its
immediate caller (msg.sender) and the resolved end-actor address (filler / canceller)
into this library; the executor is checked here, and PM settlement targets the actor.
Constants
MAX_PRIORITY_FEE
uint64 internal constant MAX_PRIORITY_FEE = type(uint64).max;MIN_PRIORITY_FEE
Default $0.10 cap for six-decimal numeraires. A pool may override this for other decimals.
uint64 internal constant MIN_PRIORITY_FEE = 100_000;PRIORITY_FEE_BPS
Below a $100 order the least bid is 10 bps of the order instead: min($0.10, 0.1% of it).
uint256 internal constant PRIORITY_FEE_BPS = 10;TRADE_FEE_BPS
Protocol fee on what each side of a book match or filler fill receives: 0.02%.
uint256 internal constant TRADE_FEE_BPS = 2;Functions
addOrder
function addOrder(
State storage self,
Book storage book,
bytes32 id,
address owner,
uint256 amountIn,
uint256 amountOutMin,
bool isBuy,
bool zeroForOne,
uint256 priorityFee
) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| id | bytes32 | |
| owner | address | |
| amountIn | uint256 | |
| amountOutMin | uint256 | |
| isBuy | bool | |
| zeroForOne | bool | |
| priorityFee | uint256 |
tradeFee
The protocol's 0.02% of a payment, rounded up. Each side of a trade receives its
proceeds less this fee, so a maker receives at least amountOutMin minus 0.02%.
function tradeFee(uint256 amount) internal pure returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| amount | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
minPriorityFee
The least bid for an order worth notional numeraire units: $0.10, or 0.1% of the
order when that is less (orders under $100).
function minPriorityFee(uint256 notional) internal pure returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| notional | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
minPriorityFee
function minPriorityFee(uint256 notional, uint64 cap) internal pure returns (uint256);Parameters
| Name | Type | Description |
|---|---|---|
| notional | uint256 | |
| cap | uint64 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint256 |
checkMinimum
Reverts unless the order's numeraire leg is at least the pool's minimum (a buy's input, a sell's minimum output) and its asset leg at least the pool's asset floor (a sell's input, a buy's minimum output). Neither reads the pool price, which whoever initializes the pool sets.
function checkMinimum(Book storage book, bool isBuy, uint256 amountIn, uint256 amountOutMin) internal view;Parameters
| Name | Type | Description |
|---|---|---|
| book | Book | |
| isBuy | bool | |
| amountIn | uint256 | |
| amountOutMin | uint256 |
settlePriorityFee
function settlePriorityFee(
State storage self,
PoolKey memory key,
bytes32 id,
address maker,
uint256 amount,
address hook
) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| key | PoolKey | |
| id | bytes32 | |
| maker | address | |
| amount | uint256 | |
| hook | address |
bestOrder
function bestOrder(State storage self, Book storage book, bool isBuy)
internal
view
returns (bool found, uint128 price, bytes32 orderId, address owner);Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| isBuy | bool |
Returns
| Name | Type | Description |
|---|---|---|
| found | bool | |
| price | uint128 | |
| orderId | bytes32 | |
| owner | address |
level
function level(Book storage book, bool isBuy, uint128 price)
internal
view
returns (bytes32 head, bytes32 tail, uint32 orderCount);Parameters
| Name | Type | Description |
|---|---|---|
| book | Book | |
| isBuy | bool | |
| price | uint128 |
Returns
| Name | Type | Description |
|---|---|---|
| head | bytes32 | |
| tail | bytes32 | |
| orderCount | uint32 |
bestAtPrice
function bestAtPrice(Book storage book, bool isBuy, uint128 price) internal view returns (bytes32 id);Parameters
| Name | Type | Description |
|---|---|---|
| book | Book | |
| isBuy | bool | |
| price | uint128 |
Returns
| Name | Type | Description |
|---|---|---|
| id | bytes32 |
updatePrice
Maker-only price update: caller must equal order.owner (the maker directly, or the
owner whose signature updatePriceWithSig verified). No executor is involved.
function updatePrice(
State storage self,
Book storage book,
AsyncOrder memory order,
bytes32 id,
uint256 newAmountOutMin,
address caller
) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| order | AsyncOrder | |
| id | bytes32 | |
| newAmountOutMin | uint256 | |
| caller | address |
fill
Full-fill. The caller (the hook contract) must be an authorized executor of the
order owner; filler is the actual end-user paying the output and receiving the
input. Must be invoked from inside an IPoolManager.unlock context.
Settle gross output (native only; ERC20 is pre-settled), pay the signed minimum less the trade fee to the maker, and mint fee claims to the vault. Burn input claims and pay the input less the trade fee to the filler. Both currency deltas net to zero. A failed fill reverts all legs.
function fill(
State storage self,
Book storage book,
AsyncOrder memory order,
bytes32 id,
address hook,
address executor,
address filler,
address feeVault,
uint256 fee
) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| order | AsyncOrder | |
| id | bytes32 | |
| hook | address | |
| executor | address | |
| filler | address | |
| feeVault | address | |
| fee | uint256 |
_payFiller
Burn the order's input claims and pay the filler all but the trade fee, which goes to the vault.
function _payFiller(
State storage self,
Currency input,
address hook,
address filler,
address feeVault,
uint256 amountIn
) private returns (uint256 tradeFeeIn);Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| input | Currency | |
| hook | address | |
| filler | address | |
| feeVault | address | |
| amountIn | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| tradeFeeIn | uint256 |
_closeOrder
Remove and delete an order, then settle its bid.
function _closeOrder(State storage self, Book storage book, PoolKey memory key, bytes32 id, address hook) private;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| key | PoolKey | |
| id | bytes32 | |
| hook | address |
settleOrderPriorityFee
function settleOrderPriorityFee(State storage self, PoolKey memory key, bytes32 id, address hook) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| key | PoolKey | |
| id | bytes32 | |
| hook | address |
cancel
Cancel an unfilled order. Must be called inside an unlock context. Auth: executor
must be either the order owner themselves (smart-contract makers calling the hook
directly from their own unlock) or an executor the maker authorised via
setExecutor. Funds always return to order.owner.
function cancel(
State storage self,
Book storage book,
AsyncOrder memory order,
bytes32 id,
address hook,
address executor
) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| order | AsyncOrder | |
| id | bytes32 | |
| hook | address | |
| executor | address |
_append
function _append(State storage self, Book storage book, bytes32 id) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| id | bytes32 |
_remove
function _remove(State storage self, Book storage book, bytes32 id) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| id | bytes32 |
_priorityKey
function _priorityKey(uint64 priorityFee, uint64 sequence) private pure returns (uint128);Parameters
| Name | Type | Description |
|---|---|---|
| priorityFee | uint64 | |
| sequence | uint64 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint128 |
refreshExactPrice
Refresh even when a partial fill changes neither the price key nor remaining bid.
function refreshExactPrice(State storage self, Book storage book, bytes32 id) internal;Parameters
| Name | Type | Description |
|---|---|---|
| self | State | |
| book | Book | |
| id | bytes32 |
exactPrice
function exactPrice(OrderInfo storage order) internal view returns (EligiblePrice.Ratio memory);Parameters
| Name | Type | Description |
|---|---|---|
| order | OrderInfo |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | EligiblePrice.Ratio |
eligibleAtPrice
function eligibleAtPrice(Book storage book, bool isBuy, uint128 price, EligiblePrice.Ratio memory limit)
internal
view
returns (bytes32);Parameters
| Name | Type | Description |
|---|---|---|
| book | Book | |
| isBuy | bool | |
| price | uint128 | |
| limit | EligiblePrice.Ratio |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | bytes32 |
mostPermissiveAtPrice
function mostPermissiveAtPrice(Book storage book, bool isBuy, uint128 price)
internal
view
returns (EligiblePrice.Ratio memory);Parameters
| Name | Type | Description |
|---|---|---|
| book | Book | |
| isBuy | bool | |
| price | uint128 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | EligiblePrice.Ratio |
_priceKey
The order's book level: the v4 tick of its exact limit, ordered by numeraire per asset
(see TickPrice.key). The exact limit is kept on the order and decides crossing.
function _priceKey(bool isBuy, bool zeroForOne, uint256 amountIn, uint256 amountOut)
internal
pure
returns (uint128);Parameters
| Name | Type | Description |
|---|---|---|
| isBuy | bool | |
| zeroForOne | bool | |
| amountIn | uint256 | |
| amountOut | uint256 |
Returns
| Name | Type | Description |
|---|---|---|
| <none> | uint128 |
Events
AsyncOrderCreated
event AsyncOrderCreated(
PoolId indexed poolId,
bytes32 indexed orderId,
address indexed owner,
bool zeroForOne,
uint256 amountIn,
uint256 amountOutMin,
bytes32 salt
);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| owner | address | |
| zeroForOne | bool | |
| amountIn | uint256 | |
| amountOutMin | uint256 | |
| salt | bytes32 |
AsyncOrderPriceUpdated
event AsyncOrderPriceUpdated(
PoolId indexed poolId, bytes32 indexed orderId, uint256 oldAmountOutMin, uint256 newAmountOutMin
);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| oldAmountOutMin | uint256 | |
| newAmountOutMin | uint256 |
AsyncOrderFilled
event AsyncOrderFilled(
PoolId indexed poolId, bytes32 indexed orderId, address indexed filler, uint256 amountIn, uint256 amountOutMin
);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| filler | address | |
| amountIn | uint256 | |
| amountOutMin | uint256 |
AsyncOrderCancelled
event AsyncOrderCancelled(PoolId indexed poolId, bytes32 indexed orderId, address indexed owner, uint256 amountIn);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| owner | address | |
| amountIn | uint256 |
OrderFeeAccrued
event OrderFeeAccrued(PoolId indexed poolId, bytes32 indexed orderId, Currency indexed currency, uint256 amount);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| currency | Currency | |
| amount | uint256 |
PriorityFeeDonated
event PriorityFeeDonated(PoolId indexed poolId, bytes32 indexed orderId, address indexed maker, uint256 amount);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| maker | address | |
| amount | uint256 |
PriorityFeeForfeited
event PriorityFeeForfeited(PoolId indexed poolId, bytes32 indexed orderId, address indexed maker, uint256 amount);Parameters
| Name | Type | Description |
|---|---|---|
| poolId | PoolId | |
| orderId | bytes32 | |
| maker | address | |
| amount | uint256 |
Errors
OrderAlreadyExists
error OrderAlreadyExists();OrderNotFound
error OrderNotFound();NotOrderOwner
error NotOrderOwner();NotAuthorizedExecutor
error NotAuthorizedExecutor();ZeroAmount
error ZeroAmount();PriorityFeeTooLarge
error PriorityFeeTooLarge();PriorityFeeTooSmall
error PriorityFeeTooSmall();BelowMinimumOrder
error BelowMinimumOrder();BelowMinimumAssetAmount
error BelowMinimumAssetAmount();Structs
OrderInfo
Open-order record. Filler fills are full-order; direct matches can reduce it partially while keeping the remaining input in escrow.
struct OrderInfo {
address owner;
uint256 amountIn;
uint256 amountOutMin;
uint128 price;
bool isBuy;
bool zeroForOne;
uint64 sequence;
/// @dev Maker reprices so far; signed reprices commit to it (`OrderSignatures.hashUpdatePrice`).
uint32 reprices;
/// @dev The bid, escrowed as hook claims since the order was created.
uint64 priorityFee;
uint128 priorityKey;
/// @dev Immutable settlement age; repricing only resets queue sequence.
uint64 createdSequence;
}Properties
| Name | Type | Description |
|---|---|---|
| owner | address | |
| amountIn | uint256 | |
| amountOutMin | uint256 | |
| price | uint128 | |
| isBuy | bool | |
| zeroForOne | bool | |
| sequence | uint64 | |
| reprices | uint32 | |
| priorityFee | uint64 | |
| priorityKey | uint128 | |
| createdSequence | uint64 |
PriceLevel
Orders at one price, highest bid first, then earliest.
struct PriceLevel {
uint32 orderCount;
RadixPriceTree.Tree priorityOrders;
mapping(uint128 priorityKey => bytes32 orderId) priorityOrderIds;
mapping(uint32 nodeId => EligiblePrice.Ratio) exactBounds;
}Properties
| Name | Type | Description |
|---|---|---|
| orderCount | uint32 | |
| priorityOrders | RadixPriceTree.Tree | |
| priorityOrderIds | mapping(uint128 priorityKey => bytes32 orderId) | |
| exactBounds | mapping(uint32 nodeId => EligiblePrice.Ratio) |
MatchAmounts
struct MatchAmounts {
uint256 assetAmount;
uint256 quoteAmount;
}Properties
| Name | Type | Description |
|---|---|---|
| assetAmount | uint256 | |
| quoteAmount | uint256 |
NewOrder
struct NewOrder {
bytes32 id;
address owner;
uint256 amountIn;
uint256 amountOutMin;
bool isBuy;
bool zeroForOne;
uint256 priorityFee;
PoolId poolId;
}Properties
| Name | Type | Description |
|---|---|---|
| id | bytes32 | |
| owner | address | |
| amountIn | uint256 | |
| amountOutMin | uint256 | |
| isBuy | bool | |
| zeroForOne | bool | |
| priorityFee | uint256 | |
| poolId | PoolId |
State
struct State {
IPoolManager poolManager;
Currency numeraire;
address feeVault;
mapping(bytes32 orderId => OrderInfo) orders;
mapping(address owner => mapping(address executor => bool)) isExecutor;
/// @dev Pool tick before the first pool fill of the current backrun window, and that fill's block.
int24 refTick;
uint64 refBlock;
}Properties
| Name | Type | Description |
|---|---|---|
| poolManager | IPoolManager | |
| numeraire | Currency | |
| feeVault | address | |
| orders | mapping(bytes32 orderId => OrderInfo) | |
| isExecutor | mapping(address owner => mapping(address executor => bool)) | |
| refTick | int24 | |
| refBlock | uint64 |
Book
struct Book {
uint64 nextSequence;
uint64 openOrderCount;
/// @dev $0.10 in this pool's numeraire base units. Zero uses the six-decimal default.
uint64 priorityFeeCap;
TickBitmap.Tree bids;
TickBitmap.Tree asks;
mapping(uint128 price => PriceLevel) bidLevels;
mapping(uint128 price => PriceLevel) askLevels;
/// @dev Least order size in numeraire base units (0: none); see `checkMinimum`.
uint256 minOrder;
/// @dev Least asset amount an order may trade, from the asset's decimals and the hook's precision.
uint256 minAssetAmount;
}Properties
| Name | Type | Description |
|---|---|---|
| nextSequence | uint64 | |
| openOrderCount | uint64 | |
| priorityFeeCap | uint64 | |
| bids | TickBitmap.Tree | |
| asks | TickBitmap.Tree | |
| bidLevels | mapping(uint128 price => PriceLevel) | |
| askLevels | mapping(uint128 price => PriceLevel) | |
| minOrder | uint256 | |
| minAssetAmount | uint256 |