Documentation

ExitQueue is a non-custodial exit queue for holders of locked Moonwell markets on Base. Each supported market has its own immutable contract; they all work the same way. This page explains exactly what the contracts do.

Overview

Several Moonwell markets on Base have almost no free cash: suppliers can withdraw only when someone deposits or repays a loan in that market, and bots race for every such inflow. ExitQueue lets holders of a market's mToken line up for that cash and choose the discount they are willing to give for exiting earlier. The discount is the service fee. Payouts, rebates and fees are always in the market's underlying token (USDC for mUSDC, cbBTC for mcbBTC, and so on).

Supported markets

One contract per market. All contracts share the same code and rules; only the market and the minimum order differ.

MarketUnderlyingExitQueue contractMin order

The minimum order is about $100 worth of the underlying token, fixed in token units when the contract was deployed. Its dollar value moves with the token price.

How the queue works

  • Join: on the market's page, approve the mToken amount you want to exit and call join(amount, discount). Your tokens stay in your wallet.
  • Discount: from 1% to 99.9% in 0.1% steps.
  • Order: the highest discount is filled first; within the same discount — first come, first served. Changing your order (amount or discount) moves you to the end of your discount level.
  • Fill: when cash arrives in the market, anyone can call fill() on that market's contract. In one transaction it takes mTokens from the queue in order, redeems them on Moonwell and pays each holder in the underlying token.
  • Partial fills: if cash covers only part of an order, the holder receives that part and the rest stays first in line.
  • Leave: call leave() or simply revoke the approval. The app does both: it leaves the queue and then sets your mToken approval back to 0.
  • Several markets: queues are independent. You can hold one order in each market; the My orders page shows them all.

Payout

payout = underlying tokens actually received for your mTokens × (1 − your discount). It is computed from the real redeem result in the same transaction. The contract never takes more than the minimum of your queued amount, your approval and your balance. Either you are paid in the same transaction, or nothing is taken from you.

Dropped vs. skipped orders

  • Dropped (removed from the queue, nothing taken): approval or balance became zero, tokens can't move (e.g. used as borrow collateral on Moonwell), the order is worth less than one smallest unit of the underlying token.
  • Skipped (keeps its place): when gas is expensive, a fully backed order whose fee doesn't cover its share of gas is skipped in the deposit race. It is filled later via loan repayments or when gas is cheaper.
  • Transfers paused by Moonwell: holders are skipped and keep their place.

Gas and the deposit race

In some markets deposits are contested by other bots that bid priority fees; in others there is little or no competition. We fill an order in a race only if its fee covers it. The market page shows, for your amount, the minimum discount that currently qualifies in that market. Orders below it still get filled via loan repayments (no race) or when competition calms down.

Repay with rebate

On the Repay page you connect your wallet and see your Moonwell position across all markets. A loan in any supported market can be repaid through repayAndFill(): the repayment goes straight to that market's queue in the same transaction, so nobody can take that cash in between. You receive 0.2% of the part of the fill funded by your repayment, in the market's underlying token (cash that was already free on the market does not count). You set a maximum amount; the contract repays at most your actual debt.

Security

  • No owner, no admin functions, no pause, no upgradeability. All parameters are fixed at deployment.
  • Fees always go to a fixed address; whoever calls fill() gets nothing — the queues work even if the operator disappears.
  • If a payout can't be sent (for example, a USDC or EURC address blacklisted by Circle), it is kept in the contract and can be claimed later with claim(); nobody else is blocked.
  • Reviewed twice (internal review and an independent adversarial review); unit, fuzz and fork tests against all five live Moonwell markets. An external professional audit has not been done yet.

Risks

  • Approval: you grant the contract the right to move the approved mTokens. Approve only the amount you want to exit.
  • Different speed per market: each queue moves only when cash arrives in its market. Inflows differ a lot between markets; in some, waiting can be long.
  • Token prices: payouts are in the underlying token. For volatile tokens (cbBTC, VIRTUAL, MORPHO) the dollar value of your payout moves with the price while you wait.
  • Moonwell governance: markets can be changed, paused or reconfigured by Moonwell governance; the contracts cannot be upgraded to follow such changes.
  • Fairness: markets with bad debt are a bank run — those who exit first get full value, the loss stays with those who remain. Choose your discount consciously.

FAQ

Can you take my tokens? No. A contract can move your mTokens only inside a fill that pays you in the same transaction, and never more than you approved and queued.

Why is my order not filled? Either cash hasn't reached your place in that market's queue, or (when gas is expensive) your order's fee doesn't cover its gas yet — it keeps its place.

Can I change the discount? Yes, join again with the new discount. You move to the end of that discount level.

Can I queue in several markets? Yes, one order per market. Each needs its own approval.