CanonicCanonic Docs
Documentation

Docs

MAOB

Midpoint Anchored Order Book (MAOB) Midpoint anchored order book with discrete bps rungs around an oracle midprice. Source: contracts/contracts/MAOB.sol Route: /reference/maob

Public state (getters)

  • FEE_DENOM()
  • MAX_RUNGS()
  • MAX_TAKER_FEE_BPS()
  • PRICE_SIGFIGS()
  • RUNG_DENOM()
  • UNWIND_DURATION()
  • baseDecimals()
  • baseScale()
  • baseToken()
  • feeCollector()
  • lastOrderId()
  • minQuoteMaker()
  • minQuoteTaker()
  • oracle()
  • pauseGuardian()
  • quoteDecimals()
  • quoteScale()
  • quoteToken()
  • stateExpiresAt()
  • takerFee()

Maker actions

  • addLiquidityBatch(LiquidityOrder[] calldata liquidityOrders) external nonReentrant returns (uint256[] memory orderIds)
  • addLiquidityBid(uint16 rung, uint256 quoteAmount) external nonReentrant returns (uint256 orderId)
  • cancelOrder(uint256 orderId, bool withdrawAfter) external nonReentrant returns (uint256 refundBase, uint256 refundQuote)
  • claimAndRequote(uint256[] calldata orderIds, LiquidityOrder[] calldata liquidityOrders) external nonReentrant returns (uint256 baseClaimed, uint256 quoteClaimed, uint256[] memory newOrderIds)
  • claimOrders(uint256[] calldata orderIds, bool withdrawAfter) external nonReentrant returns (uint256 baseClaimed, uint256 quoteClaimed)
  • claimOrders(uint256[] calldata orderIds) external nonReentrant returns (uint256 baseClaimed, uint256 quoteClaimed)
  • requoteFromWithdrawable(LiquidityOrder[] calldata liquidityOrders) external nonReentrant returns (uint256[] memory orderIds)
  • withdraw() external nonReentrant returns (uint256 baseOut, uint256 quoteOut)

Taker actions

  • buyBaseExactOut(uint256 baseAmount, uint256 maxQuoteIn, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 quoteUsed, uint256 baseFeePaid)
  • buyBaseExactOut(uint256 baseAmount, uint256 maxQuoteIn, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 quoteUsed, uint256 baseFeePaid)
  • buyBaseTargetIn(uint256 quoteIn, uint256 minBaseOut, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 baseOut, uint256 baseFeePaid)
  • buyBaseTargetIn(uint256 quoteIn, uint256 minBaseOut, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 baseOut, uint256 baseFeePaid)
  • sellBaseExactOut(uint256 quoteOut, uint256 maxBaseIn, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 baseUsed, uint256 quoteFeePaid)
  • sellBaseExactOut(uint256 quoteOut, uint256 maxBaseIn, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 baseUsed, uint256 quoteFeePaid)
  • sellBaseTargetIn(uint256 baseAmount, uint256 minQuoteOut, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 quoteOut, uint256 quoteFeePaid)
  • sellBaseTargetIn(uint256 baseAmount, uint256 minQuoteOut, uint64 deadline, uint256 minQuotePerRung) external nonReentrant returns (uint256 quoteOut, uint256 quoteFeePaid)

Admin actions

  • setFeeCollector(address newCollector) external onlyOwner
  • setMarketState(MarketState newState, string calldata reason) external
  • setMinQuoteMaker(uint256 newMinQuote) external onlyOwner
  • setMinQuoteTaker(uint256 newMinQuote) external onlyOwner
  • setPauseGuardian(address newGuardian) external onlyOwner

Views

  • getDepth(uint16 maxPerSide) external view returns ( uint16[] memory askRungBps, uint256[] memory askVolumesInBase, uint16[] memory bidRungBps, uint256[] memory bidVolumesInQuote )
  • getLastSegment(uint16 rung, bool isAsk) external view returns (uint256 priceQ, uint256 denom, uint256 remainder)
  • getMidPrice() external view returns (uint256 price, uint256 precision, uint48 updatedAt)
  • getRungs() external view returns (uint16[] memory)
  • getRungState(uint16 rung) external view returns ( uint256 askVolume, uint256 bidVolume, uint32 askGeneration, uint32 bidGeneration, uint256 askCumulative, uint256 bidCumulative )
  • previewOrder(uint256 orderId) external view returns (uint256 unfilledInput, uint256 claimableOutput)
  • rungCount() external view returns (uint256)

