Documentation
ExitQueue is a non-custodial exit queue for holders of locked Moonwell markets on Base. This page explains exactly what the contracts do.
Overview
Several Moonwell markets on Base have almost no free cash: holders can withdraw only when someone deposits or repays a loan, and bots race for every such deposit. ExitQueue lets holders line up for that cash and choose the discount they are willing to give for exiting earlier. The discount is the service fee.
How the queue works
- Join: approve the mToken amount you want to exit, then call
join(amount, discount). Your tokens stay in your wallet.
- Discount: from 1% to 99.9% in 0.1% steps. Minimum order — $100 worth of the market's token (fixed in token units at deployment).
- 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(). In one transaction the contract takes mTokens from the queue in order, redeems them on Moonwell and pays each holder.
- 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.
Payout
payout = USDC (or the market's token) 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), the order is worth less than one cent.
- 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.
- Transfer paused by Moonwell: holders are skipped and keep their place.
Gas and the deposit race
Deposits are contested by other bots that bid priority fees. We fill an order in that race only when its fee pays for its gas with a margin (gas ≤ 50% of the order's fee). The app shows, for your amount, the minimum discount that currently qualifies. Orders below it still get filled via loan repayments (no race) or when competition calms down.
Repay with rebate
A borrower (or anyone on their behalf) can repay a Moonwell loan through repayAndFill(). The repayment goes straight to the queue in the same transaction, so nobody can take that cash in between. The payer receives 0.2% of the part of the fill funded by the repayment (cash that was already free on the market does not count). The payer sets a maximum amount and a minimum rebate; if the queue changes and the rebate would be lower, the transaction reverts.
Contracts
One immutable contract per market. Source is the same for all of them.
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 queue works even if the operator disappears.
- USDC-blacklisted recipients don't block anyone: their payout is kept in the contract and can be claimed later with
claim().
- Reviewed twice (internal review and an independent adversarial review); unit, fuzz and fork tests against 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.
- Moonwell governance: markets can be changed, paused or reconfigured by Moonwell governance; the contract cannot be upgraded to follow such changes.
- Speed: the queue moves only when cash arrives. In markets with little inflow, waiting can be long.
- 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. The 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 the 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.
Документация
ExitQueue — некастодиальная очередь на выход для холдеров запертых рынков Moonwell в сети Base. Здесь описано, что именно делают контракты.
Общее
В нескольких рынках Moonwell на Base почти нет свободных денег: вывести можно, только когда кто-то вносит депозит или гасит займ, и боты соревнуются за каждый такой депозит. ExitQueue позволяет холдерам встать в очередь за этими деньгами и самим выбрать дисконт, который они готовы отдать за более ранний выход. Дисконт — это комиссия сервиса.
Как работает очередь
- Вход: сделайте approve нужной суммы mToken и вызовите
join(сумма, дисконт). Токены остаются в вашем кошельке.
- Дисконт: от 1% до 99.9% с шагом 0.1%. Минимальная заявка — эквивалент $100 в токене рынка (зафиксирован в токенах при деплое).
- Порядок: первым исполняется больший дисконт; при равном — кто раньше встал. Любое изменение заявки переносит вас в конец вашего уровня дисконта.
- Вывод: когда на рынок приходят деньги, любой может вызвать
fill(). В одной транзакции контракт забирает mToken по очереди, выводит их из Moonwell и платит каждому холдеру.
- Частичное исполнение: если денег хватило на часть заявки, холдер получает эту часть, остаток остаётся первым в очереди.
- Выход: вызовите
leave() или просто отзовите approve.
Выплата
выплата = USDC (или токен рынка), реально полученные за ваши mToken × (1 − ваш дисконт). Считается из фактического результата вывода в той же транзакции. Контракт никогда не берёт больше минимума из заявки, approve и баланса. Либо вам заплатили в той же транзакции, либо у вас ничего не взяли.
Выбывшие и пропущенные заявки
- Выбывает (удаляется из очереди, ничего не списывается): approve или баланс стали нулевыми, токены нельзя перевести (например, заложены под займ), заявка стоит меньше цента.
- Пропускается (сохраняет место): при дорогом газе полностью обеспеченная заявка, чья комиссия не покрывает её долю газа, пропускается в гонке за депозиты. Она исполнится позже через погашения займов или при дешёвом газе.
- Moonwell поставил переводы на паузу: холдеры пропускаются и сохраняют место.
Газ и гонка за депозиты
За депозиты соревнуются другие боты, повышая плату за приоритет. Мы исполняем заявку в этой гонке, только если её комиссия окупает её газ с запасом (газ ≤ 50% комиссии заявки). Приложение показывает для вашей суммы минимальный дисконт, который сейчас для этого нужен. Заявки ниже исполняются через погашения займов (без гонки) или когда конкуренция утихнет.
Погашение с кешбэком
Заёмщик (или кто угодно за него) может погасить займ в Moonwell через repayAndFill(). Деньги погашения в той же транзакции идут в очередь, и перехватить их никто не может. Плательщик получает 0.2% от части вывода, оплаченной его погашением (деньги, которые уже лежали на рынке свободно, не считаются). Плательщик задаёт максимальную сумму и минимальный кешбэк; если очередь изменилась и кешбэк выйдет меньше, транзакция откатывается.
Контракты
Отдельный неизменяемый контракт на каждый рынок. Код у всех одинаковый.
Безопасность
- Нет владельца, админ-функций, паузы и возможности обновления. Все параметры заданы при деплое.
- Комиссия всегда идёт на фиксированный адрес; тот, кто вызывает
fill(), ничего не получает — очередь работает, даже если оператор исчезнет.
- Получатели из блэклиста USDC никого не блокируют: их выплата хранится в контракте и забирается позже через
claim().
- Две проверки кода (внутренняя и независимая), юнит-, фазз- и форк-тесты на живых рынках Moonwell. Внешнего профессионального аудита пока не было.
Риски
- Approve: вы даёте контракту право перевести одобренные mToken. Одобряйте ровно ту сумму, которую хотите вывести.
- Управление Moonwell: рынки могут быть изменены, поставлены на паузу или перенастроены голосованием Moonwell; контракт нельзя обновить под такие изменения.
- Скорость: очередь движется, только когда приходят деньги. В рынках с малым притоком ждать можно долго.
- Справедливость: рынки с безнадёжным долгом — это бэнк-ран: кто выходит первым, получает полную стоимость, убыток остаётся оставшимся. Выбирайте дисконт осознанно.
Вопросы
Можете ли вы забрать мои токены? Нет. Контракт может перевести ваши mToken только внутри вывода, который платит вам в той же транзакции, и никогда больше, чем вы одобрили и поставили в очередь.
Почему моя заявка не исполняется? Либо деньги ещё не дошли до вашего места в очереди, либо (при дорогом газе) комиссия заявки пока не окупает газ — она сохраняет место.
Можно поменять дисконт? Да, встаньте в очередь заново с новым дисконтом. Вы окажетесь в конце этого уровня.