Compare commits

..

2 Commits

20 changed files with 259 additions and 24 deletions

View File

@ -0,0 +1,210 @@
# Shine Payments: e2e после переписи без Anchor и добавления Q3
## Краткое описание
Нужно вручную и через вспомогательные CLI-проверки подтвердить, что программа `shine_payments` после:
- переписи на чистый `solana_program`;
- отказа от `programs/common`;
- добавления очереди `Q3`;
- обновления HTML UI;
корректно работает на devnet с новым `program id`.
Отличие от финального боевого сценария:
- вместо DAO-механики используется обычный кошелёк `FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P`, которому даны права DAO на изменение коэффициента и выдачу лимитов менеджеру.
## Что именно проверять
### 1. Подготовка окружения
Проверить и зафиксировать:
- новый keypair программы `shine_payments`;
- новый `program id`;
- обновление `program id` в HTML UI и связанных настройках;
- наличие deploy authority, которой можно закрыть старый buffer/programdata, если это технически доступно;
- адреса тестовых кошельков:
- DAO/базовый кошелёк;
- менеджер;
- покупатель 1;
- покупатель 2;
- получатели выплат.
### 2. Очистка/смена старой программы
Проверить один из сценариев:
- если возможно, закрыть старый `program buffer/programdata` текущими ключами;
- если закрытие невозможно или нецелесообразно, зафиксировать это и продолжить с новым `program id`.
Отдельно проверить, что старые PDA предыдущей версии не используются новой программой.
### 3. Деплой и init новой программы
Проверить:
- `cargo build-sbf` проходит;
- новая программа деплоится на devnet;
- `init` выполняется один раз на пустых PDA;
- после `init` читаются:
- `config`;
- `coef_limit`;
- `queues`;
- `inflow_vault`.
Сразу после `init` запросить состояние очередей и зафиксировать, что:
- `Q1`, `Q2`, `Q3` пустые;
- `tickets_total = 0`;
- `tickets_paid = 0`;
- все суммы равны `0`.
### 4. Проверка покупки билета
На минимальных суммах проверить:
1. покупку через `buy_ticket_usd`;
2. покупку через `buy_ticket_sol`;
3. при необходимости ещё один вызов базового `buy_ticket`.
После каждой покупки:
- запросить состояние `Q1`;
- убедиться, что создался следующий ticket;
- проверить рост:
- `q1_tickets_total`;
- `q1_sum_total_usd_cents`;
- убедиться, что деньги покупки ушли в `dao_wallet`, а не в `inflow_vault`.
### 5. Проверка DAO-управления
Проверить:
1. изменение коэффициента через `update_coef_limit`;
2. повторный запрос `coef_limit` и подтверждение нового значения;
3. выдачу менеджеру прав через `grant_manager_limits`:
- отдельно под `Q1`;
- отдельно под `Q2`;
- отдельно под `Q3`.
После выдачи лимитов:
- считать `manager_allowance_pda`;
- убедиться, что лимиты записаны отдельно по трём очередям.
### 6. Проверка manager_add_ticket
На минимальных суммах создать менеджерские тикеты:
1. один ticket в `Q1`;
2. один ticket в `Q2`;
3. один ticket в `Q3`.
После каждого добавления:
- запросить состояние очередей;
- проверить рост счётчиков и сумм именно у нужной очереди;
- проверить уменьшение соответствующего manager allowance.
### 7. Проверка приоритета очередей
Подтвердить очередность `step_payout`:
1. сначала выплачивается `Q1`;
2. затем `Q2`;
3. затем `Q3`.
Для этого:
- между шагами регулярно читать `queues`;
- фиксировать, какой именно ticket был следующим к выплате;
- убедиться, что при наличии pending в `Q1` программа не уходит в `Q2` или `Q3`.
### 8. Проверка частичных выплат
Перед выплатами пополнять `inflow_vault` только минимально достаточными суммами.
Нужно проверить:
1. частичную серию выплат, когда часть тикетов ещё остаётся pending;
2. дополнительную покупку билета в промежутке между выплатами;
3. повторную проверку приоритета после появления нового билета в `Q1`.
После каждого `step_payout`:
- запрашивать состояние очередей;
- проверять:
- рост `tickets_paid`;
- рост `sum_paid_usd_cents`;
- `is_paid = true` у погашенного ticket;
- правильный DAO multiplier:
- `Q1 -> 1x`;
- `Q2 -> 2x`;
- `Q3 -> 3x`.
### 9. Проверка финального добора
После частичных выплат:
- купить ещё один билет;
- допополнить `inflow_vault`;
- выполнить оставшиеся `step_payout` до полного погашения всех трёх очередей.
В конце:
- все pending ticket должны отсутствовать;
- все суммы paid должны совпасть с total по каждой очереди;
- если вызвать `step_payout` на пустых очередях, доступный остаток `inflow_vault` должен уйти в `dao_wallet`.
### 10. Финальный возврат лампортов
После завершения теста вернуть все доступные остатки, которые можно вернуть текущими полномочиями, на базовый кошелёк:
- `FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P`
Отдельно зафиксировать:
- что именно удалось вернуть;
- что именно нельзя вернуть без специальной инструкции закрытия или без deploy authority.
## Ожидаемый результат
- `buy_ticket_usd` и `buy_ticket_sol` создают ticket без ошибок чтения state;
- `Q3` работает наравне с `Q2`, но с третьим приоритетом;
- DAO может менять коэффициент и выдавать лимиты;
- менеджер может создавать билеты во все три очереди;
- `step_payout` соблюдает порядок `Q1 -> Q2 -> Q3`;
- DAO-множитель на выплатах равен `1x/2x/3x` для `Q1/Q2/Q3`;
- HTML UI и on-chain программа используют один и тот же актуальный `program id`;
- остатки средств после теста по максимуму возвращены на базовый DAO-кошелёк.
## Статус
- `done`
## Итог выполнения
- новый `shine_payments` задеплоен в devnet с `program id`:
- `c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW`
- старый `shine_payments`:
- `m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR`
- закрыт, лампорты возвращены на базовый DAO-кошелёк
- HTML UI переведён на новый `program id`
- подтверждены:
- `init`
- `buy_ticket_usd`
- `buy_ticket_sol`
- `grant_manager_limits`
- `manager_add_ticket` для `Q1/Q2/Q3`
- `change_ticket_recipient`
- `update_coef_limit`
- `step_payout` по порядку `Q1 -> Q2 -> Q3`
- повторный возврат приоритета в `Q1` после новой покупки
- итоговые агрегаты очередей:
- `Q1 total=4, paid=4, sum_total=780, sum_paid=780`
- `Q2 total=1, paid=1, sum_total=60, sum_paid=60`
- `Q3 total=1, paid=1, sum_total=70, sum_paid=70`
- временные тестовые кошельки собраны обратно в базовый DAO-кошелёк
- в `inflow_vault` остался только rent-минимум PDA