Other

  • _buyBaseExactOut(uint256 baseAmount, uint256 maxQuoteIn, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung ) internal returns (uint256 quoteUsed, uint256 baseFeePaid) { _checkTakerNotPaused(); if (baseAmount == 0 || maxQuoteIn == 0) revert MAOB__InvalidAmount(); _checkDeadline(deadline); _requireRung(maxRung); (uint256 midPrice, uint256 precision) = _getMidPrice(); uint256 denom = precision * baseScale; uint256 priceQ = _roundPriceQ(midPrice * quoteScale); uint256 quoteAtMid = Math.mulDiv(baseAmount, priceQ, denom); _checkMinQuoteTaker(quoteAtMid); uint256 totalQuoteUsed = _fillAsks(baseAmount, maxQuoteIn, maxRung, midPrice, denom, msg.sender, minQuotePerRung); if (totalQuoteUsed != 0) { quoteToken.safeTransferFromExact(msg.sender, address(this), totalQuoteUsed); } baseFeePaid = Math.mulDiv(baseAmount, takerFee, FEE_DENOM, Math.Rounding.Ceil); uint256 baseOut = baseAmount - baseFeePaid; baseToken.safeTransfer(msg.sender, baseOut); if (baseFeePaid != 0) { baseToken.safeTransfer(feeCollector, baseFeePaid); } return (totalQuoteUsed, baseFeePaid); } function _buyBaseTargetIn( uint256 quoteIn, uint256 minBaseOut, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung ) internal returns (uint256 baseOut, uint256 baseFeePaid) { _checkTakerNotPaused(); if (quoteIn == 0) revert MAOB__InvalidAmount(); _checkMinQuoteTaker(quoteIn); _checkDeadline(deadline); _requireRung(maxRung); (uint256 midPrice, uint256 precision) = _getMidPrice(); uint256 denom = precision * baseScale; (uint256 baseAcquired, uint256 quoteUsed) = _fillAsksByQuote(quoteIn, maxRung, midPrice, denom, msg.sender, minQuotePerRung); if (baseAcquired == 0) revert MAOB__InsufficientLiquidity(); if (quoteUsed != 0) { quoteToken.safeTransferFromExact(msg.sender, address(this), quoteUsed); } baseFeePaid = Math.mulDiv(baseAcquired, takerFee, FEE_DENOM, Math.Rounding.Ceil); baseOut = baseAcquired - baseFeePaid; if (baseOut < minBaseOut) revert MAOB__MinBaseNotMet(); baseToken.safeTransfer(msg.sender, baseOut); if (baseFeePaid != 0) { baseToken.safeTransfer(feeCollector, baseFeePaid); } return (baseOut, baseFeePaid); } function _sellBaseTargetIn( uint256 baseAmount, uint256 minQuoteOut, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung ) internal returns (uint256 quoteOut, uint256 quoteFeePaid) { _checkTakerNotPaused(); if (baseAmount == 0) revert MAOB__InvalidAmount(); _checkDeadline(deadline); _requireRung(maxRung); (uint256 midPrice, uint256 precision) = _getMidPrice(); uint256 denom = precision * baseScale; uint256 priceQ = _roundPriceQ(midPrice * quoteScale); uint256 quoteAtMid = Math.mulDiv(baseAmount, priceQ, denom); _checkMinQuoteTaker(quoteAtMid); (uint256 totalQuoteOut, uint256 baseUsed) = _fillBids(baseAmount, maxRung, midPrice, denom, minQuotePerRung); if (totalQuoteOut == 0) revert MAOB__InsufficientLiquidity(); if (baseUsed != 0) { baseToken.safeTransferFromExact(msg.sender, address(this), baseUsed); } quoteFeePaid = Math.mulDiv(totalQuoteOut, takerFee, FEE_DENOM, Math.Rounding.Ceil); quoteOut = totalQuoteOut - quoteFeePaid; if (quoteOut < minQuoteOut) revert MAOB__MinQuoteNotMet(); quoteToken.safeTransfer(msg.sender, quoteOut); if (quoteFeePaid != 0) { quoteToken.safeTransfer(feeCollector, quoteFeePaid); } return (quoteOut, quoteFeePaid); } function _sellBaseExactOut( uint256 quoteOut, uint256 maxBaseIn, uint16 maxRung, uint64 deadline, uint256 minQuotePerRung ) internal returns (uint256 baseUsed, uint256 quoteFeePaid) { _checkTakerNotPaused(); if (quoteOut == 0 || maxBaseIn == 0) revert MAOB__InvalidAmount(); _checkMinQuoteTaker(quoteOut); _checkDeadline(deadline); _requireRung(maxRung); (uint256 midPrice, uint256 precision) = _getMidPrice(); uint256 denom = precision * baseScale; (uint256 grossQuote,) = _grossQuoteForNet(quoteOut); uint256 quoteFilled; (baseUsed, quoteFilled) = _fillBidsByQuote(grossQuote, maxRung, midPrice, denom, maxBaseIn, minQuotePerRung); if (baseUsed != 0) { baseToken.safeTransferFromExact(msg.sender, address(this), baseUsed); } quoteFeePaid = Math.mulDiv(quoteFilled, takerFee, FEE_DENOM, Math.Rounding.Ceil); uint256 netQuote = quoteFilled - quoteFeePaid; if (netQuote < quoteOut) revert MAOB__MinQuoteNotMet(); quoteToken.safeTransfer(msg.sender, netQuote); if (quoteFeePaid != 0) { quoteToken.safeTransfer(feeCollector, quoteFeePaid); } return (baseUsed, quoteFeePaid); } // ============================================================= // ADMIN ACTIONS // ============================================================= /// @notice Update the taker fee. /// @param newFee New fee in 1e6 units (0.01 bps increments). function setTakerFee(uint32 newFee) external onlyOwner
  • _requireOwner() internal view { if (msg.sender != owner()) revert MAOB__NotOwner(); } // ============================================================= // MAKER ACTIONS // ============================================================= /// @notice Post base liquidity as an ask in a single rung. /// @param rung Rung index (0-based). /// @param baseAmount Base token amount to deposit. /// @return orderId Newly created order id. function addLiquidityAsk(uint16 rung, uint256 baseAmount) external nonReentrant returns (uint256 orderId)

