Перейти к основному содержимому

MagnetLiquidityRent

Контракт держит позиции ликвидности Uniswap V3 и выдаёт пользователям временный доступ к их доходу. Продукт-агностичен: VIP — первый потребитель, следующий продукт добавляется планом и своим хуком-грантором, сам контракт при этом не меняется.

Файлы: apps/contracts-v2/contracts/MagnetLiquidity/MagnetLiquidityRent.sol, хранилище — storage/RentStorage.sol, интерфейс — interfaces/IMagnetLiquidityRent.sol.

Сущности

СущностьЧто описывает
Группа позицийНабор позиций одного пула с общими настройками: токены, тир, payoutToken
План арендыПравила доступа: режим завершения, длительности, окно дозабора, потолок выплаты, порог доходности, нужна ли конвертация
АрендаСвязка «пользователь ↔ позиция ↔ план» с таймерами и счётчиком выплаченного

Жизненный цикл аренды

  1. Выдача. grantAccess (для гранторов) или activateWithPermit (пользователь с подписью оператора) занимает свободную позицию группы. Доход, накопленный позицией до этого момента, уходит в казну — новый арендатор начинает с нуля.
  2. Клейм. claim собирает комиссии позиции, при необходимости конвертирует их в payoutToken и переводит пользователю. Всё, что выше потолка плана, уходит в казну.
  3. Закрытие. По истечении доступа closeExpiredRentals фиксирует остаток в снапшоте, освобождает позицию и открывает окно дозабора. Своп при закрытии не делается: транзакция чужая, задать проскальзывание некому.
  4. Дозабор. Пока идёт окно, пользователь забирает снапшот тем же claim.
  5. Сгорание. После окна sweepExpiredSnapshots переводит остаток в казну.

Режимы завершения

  • FIXED_TIME — доступ живёт durationSeconds.
  • PROFIT_TARGET — доступ живёт, пока пользователю не выплачено referenceAmount × targetPercentBps / 10000, но не дольше maxDurationSeconds. В порог засчитывается только фактически выплаченное: срезанный потолком остаток к цели не приближает.

Пороги считаются в payoutToken. Оракула в проекте нет, поэтому «вложенная сумма» задаётся админом вручную в админке — это осознанный компромисс, зафиксированный в ТЗ.

Роли

  • DEFAULT_ADMIN_ROLE — группы, позиции, планы, казна, верификатор подписи, пауза, апгрейд.
  • OPERATOR_ROLEsweepExpiredSnapshots, forceCloseRental; используется кроном бэкенда.
  • GRANTER_ROLE — продуктовые хуки, которым разрешено открывать аренду.

Пауза останавливает выдачу новых аренд, но не блокирует клейм: заработанное должно оставаться доступным.

Связь с VIP

VipPaymentHook стал кассой продукта: цена, персональный лимит покупок, вызов grantAccess при оплате. Состояние доступа он больше не хранит, а hasActiveVip / getActiveVipAccounts / getVipConfig работают как view-прокси в аренду — поэтому бэкенд и админка не переписывались.

Бесплатная активация проходит ончейн: бэкенд выдаёт подпись RentPermit, пользователь сам отправляет activateWithPermit. Использование гранта резервируется в момент выдачи подписи и возвращается заданием, если транзакция так и не пришла.

Обслуживание

Крон бэкенда (apps/backend/src/liquidity-rent/jobs/rentClosure.job.ts) раз в минуту закрывает истёкшие аренды и зачищает сгоревшие снапшоты. Если крон простаивал, выдача следующей аренды сама закроет до трёх просроченных — окно дозабора при этом отсчитывается от момента закрытия, а не от вызова крона.

Ссылки

  • ТЗ: apps/docs/docs/tz/active/liquidity-rent.md
  • Дизайн: docs/superpowers/specs/2026-07-28-liquidity-rent-design.md
  • Тесты: apps/contracts-v2/test/MagnetLiquidityRent.test.ts