174 lines
7.0 KiB
Markdown
174 lines
7.0 KiB
Markdown
# `shine_payments`
|
||
|
||
## Кратко
|
||
|
||
`shine_payments` — третья программа Solana-модуля SHiNE. Она отвечает за vault входящих средств, DAO-казну, покупку тикетов, менеджерские лимиты, очереди выплат и пошаговое исполнение выплат.
|
||
|
||
Папка программы: `shine-solana/shine/programs/shine_payments/`.
|
||
|
||
## Текущие функции
|
||
|
||
1. `init`
|
||
- Создает основные PDA: `config_pda`, `coef_limit_pda`, `queues_pda`, `inflow_vault_pda`.
|
||
- Записывает `dao_wallet` и стартовые параметры выплат.
|
||
|
||
2. `update_coef_limit`
|
||
- Обновляет коэффициент выплаты, лимит очереди и награду вызвавшему `step_payout`.
|
||
- Требует подпись DAO-кошелька из `ConfigState`.
|
||
|
||
3. `grant_manager_limits`
|
||
- DAO выдает менеджеру лимиты на создание тикетов в очередях Q1/Q2.
|
||
- Создает или обновляет `manager_allowance_pda`.
|
||
|
||
4. `buy_ticket`
|
||
- Покупка тикета с суммой в lamports, пересчетом через Pyth SOL/USD.
|
||
|
||
5. `buy_ticket_usd`
|
||
- Покупка тикета от USD-центов с защитой по максимальному платежу в lamports.
|
||
|
||
6. `buy_ticket_sol`
|
||
- Покупка тикета в lamports с проверкой минимального ожидаемого USD-эквивалента.
|
||
|
||
7. `manager_add_ticket`
|
||
- Менеджер создает тикет за счет выданного ему DAO-лимита.
|
||
|
||
8. `step_payout`
|
||
- Любой подписант может вызвать шаг выплат.
|
||
- Программа выплачивает следующий тикет, DAO-часть и награду вызывающему.
|
||
|
||
9. `change_ticket_recipient`
|
||
- Текущий получатель тикета может поменять адрес получателя, если тикет еще не следующий на выплату.
|
||
|
||
## Аргументы инструкций
|
||
|
||
`init` аргументов не принимает.
|
||
|
||
`update_coef_limit`:
|
||
|
||
- `coef_ppm: u64`
|
||
- `limit_usd_cents: u64`
|
||
- `call_reward_lamports: u64`
|
||
|
||
`grant_manager_limits`:
|
||
|
||
- `manager_wallet: Pubkey`
|
||
- `add_q1_usd_cents: u64`
|
||
- `add_q2_usd_cents: u64`
|
||
|
||
`buy_ticket`:
|
||
|
||
- `amount_lamports: u64`
|
||
- `recipient_wallet: Pubkey`
|
||
|
||
`buy_ticket_usd`:
|
||
|
||
- `amount_usd_cents: u64`
|
||
- `max_pay_lamports: u64`
|
||
- `recipient_wallet: Pubkey`
|
||
|
||
`buy_ticket_sol`:
|
||
|
||
- `amount_lamports: u64`
|
||
- `min_expected_usd_cents: u64`
|
||
- `recipient_wallet: Pubkey`
|
||
|
||
`manager_add_ticket`:
|
||
|
||
- `queue_id: u8` — только `1` или `2`
|
||
- `recipient_wallet: Pubkey`
|
||
- `payout_usd_cents: u64`
|
||
|
||
`change_ticket_recipient`:
|
||
|
||
- `new_recipient_wallet: Pubkey`
|
||
|
||
## Главные PDA
|
||
|
||
1. `config_pda`
|
||
- Seed: `shine_payments_config`.
|
||
- Хранит `dao_wallet` и `inflow_vault`.
|
||
- Размер PDA: `8 + 160` байт.
|
||
|
||
2. `coef_limit_pda`
|
||
- Seed: `shine_payments_coef_limit`.
|
||
- Хранит коэффициент выплат, лимит и награду `step_payout`.
|
||
- Размер PDA: `8 + 96` байт.
|
||
|
||
3. `queues_pda`
|
||
- Seed: `shine_payments_queues`.
|
||
- Хранит агрегаты очередей Q1/Q2.
|
||
- Размер PDA: `8 + 192` байт.
|
||
|
||
4. `inflow_vault_pda`
|
||
- Seed: `shine_payments_inflow_vault`.
|
||
- Принимает деньги от `shine_users`.
|
||
- Из него выполняются выплаты тикетам, DAO и вызывающему `step_payout`.
|
||
- Размер PDA: `8 + 32` байт.
|
||
|
||
5. `ticket_pda`
|
||
- Seed зависит от очереди и индекса тикета.
|
||
- Отдельная PDA-запись на каждый тикет.
|
||
- Q1 seed: `shine_payments_q1_ticket` + `ticket_index`.
|
||
- Q2 seed: `shine_payments_q2_ticket` + `ticket_index`.
|
||
- Размер PDA: `8 + 160` байт.
|
||
|
||
6. `manager_allowance_pda`
|
||
- Seed: `shine_p_manager_allow` + адрес менеджера.
|
||
- Хранит доступный лимит менеджера по Q1/Q2.
|
||
- Размер PDA: `8 + 128` байт.
|
||
|
||
## Текущие параметры
|
||
|
||
Параметры initial config из `programs/shine_payments/src/settings.rs`:
|
||
|
||
| Поле | Значение | Смысл |
|
||
| --- | --- | --- |
|
||
| `START_COEF_PPM` | `5_000_000` | коэффициент 5.0x в ppm-масштабе |
|
||
| `START_LIMIT_USD_CENTS` | `1_000_000` | стартовый лимит Q1: 10_000 USD |
|
||
| `START_CALL_REWARD_LAMPORTS` | `8_000_000` | награда вызвавшему `step_payout`, 0.008 SOL |
|
||
| `MAX_CALL_REWARD_LAMPORTS` | `10_000_000` | максимум награды, 0.01 SOL |
|
||
| `ORACLE_MAX_AGE_SECS` | `120` | максимальный возраст цены Pyth |
|
||
|
||
Для расчетов используется Pyth SOL/USD:
|
||
|
||
- feed id: `0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d`
|
||
- price update account: `7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE`
|
||
|
||
## Деньги
|
||
|
||
Входы:
|
||
|
||
- из `shine_users` в `inflow_vault_pda` при регистрации и увеличении лимита;
|
||
- от покупателя тикета сразу в `dao_wallet` при `buy_ticket*`.
|
||
|
||
Выходы:
|
||
|
||
- из `inflow_vault_pda` получателю тикета;
|
||
- из `inflow_vault_pda` в `dao_wallet`;
|
||
- из `inflow_vault_pda` вызвавшему `step_payout`;
|
||
- если очереди пустые, весь доступный остаток `inflow_vault_pda` переводится в DAO.
|
||
|
||
## Очереди и выплаты
|
||
|
||
Выплаты идут строго пошагово:
|
||
|
||
- если есть невыплаченные Q1-тикеты, `step_payout` берет следующий Q1;
|
||
- если Q1 пустая, берется следующий Q2;
|
||
- для Q1 DAO-часть равна сумме тикета в USD;
|
||
- для Q2 DAO-часть равна двойной сумме тикета в USD;
|
||
- перед выплатой суммы пересчитываются из USD-центов в lamports по Pyth SOL/USD;
|
||
- если в `inflow_vault_pda` не хватает средств на тикет, DAO-часть и награду вызвавшему, шаг отклоняется.
|
||
|
||
`change_ticket_recipient` запрещает менять получателя у тикета, который является следующим на выплату.
|
||
|
||
## Ключи и управление
|
||
|
||
На старте удобно считать, что у программы есть отдельный управляющий ключ `key_3`.
|
||
|
||
Целевая модель:
|
||
|
||
- `update_coef_limit` вызывает DAO;
|
||
- `grant_manager_limits` вызывает DAO;
|
||
- upgrade-authority программы после проверки передается DAO;
|
||
- `step_payout` остается открытым для любого подписанта, чтобы выплаты не зависели от одного оператора.
|