View File

@ -48,7 +48,7 @@ DAO в текущем виде не является отдельной Anchor-
| --- | --- | | --- | --- |
| `shine_login_guard` | `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo` | | `shine_login_guard` | `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo` |
| `shine_users` | `FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm` | | `shine_users` | `FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm` |
| `shine_payments` | `m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR` | | `shine_payments` | `c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW` |
Если эти адреса меняются, нужно синхронно обновить: Если эти адреса меняются, нужно синхронно обновить:

View File

@ -28,7 +28,7 @@
| --- | --- | | --- | --- |
| `SHINE_LOGIN_GUARD_PROGRAM_ID` | `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo` | | `SHINE_LOGIN_GUARD_PROGRAM_ID` | `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo` |
| `SHINE_USERS_PROGRAM_ID` | `FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm` | | `SHINE_USERS_PROGRAM_ID` | `FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm` |
| `SHINE_PAYMENTS_PROGRAM_ID` | `m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR` | | `SHINE_PAYMENTS_PROGRAM_ID` | `c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW` |
| `DAO_AUTHORITY` | `FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P` | | `DAO_AUTHORITY` | `FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P` |
| `DAO_TREASURY_WALLET` | `FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P` | | `DAO_TREASURY_WALLET` | `FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P` |

View File

@ -16,7 +16,7 @@
- `shine_login_guard`: - `shine_login_guard`:
`3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo` `3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo`
- `shine_payments`: - `shine_payments`:
`m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR` `c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW`
## Подтверждение деплоя ## Подтверждение деплоя

View File