Events

  • FeeCollectorUpdated(address indexed oldCollector, address indexed newCollector)
  • MarketStateChanged(MarketState newState, uint256 expiresAt, string reason)
  • MinQuoteMakerUpdated(uint256 oldMinQuote, uint256 newMinQuote)
  • MinQuoteTakerUpdated(uint256 oldMinQuote, uint256 newMinQuote)
  • OrderCancelled(address indexed maker, uint256 indexed orderId, bool indexed isAsk, uint16 rung, uint256 remainingInput, uint256 refundBase, uint256 refundQuote)
  • OrderClaimed(address indexed maker, uint256 indexed orderId, uint256 inputClaimed, uint256 outputClaimed)
  • OrderCreated(address indexed maker, bool indexed isAsk, uint16 indexed rung, uint256 orderId, uint256 amount)
  • PauseGuardianUpdated(address indexed oldGuardian, address indexed newGuardian)
  • RungFilled(address indexed taker, bool indexed isBuy, uint16 indexed rung, uint256 baseAmount, uint256 quoteAmount, uint256 priceE18)
  • TakerFeeUpdated(uint32 oldFee, uint32 newFee)
  • Withdrawn(address indexed user, uint256 baseAmount, uint256 quoteAmount)

Errors

  • MAOB__InsufficientLiquidity()
  • MAOB__InsufficientWithdrawable()
  • MAOB__InvalidAmount()
  • MAOB__InvalidDeadline()
  • MAOB__InvalidDecimals()
  • MAOB__InvalidFee()
  • MAOB__InvalidMarketState()
  • MAOB__InvalidMinQuote()
  • MAOB__InvalidRung()
  • MAOB__InvalidRungs()
  • MAOB__MakerPaused()
  • MAOB__MaxBaseExceeded()
  • MAOB__MaxQuoteExceeded()
  • MAOB__MinBaseNotMet()
  • MAOB__MinQuoteNotMet()
  • MAOB__NotGuardian()
  • MAOB__NotOrderOwner()
  • MAOB__NotOwner()
  • MAOB__NotOwnerOrGuardian()
  • MAOB__OracleOutOfRange()
  • MAOB__OraclePriceMissing()
  • MAOB__OracleStale()
  • MAOB__OrderNotActive()
  • MAOB__QueueOverflow()
  • MAOB__QuoteAmountTooLow()
  • MAOB__SameToken()
  • MAOB__TakerPaused()
  • MAOB__ZeroAddress()