Офчейн-сервисы
✅ Готово к разработке
Это спецификации офчейн-сервисов, а не смарт-контрактов. Разработчик может реализовать их на основе этого документа.
Это не смарт-контракты. Никаких PDA, ончейн-состояния или деплоя программ. Каждый бот — серверный процесс с выделенным кошельком. Все кошельки зарегистрированы ончейн с определёнными ролями.
Обзор сервисов
| Бот | Контракт | Инструкция | Частота | Роль кошелька |
|---|---|---|---|---|
| Pool Rebalancer | Native DEX | shift_liquidity | Каждые 60 сек (при отклонении > 1%) | dex_config.rebalancer |
| Merkle Publisher | Yield Distribution | publish_root | Каждые 10 мин | config.publish_authority |
| Revenue Crank | Ownership Token | distribute_revenue | Каждый час (при выполнении условий) | Permissionless |
| Convert & Fund Crank | Yield Distribution | convert_to_rwt | После каждого распределения дохода | Permissionless |
| Yield Claim Crank | RWT Engine + DEX + OT | claim_yield + compound_yield + claim_yd_for_treasury | Каждые 30 мин | Permissionless |
| Nexus Manager | Native DEX | nexus_deposit, nexus_swap, nexus_add/remove_liquidity | На основе стратегии | dex_config.nexus_manager + Permissionless (deposit) |
Pool Rebalancer
Перераспределяет бины концентрированной ликвидности в пулах DEX для отслеживания цены NAV токена RWT. Считывает ончейн NAV из RWT Engine, рассчитывает целевой бин и вызываетshift_liquidity при превышении порога отклонения.
Как это работает
Чтение состояния пула
Для каждого концентрированного пула: запрос
pool_state.active_bin_id и bin_array. Расчёт текущей цены пула по активному бину: price = (1 + bin_step_bps/10000) ^ active_bin_id.Проверка отклонения
deviation = abs(pool_price - nav_price) / nav_price. Если deviation > REBALANCE_THRESHOLD → требуется ребалансировка.Выполнение сдвига
Вызов
native_dex::shift_liquidity(nav_bin, TARGET_BIN_COUNT). Кошелёк бота подписывает как rebalancer. Ончейн DEX рассчитывает целевое пирамидальное распределение и выполняет diff-ребалансировку:- Асимметричная пирамида (2:1 bid/ask с центром на NAV)
- Перемещение токенов из избыточных бинов → в дефицитные (без полного изъятия)
active_bin_idНЕ изменяется — цену двигают только свопы- Ликвидность всегда присутствует — без разрыва во время ребалансировки
Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
REBALANCE_THRESHOLD | 0.01 (1%) | Минимальное отклонение NAV для запуска ребалансировки |
TARGET_BIN_COUNT | 40 | Количество бинов для концентрации вокруг NAV |
CHECK_INTERVAL_SECS | 60 | Как часто проверять отклонение (секунды) |
Ончейн-взаимодействие
| Действие | Инструкция | Аккаунты |
|---|---|---|
| Чтение NAV | — | rwt_vault (read) |
| Чтение бинов | — | pool_state, bin_array (read) |
| Сдвиг | native_dex::shift_liquidity | rebalancer (signer), dex_config, pool_state (mut), bin_array (mut) |
Полномочия
- МОЖЕТ: вызывать
shift_liquidityна любом концентрированном пуле - НЕ МОЖЕТ: свопать, добавлять/удалять ликвидность, менять конфигурацию, ставить пулы на паузу
- При компрометации: может только сдвигать бины (без извлечения средств). Команда заменяет через
update_dex_config(rebalancer: new_wallet)
Условия пропуска
- Пул на паузе (
pool_state.is_active == false) - В пуле нет ликвидности (
reserve_a == 0 || reserve_b == 0) - Отклонение ниже порога
- С последней ребалансировки прошло < 30 секунд (дебаунс)
Merkle Publisher
Строит деревья Меркла с весами держателей OT офчейн и публикует корни ончейн. Это ядро системы распределения доходности — без опубликованных корней держатели не могут клеймить.Как это работает
Сканирование держателей
Для каждого OT-проекта: вызов
getParsedProgramAccounts для получения всех токен-аккаунтов минта OT. Включает обычные кошельки, RWT Vault PDA (хранит OT как обеспечение), PDA пулов DEX (хранят OT в резервах) и OT Treasury PDA. Фильтрация до держателей с ≥ $100 общих протокольных холдингов (OT + RWT вместе).Расчёт весов
Для каждого подходящего держателя (включая PDA):Доля неподходящих держателей → ARL OtTreasury PDA
["ot_treasury", arl_ot_mint] как лист в дереве (доход протокола). Примечание: RWT Vault PDA и PDA пулов DEX — обычные держатели OT в дереве, они клеймят через соответствующие CPI-инструкции (claim_yield, compound_yield). ARL Treasury клеймит через claim_yd_for_treasury на экземпляре ARL OT.Построение дерева
Построение дерева Меркла. Формат листа:
sha256(claimant_pubkey_bytes || cumulative_amount_le_bytes).Публикация корня
Вызов
yield_distribution::publish_root(merkle_root, max_total_claim). Серверный кошелёк подписывает как publish authority.Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
PUBLISH_INTERVAL_SECS | 600 (10 мин) | Как часто перестраивать и публиковать |
MIN_HOLDING_USD | 100 | Минимальный холдинг для участия ($100) |
PROOF_STORAGE | — | Путь или БД для хранения доказательств для UI клейма |
Ончейн-взаимодействие
| Действие | Инструкция | Аккаунты |
|---|---|---|
| Чтение держателей | — | Токен-аккаунты OT (чтение через RPC) |
| Чтение дистрибьютора | — | merkle_distributor (read) |
| Публикация | yield_distribution::publish_root | publish_authority (signer), config, distributor (mut) |
Полномочия
- МОЖЕТ: вызывать
publish_rootна любом дистрибьюторе - НЕ МОЖЕТ: фондировать, клеймить, закрывать дистрибьюторы, обновлять конфигурацию
- При компрометации: атакующий может публиковать мошеннические корни → опустошить хранилища наград через поддельные клеймы. Команда немедленно заменяет через
update_publish_authority. Все публикации видны в событияхRootPublished.
Стоимость
~0.0006/TX).Revenue Crank
Запускает распределение дохода OT при выполнении условий. Проверяет баланс RevenueAccount каждого OT-проекта и вызываетdistribute_revenue, если баланс выше минимума и период ожидания прошёл.
Как это работает
Проверка баланса
Для каждого OT-проекта: чтение баланса ATA RevenueAccount. Если
balance < min_distribution_amount ($100), пропуск.Проверка кулдауна
Чтение
revenue_config.last_distribution_ts. Если now - last_distribution_ts < 604,800 (7 дней), пропуск.Распределение
Вызов
ownership_token::distribute_revenue. Permissionless — любой кошелёк может вызвать.- Сначала вычитается комиссия протокола: 0.25% (25 bps) от общего баланса →
areal_fee_destination(USDC ATA Areal Finance) - Остаток распределяется пропорционально настроенным направлениям (по умолчанию):
- 70% (7,000 bps) → YD Accumulator (USDC)
- 20% (2,000 bps) → OT Treasury
- 10% (1,000 bps) → Crank USDC ATA → Nexus через
nexus_deposit
Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
CHECK_INTERVAL_SECS | 3600 (1 час) | Как часто проверять каждый OT-проект |
OT_PROJECTS | — | Список адресов минтов OT для мониторинга |
Ончейн-взаимодействие
| Действие | Инструкция | Аккаунты |
|---|---|---|
| Чтение баланса | — | RevenueAccount ATA (read) |
| Чтение кулдауна | — | revenue_config (read) |
| Распределение | ownership_token::distribute_revenue | crank (signer), ot_config, revenue_config (mut), revenue_ata (mut), destination ATAs (mut) |
Полномочия
- Permissionless — специальная роль кошелька не требуется. Любой кошелёк может запустить распределение.
- При компрометации: нет риска — кранк только запускает распределение на предварительно настроенные ончейн-направления. Не может менять направления или извлекать средства.
Convert & Fund Crank
Конвертирует накопленные USDC в YD Accumulator PDA в RWT и депонирует в хранилища наград дистрибьютора. Должен запускаться сразу после каждого распределения дохода, чтобы минимизировать время между поступлением USDC и доступностью RWT для клеймов.Как это работает
Проверка аккумулятора
Для каждого OT-проекта: чтение баланса USDC ATA аккумулятора. Если 0, пропуск.
Конвертация
Вызов
yield_distribution::convert_to_rwt(max_swap_amount). Атомарная инструкция, которая:- Свопает USDC → RWT на DEX (до цены NAV)
- Минтит остаток по NAV через RWT Engine
- Вычитает комиссию протокола 0.25% в RWT
- Депонирует чистый RWT в хранилище наград
- Обновляет состояние вестинга (блокирует ранее вестированное, запускает новый вестинг)
Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
CHECK_INTERVAL_SECS | 300 (5 мин) | Как часто проверять аккумуляторы |
MAX_SWAP_RATIO | 0.5 | Максимальная доля USDC для свопа на DEX (остаток минтится по NAV) |
Ончейн-взаимодействие
| Действие | Инструкция | Аккаунты |
|---|---|---|
| Чтение баланса | — | Accumulator USDC ATA (read) |
| Конвертация + фондирование | yield_distribution::convert_to_rwt | crank (signer), config, distributor (mut), accumulator, ATAs, DEX accounts, RWT Engine accounts |
Полномочия
- Permissionless — любой кошелёк может вызвать. Accumulator PDA подписывает все внутренние переводы.
- При компрометации: нет риска — инструкция только конвертирует USDC, уже находящиеся в Accumulator, в RWT в хранилище наград. Не может перенаправить средства.
Триггер
В идеале запускается сразу после того, как Revenue Crank распределит USDC в Accumulator. Может опрашивать по интервалу как запасной вариант.Yield Claim Crank
Клеймит доходность в RWT из merkle-потоков YD от имени трёх типов ончейн PDA:- RWT Vault PDA — хранит позиции OT, получает доходность как держатель OT. Заклеймленный RWT распределяется: 70% NAV / 15% Nexus / 15% ARL Treasury.
- PDA пулов DEX — пулы OT/RWT хранят OT в резервах и получают доходность. Заклеймленный RWT автоматически компаундится в резервы пула, принося выгоду всем держателям LP.
- OT Treasury PDA — доля доходности неподходящих держателей (< $100) выделяется OT Treasury PDA в дереве Меркла. Заклеймленный RWT остаётся в казначействе.
Как это работает
Получение доказательств
Чтение последних доказательств Меркла из хранилища доказательств Merkle Publisher для:
- RWT Vault PDA (один на протокол)
- Каждого PDA пула OT/RWT, содержащего OT (один на пул)
Клейм для RWT Vault
Вызов
rwt_engine::claim_yield(cumulative_amount, proof). Permissionless-инструкция, которая:- Выполняет CPI к
yield_distribution::claimс vault PDA как claimant - Распределяет заклеймленный RWT: 70% остаётся в vault (рост NAV), 15% → кошелёк кранка, 15% → ARL Treasury
- Обновляет
total_invested_capitalи пересчитывает NAV - Кранк затем вызывает
native_dex::nexus_depositдля маршрутизации 15% RWT в Nexus с отслеживанием принципала
Компаунд для пулов DEX
Для каждого пула OT/RWT: вызов
native_dex::compound_yield(cumulative_amount, proof). Permissionless-инструкция, которая:- Выполняет CPI к
yield_distribution::claimс pool PDA как claimant - Заклеймленный RWT добавляется напрямую в резервы пула (авто-компаунд)
- Все держатели LP получают выгоду пропорционально — индивидуальный клейм не требуется
Клейм для ARL Treasury (доходность неподходящих)
Вызов
ownership_token::claim_yd_for_treasury(cumulative_amount, proof) на экземпляре ARL OT. Клеймит доходность неподходящих держателей из ВСЕХ OT-проектов как протокольный доход:- Выполняет CPI к
yield_distribution::claimс ARL OtTreasury PDA как claimant - Заклеймленный RWT поступает на RWT ATA ARL Treasury
- RWT является протокольным доходом — может быть потрачен управлением ARL Futarchy через
spend_treasury
Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
CLAIM_INTERVAL_SECS | 1800 (30 мин) | Как часто пытаться клеймить |
PROOF_SOURCE | — | Хранилище доказательств Merkle Publisher (БД или API) |
OT_RWT_POOLS | — | Список адресов пулов OT/RWT для компаунда |
Ончейн-взаимодействие
| Действие | Инструкция | Аккаунты |
|---|---|---|
| Чтение доказательств | — | Офчейн: хранилище доказательств Merkle Publisher |
| Клейм для vault | rwt_engine::claim_yield | crank (signer, mut), rwt_vault (mut), dist_config, RWT ATAs, YD CPI accounts |
| Компаунд для пула | native_dex::compound_yield | crank (signer, mut), pool_state (mut), target_vault (mut), YD CPI accounts |
| Клейм для казначейства | ownership_token::claim_yd_for_treasury | crank (signer, mut), ot_treasury, treasury_rwt_ata, YD CPI accounts |
| Маршрут в Nexus | native_dex::nexus_deposit | crank (signer), nexus (mut), token accounts |
Полномочия
- Permissionless — любой кошелёк может вызвать все три инструкции. PDA подписывают свои CPI-клеймы внутренне.
- При компрометации: нет риска — заклеймленный RWT поступает на предварительно настроенные ончейн-направления. Не может менять пропорции распределения, направления или перенаправлять компаунд пула.
Зависимость
Требует, чтобы Merkle Publisher опубликовал корень, включающий RWT Vault PDA и PDA пулов как claimants. Если валидное доказательство отсутствует, клейм завершится ошибкойInvalidProof.
Nexus Manager
Управляет позициями Liquidity Nexus PDA в пулах DEX. Nexus хранит ликвидность, принадлежащую протоколу (финансируется из 10% дохода OT + 15% доходности RWT). Бот-менеджер решает, когда и куда размещать этот капитал. Принципал заблокирован навсегда — только прибыль от LP (комиссии за свопы, авто-компаунд) может быть выведена в Areal Treasury authority.Как это работает
Депозит капитала
После того как OT
distribute_revenue отправляет 10% USDC кранку, или после того как RWT claim_yield отправляет 15% RWT кранку — кранк вызывает native_dex::nexus_deposit для маршрутизации токенов в Nexus с отслеживанием принципала. Это единственный способ поступления капитала в Nexus.Мониторинг баланса Nexus
Чтение балансов RWT и USDC Liquidity Nexus. Проверка наличия неразмещённого капитала.
Оценка пулов
Анализ пулов DEX: TVL, объём, спред, утилизация. Определение пулов, нуждающихся в дополнительной ликвидности.
Размещение ликвидности
Вызов
native_dex::nexus_add_liquidity для предоставления LP в целевые пулы. Также может вызвать nexus_swap для ребалансировки между токенами перед добавлением.Ребалансировка
Периодическая ребалансировка позиций:
nexus_remove_liquidity из неэффективных пулов, nexus_add_liquidity в более выгодные пулы.Конфигурация
| Параметр | По умолчанию | Описание |
|---|---|---|
CHECK_INTERVAL_SECS | 300 (5 мин) | Как часто оценивать позиции |
MIN_DEPLOY_AMOUNT | 1,000,000 ($1 RWT) | Минимальная сумма для размещения за одну операцию |
MAX_POOL_CONCENTRATION | 0.5 (50%) | Максимальная доля капитала Nexus в одном пуле |
Ончейн-взаимодействие
| Действие | Инструкция | Аккаунты |
|---|---|---|
| Депозит | native_dex::nexus_deposit | crank (signer), nexus (mut), token accounts |
| Чтение баланса | — | Nexus ATAs (read) |
| Своп | native_dex::nexus_swap | nexus_manager (signer), dex_config, nexus, pool accounts |
| Добавление LP | native_dex::nexus_add_liquidity | nexus_manager (signer), dex_config, nexus, pool accounts |
| Удаление LP | native_dex::nexus_remove_liquidity | nexus_manager (signer), dex_config, nexus, pool accounts |
| Вывод прибыли | native_dex::nexus_withdraw_profits | authority (signer), dex_config, nexus (mut), token accounts |
Полномочия
- МОЖЕТ: свопать, добавлять/удалять ликвидность, используя средства Nexus PDA
- НЕ МОЖЕТ: выводить принципал, менять конфигурацию DEX, ставить пулы на паузу
- При компрометации: атакующий может совершать невыгодные сделки со средствами Nexus (LP в плохие пулы, свопы по плохим ценам), но не может извлечь принципал — защищено ончейн (
ata_balance - withdrawal >= principal). Команда заменяет черезupdate_nexus_manager.
Общая инфраструктура
Все шесть ботов работают на одном VPS с общей конфигурацией:Архитектура
Кошельки
| Бот | Тип кошелька | Зарегистрирован как |
|---|---|---|
| Pool Rebalancer | Выделенный keypair | dex_config.rebalancer |
| Merkle Publisher | Выделенный keypair | config.publish_authority |
| Revenue Crank | Общий кранк-кошелёк | Permissionless (без регистрации) |
| Convert & Fund | Общий кранк-кошелёк | Permissionless (без регистрации) |
| Yield Claim | Общий кранк-кошелёк | Permissionless (без регистрации) |
| Nexus Manager | Выделенный keypair | dex_config.nexus_manager |
Переменные окружения
| Переменная | Описание |
|---|---|
RPC_URL | Эндпоинт Solana RPC (бесплатного тарифа Helius достаточно) |
REBALANCER_KEYPAIR | Keypair кошелька Pool Rebalancer |
PUBLISHER_KEYPAIR | Keypair кошелька Merkle Publisher |
NEXUS_MANAGER_KEYPAIR | Keypair кошелька Nexus Manager |
CRANK_KEYPAIR | Общий кошелёк для permissionless-операций |
RWT_VAULT_ADDRESS | PDA хранилища RWT Engine |
CONCENTRATED_POOLS | Список адресов концентрированных пулов (требуется перезапуск при изменении) |
OT_PROJECTS | Список {ot_mint, distributor, accumulator, revenue_config} на проект (требуется перезапуск при изменении) |
Оценка стоимости
| Компонент | Стоимость/мес |
|---|---|
| VPS | $10 |
| Комиссии Solana TX (~500 TX итого) | ~$0.30 |
| RPC (бесплатный тариф Helius) | $0 |
| Итого | ~$10/мес |
Операционные требования
| Требование | Детали |
|---|---|
| Инфраструктура | VPS, постоянно работающий, systemd или Docker |
| Баланс SOL | Каждый кошелёк: ~0.1 SOL на комиссии TX |
| Мониторинг | Логирование каждой TX с именем бота, инструкцией, результатом |
| Алертинг | Алерт, если любой бот не работает > 15 минут |
| Управление ключами | Keypair зашифрованы в покое, никогда не коммитятся в git |
| Политика перезапуска | Авто-перезапуск при падении, экспоненциальный бэкофф |
Оптимизации на основе событий
Вместо чисто интервального опроса боты могут подписываться на события Solana для более быстрой реакции:| Событие | Запускает |
|---|---|
CapitalAdjusted (RWT Engine) | Pool Rebalancer проверяет немедленно (NAV изменился) |
| SPL-перевод дохода на RevenueAccount | Revenue Crank проверяет немедленно |
StreamConverted (YD) | Merkle Publisher публикует новый корень (total_funded изменился) |
RootPublished (YD) | Yield Claim Crank клеймит немедленно (доступно новое доказательство) |
Порядок развёртывания
- Деплой всех смарт-контрактов
- Бутстрап:
initialize_*всех контрактов, установка authority, регистрация кошельков - Регистрация кошельков ботов ончейн:
update_dex_config(rebalancer: rebalancer_pubkey)— Pool Rebalancerupdate_dex_config(nexus_manager: manager_pubkey)— Nexus Manager- Publish authority задаётся при
initialize_config— Merkle Publisher
- Пополнение кошельков ботов ~0.1 SOL каждый
- Запуск всех сервисов, проверка логов
- Передача authorities командному мультисигу
Сводка по доверию
| Бот | Уровень доверия | При компрометации |
|---|---|---|
| Pool Rebalancer | Низкий | Может сдвинуть бины в плохие позиции. Без извлечения средств. Замена кошелька. |
| Merkle Publisher | Высокий | Может публиковать поддельные корни → опустошить хранилища наград. Немедленная замена + мониторинг. |
| Revenue Crank | Нет | Permissionless. Может только запускать распределение на заданные направления. |
| Convert & Fund | Нет | Permissionless. Конвертирует в заданное хранилище. |
| Yield Claim | Нет | Permissionless. Клеймит на заданные направления. |
| Nexus Manager | Средний | Может совершать невыгодные сделки со средствами Nexus. Не может извлечь. Замена кошелька. |