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.
| Market | Underlying | ExitQueue contract | Min 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.
Документация
ExitQueue — некастодиальная очередь на выход для холдеров запертых рынков Moonwell в сети Base. У каждого поддерживаемого рынка свой неизменяемый контракт, все работают одинаково. Здесь описано, что именно делают контракты.
Общее
В нескольких рынках Moonwell на Base почти нет свободных денег: вкладчики могут вывести средства, только когда кто-то вносит депозит или гасит займ в этом рынке, и боты соревнуются за каждый такой приток. ExitQueue позволяет холдерам mToken рынка встать в очередь за этими деньгами и самим выбрать дисконт, который они готовы отдать за более ранний выход. Дисконт — это комиссия сервиса. Выплаты, кешбэк и комиссия всегда в базовом токене рынка (USDC для mUSDC, cbBTC для mcbBTC и так далее).
Поддерживаемые рынки
По одному контракту на рынок. Код и правила у всех одинаковые, различаются только рынок и минимальная заявка.
| Рынок | Базовый токен | Контракт ExitQueue | Мин. заявка |
|---|
Минимальная заявка — около $100 в базовом токене, зафиксирована в токенах при деплое контракта. Её долларовая стоимость меняется вместе с ценой токена.
Как работает очередь
- Вход: на странице рынка сделайте approve нужной суммы mToken и вызовите
join(сумма, дисконт). Токены остаются в вашем кошельке.
- Дисконт: от 1% до 99.9% с шагом 0.1%.
- Порядок: первым исполняется больший дисконт; при равном — кто раньше встал. Любое изменение заявки переносит вас в конец вашего уровня дисконта.
- Вывод: когда на рынок приходят деньги, любой может вызвать
fill() у контракта этого рынка. В одной транзакции он забирает mToken по очереди, выводит их из Moonwell и платит каждому холдеру в базовом токене.
- Частичное исполнение: если денег хватило на часть заявки, холдер получает эту часть, остаток остаётся первым в очереди.
- Выход: вызовите
leave() или просто отзовите approve. Приложение делает и то и другое: выводит из очереди и обнуляет approve на mToken.
- Несколько рынков: очереди независимы. В каждом рынке можно держать одну заявку; все они видны на странице Мои заявки.
Выплата
выплата = базовые токены, реально полученные за ваши mToken × (1 − ваш дисконт). Считается из фактического результата вывода в той же транзакции. Контракт никогда не берёт больше минимума из заявки, approve и баланса. Либо вам заплатили в той же транзакции, либо у вас ничего не взяли.
Выбывшие и пропущенные заявки
- Выбывает (удаляется из очереди, ничего не списывается): approve или баланс стали нулевыми, токены нельзя перевести (например, заложены под займ в Moonwell), заявка стоит меньше минимальной единицы базового токена.
- Пропускается (сохраняет место): при дорогом газе полностью обеспеченная заявка, чья комиссия не покрывает её долю газа, пропускается в гонке за депозиты. Она исполнится позже через погашения займов или при дешёвом газе.
- Moonwell поставил переводы на паузу: холдеры пропускаются и сохраняют место.
Газ и гонка за депозиты
В одних рынках за депозиты соревнуются другие боты, повышая плату за приоритет; в других конкуренции почти нет. Мы исполняем заявку в гонке, только если её комиссия окупает её. Страница рынка показывает для вашей суммы минимальный дисконт, который сейчас для этого нужен именно в этом рынке. Заявки ниже исполняются через погашения займов (без гонки) или когда конкуренция утихнет.
Погашение с кешбэком
На странице Погашение вы подключаете кошелёк и видите свою позицию в Moonwell по всем рынкам. Займ в любом поддерживаемом рынке можно погасить через repayAndFill(): деньги погашения в той же транзакции идут в очередь этого рынка, и перехватить их никто не может. Вы получаете 0.2% от части вывода, оплаченной вашим погашением, в базовом токене рынка (деньги, которые уже лежали на рынке свободно, не считаются). Вы задаёте максимальную сумму; контракт гасит не больше вашего реального долга.
Безопасность
- Нет владельца, админ-функций, паузы и возможности обновления. Все параметры заданы при деплое.
- Комиссия всегда идёт на фиксированный адрес; тот, кто вызывает
fill(), ничего не получает — очереди работают, даже если оператор исчезнет.
- Если выплату нельзя отправить (например, адрес в блэклисте Circle для USDC или EURC), она хранится в контракте и забирается позже через
claim(); остальные не блокируются.
- Две проверки кода (внутренняя и независимая), юнит-, фазз- и форк-тесты на всех пяти живых рынках Moonwell. Внешнего профессионального аудита пока не было.
Риски
- Approve: вы даёте контракту право перевести одобренные mToken. Одобряйте ровно ту сумму, которую хотите вывести.
- Разная скорость рынков: каждая очередь движется, только когда деньги приходят в её рынок. Приток в рынках сильно различается; где-то ждать можно долго.
- Цена токена: выплата идёт в базовом токене. У волатильных токенов (cbBTC, VIRTUAL, MORPHO) долларовая стоимость выплаты меняется вместе с ценой, пока вы ждёте.
- Управление Moonwell: рынки могут быть изменены, поставлены на паузу или перенастроены голосованием Moonwell; контракты нельзя обновить под такие изменения.
- Справедливость: рынки с безнадёжным долгом — это бэнк-ран: кто выходит первым, получает полную стоимость, убыток остаётся оставшимся. Выбирайте дисконт осознанно.
Вопросы
Можете ли вы забрать мои токены? Нет. Контракт может перевести ваши mToken только внутри вывода, который платит вам в той же транзакции, и никогда больше, чем вы одобрили и поставили в очередь.
Почему моя заявка не исполняется? Либо деньги ещё не дошли до вашего места в очереди этого рынка, либо (при дорогом газе) комиссия заявки пока не окупает газ — она сохраняет место.
Можно поменять дисконт? Да, встаньте в очередь заново с новым дисконтом. Вы окажетесь в конце этого уровня.
Можно встать в очередь в нескольких рынках? Да, по одной заявке на рынок. Для каждой нужен свой approve.