@ -43,7 +43,7 @@ shine-UI/server-ui.html
Актуальные адреса программ Solana (devnet): Актуальные адреса программ Solana (devnet):
- `shine_users`: `FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm` - `shine_users`: `FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm`
- `shine_payments`: `m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR` - `shine_payments`: `c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW`
Подробнее: `Dev_Docs/Инициализация_Solana_регистрации/README.md` Подробнее: `Dev_Docs/Инициализация_Solana_регистрации/README.md`

View File

@ -16,6 +16,6 @@ public final class SolanaProgramsConfig {
// Отдельно фиксируем адреса связанной инфраструктуры, чтобы UI/сервер ссылались одинаково. // Отдельно фиксируем адреса связанной инфраструктуры, чтобы UI/сервер ссылались одинаково.
public static final String SHINE_LOGIN_GUARD_PROGRAM_ID = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo"; public static final String SHINE_LOGIN_GUARD_PROGRAM_ID = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo";
public static final String SHINE_PAYMENTS_PROGRAM_ID = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"; public static final String SHINE_PAYMENTS_PROGRAM_ID = "c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW";
} }

View File

@ -1,2 +1,2 @@
client.version=1.2.131 client.version=1.2.132
server.version=1.2.123 server.version=1.2.124

View File

@ -5,4 +5,4 @@ export const SOLANA_ENDPOINT_DEFAULT = 'https://api.devnet.solana.com';
export const SHINE_USERS_PROGRAM_ID = 'FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm'; export const SHINE_USERS_PROGRAM_ID = 'FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm';
export const SHINE_USERS_ECONOMY_CONFIG_SEED = 'shine_users_economy_config'; export const SHINE_USERS_ECONOMY_CONFIG_SEED = 'shine_users_economy_config';
export const SHINE_LOGIN_GUARD_PROGRAM_ID = '3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo'; export const SHINE_LOGIN_GUARD_PROGRAM_ID = '3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo';
export const SHINE_PAYMENTS_PROGRAM_ID = 'm48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR'; export const SHINE_PAYMENTS_PROGRAM_ID = 'c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW';

View File

@ -6,12 +6,12 @@ resolution = true
skip-lint = false skip-lint = false
[programs.devnet] [programs.devnet]
shine_payments = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR" shine_payments = "c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW"
shine_users = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm" shine_users = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm"
shine_login_guard = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo" shine_login_guard = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo"
[programs.localnet] [programs.localnet]
shine_payments = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR" shine_payments = "c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW"
shine_users = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm" shine_users = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm"
shine_login_guard = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo" shine_login_guard = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo"

View File

@ -46,5 +46,5 @@ tasks.register("checkUiRemote", Exec) {
"grep -n 'test-solana-tickets.shineup.me\\|test-solana-tickets.shiningpeople.ru' /home/player/SHiNE/caddy/Caddyfile; " + "grep -n 'test-solana-tickets.shineup.me\\|test-solana-tickets.shiningpeople.ru' /home/player/SHiNE/caddy/Caddyfile; " +
"echo; " + "echo; " +
"echo 'Program ID в загруженных html:'; " + "echo 'Program ID в загруженных html:'; " +
"grep -R -n 'm48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR' /home/player/sites/test-solana-tickets.shineup.me/*.html" "grep -R -n 'c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW' /home/player/sites/test-solana-tickets.shineup.me/*.html"
} }

View File

@ -22,7 +22,7 @@
Текущий program id: Текущий program id:
- `m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR` - `c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW`
## 2. Основная модель ## 2. Основная модель

View File

@ -6,7 +6,7 @@
// ========================= // =========================
/// `SHINE_PAYMENTS_PROGRAM_ID` — адрес программы `shine_payments` для текущего окружения. /// `SHINE_PAYMENTS_PROGRAM_ID` — адрес программы `shine_payments` для текущего окружения.
pub const SHINE_PAYMENTS_PROGRAM_ID: &str = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"; pub const SHINE_PAYMENTS_PROGRAM_ID: &str = "c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW";
/// `SHINE_USERS_PROGRAM_ID` — адрес программы `shine_users` для текущего окружения. /// `SHINE_USERS_PROGRAM_ID` — адрес программы `shine_users` для текущего окружения.
pub const SHINE_USERS_PROGRAM_ID: &str = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm"; pub const SHINE_USERS_PROGRAM_ID: &str = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm";

View File

@ -14,7 +14,7 @@ use std::str::FromStr;
pub mod settings; pub mod settings;
solana_program::declare_id!("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); solana_program::declare_id!("c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW");
entrypoint!(process_instruction); entrypoint!(process_instruction);
const IX_INIT: u8 = 1; const IX_INIT: u8 = 1;
@ -250,11 +250,16 @@ impl<'a> Reader<'a> {
} }
trait StateCodec: Sized { trait StateCodec: Sized {
fn encoded_len() -> usize;
fn encode(&self) -> Vec<u8>; fn encode(&self) -> Vec<u8>;
fn decode(data: &[u8]) -> Result<Self, ProgramError>; fn decode(data: &[u8]) -> Result<Self, ProgramError>;
} }
impl StateCodec for ConfigState { impl StateCodec for ConfigState {
fn encoded_len() -> usize {
1 + 32 + 32
}
fn encode(&self) -> Vec<u8> { fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(65); let mut out = Vec::with_capacity(65);
out.push(self.version); out.push(self.version);
@ -274,6 +279,10 @@ impl StateCodec for ConfigState {
} }
impl StateCodec for CoefLimitState { impl StateCodec for CoefLimitState {
fn encoded_len() -> usize {
1 + 8 + 8 + 8
}
fn encode(&self) -> Vec<u8> { fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(25); let mut out = Vec::with_capacity(25);
out.push(self.version); out.push(self.version);
@ -295,6 +304,10 @@ impl StateCodec for CoefLimitState {
} }
impl StateCodec for QueuesState { impl StateCodec for QueuesState {
fn encoded_len() -> usize {
1 + 12 * 8
}
fn encode(&self) -> Vec<u8> { fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(97); let mut out = Vec::with_capacity(97);
out.push(self.version); out.push(self.version);
@ -339,6 +352,10 @@ impl StateCodec for QueuesState {
} }
impl StateCodec for TicketState { impl StateCodec for TicketState {
fn encoded_len() -> usize {
1 + 1 + 8 + 1 + 32 + 8 + 8
}
fn encode(&self) -> Vec<u8> { fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(59); let mut out = Vec::with_capacity(59);
out.push(self.version); out.push(self.version);
@ -370,6 +387,10 @@ impl StateCodec for TicketState {
} }
impl StateCodec for ManagerAllowanceState { impl StateCodec for ManagerAllowanceState {
fn encoded_len() -> usize {
1 + 32 + 8 + 8 + 8
}
fn encode(&self) -> Vec<u8> { fn encode(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(57); let mut out = Vec::with_capacity(57);
out.push(self.version); out.push(self.version);
@ -393,6 +414,10 @@ impl StateCodec for ManagerAllowanceState {
} }
impl StateCodec for VaultState { impl StateCodec for VaultState {
fn encoded_len() -> usize {
1
}
fn encode(&self) -> Vec<u8> { fn encode(&self) -> Vec<u8> {
vec![self.version] vec![self.version]
} }
@ -1162,9 +1187,9 @@ fn read_state<T: StateCodec>(pda: &AccountInfo) -> Result<T, ProgramError> {
require!(!is_uninitialized_account(pda), PaymentsError::EmptyState); require!(!is_uninitialized_account(pda), PaymentsError::EmptyState);
require_keys_eq!(*pda.owner, id(), PaymentsError::InvalidPdaAddress); require_keys_eq!(*pda.owner, id(), PaymentsError::InvalidPdaAddress);
let data = pda.try_borrow_data()?; let data = pda.try_borrow_data()?;
let used_len = data.iter().rposition(|b| *b != 0).map(|idx| idx + 1).unwrap_or(0); let encoded_len = T::encoded_len();
require!(used_len > 0, PaymentsError::EmptyState); require!(data.len() >= encoded_len, PaymentsError::InvalidAccountData);
T::decode(&data[..used_len]) T::decode(&data[..encoded_len])
} }
fn is_uninitialized_account(account: &AccountInfo) -> bool { fn is_uninitialized_account(account: &AccountInfo) -> bool {

View File

@ -110,7 +110,7 @@
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script> <script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
<script> <script>
const PROGRAM_ID = new solanaWeb3.PublicKey("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); const PROGRAM_ID = new solanaWeb3.PublicKey("c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW");
const USERS_PROGRAM_ID = new solanaWeb3.PublicKey("FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm"); const USERS_PROGRAM_ID = new solanaWeb3.PublicKey("FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm");
const RPC_URL = "https://api.devnet.solana.com"; const RPC_URL = "https://api.devnet.solana.com";
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed"); const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");

View File

@ -79,7 +79,7 @@
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script> <script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
<script> <script>
const PROGRAM_ID = new solanaWeb3.PublicKey("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); const PROGRAM_ID = new solanaWeb3.PublicKey("c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW");
const RPC_URL = "https://api.devnet.solana.com"; const RPC_URL = "https://api.devnet.solana.com";
const ORACLE_ACCOUNT = new solanaWeb3.PublicKey("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE"); const ORACLE_ACCOUNT = new solanaWeb3.PublicKey("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE");
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed"); const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");

View File

@ -84,7 +84,7 @@
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script> <script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
<script> <script>
const PROGRAM_ID = new solanaWeb3.PublicKey("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); const PROGRAM_ID = new solanaWeb3.PublicKey("c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW");
const RPC_URL = "https://api.devnet.solana.com"; const RPC_URL = "https://api.devnet.solana.com";
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed"); const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
const SEEDS = { const SEEDS = {

View File

@ -77,7 +77,7 @@
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script> <script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
<script> <script>
const PROGRAM_ID = new solanaWeb3.PublicKey("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); const PROGRAM_ID = new solanaWeb3.PublicKey("c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW");
const RPC_URL = "https://api.devnet.solana.com"; const RPC_URL = "https://api.devnet.solana.com";
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed"); const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");
const SEEDS = { const SEEDS = {

View File

@ -77,7 +77,7 @@
<script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script> <script src="https://unpkg.com/@solana/web3.js@1.95.3/lib/index.iife.min.js"></script>
<script> <script>
const PROGRAM_ID = new solanaWeb3.PublicKey("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); const PROGRAM_ID = new solanaWeb3.PublicKey("c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW");
const RPC_URL = "https://api.devnet.solana.com"; const RPC_URL = "https://api.devnet.solana.com";
const ORACLE_ACCOUNT = new solanaWeb3.PublicKey("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE"); const ORACLE_ACCOUNT = new solanaWeb3.PublicKey("7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE");
const connection = new solanaWeb3.Connection(RPC_URL, "confirmed"); const connection = new solanaWeb3.Connection(RPC_URL, "confirmed");

View File

@ -11,7 +11,7 @@ pub const USERS_ECONOMY_CONFIG_SPACE: usize = 32;
pub const DAO_AUTHORITY: &str = "FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P"; pub const DAO_AUTHORITY: &str = "FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P";
/// Адрес программы `shine_payments`, от которой вычисляется PDA inflow-вольта. /// Адрес программы `shine_payments`, от которой вычисляется PDA inflow-вольта.
pub const SHINE_PAYMENTS_PROGRAM_ID: &str = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"; pub const SHINE_PAYMENTS_PROGRAM_ID: &str = "c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW";
/// Seed inflow-вольта в программе `shine_payments`. /// Seed inflow-вольта в программе `shine_payments`.
pub const SHINE_PAYMENTS_INFLOW_VAULT_SEED: &[u8] = b"shine_payments_inflow_vault"; pub const SHINE_PAYMENTS_INFLOW_VAULT_SEED: &[u8] = b"shine_payments_inflow_vault";
/// Адрес отдельной программы проверки премиальности логина. /// Адрес отдельной программы проверки премиальности логина.

View File

@ -31,7 +31,7 @@ const LIMIT_STEP = 10_000n;
const START_BONUS_LIMIT = 100_000n; const START_BONUS_LIMIT = 100_000n;
const USERS_ECONOMY_CONFIG_SEED = "shine_users_economy_config"; const USERS_ECONOMY_CONFIG_SEED = "shine_users_economy_config";
const SHINE_PAYMENTS_PROGRAM_ID = new PublicKey( const SHINE_PAYMENTS_PROGRAM_ID = new PublicKey(
"m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR" "c4yTa4JT9EtQDCBX9LmWFK6T2gp4JGsuymFbom2EudW"
); );
const SHINE_PAYMENTS_INFLOW_VAULT_SEED = "shine_payments_inflow_vault"; const SHINE_PAYMENTS_INFLOW_VAULT_SEED = "shine_payments_inflow_vault";