From 56cd90a19763d9087bb399d8686b766f644ad6414ff8c59fd0272f6b2acf72db Mon Sep 17 00:00:00 2001 From: AidarKC Date: Sun, 24 May 2026 12:16:39 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D1=82=D0=BA=D0=BB=D1=8E=D1=87=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=80=D0=B5=D0=BF=D0=BE=D1=81=D1=82=D1=8B=20?= =?UTF-8?q?=D0=B8=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D1=82=D1=8C=20Sol?= =?UTF-8?q?ana-=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 23 + AGENTS.md | 16 + .../API/04_Add_Block_to_Blockchain_API.md | 5 +- Dev_Docs/Blockchain/11_TEXT_Blocks.md | 3 +- Dev_Docs/Blockchain/CHANGELOG.md | 6 + ...6-05-24_1140_репосты_в_каналах_и_тредах.md | 93 + Dev_Docs/Future_Features/README.md | 14 + ...6-05-21_1908_репосты_в_каналах_и_тредах.md | 21 - ...2026-05-24_1032_agent-bot-групповой-чат.md | 23 + SHiNE-agent-bot-coder/AGENT.md | 8 +- SHiNE-agent-bot-coder/README.md | 6 +- SHiNE-agent-bot-coder/py_bot_service.py | 87 +- VERSION.properties | 4 +- shine-UI/js/pages/channel-thread-view.js | 21 +- shine-UI/js/pages/channel-view.js | 16 +- .../blockchain/Net_AddBlock_Handler.java | 10 + shine-solana/shine/.gitignore | 9 + shine-solana/shine/.prettierignore | 7 + shine-solana/shine/AGENTS.md | 63 + shine-solana/shine/Anchor.toml | 29 + shine-solana/shine/Cargo.lock | 7464 +++++++++++++++++ shine-solana/shine/Cargo.toml | 20 + shine-solana/shine/build.gradle | 44 + shine-solana/shine/doc/FUNDS_FLOW.md | 47 + .../shine/doc/SHiNE-user-format-v.1.0.md | 225 + .../shine/doc/devnet_keys_and_deploy.md | 55 + shine-solana/shine/migrations/deploy.ts | 12 + shine-solana/shine/package-lock.json | 3021 +++++++ shine-solana/shine/package.json | 27 + shine-solana/shine/programs/common/Cargo.toml | 10 + .../programs/common/src/deploy_config.rs | 43 + shine-solana/shine/programs/common/src/lib.rs | 2 + .../shine/programs/common/src/utils.rs | 359 + .../programs/shine_login_guard/Cargo.toml | 26 + .../shine/programs/shine_login_guard/build.rs | 114 + .../dictionaries/premium/adjectives_core.txt | 88 + .../dictionaries/premium/nicknames_people.txt | 421 + .../src/dictionaries/premium/nouns_core.txt | 204 + .../src/dictionaries/premium/people_names.txt | 1221 +++ .../premium/prefixes_connectors.txt | 45 + .../src/dictionaries/premium/web3_finance.txt | 41 + .../dictionaries/trademarks/consumer_auto.txt | 193 + .../dictionaries/trademarks/tech_global.txt | 364 + .../trademarks/top500_marketcap_global.txt | 502 ++ .../programs/shine_login_guard/src/lib.rs | 105 + .../shine/programs/shine_payments/Cargo.toml | 28 + .../shine/programs/shine_payments/src/lib.rs | 1147 +++ .../programs/shine_payments/src/settings.rs | 54 + .../shine_payments/web/admin_tools.html | 561 ++ .../shine_payments/web/buy_ticket.html | 428 + .../shine_payments/web/dao_revoke_vote.html | 342 + .../shine_payments/web/dao_tools.html | 274 + .../programs/shine_payments/web/index.html | 90 + .../shine_payments/web/logic_overview.html | 65 + .../shine_payments/web/manager_tools.html | 280 + .../shine_payments/web/roadmap_dao.html | 45 + .../shine_payments/web/test_plan.html | 63 + .../shine_payments/web/track_ticket.html | 506 ++ .../shine/programs/shine_users/Cargo.toml | 29 + .../shine/programs/shine_users/src/lib.rs | 32 + .../programs/shine_users/src/settings.rs | 30 + .../shine/programs/shine_users/src/users.rs | 993 +++ .../00_prepare_voter2_deposit.js | 38 + .../01_create_nft_for_wallet_admin.js | 56 + .../01b_create_empty_nft_template.js | 44 + .../02_propose_vote_mint_nft.js | 60 + .../03_execute_mint_nft.js | 30 + .../04_propose_vote_burn_nft.js | 53 + .../05_execute_burn_nft.js | 26 + .../CreateGovernmentNFTAndDAO/README.md | 66 + .../CreateGovernmentNFTAndDAO/js_common.js | 50 + .../01_create_governance_token.sh | 11 + .../02_mint_token_to_wallet.sh | 21 + .../03_force_burn_from_wallet.sh | 19 + .../04_create_dao.sh | 10 + .../05_transfer_rights_to_governance_pda.sh | 11 + .../CreateGovernmentTokenAndDAO/README.md | 74 + .../grind_vanity_mint.sh | 19 + .../js/01_create_governance_token_exec.js | 40 + .../js/02_mint_membership_to_wallet_exec.js | 34 + .../js/03_force_burn_from_wallet_exec.js | 22 + ..._transfer_rights_to_governance_pda_exec.js | 28 + .../js/05_create_dao_exec.js | 191 + .../CreateGovernmentTokenAndDAO/js/_common.js | 118 + .../js/grind_vanity_mint_exec.js | 36 + shine-solana/shine/scripts/dao/README.md | 60 + .../dao/create_realm_dao_full_build_exec.js | 456 + .../scripts/dao/create_realm_dao_full_test.sh | 106 + .../execute_revoke_transaction_full_exec.js | 107 + .../propose_vote_execute_revoke_full_exec.js | 399 + .../dao/revoke_member_token_full_exec.js | 111 + shine-solana/shine/settings.gradle | 1 + shine-solana/shine/tests/shine.ts | 328 + shine-solana/shine/tsconfig.json | 10 + shine-solana/shine/yarn.lock | 1606 ++++ 95 files changed, 24261 insertions(+), 64 deletions(-) create mode 100644 Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md create mode 100644 Dev_Docs/Future_Features/README.md delete mode 100644 Dev_Docs/Pending_Features/2026-05-21_1908_репосты_в_каналах_и_тредах.md create mode 100644 Dev_Docs/Pending_Features/2026-05-24_1032_agent-bot-групповой-чат.md create mode 100644 shine-solana/shine/.gitignore create mode 100644 shine-solana/shine/.prettierignore create mode 100644 shine-solana/shine/AGENTS.md create mode 100644 shine-solana/shine/Anchor.toml create mode 100644 shine-solana/shine/Cargo.lock create mode 100644 shine-solana/shine/Cargo.toml create mode 100644 shine-solana/shine/build.gradle create mode 100644 shine-solana/shine/doc/FUNDS_FLOW.md create mode 100644 shine-solana/shine/doc/SHiNE-user-format-v.1.0.md create mode 100644 shine-solana/shine/doc/devnet_keys_and_deploy.md create mode 100644 shine-solana/shine/migrations/deploy.ts create mode 100644 shine-solana/shine/package-lock.json create mode 100644 shine-solana/shine/package.json create mode 100644 shine-solana/shine/programs/common/Cargo.toml create mode 100644 shine-solana/shine/programs/common/src/deploy_config.rs create mode 100644 shine-solana/shine/programs/common/src/lib.rs create mode 100644 shine-solana/shine/programs/common/src/utils.rs create mode 100644 shine-solana/shine/programs/shine_login_guard/Cargo.toml create mode 100644 shine-solana/shine/programs/shine_login_guard/build.rs create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/adjectives_core.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nicknames_people.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nouns_core.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/people_names.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/prefixes_connectors.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/web3_finance.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/consumer_auto.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/tech_global.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/top500_marketcap_global.txt create mode 100644 shine-solana/shine/programs/shine_login_guard/src/lib.rs create mode 100644 shine-solana/shine/programs/shine_payments/Cargo.toml create mode 100644 shine-solana/shine/programs/shine_payments/src/lib.rs create mode 100644 shine-solana/shine/programs/shine_payments/src/settings.rs create mode 100644 shine-solana/shine/programs/shine_payments/web/admin_tools.html create mode 100644 shine-solana/shine/programs/shine_payments/web/buy_ticket.html create mode 100644 shine-solana/shine/programs/shine_payments/web/dao_revoke_vote.html create mode 100644 shine-solana/shine/programs/shine_payments/web/dao_tools.html create mode 100644 shine-solana/shine/programs/shine_payments/web/index.html create mode 100644 shine-solana/shine/programs/shine_payments/web/logic_overview.html create mode 100644 shine-solana/shine/programs/shine_payments/web/manager_tools.html create mode 100644 shine-solana/shine/programs/shine_payments/web/roadmap_dao.html create mode 100644 shine-solana/shine/programs/shine_payments/web/test_plan.html create mode 100644 shine-solana/shine/programs/shine_payments/web/track_ticket.html create mode 100644 shine-solana/shine/programs/shine_users/Cargo.toml create mode 100644 shine-solana/shine/programs/shine_users/src/lib.rs create mode 100644 shine-solana/shine/programs/shine_users/src/settings.rs create mode 100644 shine-solana/shine/programs/shine_users/src/users.rs create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/00_prepare_voter2_deposit.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01_create_nft_for_wallet_admin.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01b_create_empty_nft_template.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/02_propose_vote_mint_nft.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/03_execute_mint_nft.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/04_propose_vote_burn_nft.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/05_execute_burn_nft.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/README.md create mode 100644 shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/js_common.js create mode 100755 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/01_create_governance_token.sh create mode 100755 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/02_mint_token_to_wallet.sh create mode 100755 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/03_force_burn_from_wallet.sh create mode 100755 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/04_create_dao.sh create mode 100755 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/05_transfer_rights_to_governance_pda.sh create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/README.md create mode 100755 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/grind_vanity_mint.sh create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/01_create_governance_token_exec.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/02_mint_membership_to_wallet_exec.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/03_force_burn_from_wallet_exec.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/04_transfer_rights_to_governance_pda_exec.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/05_create_dao_exec.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/_common.js create mode 100644 shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/grind_vanity_mint_exec.js create mode 100644 shine-solana/shine/scripts/dao/README.md create mode 100755 shine-solana/shine/scripts/dao/create_realm_dao_full_build_exec.js create mode 100755 shine-solana/shine/scripts/dao/create_realm_dao_full_test.sh create mode 100644 shine-solana/shine/scripts/dao/execute_revoke_transaction_full_exec.js create mode 100755 shine-solana/shine/scripts/dao/propose_vote_execute_revoke_full_exec.js create mode 100755 shine-solana/shine/scripts/dao/revoke_member_token_full_exec.js create mode 100644 shine-solana/shine/settings.gradle create mode 100644 shine-solana/shine/tests/shine.ts create mode 100644 shine-solana/shine/tsconfig.json create mode 100644 shine-solana/shine/yarn.lock diff --git a/.gitignore b/.gitignore index dd98de0..34a8e4b 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,26 @@ bin/ # временный debug token .debug-token + +# Локальные артефакты и секреты Solana-модуля +shine-solana/.git/ +shine-solana/.git-local-backup/ +shine-solana/.idea/ +shine-solana/shine/.idea/ +shine-solana/shine/.gradle/ +shine-solana/shine/.anchor/ +shine-solana/shine/.yarn/ +shine-solana/shine/.vendor/ +shine-solana/shine/node_modules/ +shine-solana/shine/target/ +shine-solana/shine/test-ledger/ +shine-solana/shine/old_vers/ +shine-solana/shine/program-keypair.json +shine-solana/shine/keys/ +shine-solana/shine/validator.log +shine-solana/shine/doc/КОШЕЛЬКИ_DEVNET_ТЕСТ.md +shine-solana/shine/scripts/del/ +shine-solana/shine/scripts/**/keypairs/ +shine-solana/shine/scripts/**/runs/ +shine-solana/shine/scripts/**/*.env +shine-solana/shine/scripts/**/TEMP_*.md diff --git a/AGENTS.md b/AGENTS.md index 7a9b0be..eb82179 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,6 +13,13 @@ - Сервис принимает сообщения из Telegram, ведёт историю диалога, ставит задачи в очередь и вызывает Codex CLI для обработки запросов по проекту. - Подробные правила работы сервиса, его очередь, история, systemd-запуск и особенности ответов описывать в `SHiNE-agent-bot-coder/AGENT.md`. +## Solana-модуль +- В проекте есть отдельный Solana/Anchor-модуль в папке `shine-solana/shine/`. +- Модуль логически связан с SHiNE, но не должен автоматически подключаться к сборке или деплою основного сервера без отдельного решения. +- В Solana-модуле действуют локальные инструкции `shine-solana/shine/AGENTS.md`; при изменениях внутри модуля сначала читать их. +- В git добавлять исходники, lock-файлы, настройки проекта и документацию Solana-модуля, но не добавлять локальные ключи, `.git`, `.idea`, `.gradle`, `target`, `node_modules`, `test-ledger`, логи, временные run-отчёты и `.env`-конфиги. +- Для Solana deploy/push использовать правила из локального `shine-solana/shine/AGENTS.md`; не смешивать deploy Solana-модуля с `deployServer`/`deployUI` основного проекта. + ## Документация блокчейна - Актуальная документация по форматам блокчейна находится в `Dev_Docs/Blockchain/README.md`. - Это точка входа (оглавление), рядом расположены детальные файлы по форматам, типам каналов и командным сообщениям. @@ -90,6 +97,15 @@ - После подтверждения, что фича проверена и работает корректно, соответствующий файл удалять. - В `Dev_Docs/Pending_Features/README.md` вести краткий регламент и поддерживать актуальность. +## Будущие фичи +- Папка для задач, сознательно отложенных на будущее: `Dev_Docs/Future_Features/`. +- Файлы из этой папки не считать активными задачами и не начинать реализацию без явной просьбы пользователя. +- Если часть кода временно отключена или закомментирована, в файле будущей фичи подробно описывать: + - какие файлы и участки отключены; + - что осталось в коде как заготовка; + - какие документы нужно обновить при возврате; + - с какого сценария продолжать разработку. + ## Коммуникация по новым задачам (обязательно) - При получении нового задания сначала кратко пересказать задачу своими словами. - До начала реализации задать недостающие уточняющие вопросы (если они есть). diff --git a/Dev_Docs/API/04_Add_Block_to_Blockchain_API.md b/Dev_Docs/API/04_Add_Block_to_Blockchain_API.md index 62d839d..cc3ae4c 100644 --- a/Dev_Docs/API/04_Add_Block_to_Blockchain_API.md +++ b/Dev_Docs/API/04_Add_Block_to_Blockchain_API.md @@ -81,11 +81,12 @@ - `bad_signature`, `signature_verify_failed` - `prev_line_block_not_found`, `bad_prev_line_hash` - `limit_exceeded` +- `repost_disabled` — репосты временно отключены до будущей реализации - `internal_error` ## 5. Какие блоки реально можно добавлять через `AddBlock` -Через `AddBlock` можно писать все поддержанные форматы: +Через `AddBlock` можно писать поддержанные форматы, кроме явно отключённых временных фич: 1. **TECH (type=0)** - `HEADER_COMPAT (subType=0)` @@ -96,7 +97,7 @@ - `TEXT_EDIT_POST (11)` - `TEXT_REPLY (20)` - `TEXT_EDIT_REPLY (21)` - - `TEXT_REPOST (30)` + - `TEXT_REPOST (30)` — формат зарезервирован, но новые блоки временно отклоняются с `repost_disabled` 3. **REACTION (type=2)** - `REACTION_LIKE (1)` diff --git a/Dev_Docs/Blockchain/11_TEXT_Blocks.md b/Dev_Docs/Blockchain/11_TEXT_Blocks.md index c9e5bf0..fdf58f2 100644 --- a/Dev_Docs/Blockchain/11_TEXT_Blocks.md +++ b/Dev_Docs/Blockchain/11_TEXT_Blocks.md @@ -24,7 +24,8 @@ TEXT-тип хранит сообщения и редактирования. 5. `subType=30` — `TEXT_REPOST` - репост сообщения в линию канала; - содержит line-поля + target на оригинальное сообщение + текст комментария; - - на текущем этапе продуктовой логики репост не редактируется (версии не накапливаются). + - на текущем этапе продуктовой логики репост не редактируется (версии не накапливаются); + - временно отключён для записи через `AddBlock` до будущей реализации репостов. ## Правило для edit diff --git a/Dev_Docs/Blockchain/CHANGELOG.md b/Dev_Docs/Blockchain/CHANGELOG.md index 7b8e486..3feb46b 100644 --- a/Dev_Docs/Blockchain/CHANGELOG.md +++ b/Dev_Docs/Blockchain/CHANGELOG.md @@ -1,5 +1,11 @@ # История изменений документации блокчейна +## 2026-05-24 11:40:00 +0300 +- Базовый коммит-ориентир: `abdce05`. +- `TEXT_REPOST (subType=30)` оставлен как зарезервированный формат, но новые блоки репоста временно отключены на уровне `AddBlock`. +- В `11_TEXT_Blocks.md` зафиксировано, что запись `TEXT_REPOST` временно не используется до будущей реализации. +- В `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md` добавлен код отказа `repost_disabled`. + ## 2026-05-21 19:05:00 +0300 - Базовый коммит-ориентир: `5344c42`. - Добавлен новый TEXT-подтип `TEXT_REPOST (subType=30)`: diff --git a/Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md b/Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md new file mode 100644 index 0000000..14238fa --- /dev/null +++ b/Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md @@ -0,0 +1,93 @@ +# Репосты в каналах и тредах + +- Статус: + `future` + +- Решение от 2026-05-24: + Репосты временно убраны из активной разработки. Фича уже была частично реализована, но не доведена до финальной проверки. Чтобы она не мешала запуску проекта, пользовательский вход в репосты отключён в UI, а сервер больше не принимает новые `TEXT_REPOST` через `AddBlock`. + +## Что должна делать фича + +Репост должен позволять взять сообщение из канала или треда и опубликовать его в один из своих каналов с комментарием. + +Ожидаемый пользовательский сценарий после возврата к задаче: + +1. Пользователь открывает сообщение в канале или треде. +2. Нажимает `Репост`. +3. Выбирает один из своих каналов. +4. Добавляет комментарий. +5. Отправляет репост. +6. В целевом канале появляется новый пост-репост. +7. У репоста есть переход к исходному сообщению через действие `Оригинал`. + +## Что уже есть в коде + +- В блокчейн-формате зарезервирован и описан подтип `TEXT_REPOST (30)`. +- Парсер блокчейна умеет распознавать тело репоста как `TextLineBody`. +- В UI есть функция сборки тела репоста: + `shine-UI/js/services/auth-service.js`, `makeTextRepostBodyBytes`. +- В UI есть клиентская операция: + `shine-UI/js/services/auth-service.js`, `addBlockRepost`. +- В экране канала был обработчик репоста: + `shine-UI/js/pages/channel-view.js`, `onRepost`. +- В экране треда был обработчик репоста: + `shine-UI/js/pages/channel-thread-view.js`, `onRepost`. +- Серверная выдача каналов и тредов частично учитывает `TEXT_REPOST` и target-поля: + `targetBlockchainName`, `targetBlockNumber`, `targetBlockHash`. +- В списке подписок `TEXT_REPOST` считается публикацией канала. + +## Что сейчас отключено + +- В `shine-UI/js/pages/channel-view.js` кнопка `Репост` больше не создаётся и не добавляется в список действий сообщения. +- В `shine-UI/js/pages/channel-thread-view.js` кнопка `Репост` больше не создаётся и не добавляется в список действий ответа/сообщения треда. +- В `shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java` добавлена явная временная блокировка: + если новый блок имеет `type=1` и `subType=TEXT_REPOST (30)`, `AddBlock` возвращает ошибку `repost_disabled`. + +## Что осталось активным намеренно + +- Константа `TEXT_REPOST (30)` остаётся в коде и документации как зарезервированный формат. +- Парсер блокчейна продолжает знать формат `TEXT_REPOST`, чтобы не потерять уже написанную основу и не ломать потенциальное чтение старых тестовых данных. +- Код формирования репоста в `auth-service.js` не удалён: его можно будет использовать как основу при возвращении к задаче. +- Код отображения target-полей и перехода к оригиналу не удалён: он нужен для будущей проверки и возможной совместимости с уже созданными тестовыми блоками. + +## Почему это не лежит в Pending_Features + +`Dev_Docs/Pending_Features/` предназначена для фич, которые уже реализованы и ждут ручной проверки. + +Репосты сейчас не подходят под этот статус: они не должны проверяться как готовая фича, потому что пользовательский сценарий временно закрыт, а серверная запись новых репостов заблокирована. Поэтому старый pending-файл удалён, а задача перенесена сюда как будущая. + +## Что сделать при возврате к реализации + +1. Решить, остаётся ли формат `TEXT_REPOST (30)` финальным. +2. Если формат меняется, заранее предупредить пользователя и получить отдельное подтверждение на изменение блокчейн-формата. +3. Вернуть UI-кнопки репоста в: + - `shine-UI/js/pages/channel-view.js`; + - `shine-UI/js/pages/channel-thread-view.js`. +4. Снять временную блокировку `repost_disabled` в: + `shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java`. +5. Проверить `auth-service.js`: + - `makeTextRepostBodyBytes`; + - `addBlockRepost`; + - актуализацию вершины блокчейна перед `AddBlock`; + - корректность target-полей исходного сообщения. +6. Проверить серверное чтение: + - `GetChannelMessages`; + - `GetMessageThread`; + - отображение `targetBlockchainName`, `targetBlockNumber`, `targetBlockHash`. +7. Добавить или обновить тесты на успешный репост и отказ некорректных target-полей. +8. Обновить документацию: + - `Dev_Docs/Blockchain/11_TEXT_Blocks.md`; + - `Dev_Docs/Blockchain/CHANGELOG.md`; + - `Dev_Docs/API/04_Add_Block_to_Blockchain_API.md`; + - документы API чтения каналов/тредов, если изменятся поля ответа. +9. После реализации перенести задачу из `Dev_Docs/Future_Features/` в `Dev_Docs/Pending_Features/` как фичу, требующую ручной проверки. + +## Минимальный чек-лист ручной проверки в будущем + +1. Репост из сообщения канала в свой канал. +2. Репост из ответа в треде в свой канал. +3. Ошибка при попытке репоста в чужой канал. +4. Переход `Оригинал` из репоста к исходному сообщению. +5. Корректное отображение комментария к репосту. +6. Корректная работа после перезагрузки страницы. +7. Отсутствие поломки обычных постов, ответов, лайков и отправки ссылки. diff --git a/Dev_Docs/Future_Features/README.md b/Dev_Docs/Future_Features/README.md new file mode 100644 index 0000000..6a51e70 --- /dev/null +++ b/Dev_Docs/Future_Features/README.md @@ -0,0 +1,14 @@ +# Будущие фичи + +Эта папка хранит задачи, которые сознательно отложены и сейчас не должны попадать в активную разработку или ручную проверку. + +## Как использовать + +1. Каждая будущая фича описывается отдельным markdown-файлом. +2. В файле нужно фиксировать: + - зачем нужна фича; + - что уже было сделано в коде; + - что временно отключено или закомментировано; + - какие документы нужно обновить при возврате к задаче; + - с какого места продолжать разработку. +3. Агент не должен начинать реализацию файлов из этой папки без явной просьбы пользователя. diff --git a/Dev_Docs/Pending_Features/2026-05-21_1908_репосты_в_каналах_и_тредах.md b/Dev_Docs/Pending_Features/2026-05-21_1908_репосты_в_каналах_и_тредах.md deleted file mode 100644 index a4ad03d..0000000 --- a/Dev_Docs/Pending_Features/2026-05-21_1908_репосты_в_каналах_и_тредах.md +++ /dev/null @@ -1,21 +0,0 @@ -# Репосты в каналах и тредах - -- Краткое описание: - Добавлен подтип `TEXT_REPOST (30)` и UI-режим репоста с комментарием. Репост можно делать как из сообщения канала, так и из сообщения в треде. Для репоста выбирается один из своих каналов. - -- Что проверять: - 1. В канале открыть любое сообщение и нажать `Репост`. - 2. Выбрать свой канал, ввести комментарий, отправить. - 3. Убедиться, что в целевом канале появился новый пост-репост. - 4. Нажать `Оригинал` у репоста и подтвердить переход. - 5. Проверить, что переход открывает исходное сообщение. - 6. Повторить сценарий из треда (для сообщения-ответа). - -- Ожидаемый результат: - - Репост успешно записывается в блокчейн как `TEXT_REPOST`. - - В выдаче `GetChannelMessages`/`GetMessageThread` возвращаются поля target (`targetBlockchainName`, `targetBlockNumber`, `targetBlockHash`) для репоста. - - Кнопка `Оригинал` открывает нужное исходное сообщение. - - Для репоста не отображается история редактирования (одна версия). - -- Статус: - `pending` diff --git a/Dev_Docs/Pending_Features/2026-05-24_1032_agent-bot-групповой-чат.md b/Dev_Docs/Pending_Features/2026-05-24_1032_agent-bot-групповой-чат.md new file mode 100644 index 0000000..986f099 --- /dev/null +++ b/Dev_Docs/Pending_Features/2026-05-24_1032_agent-bot-групповой-чат.md @@ -0,0 +1,23 @@ +# Групповой чат агента-кодера + +## Что сделано +- Сервис `SHiNE-agent-bot-coder` теперь сохраняет сообщения участников обычной Telegram-группы и supergroup как контекст. +- На сообщения других участников группы сервис отвечает в тот же чат коротким подтверждением `Получил сообщение.`, но не создаёт задачу Codex. +- При миграции обычной группы в supergroup сервис запоминает новый `chat_id` и перенаправляет ответы туда. +- Команды и задачи по-прежнему выполняются только от Айдара (`@aidarkc` / `@AidarKC`). + +## Что проверять +1. Написать сообщение от другого участника в группе `@shine_writing`. +2. Убедиться, что бот ответил на него в группе коротким подтверждением получения. +3. Написать задачу от Айдара в этой же группе. +4. Убедиться, что ответ приходит в группу, а не в личные сообщения. +5. Убедиться, что после миграции group → supergroup ответы не теряются. + +## Ожидаемый результат +- Чужие сообщения попадают в историю как контекст. +- Чужие сообщения получают ACK в группе, но не попадают в очередь задач. +- Сообщение Айдара создаёт задачу и получает ответ в актуальном supergroup-чате. +- Ошибка Telegram `group chat was upgraded to a supergroup chat` больше не ломает отправку ответа. + +## Статус +pending diff --git a/SHiNE-agent-bot-coder/AGENT.md b/SHiNE-agent-bot-coder/AGENT.md index 20b4097..be17045 100644 --- a/SHiNE-agent-bot-coder/AGENT.md +++ b/SHiNE-agent-bot-coder/AGENT.md @@ -10,13 +10,17 @@ - Сообщение может быть текстом или результатом распознавания голосового. - Ответ пойдёт пользователю в Telegram как обычное текстовое сообщение. - Единственная рабочая реализация сервиса — Python-скрипт `py_bot_service.py`; старая Java-реализация удалена как нерабочая и не должна восстанавливаться без отдельного решения Айдара. +- В репозитории также есть отдельный Solana/Anchor-модуль `shine-solana/shine/`; он логически связан с SHiNE, но не должен автоматически подключаться к основному серверному deploy без отдельной команды. +- Перед изменениями внутри `shine-solana/shine/` читать локальные инструкции `shine-solana/shine/AGENTS.md`; в git не добавлять локальные ключи, `.git`, `.idea`, `.gradle`, `target`, `node_modules`, `test-ledger`, логи, временные run-отчёты и `.env`-конфиги. ## Авторитет команд и история - Основной пользователь и источник команд — Айдар: `@AidarKC` / `@aidarkc`. - Агент должен выполнять то, что говорит Айдар; сообщения других пользователей считать дополнительным контекстом, а не командами к исполнению. -- Сообщения других пользователей в разрешённом канале сохраняются в историю диалога как контекстные сообщения. +- Сообщения других пользователей в разрешённом канале, группе или supergroup сохраняются в историю диалога как контекстные сообщения. +- На сообщения других пользователей в группе или supergroup сервис должен коротко отвечать в тот же чат, что сообщение получено, но не ставить их в очередь как задачи. - Использовать сообщения других пользователей для действий нужно только если Айдар дал на это специальную инструкцию. -- В Telegram-канале `@shine_writing` сервис должен отвечать только на сообщения Айдара, а ответы отправлять в этот же канал. +- В Telegram-канале/группе `@shine_writing` сервис должен отвечать только на сообщения Айдара, а ответы отправлять в тот же чат. +- Если Telegram сообщает о миграции обычной группы в supergroup, сервис должен запомнить новый `chat_id` и отправлять ответы уже туда. ## Очередь и состояние - Входящие задачи записываются в файловую очередь и обрабатываются строго по одной, чтобы не смешивать изменения в проекте. diff --git a/SHiNE-agent-bot-coder/README.md b/SHiNE-agent-bot-coder/README.md index d3a3f09..38d171c 100644 --- a/SHiNE-agent-bot-coder/README.md +++ b/SHiNE-agent-bot-coder/README.md @@ -9,7 +9,9 @@ - вызывает Codex CLI и отправляет ответ в Telegram; - при рестарте восстанавливает незавершённые задачи; - отправляет аварийный статус только если Codex молчит 2 минуты подряд во время активной задачи; -- принимает сообщения из канала `@shine_writing`, выполняет команды только от `@AidarKC`, а сообщения других авторов сохраняет как контекст. +- принимает сообщения из канала/группы `@shine_writing`, выполняет команды только от `@AidarKC`, а сообщения других авторов сохраняет как контекст; +- на сообщения других участников группы отвечает в тот же чат коротким подтверждением получения, не создавая задачу Codex; +- учитывает миграцию обычной Telegram-группы в supergroup и перенаправляет ответы на новый `chat_id`. Рабочая реализация сервиса — только `py_bot_service.py`. Старая Java-реализация удалена, потому что не заработала и больше не используется. @@ -27,7 +29,7 @@ 2. Заполнить секреты в `.env`. - `TELEGRAM_BOT_TOKEN` — токен рабочего Telegram-бота. - `ALLOWED_TELEGRAM_USERNAME` — пользователь, чьи сообщения выполняются как команды. - - `ALLOWED_TELEGRAM_CHANNEL_USERNAME` — канал, из которого принимаются `channel_post`. + - `ALLOWED_TELEGRAM_CHANNEL_USERNAME` — канал, из которого принимаются `channel_post`; обычные group/supergroup-сообщения обрабатываются как `message`. 3. Запуск: - `python3 SHiNE-agent-bot-coder/py_bot_service.py` diff --git a/SHiNE-agent-bot-coder/py_bot_service.py b/SHiNE-agent-bot-coder/py_bot_service.py index 6a76d3e..9159315 100644 --- a/SHiNE-agent-bot-coder/py_bot_service.py +++ b/SHiNE-agent-bot-coder/py_bot_service.py @@ -8,6 +8,7 @@ import json import mimetypes import os import random +import re import string import subprocess import tempfile @@ -350,6 +351,56 @@ class ShinePyBotService: history_path = self._current_history_file() self._append_history(history_path, "system_event", {"event": event_type, **payload}) + def _resolve_chat_id(self, chat_id: int) -> int: + migrations = self.state.get("chat_id_migrations") + if not isinstance(migrations, dict): + return chat_id + current = chat_id + visited: set[int] = set() + while current not in visited: + visited.add(current) + next_chat_id = migrations.get(str(current)) + if not isinstance(next_chat_id, int): + break + current = next_chat_id + return current + + def _remember_chat_migration(self, old_chat_id: int, new_chat_id: int, source: str) -> None: + if old_chat_id == new_chat_id: + return + migrations = self.state.get("chat_id_migrations") + if not isinstance(migrations, dict): + migrations = {} + self.state["chat_id_migrations"] = migrations + if migrations.get(str(old_chat_id)) == new_chat_id: + return + migrations[str(old_chat_id)] = new_chat_id + self._persist_state() + with self.queue_lock: + changed = False + for job in self.queue: + if job.get("chat_id") == old_chat_id: + job["chat_id"] = new_chat_id + job["updated_at"] = now_iso() + changed = True + if changed: + self._persist_queue() + self._append_history_event("chat_migrated_to_supergroup", { + "oldChatId": old_chat_id, + "newChatId": new_chat_id, + "source": source, + }) + + @staticmethod + def _extract_migrate_to_chat_id(error_text: str) -> int | None: + match = re.search(r'"migrate_to_chat_id"\s*:\s*(-?\d+)', error_text) + if match: + return int(match.group(1)) + match = re.search(r"'migrate_to_chat_id'\s*:\s*(-?\d+)", error_text) + if match: + return int(match.group(1)) + return None + def _handle_update(self, update: dict[str, Any]) -> None: message = update.get("message") update_type = "message" @@ -371,11 +422,17 @@ class ShinePyBotService: if not isinstance(chat_id, int) or not isinstance(message_id, int): return + migrate_to_chat_id = message.get("migrate_to_chat_id") + if isinstance(migrate_to_chat_id, int): + self._remember_chat_migration(chat_id, migrate_to_chat_id, "telegram_message") + return + update_key = f"{chat_id}:{message_id}" if self._mark_processed_update(update_key): return is_channel_post = update_type == "channel_post" or chat_type == "channel" + is_group_message = update_type == "message" and chat_type in ("group", "supergroup") is_allowed_channel = ( not is_channel_post or not self.cfg.allowed_channel_username @@ -387,10 +444,12 @@ class ShinePyBotService: text = (message.get("text") or message.get("caption") or "").strip() history_path = self._current_history_file() if author_username != self.cfg.allowed_username: - if is_channel_post: - self._append_history(history_path, "channel_context_message", { + if is_channel_post or is_group_message: + self._append_history(history_path, "chat_context_message", { "chatId": chat_id, "messageId": message_id, + "updateType": update_type, + "chatType": chat_type, "chatUsername": chat_username, "chatTitle": chat_title, "username": username, @@ -399,6 +458,8 @@ class ShinePyBotService: "hasVoice": bool(message.get("voice")), "hasAudio": bool(message.get("audio")), }) + if is_group_message: + self._safe_send(chat_id, "Получил сообщение.", reply_to=message_id) return if not text: @@ -412,6 +473,7 @@ class ShinePyBotService: chat_username=chat_username, chat_title=chat_title, author_signature=author_signature, + chat_type=chat_type, ) return if message.get("audio"): @@ -424,6 +486,7 @@ class ShinePyBotService: chat_username=chat_username, chat_title=chat_title, author_signature=author_signature, + chat_type=chat_type, ) return self._safe_send(chat_id, "Поддерживаются текст, voice и audio.", reply_to=message_id) @@ -437,6 +500,7 @@ class ShinePyBotService: "chatId": chat_id, "messageId": message_id, "updateType": update_type, + "chatType": chat_type, "chatUsername": chat_username, "chatTitle": chat_title, "username": author_username, @@ -447,6 +511,7 @@ class ShinePyBotService: job["type"] = "text" job["text"] = text job["update_type"] = update_type + job["chat_type"] = chat_type job["chat_username"] = chat_username job["chat_title"] = chat_title job["author_signature"] = author_signature @@ -466,6 +531,7 @@ class ShinePyBotService: chat_username: str = "", chat_title: str = "", author_signature: str = "", + chat_type: str = "", ) -> None: if not file_id: self._safe_send(chat_id, "Не удалось прочитать file_id голосового.", reply_to=message_id) @@ -475,6 +541,7 @@ class ShinePyBotService: "chatId": chat_id, "messageId": message_id, "updateType": update_type, + "chatType": chat_type, "chatUsername": chat_username, "chatTitle": chat_title, "username": username, @@ -485,6 +552,7 @@ class ShinePyBotService: job["type"] = "voice" job["telegram_file_id"] = file_id job["update_type"] = update_type + job["chat_type"] = chat_type job["chat_username"] = chat_username job["chat_title"] = chat_title job["author_signature"] = author_signature @@ -507,6 +575,7 @@ class ShinePyBotService: "message_id": message_id, "username": username, "update_type": "message", + "chat_type": "", "chat_username": "", "chat_title": "", "author_signature": "", @@ -717,6 +786,7 @@ class ShinePyBotService: "Пришло сообщение в Telegram.\n" f"Тип: {job.get('type')}\n" f"Источник Telegram: {job.get('update_type', 'message')}\n" + f"Тип чата: {job.get('chat_type') or ''}\n" f"Канал/чат: @{job.get('chat_username') or ''} {job.get('chat_title') or ''}\n" f"Username отправителя: @{job.get('username')}\n" f"Подпись автора в Telegram: {job.get('author_signature') or ''}\n" @@ -892,9 +962,20 @@ class ShinePyBotService: return if len(text) > 3900: text = text[:3900] + "\n...[обрезано]" + resolved_chat_id = self._resolve_chat_id(chat_id) + resolved_reply_to = reply_to if resolved_chat_id == chat_id else None try: - self.telegram.send_message(chat_id, text, reply_to_message_id=reply_to) + self.telegram.send_message(resolved_chat_id, text, reply_to_message_id=resolved_reply_to) except Exception as e: + migrate_to_chat_id = self._extract_migrate_to_chat_id(str(e)) + if migrate_to_chat_id is not None: + self._remember_chat_migration(resolved_chat_id, migrate_to_chat_id, "send_message_error") + try: + self.telegram.send_message(migrate_to_chat_id, text, reply_to_message_id=None) + return + except Exception as retry_error: + print(f"[py-bot] sendMessage retry after migration error: {retry_error}", flush=True) + return print(f"[py-bot] sendMessage error: {e}", flush=True) def _schedule_self_restart(self) -> None: diff --git a/VERSION.properties b/VERSION.properties index b7fb5a7..6c437af 100644 --- a/VERSION.properties +++ b/VERSION.properties @@ -1,2 +1,2 @@ -client.version=1.2.87 -server.version=1.2.81 +client.version=1.2.88 +server.version=1.2.82 diff --git a/shine-UI/js/pages/channel-thread-view.js b/shine-UI/js/pages/channel-thread-view.js index 78287e8..b610c61 100644 --- a/shine-UI/js/pages/channel-thread-view.js +++ b/shine-UI/js/pages/channel-thread-view.js @@ -709,24 +709,9 @@ function renderNodeCard(node, heading, handlers, localNumber) { await handlers.onShare(target); }); - const repostButton = document.createElement('button'); - repostButton.type = 'button'; - repostButton.className = 'channel-action-item thread-reply-btn'; - repostButton.innerHTML = ` - - Репост - `; - repostButton.addEventListener('click', async (event) => { - event.stopPropagation(); - animatePress(event.currentTarget); - try { - await handlers.onRepost(target); - } catch (error) { - handlers?.onActionError?.(error, 'repost'); - } - }); - - actions.append(likeButton, replyButton, repostButton, shareButton); + // Репосты временно отключены до будущей реализации. + // Точка возврата: Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md + actions.append(likeButton, replyButton, shareButton); if (repostTarget) { const originalButton = document.createElement('button'); originalButton.type = 'button'; diff --git a/shine-UI/js/pages/channel-view.js b/shine-UI/js/pages/channel-view.js index 90775d7..faeb42b 100644 --- a/shine-UI/js/pages/channel-view.js +++ b/shine-UI/js/pages/channel-view.js @@ -1004,19 +1004,9 @@ function renderPostCard(post, { onSubmit: async (text) => onReply(post.messageRef, text), }); }); - const repostButton = document.createElement('button'); - repostButton.type = 'button'; - repostButton.className = 'channel-action-item channel-action-reply'; - repostButton.innerHTML = ` - - Репост - `; - repostButton.addEventListener('click', (event) => { - event.stopPropagation(); - animatePress(event.currentTarget); - onRepost(post.messageRef); - }); - actions.append(likeButton, replyButton, repostButton); + // Репосты временно отключены до будущей реализации. + // Точка возврата: Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md + actions.append(likeButton, replyButton); const shareButton = document.createElement('button'); shareButton.type = 'button'; diff --git a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java index eb3ef1f..5b98a18 100644 --- a/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java +++ b/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/blockchain/Net_AddBlock_Handler.java @@ -146,6 +146,7 @@ public final class Net_AddBlock_Handler implements JsonMessageHandler { case "bad_prev_line_hash" -> "Некорректный prevLineHash"; case "db_error_prev_line_check" -> "Ошибка БД при проверке prevLine"; case "channel_name_already_exists" -> "Такое название канала уже занято"; + case "repost_disabled" -> "Репосты временно отключены до будущей реализации"; case "internal_error" -> "Внутренняя ошибка сервера при записи блока"; default -> "Ошибка: " + code; }; @@ -246,6 +247,15 @@ public final class Net_AddBlock_Handler implements JsonMessageHandler { return new AddBlockResult(WireCodes.Status.BAD_REQUEST, "bad_block_body", serverLastNum, serverLastHashHex); } + // Репосты временно отключены до будущей реализации. + // Точка возврата: Dev_Docs/Future_Features/2026-05-24_1140_репосты_в_каналах_и_тредах.md + if ((block.type & 0xFFFF) == 1 + && (block.subType & 0xFFFF) == (MsgSubType.TEXT_REPOST & 0xFFFF)) { + log.warn("AddBlock: repost_disabled (login={}, blockchainName={}, blockNumber={})", + login, blockchainName, block.blockNumber); + return new AddBlockResult(WireCodes.Status.BAD_REQUEST, "repost_disabled", serverLastNum, serverLastHashHex); + } + ChannelNameStateEntry channelNameStateEntry = null; Chat200CreateSeed chat200CreateSeed = null; if (block.body instanceof CreateChannelBody createChannelBody) { diff --git a/shine-solana/shine/.gitignore b/shine-solana/shine/.gitignore new file mode 100644 index 0000000..e0a7041 --- /dev/null +++ b/shine-solana/shine/.gitignore @@ -0,0 +1,9 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn +program-keypair.json +/old_vers/ diff --git a/shine-solana/shine/.prettierignore b/shine-solana/shine/.prettierignore new file mode 100644 index 0000000..c50ed90 --- /dev/null +++ b/shine-solana/shine/.prettierignore @@ -0,0 +1,7 @@ +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/shine-solana/shine/AGENTS.md b/shine-solana/shine/AGENTS.md new file mode 100644 index 0000000..2b2b851 --- /dev/null +++ b/shine-solana/shine/AGENTS.md @@ -0,0 +1,63 @@ +# AGENTS.md + +## Documentation Rule + +В проекте есть спецификация пользовательской PDA-записи: + +- актуальные документы в `doc/`. + +Если меняется формат записи, сериализация, правила подписи, `prev_hash`, экономика лимитов или связанные ограничения create/update, соответствующую документацию в `doc/` нужно обновлять в том же изменении. + +## Language Rule + +Во всем проекте использовать русский язык: + +- комментарии в коде; +- тексты в файлах настроек и справочных файлах; +- сообщения и описания в коммитах; +- сопроводительные технические заметки. + +## Rule: Logic and Docs + +Если меняется бизнес-логика смарт-контрактов, сериализация PDA, правила переводов или экономика: + +1. Обновить соответствующий документ в `doc/` в том же изменении. +2. Если документ сразу обновить нельзя, обязательно явно согласовать это с пользователем в чате и зафиксировать план обновления. + +## Rule: Git Push + +Для push в удаленный репозиторий использовать токен из переменной окружения: + +- `GITEA_TOKEN` + +Push выполнять через `http.extraHeader` (Authorization) без вывода токена в логи. + +## Rule: Commit Messages + +Текст commit message писать на русском языке. +Это обязательное правило для всех новых коммитов в этом репозитории. + +## Rule: UI Deploy + +Деплой UI Shine Payments выполнять через Gradle из папки `shine`: + +1. `gradle deployUi` +2. `gradle checkUiRemote` + +Где смотреть детали (пути деплоя, путь Caddy, рабочие URL): + +- комментарии в `build.gradle` (в корне `shine/`). + +## Rule: Dictionary Growth Reporting + +Если пользователь просит увеличить количество слов в словарях `shine_login_guard`: + +1. Увеличивать словарь в первую очередь в явно указанных пользователем категориях/файлах. +2. Если в конкретной категории добавлять новые уместные слова уже затруднительно, прямо сообщать об этом и предлагать соседние категории для расширения. +3. После каждого такого изменения выводить количество слов по каждому файлу словаря: + - `src/dictionaries/premium/*.txt` + - `src/dictionaries/trademarks/*.txt` +4. В отчете дополнительно кратко оценивать заполненность категорий (где есть смысл расширять, где уже близко к насыщению). +5. В конце каждого увеличения словаря обязательно выводить итог: + - общее число слов для premium; + - общее число слов для trademarks. diff --git a/shine-solana/shine/Anchor.toml b/shine-solana/shine/Anchor.toml new file mode 100644 index 0000000..910a504 --- /dev/null +++ b/shine-solana/shine/Anchor.toml @@ -0,0 +1,29 @@ +[toolchain] +package_manager = "yarn" + +[features] +resolution = true +skip-lint = false + +[programs.devnet] +shine_payments = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR" +shine_users = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm" +shine_login_guard = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo" + +[programs.localnet] +shine_payments = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR" +shine_users = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm" +shine_login_guard = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "devnet" +wallet = "~/.config/solana/id.json" + +[workspace] +members = ["programs/shine_users", "programs/shine_payments", "programs/shine_login_guard"] + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/shine-solana/shine/Cargo.lock b/shine-solana/shine/Cargo.lock new file mode 100644 index 0000000..83a9304 --- /dev/null +++ b/shine-solana/shine/Cargo.lock @@ -0,0 +1,7464 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "agave-feature-set" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a2c365c0245cbb8959de725fc2b44c754b673fdf34c9a7f9d4a25c35a7bf1" +dependencies = [ + "ahash 0.8.12", + "solana-epoch-schedule 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.2.1", + "solana-svm-feature-set", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f70fd141a4d18adf11253026b32504f885447048c7494faf5fa83b01af9c0cf" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715a261c57c7679581e06f07a74fa2af874ac30f86bd8ea07cca4a7e5388a064" +dependencies = [ + "anchor-syn", + "bs58", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730d6df8ae120321c5c25e0779e61789e4b70dc8297102248902022f286102e4" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e6e449cc3a37b2880b74dcafb8e5a17b954c0e58e376432d7adc646fb333ef" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7710e4c54adf485affcd9be9adec5ef8846d9c71d7f31e16ba86ff9fc1dd49f" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ecfd49b2aeadeb32f35262230db402abed76ce87e27562b34f61318b2ec83c" +dependencies = [ + "anchor-lang-idl", + "anchor-syn", + "anyhow", + "bs58", + "heck 0.3.3", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be89d160793a88495af462a7010b3978e48e30a630c91de47ce2c1d3cb7a6149" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abc6ee78acb7bfe0c2dd2abc677aaa4789c0281a0c0ef01dbf6fe85e0fd9e6e4" +dependencies = [ + "anchor-syn", + "borsh-derive-internal 0.10.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134a01c0703f6fd355a0e472c033f6f3e41fac1ef6e370b20c50f4c8d022cea7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bab117055905e930f762c196e08f861f8dfe7241b92cee46677a3b15561a0a" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-lang-idl", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bytemuck", + "solana-program 2.2.1", + "thiserror 1.0.69", +] + +[[package]] +name = "anchor-lang-idl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e8599d21995f68e296265aa5ab0c3cef582fd58afec014d01bd0bce18a4418" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck 0.3.3", + "regex", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdf143115440fe621bdac3a29a1f7472e09f6cd82b2aa569429a0c13f103838" +dependencies = [ + "anyhow", + "serde", +] + +[[package]] +name = "anchor-syn" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dc7a6d90cc643df0ed2744862cdf180587d1e5d28936538c18fc8908489ed67" +dependencies = [ + "anyhow", + "bs58", + "cargo_toml", + "heck 0.3.3", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "syn 1.0.109", + "thiserror 1.0.69", +] + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener 5.4.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +dependencies = [ + "serde", +] + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +dependencies = [ + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +dependencies = [ + "borsh-derive 1.5.7", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +dependencies = [ + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal 0.10.4", + "borsh-schema-derive-internal 0.10.4", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +dependencies = [ + "once_cell", + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bstr" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "caps" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd1ddba47aba30b6a889298ad0109c3b8dcb0e8fc993b459daa7067d46f865e0" +dependencies = [ + "libc", +] + +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.22", +] + +[[package]] +name = "cc" +version = "1.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f4ac86a9e5bc1e2b3449ab9d7d3a6a405e3d1bb28d7b9be8614f55846ae3766" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "common" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] + +[[package]] +name = "compression-codecs" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2548391e9c1929c21bf6aa2680af86fe4c1b33e6cea9ac1cfeec0bd11218cf" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.6", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.2.0", + "spki", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "rand_core 0.6.4", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" +dependencies = [ + "derivation-path", + "ed25519-dalek 2.2.0", + "hmac 0.12.1", + "sha2 0.10.9", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "env_filter" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a1c3cc8e57274ec99de65301228b537f1e4eedc1b8e0f9411c6caac8ae7308f" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2daee4ea451f429a58296525ddf28b45a3b64f1acf6587e2067437bb11e218d" +dependencies = [ + "env_filter", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.1", + "pin-project-lite", +] + +[[package]] +name = "fast-math" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2465292146cdfc2011350fe3b1c616ac83cf0faeedb33463ba1c332ed8948d66" +dependencies = [ + "ieee754", +] + +[[package]] +name = "fastbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.4", + "libm", + "rand 0.9.4", + "siphasher 1.0.3", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "five8" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-executor" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "rand_core 0.10.1", + "wasip2", + "wasip3", +] + +[[package]] +name = "governor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +dependencies = [ + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.12", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "hyper" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http 1.4.0", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http 1.4.0", + "hyper", + "hyper-util", + "rustls 0.23.40", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", + "webpki-roots 1.0.7", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.3", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ieee754" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9007da9cacbd3e6343da136e98b0d2df013f553d35bdec8b518f07bea768e19c" + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + +[[package]] +name = "ipnet" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.9", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "libsecp256k1-core 0.2.2", + "libsecp256k1-gen-ecmult 0.2.1", + "libsecp256k1-gen-genmult 0.2.1", + "rand 0.7.3", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79019718125edc905a079a70cfa5f3820bc76139fc91d6f9abc27ea2a887139" +dependencies = [ + "arrayref", + "base64 0.22.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core 0.3.0", + "libsecp256k1-gen-ecmult 0.3.0", + "libsecp256k1-gen-genmult 0.3.0", + "rand 0.8.5", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core 0.3.0", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core 0.2.2", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core 0.3.0", +] + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex 0.2.4", + "num-integer", + "num-iter", + "num-rational 0.2.4", + "num-traits", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint 0.4.6", + "num-complex 0.4.6", + "num-integer", + "num-iter", + "num-rational 0.4.2", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint 0.4.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro-crate 3.3.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num 0.2.1", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + +[[package]] +name = "proc-macro-crate" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags", + "num-traits", + "rand 0.9.4", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "pyth-sdk" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5c805ba3dfb5b7ed6a8ffa62ec38391f485a79c7cf6b3b11d3bd44fb0325824" +dependencies = [ + "borsh 0.9.3", + "borsh-derive 0.9.3", + "hex", + "schemars", + "serde", +] + +[[package]] +name = "pyth-solana-receiver-sdk" +version = "0.6.0" +dependencies = [ + "anchor-lang", + "bytemuck_derive", + "hex", + "pythnet-sdk", +] + +[[package]] +name = "pythnet-sdk" +version = "2.3.1" +dependencies = [ + "anchor-lang", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bytemuck", + "byteorder", + "fast-math", + "hex", + "libsecp256k1 0.7.2", + "proptest", + "pyth-sdk", + "quickcheck", + "rand 0.7.3", + "rand 0.8.5", + "rustc_version", + "serde", + "serde_json", + "serde_wormhole", + "sha3", + "slow_primes", + "solana-client", + "solana-program 2.2.1", + "solana-sdk", + "strum", + "thiserror 1.0.69", + "wormhole-vaas-serde", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quickcheck" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b" +dependencies = [ + "env_logger", + "log", + "rand 0.10.1", +] + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.40", + "socket2 0.6.3", + "thiserror 2.0.12", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +dependencies = [ + "bytes", + "fastbloom", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", + "rustc-hash", + "rustls 0.23.40", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.12", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.3", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[package]] +name = "rand" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" +dependencies = [ + "getrandom 0.4.2", + "rand_core 0.10.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", +] + +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags", +] + +[[package]] +name = "rayon" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.40", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.7", +] + +[[package]] +name = "reqwest-middleware" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" +dependencies = [ + "anyhow", + "async-trait", + "http 1.4.0", + "reqwest", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.23.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.13", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +dependencies = [ + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.40", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.13", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.117", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c522100790450cf78eeac1507263d0a350d4d5b30df0c8e1fe051a10c22b376e" +dependencies = [ + "serde", + "serde_derive", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "3.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327ada00f7d64abaac1e55a6911e90cf665aa051b9a561c7006c157f4633135e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "serde_wormhole" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b022bf813578a06341fd453c3fd6e64945d9975191193d5d45e8dbd97d1d84" +dependencies = [ + "base64 0.13.1", + "itoa", + "serde", + "serde_bytes", + "thiserror 1.0.69", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shine_login_guard" +version = "0.1.0" +dependencies = [ + "anchor-lang", +] + +[[package]] +name = "shine_payments" +version = "0.2.0" +dependencies = [ + "anchor-lang", + "common", + "pyth-solana-receiver-sdk", +] + +[[package]] +name = "shine_users" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "common", + "shine_login_guard", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slow_primes" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58267dd2fbaa6dceecba9e3e106d2d90a2b02497c0e8b01b8759beccf5113938" +dependencies = [ + "num 0.4.3", +] + +[[package]] +name = "smallvec" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socket2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 2.2.1", + "solana-clock 2.2.2", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-sysvar 2.2.2", +] + +[[package]] +name = "solana-account" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f885ce7f937871ecb56aadbeaaec963b234a580b7d6ebbdb8fa4249a36f92433" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 3.0.0", + "solana-clock 3.0.0", + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-sysvar 3.0.0", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5519e8343325b707f17fbed54fcefb325131b692506d0af9e08a539d15e4f8cf" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account 2.2.1", + "solana-pubkey 2.4.0", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" +dependencies = [ + "bincode", + "serde", + "solana-program-error 2.2.2", + "solana-program-memory 2.2.1", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-account-info" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82f4691b69b172c687d218dd2f1f23fc7ea5e9aa79df9ac26dab3d8dd829ce48" +dependencies = [ + "bincode", + "serde", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-address" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a7a457086457ea9db9a5199d719dc8734dc2d0342fad0d8f77633c31eb62f19" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8 0.2.1", + "five8_const 0.1.4", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64 3.0.1", + "solana-define-syscall 3.0.0", + "solana-program-error 3.0.0", + "solana-sanitize 3.0.1", + "solana-sha256-hasher 3.1.0", +] + +[[package]] +name = "solana-address" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1384b52c435a750cc9c538760fc7bb472fd78e65a9900a2d07312c5bb335b72" +dependencies = [ + "curve25519-dalek 4.1.3", + "five8 1.0.0", + "five8_const 1.0.0", + "sha2-const-stable", + "solana-define-syscall 5.1.0", + "solana-program-error 3.0.0", + "solana-sanitize 3.0.1", + "solana-sha256-hasher 3.1.0", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock 2.2.2", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-slot-hashes 2.2.1", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115b4f773acc4f3f3cb986b0d335e9845c0368c82b0940410935bc11ae065578" +dependencies = [ + "solana-clock 3.0.0", + "solana-pubkey 4.2.0", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.0", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-atomic-u64" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085db4906d89324cef2a30840d59eaecf3d4231c560ec7c9f6614a93c652f501" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 2.3.0", +] + +[[package]] +name = "solana-big-mod-exp" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode", + "serde", + "solana-instruction 2.3.0", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-blake3-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" +dependencies = [ + "blake3", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", +] + +[[package]] +name = "solana-borsh" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04abbae16f57178a163125805637b8a076175bb5c0002fb04f4792bea901cf7" +dependencies = [ + "borsh 1.5.7", +] + +[[package]] +name = "solana-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc55d1f263e0be4127daf33378d313ea0977f9ffd3fba50fa544ca26722fc695" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap", + "indicatif", + "log", + "quinn", + "rayon", + "solana-account 2.2.1", + "solana-client-traits", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-keypair 2.2.3", + "solana-measure", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-pubsub-client", + "solana-quic-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-streamer", + "solana-thin-client", + "solana-time-utils 2.2.1", + "solana-tpu-client", + "solana-transaction 2.2.3", + "solana-transaction-error 2.2.1", + "solana-udp-client", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-client-traits" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83f0071874e629f29e0eb3dab8a863e98502ac7aba55b7e0df1803fc5cac72a7" +dependencies = [ + "solana-account 2.2.1", + "solana-commitment-config", + "solana-epoch-info 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction 2.2.3", + "solana-transaction-error 2.2.1", +] + +[[package]] +name = "solana-clock" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb482ab70fced82ad3d7d3d87be33d466a3498eb8aa856434ff3c0dfc2e2e31" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-clock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-cluster-type" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ace9fea2daa28354d107ea879cff107181d85cd4e0f78a2bedb10e1a428c97e" +dependencies = [ + "solana-hash 2.3.0", +] + +[[package]] +name = "solana-commitment-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac49c4dde3edfa832de1697e9bcdb7c3b3f7cb7a1981b7c62526c8bb6700fb73" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-connection-cache" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45c1cff5ebb26aefff52f1a8e476de70ec1683f8cc6e4a8c86b615842d91f436" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap", + "log", + "rand 0.8.5", + "rayon", + "solana-keypair 2.2.3", + "solana-measure", + "solana-metrics", + "solana-time-utils 2.2.1", + "solana-transaction-error 2.2.1", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info 2.2.1", + "solana-define-syscall 2.3.0", + "solana-instruction 2.3.0", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-stable-layout 2.2.1", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info 3.0.0", + "solana-define-syscall 4.0.1", + "solana-instruction 3.0.0", + "solana-program-error 3.0.0", + "solana-pubkey 4.2.0", + "solana-stable-layout 3.0.0", +] + +[[package]] +name = "solana-decode-error" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c781686a18db2f942e70913f7ca15dc120ec38dcab42ff7557db2c70c625a35" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" + +[[package]] +name = "solana-define-syscall" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" + +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-define-syscall" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e14a4f604117f379840956a8fc8695e4c84f5b0ebed192f31f60d9b85d581d" + +[[package]] +name = "solana-derivation-path" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff71743072690fdbdfcdc37700ae1cb77485aaad49019473a81aee099b1e0b8c" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ef6f0b449290b0b9f32973eefd95af35b01c5c0c34c569f936c34c5b20d77b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-info" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a6b69bd71386f61344f2bcf0f527f5fd6dd3b22add5880e2e1bf1dd1fa8059" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-epoch-rewards" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee8beac9bff4db9225e57d532d169b0be5e447f1e6601a2f50f27a01bf5518f" +dependencies = [ + "siphasher 0.3.11", + "solana-address 2.6.0", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-epoch-stake" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "027e6d0b9e7daac5b2ac7c3f9ca1b727861121d9ef05084cf435ff736051e7c2" +dependencies = [ + "solana-define-syscall 5.1.0", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface 2.2.2", + "solana-clock 2.2.2", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-keccak-hasher 2.2.1", + "solana-message 2.4.0", + "solana-nonce 2.2.1", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-example-mocks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978855d164845c1b0235d4b4d101cadc55373fffaf0b5b6cfa2194d25b2ed658" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.0", + "solana-hash 3.0.0", + "solana-instruction 3.0.0", + "solana-keccak-hasher 3.1.0", + "solana-message 3.0.1", + "solana-nonce 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-system-interface 2.0.0", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account 2.2.1", + "solana-account-info 2.2.1", + "solana-instruction 2.3.0", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a73cc03ca4bed871ca174558108835f8323e85917bb38b9c81c7af2ab853efe" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hard-forks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52fd9cc610fd0782f09482527cb7b4f41ec22071303742718b7b57fc43bb236b" + +[[package]] +name = "solana-hash" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "five8 0.2.1", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64 2.2.1", + "solana-sanitize 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-hash" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a063723b9e84c14d8c0d2cdf0268207dc7adecf546e31251f9e07c7b00b566c" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "five8 0.2.1", + "serde", + "serde_derive", + "solana-atomic-u64 3.0.1", + "solana-sanitize 3.0.1", +] + +[[package]] +name = "solana-hash" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b113239362cee7093bfb250467138f079a2a03673181dc15bff6ccd677912d" +dependencies = [ + "five8 1.0.0", +] + +[[package]] +name = "solana-inflation" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23eef6a09eb8e568ce6839573e4966850e85e9ce71e6ae1a6c930c1c43947de3" + +[[package]] +name = "solana-inflation" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e92f37a14e7c660628752833250dd3dcd8e95309876aee751d7f8769a27947c6" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-instruction" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47298e2ce82876b64f71e9d13a46bc4b9056194e7f9937ad3084385befa50885" +dependencies = [ + "bincode", + "borsh 1.5.7", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall 2.3.0", + "solana-pubkey 2.4.0", + "wasm-bindgen", +] + +[[package]] +name = "solana-instruction" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df4e8fcba01d7efa647ed20a081c234475df5e11a93acb4393cc2c9a7b99bab" +dependencies = [ + "bincode", + "borsh 1.5.7", + "serde", + "serde_derive", + "solana-define-syscall 3.0.0", + "solana-instruction-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f0d483b8ae387178d9210e0575b666b05cdd4bd0f2f188128249f6e454d39d" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" +dependencies = [ + "bitflags", + "solana-account-info 2.2.1", + "solana-instruction 2.3.0", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serialize-utils 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" +dependencies = [ + "bitflags", + "solana-account-info 3.0.0", + "solana-instruction 3.0.0", + "solana-instruction-error", + "solana-program-error 3.0.0", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-serialize-utils 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" +dependencies = [ + "sha3", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-keypair" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd3f04aa1a05c535e93e121a95f66e7dcccf57e007282e8255535d24bf1e98bb" +dependencies = [ + "ed25519-dalek 1.0.1", + "five8 0.2.1", + "rand 0.7.3", + "solana-pubkey 2.4.0", + "solana-seed-phrase 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-keypair" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8be597c9e231b0cab2928ce3bc3e4ee77d9c0ad92977b9d901f3879f25a7a" +dependencies = [ + "ed25519-dalek 2.2.0", + "ed25519-dalek-bip32", + "five8 1.0.0", + "rand 0.8.5", + "solana-address 2.6.0", + "solana-derivation-path", + "solana-seed-derivable", + "solana-seed-phrase 3.0.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-measure" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11dcd67cd2ae6065e494b64e861e0498d046d95a61cbbf1ae3d58be1ea0f42ed" + +[[package]] +name = "solana-message" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1796aabce376ff74bf89b78d268fa5e683d7d7a96a0a4e4813ec34de49d5314b" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction-error 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-message" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85666605c9fd727f865ed381665db0a8fc29f984a030ecc1e40f43bfb2541623" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-address 1.0.0", + "solana-hash 3.0.0", + "solana-instruction 3.0.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.0.0", + "solana-transaction-error 3.0.0", +] + +[[package]] +name = "solana-metrics" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0375159d8460f423d39e5103dcff6e07796a5ec1850ee1fcfacfd2482a8f34b5" +dependencies = [ + "crossbeam-channel", + "gethostname", + "log", + "reqwest", + "solana-cluster-type", + "solana-sha256-hasher 2.2.1", + "solana-time-utils 2.2.1", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall 2.3.0", +] + +[[package]] +name = "solana-msg" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726b7cbbc6be6f1c6f29146ac824343b9415133eee8cce156452ad1db93f8008" +dependencies = [ + "solana-define-syscall 5.1.0", +] + +[[package]] +name = "solana-native-token" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307fb2f78060995979e9b4f68f833623565ed4e55d3725f100454ce78a99a1a3" + +[[package]] +name = "solana-native-token" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" + +[[package]] +name = "solana-net-utils" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a9e831d0f09bd92135d48c5bc79071bb59c0537b9459f1b4dec17ecc0558fa" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "itertools", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2 0.5.10", + "solana-serde 2.2.1", + "tokio", + "url", +] + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.2.1", +] + +[[package]] +name = "solana-nonce" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abbdc6c8caf1c08db9f36a50967539d0f72b9f1d4aea04fec5430f532e5afadc" +dependencies = [ + "solana-fee-calculator 3.0.0", + "solana-hash 3.0.0", + "solana-pubkey 3.0.0", + "solana-sha256-hasher 3.1.0", +] + +[[package]] +name = "solana-offchain-message" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e2a1141a673f72a05cf406b99e4b2b8a457792b7c01afa07b3f00d4e2de393" +dependencies = [ + "num_enum", + "solana-hash 3.0.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", + "solana-sha256-hasher 3.1.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", +] + +[[package]] +name = "solana-packet" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004f2d2daf407b3ec1a1ca5ec34b3ccdfd6866dd2d3c7d0715004a96e4b6d127" +dependencies = [ + "bincode", + "bitflags", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-packet" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "solana-perf" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37192c0be5c222ca49dbc5667288c5a8bb14837051dd98e541ee4dad160a5da9" +dependencies = [ + "ahash 0.8.12", + "bincode", + "bv", + "bytes", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-hash 2.3.0", + "solana-message 2.4.0", + "solana-metrics", + "solana-packet 2.2.1", + "solana-pubkey 2.4.0", + "solana-rayon-threadlimit", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-signature 2.3.0", + "solana-time-utils 2.2.1", +] + +[[package]] +name = "solana-presigner" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f704eaf825be3180832445b9e4983b875340696e8e7239bf2d535b0f86c14a2" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", +] + +[[package]] +name = "solana-program" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" +dependencies = [ + "bincode", + "blake3", + "borsh 0.10.4", + "borsh 1.5.7", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.16", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 2.2.1", + "solana-address-lookup-table-interface 2.2.2", + "solana-atomic-u64 2.2.1", + "solana-big-mod-exp 2.2.1", + "solana-bincode", + "solana-blake3-hasher 2.2.1", + "solana-borsh 2.2.1", + "solana-clock 2.2.2", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-example-mocks 2.2.1", + "solana-feature-gate-interface", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-instructions-sysvar 2.2.2", + "solana-keccak-hasher 2.2.1", + "solana-last-restart-slot 2.2.1", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message 2.4.0", + "solana-msg 2.2.1", + "solana-native-token 2.2.2", + "solana-nonce 2.2.1", + "solana-program-entrypoint 2.2.1", + "solana-program-error 2.2.2", + "solana-program-memory 2.2.1", + "solana-program-option 2.2.1", + "solana-program-pack 2.2.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-secp256k1-recover 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-sha256-hasher 2.2.1", + "solana-short-vec 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stable-layout 2.2.1", + "solana-stake-interface", + "solana-system-interface 1.0.0", + "solana-sysvar 2.2.2", + "solana-sysvar-id 2.2.1", + "solana-vote-interface", + "thiserror 2.0.12", + "wasm-bindgen", +] + +[[package]] +name = "solana-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b12305dd81045d705f427acd0435a2e46444b65367d7179d7bdcfc3bc5f5eb" +dependencies = [ + "memoffset", + "solana-account-info 3.0.0", + "solana-big-mod-exp 3.0.0", + "solana-blake3-hasher 3.1.0", + "solana-borsh 3.0.2", + "solana-clock 3.0.0", + "solana-cpi 3.1.0", + "solana-define-syscall 3.0.0", + "solana-epoch-rewards 3.0.0", + "solana-epoch-schedule 3.0.0", + "solana-epoch-stake", + "solana-example-mocks 3.0.0", + "solana-fee-calculator 3.0.0", + "solana-hash 3.0.0", + "solana-instruction 3.0.0", + "solana-instruction-error", + "solana-instructions-sysvar 3.0.0", + "solana-keccak-hasher 3.1.0", + "solana-last-restart-slot 3.0.0", + "solana-msg 3.1.0", + "solana-native-token 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", + "solana-pubkey 3.0.0", + "solana-rent 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-recover 3.1.0", + "solana-serde-varint 3.0.0", + "solana-serialize-utils 3.1.0", + "solana-sha256-hasher 3.1.0", + "solana-short-vec 3.0.0", + "solana-slot-hashes 3.0.0", + "solana-slot-history 3.0.0", + "solana-stable-layout 3.0.0", + "solana-sysvar 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" +dependencies = [ + "solana-account-info 2.2.1", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info 3.0.0", + "solana-define-syscall 4.0.1", + "solana-program-error 3.0.0", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-program-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" +dependencies = [ + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.0", + "solana-msg 2.2.1", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" +dependencies = [ + "borsh 1.5.7", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-program-memory" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" +dependencies = [ + "num-traits", + "solana-define-syscall 2.3.0", +] + +[[package]] +name = "solana-program-memory" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" +dependencies = [ + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + +[[package]] +name = "solana-program-option" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a88006a9b8594088cec9027ab77caaaa258a2aaa2083d3f086c44b42e50aeab" + +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error 2.2.2", +] + +[[package]] +name = "solana-program-pack" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7701cb15b90667ae1c89ef4ac35a59c61e66ce58ddee13d729472af7f41d59" +dependencies = [ + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-pubkey" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8 0.2.1", + "five8_const 0.1.4", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-atomic-u64 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-sanitize 2.2.1", + "solana-sha256-hasher 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "rand 0.8.5", + "solana-address 1.0.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db719574990de7e8b0f55a8593ac92a5ccb42c8ce67b3e4bf05b139d5d9ee71" +dependencies = [ + "solana-address 2.6.0", +] + +[[package]] +name = "solana-pubsub-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d18a7476e1d2e8df5093816afd8fffee94fbb6e442d9be8e6bd3e85f88ce8d5c" +dependencies = [ + "crossbeam-channel", + "futures-util", + "http 0.2.12", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock 2.2.2", + "solana-pubkey 2.4.0", + "solana-rpc-client-types", + "solana-signature 2.3.0", + "thiserror 2.0.12", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feb5f4a97494459c435aa56de810500cc24e22d0afc632990a8e54a07c05a4" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.40", + "solana-connection-cache", + "solana-keypair 2.2.3", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-pubkey 2.4.0", + "solana-quic-definitions", + "solana-rpc-client-api", + "solana-signer 2.2.1", + "solana-streamer", + "solana-tls-utils", + "solana-transaction-error 2.2.1", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-quic-definitions" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf0d4d5b049eb1d0c35f7b18f305a27c8986fc5c0c9b383e97adaa35334379e" +dependencies = [ + "solana-keypair 2.2.3", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02cc2a4cae3ef7bb6346b35a60756d2622c297d5fa204f96731db9194c0dc75b" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-rent" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b702d8c43711e3c8a9284a4f1bbc6a3de2553deb25b0c8142f9a44ef0ce5ddc1" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-reward-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18205b69139b1ae0ab8f6e11cdcb627328c0814422ad2482000fa2ca54ae4a2f" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-rpc-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8d3161ac0918178e674c1f7f1bfac40de3e7ed0383bd65747d63113c156eaeb" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "futures", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account 2.2.1", + "solana-account-decoder-client-types", + "solana-clock 2.2.2", + "solana-commitment-config", + "solana-epoch-info 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-feature-gate-interface", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-rpc-client-api", + "solana-signature 2.3.0", + "solana-transaction 2.2.3", + "solana-transaction-error 2.2.1", + "solana-transaction-status-client-types", + "solana-version", + "solana-vote-interface", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dbc138685c79d88a766a8fd825057a74ea7a21e1dd7f8de275ada899540fff7" +dependencies = [ + "anyhow", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock 2.2.2", + "solana-rpc-client-types", + "solana-signer 2.2.1", + "solana-transaction-error 2.2.1", + "solana-transaction-status-client-types", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f0ee41b9894ff36adebe546a110b899b0d0294b07845d8acdc73822e6af4b0" +dependencies = [ + "solana-account 2.2.1", + "solana-commitment-config", + "solana-hash 2.3.0", + "solana-message 2.4.0", + "solana-nonce 2.2.1", + "solana-pubkey 2.4.0", + "solana-rpc-client", + "solana-sdk-ids 2.2.1", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-rpc-client-types" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea428a81729255d895ea47fba9b30fd4dacbfe571a080448121bd0592751676" +dependencies = [ + "base64 0.22.1", + "bs58", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account 2.2.1", + "solana-account-decoder-client-types", + "solana-clock 2.2.2", + "solana-commitment-config", + "solana-fee-calculator 2.2.1", + "solana-inflation 2.2.1", + "solana-pubkey 2.4.0", + "solana-transaction-error 2.2.1", + "solana-transaction-status-client-types", + "solana-version", + "spl-generic-token", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sdk" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f03df7969f5e723ad31b6c9eadccc209037ac4caa34d8dc259316b05c11e82b" +dependencies = [ + "bincode", + "bs58", + "serde", + "solana-account 3.0.0", + "solana-epoch-info 3.0.0", + "solana-epoch-rewards-hasher", + "solana-fee-structure", + "solana-inflation 3.0.0", + "solana-keypair 3.1.0", + "solana-message 3.0.1", + "solana-offchain-message", + "solana-presigner", + "solana-program 3.0.0", + "solana-program-memory 3.1.0", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-seed-derivable", + "solana-seed-phrase 3.0.0", + "solana-serde 3.0.0", + "solana-serde-varint 3.0.0", + "solana-short-vec 3.0.0", + "solana-shred-version", + "solana-signature 3.1.0", + "solana-signer 3.0.0", + "solana-time-utils 3.0.0", + "solana-transaction 3.0.1", + "solana-transaction-error 3.0.0", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.6.0", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "libsecp256k1 0.6.0", + "solana-define-syscall 2.3.0", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de18cfdab99eeb940fbedd8c981fa130c0d76252da75d05446f22fae8b51932" +dependencies = [ + "k256", + "solana-define-syscall 4.0.1", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-seed-derivable" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-seed-phrase" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-serde" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1931484a408af466e14171556a47adaa215953c7f48b24e5f6b0282763818b04" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709a93cab694c70f40b279d497639788fc2ccbcf9b4aa32273d4b361322c02dd" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7e155eba458ecfb0107b98236088c3764a09ddf0201ec29e52a0be40857113" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5174c57d5ff3c1995f274d17156964664566e2cde18a07bba1586d35a70d3b" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-serialize-utils" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e41dd8feea239516c623a02f0a81c2367f4b604d7965237fed0751aeec33ed" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-short-vec" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69d029da5428fc1c57f7d49101b2077c61f049d4112cd5fb8456567cc7d2638" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-shred-version" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c79722e299d957958bf33695f7cd1ef6724ff55563c60fd9e3e24487cccde2" +dependencies = [ + "solana-hard-forks", + "solana-hash 4.3.0", + "solana-sha256-hasher 3.1.0", +] + +[[package]] +name = "solana-signature" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" +dependencies = [ + "ed25519-dalek 1.0.1", + "five8 0.2.1", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-signature" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bb8057cc0e9f7b5e89883d49de6f407df655bb6f3a71d0b7baf9986a2218fd9" +dependencies = [ + "ed25519-dalek 2.2.0", + "five8 0.2.1", + "rand 0.8.5", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize 3.0.1", +] + +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-signature 2.3.0", + "solana-transaction-error 2.2.1", +] + +[[package]] +name = "solana-signer" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature 3.1.0", + "solana-transaction-error 3.0.0", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-slot-history" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +dependencies = [ + "solana-instruction 3.0.0", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.2", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.0", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-system-interface 1.0.0", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-streamer" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5643516e5206b89dd4bdf67c39815606d835a51a13260e43349abdb92d241b1d" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap", + "itertools", + "libc", + "log", + "nix", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.40", + "smallvec", + "socket2 0.5.10", + "solana-keypair 2.2.3", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-packet 2.2.1", + "solana-perf", + "solana-pubkey 2.4.0", + "solana-quic-definitions", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-time-utils 2.2.1", + "solana-tls-utils", + "solana-transaction-error 2.2.1", + "solana-transaction-metrics-tracker", + "thiserror 2.0.12", + "tokio", + "tokio-util", + "x509-parser", +] + +[[package]] +name = "solana-svm-feature-set" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f24b836eb4d74ec255217bdbe0f24f64a07adeac31aca61f334f91cd4a3b1d5" + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "wasm-bindgen", +] + +[[package]] +name = "solana-system-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" +dependencies = [ + "num-traits", + "solana-msg 3.1.0", + "solana-program-error 3.0.0", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50c92bc019c590f5e42c61939676e18d14809ed00b2a59695dd5c67ae72c097" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info 2.2.1", + "solana-clock 2.2.2", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-instructions-sysvar 2.2.2", + "solana-last-restart-slot 2.2.1", + "solana-program-entrypoint 2.2.1", + "solana-program-error 2.2.2", + "solana-program-memory 2.2.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stake-interface", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63205e68d680bcc315337dec311b616ab32fea0a612db3b883ce4de02e0953f9" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info 3.0.0", + "solana-clock 3.0.0", + "solana-define-syscall 3.0.0", + "solana-epoch-rewards 3.0.0", + "solana-epoch-schedule 3.0.0", + "solana-fee-calculator 3.0.0", + "solana-hash 3.0.0", + "solana-instruction 3.0.0", + "solana-last-restart-slot 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", + "solana-pubkey 3.0.0", + "solana-rent 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-slot-hashes 3.0.0", + "solana-slot-history 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.6.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-thin-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c1025715a113e0e2e379b30a6bfe4455770dc0759dabf93f7dbd16646d5acbe" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-account 2.2.1", + "solana-client-traits", + "solana-clock 2.2.2", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction 2.2.3", + "solana-transaction-error 2.2.1", +] + +[[package]] +name = "solana-time-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af261afb0e8c39252a04d026e3ea9c405342b08c871a2ad8aa5448e068c784c" + +[[package]] +name = "solana-time-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced92c60aa76ec4780a9d93f3bd64dfa916e1b998eacc6f1c110f3f444f02c9" + +[[package]] +name = "solana-tls-utils" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14494aa87a75a883d1abcfee00f1278a28ecc594a2f030084879eb40570728f6" +dependencies = [ + "rustls 0.23.40", + "solana-keypair 2.2.3", + "solana-pubkey 2.4.0", + "solana-signer 2.2.1", + "x509-parser", +] + +[[package]] +name = "solana-tpu-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17895ce70fd1dd93add3fbac87d599954ded93c63fa1c66f702d278d96a6da14" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap", + "indicatif", + "log", + "rayon", + "solana-client-traits", + "solana-clock 2.2.2", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-schedule 2.2.1", + "solana-measure", + "solana-message 2.4.0", + "solana-net-utils", + "solana-pubkey 2.4.0", + "solana-pubsub-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-transaction 2.2.3", + "solana-transaction-error 2.2.1", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-transaction" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80657d6088f721148f5d889c828ca60c7daeedac9a8679f9ec215e0c42bcbf41" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction-error 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-transaction" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64928e6af3058dcddd6da6680cbe08324b4e071ad73115738235bbaa9e9f72a5" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-address 1.0.0", + "solana-hash 3.0.0", + "solana-instruction 3.0.0", + "solana-instruction-error", + "solana-message 3.0.1", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.0.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", + "solana-transaction-error 3.0.0", +] + +[[package]] +name = "solana-transaction-context" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a312304361987a85b2ef2293920558e6612876a639dd1309daf6d0d59ef2fe" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account 2.2.1", + "solana-instruction 2.3.0", + "solana-instructions-sysvar 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-transaction-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction-error", + "solana-sanitize 3.0.1", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03fc4e1b6252dc724f5ee69db6229feb43070b7318651580d2174da8baefb993" +dependencies = [ + "base64 0.22.1", + "bincode", + "log", + "rand 0.8.5", + "solana-packet 2.2.1", + "solana-perf", + "solana-short-vec 2.2.1", + "solana-signature 2.3.0", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f1d7c2387c35850848212244d2b225847666cb52d3bd59a5c409d2c300303d" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config", + "solana-message 2.4.0", + "solana-reward-info", + "solana-signature 2.3.0", + "solana-transaction 2.2.3", + "solana-transaction-context", + "solana-transaction-error 2.2.1", + "thiserror 2.0.12", +] + +[[package]] +name = "solana-udp-client" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dd36227dd3035ac09a89d4239551d2e3d7d9b177b61ccc7c6d393c3974d0efa" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-keypair 2.2.3", + "solana-net-utils", + "solana-streamer", + "solana-transaction-error 2.2.1", + "thiserror 2.0.12", + "tokio", +] + +[[package]] +name = "solana-version" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3324d46c7f7b7f5d34bf7dc71a2883bdc072c7b28ca81d0b2167ecec4cf8da9f" +dependencies = [ + "agave-feature-set", + "rand 0.8.5", + "semver", + "serde", + "serde_derive", + "solana-sanitize 2.2.1", + "solana-serde-varint 2.2.2", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef4f08746f154458f28b98330c0d55cb431e2de64ee4b8efc98dcbe292e0672b" +dependencies = [ + "bincode", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.2", + "solana-decode-error", + "solana-hash 2.3.0", + "solana-instruction 2.3.0", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "spl-generic-token" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741a62a566d97c58d33f9ed32337ceedd4e35109a686e31b1866c5dfa56abddc" +dependencies = [ + "bytemuck", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tempfile" +version = "3.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +dependencies = [ + "fastrand", + "getrandom 0.3.4", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "time" +version = "0.3.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" + +[[package]] +name = "time-macros" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.3", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls 0.23.40", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68d6fdd9f81c2819c9a8b0e0cd91660e7746a8e6ea2ba7c6b2b057985f6bcb51" +dependencies = [ + "async-compression", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body", + "http-body-util", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", + "url", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.12", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.12", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + +[[package]] +name = "typenum" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasip2" +version = "1.0.3+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +dependencies = [ + "wit-bindgen 0.57.1", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.2", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki 0.101.7", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "wormhole-supported-chains" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f42a80a24212937cc7d7b0ab8115bb87d82f949a1a42f75d500807072c94ba4" +dependencies = [ + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "wormhole-vaas-serde" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240c5a6136dc66ecc65097bb6d159e849b5df4ecbbbb220868d0edbdcc568ed3" +dependencies = [ + "anyhow", + "bstr", + "schemars", + "serde", + "serde_wormhole", + "sha3", + "thiserror 1.0.69", + "wormhole-supported-chains", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure 0.13.2", +] + +[[package]] +name = "zerocopy" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure 0.13.2", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/shine-solana/shine/Cargo.toml b/shine-solana/shine/Cargo.toml new file mode 100644 index 0000000..f69b9ad --- /dev/null +++ b/shine-solana/shine/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +members = [ + "programs/common", + "programs/shine_login_guard", + "programs/shine_users", + "programs/shine_payments", +] +resolver = "2" + +[profile.release] +overflow-checks = true +opt-level = "z" +lto = true +codegen-units = 1 +panic = "abort" +strip = true +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/shine-solana/shine/build.gradle b/shine-solana/shine/build.gradle new file mode 100644 index 0000000..dc9c030 --- /dev/null +++ b/shine-solana/shine/build.gradle @@ -0,0 +1,44 @@ +/* + * Gradle-задачи для утилитного деплоя UI Shine Payments. + * + * Куда деплоим файлы UI: + * /home/player/sites/test-solana-tickets.shineup.me + * + * Где расположен Caddy-конфиг на сервере: + * /home/player/SHiNE/caddy/Caddyfile + * + * По каким URL должен работать UI: + * https://test-solana-tickets.shineup.me + * https://sol.shiningpeople.ru + */ + +tasks.register("deployUi", Exec) { + group = "deploy" + description = "Деплой HTML UI Shine Payments на 45.136.124.227 в /home/player/sites/test-solana-tickets.shineup.me (URL: test-solana-tickets.shineup.me, sol.shiningpeople.ru)" + + // Источник локальных UI-страниц: + // shine/programs/shine_payments/web/ + def localUiDir = "${projectDir}/programs/shine_payments/web/" + + // Целевая директория на сервере: + // /home/player/sites/test-solana-tickets.shineup.me + def remoteTarget = "player@45.136.124.227:/home/player/sites/test-solana-tickets.shineup.me/" + + commandLine "rsync", "-av", "--delete", localUiDir, remoteTarget +} + +tasks.register("checkUiRemote", Exec) { + group = "deploy" + description = "Проверка на сервере: Caddy-конфиг и наличие новых Program ID в UI" + + commandLine "ssh", "-o", "StrictHostKeyChecking=no", "player@45.136.124.227", + "set -e; " + + "echo 'Caddy file:'; " + + "ls -la /home/player/SHiNE/caddy/Caddyfile; " + + "echo; " + + "echo 'Домены в Caddy:'; " + + "grep -n 'test-solana-tickets.shineup.me\\|sol.shiningpeople.ru' /home/player/SHiNE/caddy/Caddyfile; " + + "echo; " + + "echo 'Program ID в загруженных html:'; " + + "grep -R -n 'm48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR' /home/player/sites/test-solana-tickets.shineup.me/*.html" +} diff --git a/shine-solana/shine/doc/FUNDS_FLOW.md b/shine-solana/shine/doc/FUNDS_FLOW.md new file mode 100644 index 0000000..5352066 --- /dev/null +++ b/shine-solana/shine/doc/FUNDS_FLOW.md @@ -0,0 +1,47 @@ +# Движение Средств (Shine) + +Документ описывает, как перемещаются средства между счетами в текущей схеме. + +## 1) Регистрация и увеличение лимита (`shine_users`) + +### Регистрация пользователя (`create_user_pda`) + +1. Плательщик: кошелек `signer` (кто отправил транзакцию). +2. Получатель комиссии: `inflow_vault` (PDA в программе `shine_payments`). +3. Сумма перевода: + - `registration_fee_lamports` из economy-конфига `shine_users`; + - плюс комиссия за `additional_limit` (по формуле через `limit_step` и `lamports_per_limit_step`). + +### Увеличение лимита (`update_user_pda`) + +1. Плательщик: кошелек `signer`. +2. Получатель комиссии: `inflow_vault` (тот же PDA `shine_payments`). +3. Сумма перевода: + - только комиссия за `additional_limit` (без регистрационной части). + +## 2) Покупка билета (`shine_payments`) + +### Покупка (`buy_ticket`, `buy_ticket_usd`, `buy_ticket_sol`) + +1. Плательщик: кошелек покупателя (`signer`). +2. Получатель: `dao_wallet` (казна DAO из `ConfigState`). +3. В `inflow_vault` на этом шаге средства не зачисляются. + +## 3) Шаг выплат (`shine_payments::step_payout`) + +Источник выплат: `inflow_vault` (`ConfigState.inflow_vault`). + +При шаге выплаты: +1. Из `inflow_vault` переводится `ticket` получателю тикета. +2. Из `inflow_vault` переводится DAO-часть в `dao_wallet`. +3. Из `inflow_vault` переводится `call_reward_lamports` вызывающему шаг. + +Если очереди пусты: +1. Весь доступный остаток `inflow_vault` переводится в `dao_wallet`. + +## 4) Какие адреса задаются настройками + +1. `dao_wallet` — хранится в `ConfigState` (`shine_payments`), задается при `init`. +2. `inflow_vault` — PDA `shine_payments`, вычисляется по seed и program id. +3. Для `shine_users` получатель комиссии не настраивается отдельно: + - всегда используется PDA `inflow_vault` программы `shine_payments`. diff --git a/shine-solana/shine/doc/SHiNE-user-format-v.1.0.md b/shine-solana/shine/doc/SHiNE-user-format-v.1.0.md new file mode 100644 index 0000000..cfb260f --- /dev/null +++ b/shine-solana/shine/doc/SHiNE-user-format-v.1.0.md @@ -0,0 +1,225 @@ +# SHINY USER FORMAT v1.0 (DRAFT) + +Документ описывает целевой бинарный формат пользовательской записи в `user_pda` для программы `shine_users`. + +## 1) Статус версии и цель + +- Текущий on-chain формат: `v1.0`. +- Этот документ: `v1.0 (draft)` для текущего этапа. +- Цель текущей версии: зафиксировать рабочий формат и сразу оставить в нем поля для будущего расширения. + +Новые статусные поля: +- `root_key_status` +- `blockchain_key_status` +- `device_key_status` + +Текущее значение каждого статуса: `0` (ключ создан и не менялся). + +## 2) Общие правила кодирования + +- Числа: Little Endian (`LE`). +- Строки: `UTF-8` с префиксом длины `u8`. +- Публичные ключи: 32 байта (`Pubkey`). +- Подпись: 64 байта (Ed25519). +- Размер PDA фиксированный: `USER_PDA_SPACE` (сейчас 1024 байта). +- `record_len` хранит длину полезной записи от `magic` до `signature` включительно (без `padding`). + +## 3) Единый список полей в порядке хранения + +1. `magic` + Размер: 5 байт. + Значение: `"SHiNE"`. + Назначение: маркер формата записи. + +2. `format_major` + Размер: 1 байт (`u8`). + Текущее значение: `1`. + Назначение: major-версия формата. + +3. `format_minor` + Размер: 1 байт (`u8`). + Текущее значение: `0`. + Назначение: minor-версия формата. + +4. `record_len` + Размер: 2 байта (`u16`, LE). + Назначение: длина полезных данных записи (без `padding`). + +5. `created_at_ms` + Размер: 8 байт (`u64`, LE). + Назначение: время создания записи (Unix time, ms). + +6. `updated_at_ms` + Размер: 8 байт (`u64`, LE). + Назначение: время последнего обновления записи (Unix time, ms). + +7. `record_number` (`version`) + Размер: 4 байта (`u32`, LE). + Назначение: порядковый номер записи пользователя. + Правило обновления: новая запись должна иметь `last_record_number + 1`; проверяется программой. + +8. `prev_record_hash` (`prev_hash`) + Размер: 32 байта. + Назначение: хэш unsigned-части предыдущей записи для связи истории. + +9. `login_len` + Размер: 1 байт (`u8`). + Назначение: длина поля `login` в байтах. + +10. `login` + Размер: `login_len` байт (UTF-8). + Назначение: логин пользователя. + Текущие ограничения: от 1 до 25 символов, только `a-z`, `0-9`, `_`. + +11. `root_key_status` + Размер: 1 байт (`u8`). + Текущее значение: `0`. + Назначение: статус `root_key`. + Комментарий: будущие статусы ротации зарезервированы, смена root-ключа пока не реализована. + +12. `root_key` + Размер: 32 байта (`Pubkey`). + Назначение: корневой ключ пользователя для подписи записи. + +13. `blockchain_key_status` + Размер: 1 байт (`u8`). + Текущее значение: `0`. + Назначение: статус `blockchain_key`. + Комментарий: будущие статусы ротации зарезервированы. + +14. `blockchain_key` + Размер: 32 байта (`Pubkey`). + Назначение: рабочий блокчейн-ключ пользователя. + +15. `device_key_status` + Размер: 1 байт (`u8`). + Текущее значение: `0`. + Назначение: статус `device_key`. + Комментарий: будущие статусы ротации зарезервированы. + +16. `device_key` + Размер: 32 байта (`Pubkey`). + Назначение: ключ устройства пользователя. + +17. `chain_number` + Размер: 2 байта (`u16`, LE). + Назначение: номер блокчейн-профиля пользователя. + Текущее использование: базовый сценарий с одним профилем (обычно `1`). + +18. `balance` + Размер: 8 байт (`u64`, LE). + Назначение: лимит/баланс пользователя. + +19. `is_server` + Размер: 1 байт (`u8`). + Значения: `0` или `1`. + Назначение: флаг серверного профиля. + +20. `server_key` (только если `is_server = 1`) + Размер: 32 байта (`Pubkey`). + Назначение: публичный ключ сервера. + +21. `server_address_len` (только если `is_server = 1`) + Размер: 1 байт (`u8`). + Назначение: длина строки `server_address`. + +22. `server_address` (только если `is_server = 1`) + Размер: `server_address_len` байт (UTF-8). + Назначение: адрес сервера. + +23. `sync_servers_count` (только если `is_server = 1`) + Размер: 1 байт (`u8`). + Назначение: количество серверов, с которыми сервер синхронизирует данные. + Ограничение: максимум `32`. + +24. Повтор `sync_servers_count` раз (только если `is_server = 1`): + `server_login_len` — 1 байт (`u8`), + `server_login` — `server_login_len` байт (UTF-8). + Назначение: логины серверов синхронизации. + +25. `access_servers_count` + Размер: 1 байт (`u8`). + Назначение: количество серверов доступа (relay), через которые можно достучаться до пользователя. + +26. Повтор `access_servers_count` раз: + `server_login_len` — 1 байт (`u8`), + `server_login` — `server_login_len` байт (UTF-8). + Назначение: логины серверов доступа. + +27. `trusted_count` + Размер: 1 байт (`u8`). + Назначение: текущее число trusted-контактов. + Текущее состояние: пока только счетчик, без отдельной trusted-логики. + +28. `reserved` + Размер: 5 байт. + Текущее значение: `0x00 0x00 0x00 0x00 0x00`. + Назначение: резерв под будущие расширения. + +29. `signature` + Размер: 64 байта. + Назначение: Ed25519-подпись хэша unsigned-части записи. + +30. `padding` + Размер: до полного `USER_PDA_SPACE`. + Текущее значение: `0x00`. + Назначение: добивка до фиксированного размера PDA. + +## 4) Что подписывается + +Подписывается SHA-256 от unsigned-части записи: +- от `magic` до `reserved` включительно; +- без `signature`; +- без `padding`. + +## 5) Что сейчас работает в логике + +Сейчас в рабочем потоке используются 2 операции: +1. `create_user_pda` — регистрация пользователя. +2. `update_user_pda` — обновление записи пользователя. + +Через `update_user_pda` сейчас можно: +- увеличить `balance` через `additional_limit`; +- обновить серверные поля (`is_server`, `server_key`, `server_address`, `sync_servers`, `access_servers`); +- увеличить `record_number` (`version`) на 1. + +Оплата идет на адрес, заданный в `REGISTRATION_FEE_RECEIVER` (не в DAO по умолчанию). + +## 6) Ограничения и отложенные расширения + +Это функции и сценарии, которые предусмотрены структурой данных формата `v1.0`, но пока не реализованы программно. + +1. Смена ключей пока недоступна + `root_key`, `blockchain_key`, `device_key` считаются без ротации; статусные поля пока фактически только `0`. + +2. Multi-chain профили пока не реализованы + Пока используется один базовый профиль (`chain_number`), расширение до нескольких профилей/форков — отдельный этап. + +3. Trusted-логика пока не реализована + Пока хранится только `trusted_count`; список trusted, очередь, таймеры и голосование будут добавляться отдельно. + +4. Работа с несколькими серверами на уровне приложения ограничена + В записи можно хранить `sync_servers` и `access_servers`, но фактическая клиентская логика выбора/обхода серверов может быть ограничена. + + +## 7) Константы и фиксированные значения (точки будущего расширения) + +Ниже перечислены места, где сейчас используются константы/фиксированные значения, а в будущем возможна доработка: + +1. Версия формата: `format_major = 1`, `format_minor = 0`. + Расширение: переход на следующую минорную/мажорную версию при изменении бинарной схемы. + +2. Размер PDA: `USER_PDA_SPACE = 1024`. + Расширение: увеличение размера или переход на иное хранение при росте структуры. + +3. Статусы ключей: все три `*_key_status` пока равны `0`. + Расширение: добавить коды состояний для ротации/восстановления ключей. + +4. `chain_number`: текущий рабочий сценарий с одним профилем (обычно `1`). + Расширение: поддержка нескольких блокчейн-форков. + +5. `trusted_count`: пока только счетчик, обычно `0`. + Расширение: отдельные структуры trusted-списка, очередей и таймеров. + +6. `reserved` (5 байт): сейчас всегда нули. + Расширение: использовать как флаги/дополнительные поля без слома общей схемы. diff --git a/shine-solana/shine/doc/devnet_keys_and_deploy.md b/shine-solana/shine/doc/devnet_keys_and_deploy.md new file mode 100644 index 0000000..509c290 --- /dev/null +++ b/shine-solana/shine/doc/devnet_keys_and_deploy.md @@ -0,0 +1,55 @@ +# Ключи и деплой (тестовое пояснение) + +## 1) Какие адреса участвуют + +В проекте есть **2 программы**, поэтому у них **2 разных Program ID**: + +1. `shine_users` -> отдельный адрес программы +2. `shine_payments` -> отдельный адрес программы + +Это нормальная схема Solana: одна программа = один Program ID. + +Отдельно есть адрес кошелька-деплоера (upgrade authority), сейчас это: + +- keypair: `~/.config/solana/id.json` +- адрес: `4yzHKs2zFXpyqqCETe8KpAs4xhEo4QhJ2ybyTgRZphZv` + +Именно этот кошелек: + +- платит комиссии/ренту при деплое; +- владеет правом апгрейда программ; +- получает обратно SOL при `solana program close`. + +## 2) Почему раньше "плавали" адреса программ + +`anchor deploy` берет адрес программы из program keypair файла (`target/deploy/*-keypair.json`). +Если keypair другой, Program ID тоже будет другой. + +Чтобы этого не было, нужно держать синхронно: + +1. `declare_id!` в `programs/*/src/lib.rs` +2. `[programs.devnet]` и `[programs.localnet]` в `Anchor.toml` +3. соответствующие `*-keypair.json` для программ + +Сделано: + +- выполнен `anchor keys sync`; +- keypair CLI по умолчанию переключен на `~/.config/solana/id.json`; +- сохранены копии program keypair в `shine/keys/`. + +## 3) Сколько SOL занимали программы раньше (до закрытия) + +Перед очисткой были закрыты 4 программы с такими возвратами: + +1. `8Z3HQizFRhyVu5cNBwWNBXZHTpu89VMkn7Wuk1oCtkeJ` -> `3.38059032 SOL` +2. `qpgnAKhsXgPPaqQWfXhpme7UnG8GyStssuoSjF6Fzy3` -> `2.11208856 SOL` +3. `5dFcWDNp42Xn9Vv4oDMJzM4obBJ8hvDuAtPX54fT5L3t` -> `1.76425560 SOL` +4. `92sgkgx7KHpbhQu81mNGHaKa7skJB7esArVdPM7paDSW` -> `1.66820760 SOL` + +Итого было занято программами: + +- `8.92514208 SOL` + +Из них "актуальная пара" (2 программы последнего деплоя) занимала: + +- `3.38059032 + 2.11208856 = 5.49267888 SOL` diff --git a/shine-solana/shine/migrations/deploy.ts b/shine-solana/shine/migrations/deploy.ts new file mode 100644 index 0000000..bcde4b8 --- /dev/null +++ b/shine-solana/shine/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +import * as anchor from "@coral-xyz/anchor"; + +module.exports = async function (provider: anchor.AnchorProvider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/shine-solana/shine/package-lock.json b/shine-solana/shine/package-lock.json new file mode 100644 index 0000000..383a410 --- /dev/null +++ b/shine-solana/shine/package-lock.json @@ -0,0 +1,3021 @@ +{ + "name": "shine", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "license": "ISC", + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "@metaplex-foundation/mpl-token-metadata": "^3.4.0", + "@metaplex-foundation/mpl-toolbox": "^0.10.0", + "@metaplex-foundation/umi": "^1.5.1", + "@metaplex-foundation/umi-bundle-defaults": "^1.5.1", + "@metaplex-foundation/umi-web3js-adapters": "^1.5.1", + "@solana/spl-governance": "^0.3.28", + "@solana/spl-token": "^0.4.14" + }, + "devDependencies": { + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "chai": "^4.3.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^5.7.3" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz", + "integrity": "sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.1.tgz", + "integrity": "sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.69.0" + } + }, + "node_modules/@metaplex-foundation/mpl-token-metadata": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/mpl-token-metadata/-/mpl-token-metadata-3.4.0.tgz", + "integrity": "sha512-AxBAYCK73JWxY3g9//z/C9krkR0t1orXZDknUPS4+GjwGH2vgPfsk04yfZ31Htka2AdS9YE/3wH7sMUBHKn9Rg==", + "license": "Apache-2.0", + "dependencies": { + "@metaplex-foundation/mpl-toolbox": "^0.10.0" + }, + "peerDependencies": { + "@metaplex-foundation/umi": ">= 0.8.2 <= 1" + } + }, + "node_modules/@metaplex-foundation/mpl-toolbox": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/mpl-toolbox/-/mpl-toolbox-0.10.0.tgz", + "integrity": "sha512-84KD1L5cFyw5xnntHwL4uPwfcrkKSiwuDeypiVr92qCUFuF3ZENa2zlFVPu+pQcjTlod2LmEX3MhBmNjRMpdKg==", + "license": "Apache-2.0", + "peerDependencies": { + "@metaplex-foundation/umi": ">= 0.8.2 <= 1" + } + }, + "node_modules/@metaplex-foundation/umi": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi/-/umi-1.5.1.tgz", + "integrity": "sha512-ONRv5a0kv+23AMlR8oyFBHnjVg3o3N8pUfFcV4gzbg6OgZf87zHsPWBfED3OTJqx267v1bEn6d6DABXNFq9Z3A==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-options": "^1.5.1", + "@metaplex-foundation/umi-public-keys": "^1.5.1", + "@metaplex-foundation/umi-serializers": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-bundle-defaults": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-bundle-defaults/-/umi-bundle-defaults-1.5.1.tgz", + "integrity": "sha512-7qoXenAkQbcj468HGAeLZDyg3eEhcS9rWAnGqjnKgWOlL1czL2Qwho0FEtqOv57IHwAJSTpbHbcvABmdpTjjdw==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-downloader-http": "^1.5.1", + "@metaplex-foundation/umi-eddsa-web3js": "^1.5.1", + "@metaplex-foundation/umi-http-fetch": "^1.5.1", + "@metaplex-foundation/umi-program-repository": "^1.5.1", + "@metaplex-foundation/umi-rpc-chunk-get-accounts": "^1.5.1", + "@metaplex-foundation/umi-rpc-web3js": "^1.5.1", + "@metaplex-foundation/umi-serializer-data-view": "^1.5.1", + "@metaplex-foundation/umi-transaction-factory-web3js": "^1.5.1" + }, + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1", + "@solana/web3.js": "^1.72.0" + } + }, + "node_modules/@metaplex-foundation/umi-downloader-http": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-downloader-http/-/umi-downloader-http-1.5.1.tgz", + "integrity": "sha512-1s9gSTaDtwELyxBRE6Wmdr3xWeb4Z1uU04dj3Hg8VU+TN6/3wchh93+rIGZT5D3zzdh4+yPxdYV+4ZEr3T5glQ==", + "license": "MIT", + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-eddsa-web3js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-eddsa-web3js/-/umi-eddsa-web3js-1.5.1.tgz", + "integrity": "sha512-ZlzmXXAa1Ujk00G5TmqXM81J25+k/8sqt0zxBUlLTUSOxzlhxhlUKdErIhpHazbKq+eGck+Onm17oAwVKdKAcw==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-web3js-adapters": "^1.5.1", + "@noble/curves": "^1.0.0", + "yaml": "^2.7.0" + }, + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1", + "@solana/web3.js": "^1.72.0" + } + }, + "node_modules/@metaplex-foundation/umi-http-fetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-http-fetch/-/umi-http-fetch-1.5.1.tgz", + "integrity": "sha512-AOjZJo3Ua4a2FvgA85x5f0TkMSb+13Ao3uLIQ9FbScV42kqZnDox8KjJ7tKm1ZtYDlCYD0pSFMKPOC9NPDnHDg==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.7" + }, + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-options": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-options/-/umi-options-1.5.1.tgz", + "integrity": "sha512-ZE6uXgFA3rElFq4gJxZM2diAqZdFqL65bOnAggwdnnei5XXRzFyNF16wYSqlHnPLvG6ohRHWiXww8d2Mb83xFg==", + "license": "MIT" + }, + "node_modules/@metaplex-foundation/umi-program-repository": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-program-repository/-/umi-program-repository-1.5.1.tgz", + "integrity": "sha512-E5W0IjwFgDGuBTshISbbEh/s8deqxcOzzEjOOlYdMXnevVsfNLwBBIAY4NPJg3v5vpFlKODwUGB5BxCUVthzJg==", + "license": "MIT", + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-public-keys": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-public-keys/-/umi-public-keys-1.5.1.tgz", + "integrity": "sha512-joTnI1mRtYRfIaTo98uaYRjBPszsdyHuq0vvd6QbSX+MPvu3enkWi+UicuykEc3VXd5tcGdNMiGSx4jgXG6pkw==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-serializers-encodings": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-rpc-chunk-get-accounts": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-rpc-chunk-get-accounts/-/umi-rpc-chunk-get-accounts-1.5.1.tgz", + "integrity": "sha512-3dnGobT1Xwul7fXzQr8660UHSnFOCWEed4T449oNekrVsHp2o00fdOqjXwo11DYhS1rjm+gbzRSazRKb62uF2Q==", + "license": "MIT", + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-rpc-web3js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-rpc-web3js/-/umi-rpc-web3js-1.5.1.tgz", + "integrity": "sha512-CxHyruh2gW2b/ZOwHFFtooOgtu9hBrOJTd3HUMtD/jpaturApa3itsL/zNt4K34tELzVIUL7N78LDjNpzbu9Kw==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-web3js-adapters": "^1.5.1" + }, + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1", + "@solana/web3.js": "^1.72.0" + } + }, + "node_modules/@metaplex-foundation/umi-serializer-data-view": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-serializer-data-view/-/umi-serializer-data-view-1.5.1.tgz", + "integrity": "sha512-9Wxqk3bGVJ0xNmHhHrOUhdu/90Q1IT3FZRZN4eGckb0sf7Bgls7kBTkFfgXFmUh2VBnE0GnnncXeHKtop5RSFA==", + "license": "MIT", + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-serializers": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-serializers/-/umi-serializers-1.5.1.tgz", + "integrity": "sha512-scXciBylbJ4iwfxOF1Xx2XiBzoYUD8fSKWTsMal5Rj1hMRDe6b2XZcsBOjio61iAr8aTtFPmKpqxeBdLwmQ0ZQ==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-options": "^1.5.1", + "@metaplex-foundation/umi-public-keys": "^1.5.1", + "@metaplex-foundation/umi-serializers-core": "^1.5.1", + "@metaplex-foundation/umi-serializers-encodings": "^1.5.1", + "@metaplex-foundation/umi-serializers-numbers": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-serializers-core": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-serializers-core/-/umi-serializers-core-1.5.1.tgz", + "integrity": "sha512-6nYsbTCLq421x7JT1B3/iNgPpSARj/wL9naoKbOreHrk2ip/4R7vQstVRMl0Gx+Hv2tHnEIbFo3JBtWyC377Qw==", + "license": "MIT" + }, + "node_modules/@metaplex-foundation/umi-serializers-encodings": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-serializers-encodings/-/umi-serializers-encodings-1.5.1.tgz", + "integrity": "sha512-cVvwWmREE/Pmvjvsd50F18P53HDT0vzZECD6uYWIVzxgwpOiRDFu6r/vGbweomHoWzfTvuU6hiKuKv2KsOoXQA==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-serializers-core": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-serializers-numbers": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-serializers-numbers/-/umi-serializers-numbers-1.5.1.tgz", + "integrity": "sha512-7DVF1VJIdT44Pe6qWKaqGu4YVgE10OeLMYpm7C16SujSBgQGB/I2bh8NBifyH2R3oHhoyfE9qgIKB3dgRazN6A==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-serializers-core": "^1.5.1" + } + }, + "node_modules/@metaplex-foundation/umi-transaction-factory-web3js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-transaction-factory-web3js/-/umi-transaction-factory-web3js-1.5.1.tgz", + "integrity": "sha512-g4NfvtnmXtH1Q/Y9LdCsFtDRHQZmZWW7uKz+N9a+IVsJTTvpWFALMHm66dFDQGa0ExAYxAj7j6uZH2qDn0zarA==", + "license": "MIT", + "dependencies": { + "@metaplex-foundation/umi-web3js-adapters": "^1.5.1" + }, + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1", + "@solana/web3.js": "^1.72.0" + } + }, + "node_modules/@metaplex-foundation/umi-web3js-adapters": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@metaplex-foundation/umi-web3js-adapters/-/umi-web3js-adapters-1.5.1.tgz", + "integrity": "sha512-6W3JElD0B0EbgHofVKqk4PbP/JDrUHIKWciM7tEuXTDXbuXbSECDe7qlTU0JZXmVZNfYufI6FHnkCfPys2ZnIQ==", + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3" + }, + "peerDependencies": { + "@metaplex-foundation/umi": "^1.5.1", + "@solana/web3.js": "^1.72.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/buffer-layout-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", + "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/web3.js": "^1.32.0", + "bigint-buffer": "^1.1.5", + "bignumber.js": "^9.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@solana/codecs": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-rc.1.tgz", + "integrity": "sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-data-structures": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/codecs-strings": "2.0.0-rc.1", + "@solana/options": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.1.1.tgz", + "integrity": "sha512-iPQW3UZ2Vi7QFBo2r9tw0NubtH8EdrhhmZulx6lC8V5a+qjaxovtM/q/UW2BTNpqqHLfO0tIcLyBLrNH4HTWPg==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.1.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-data-structures": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz", + "integrity": "sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-data-structures/node_modules/@solana/codecs-core": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz", + "integrity": "sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-data-structures/node_modules/@solana/codecs-numbers": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz", + "integrity": "sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-data-structures/node_modules/@solana/errors": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz", + "integrity": "sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-data-structures/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/codecs-data-structures/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.1.1.tgz", + "integrity": "sha512-m20IUPJhPUmPkHSlZ2iMAjJ7PaYUvlMtFhCQYzm9BEBSI6OCvXTG3GAPpAnSGRBfg5y+QNqqmKn4QHU3B6zzCQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.1.1", + "@solana/errors": "2.1.1" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz", + "integrity": "sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-strings/node_modules/@solana/codecs-core": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz", + "integrity": "sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-strings/node_modules/@solana/codecs-numbers": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz", + "integrity": "sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-strings/node_modules/@solana/errors": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz", + "integrity": "sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs-strings/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/codecs-strings/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/codecs/node_modules/@solana/codecs-core": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz", + "integrity": "sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs/node_modules/@solana/codecs-numbers": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz", + "integrity": "sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs/node_modules/@solana/errors": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz", + "integrity": "sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/codecs/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/codecs/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/errors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.1.1.tgz", + "integrity": "sha512-sj6DaWNbSJFvLzT8UZoabMefQUfSW/8tXK7NTiagsDmh+Q87eyQDDC9L3z+mNmx9b6dEf6z660MOIplDD2nfEw==", + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/errors/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/errors/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/options": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-rc.1.tgz", + "integrity": "sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/codecs-data-structures": "2.0.0-rc.1", + "@solana/codecs-numbers": "2.0.0-rc.1", + "@solana/codecs-strings": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/options/node_modules/@solana/codecs-core": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz", + "integrity": "sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/options/node_modules/@solana/codecs-numbers": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz", + "integrity": "sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.0.0-rc.1", + "@solana/errors": "2.0.0-rc.1" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/options/node_modules/@solana/errors": { + "version": "2.0.0-rc.1", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz", + "integrity": "sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "commander": "^12.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "peerDependencies": { + "typescript": ">=5" + } + }, + "node_modules/@solana/options/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/options/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@solana/spl-governance": { + "version": "0.3.28", + "resolved": "https://registry.npmjs.org/@solana/spl-governance/-/spl-governance-0.3.28.tgz", + "integrity": "sha512-CUi1hMvzId2rAtMFTlxMwOy0EmFeT0VcmiC+iQnDhRBuM8LLLvRrbTYBWZo3xIvtPQW9HfhVBoL7P/XNFIqYVQ==", + "license": "MIT", + "dependencies": { + "@solana/web3.js": "^1.22.0", + "axios": "^1.1.3", + "bignumber.js": "^9.0.1", + "bn.js": "^5.1.3", + "borsh": "^0.3.1", + "bs58": "^4.0.1", + "superstruct": "^0.15.2" + } + }, + "node_modules/@solana/spl-governance/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@solana/spl-governance/node_modules/borsh": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.3.1.tgz", + "integrity": "sha512-gJoSTnhwLxN/i2+15Y7uprU8h3CKI+Co4YKZKvrGYUy0FwHWM20x5Sx7eU8Xv4HQqV+7rb4r3P7K1cBIQe3q8A==", + "license": "Apache-2.0", + "dependencies": { + "@types/bn.js": "^4.11.5", + "bn.js": "^5.0.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/@solana/spl-token": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.14.tgz", + "integrity": "sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-group": "^0.0.7", + "@solana/spl-token-metadata": "^0.1.6", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.5" + } + }, + "node_modules/@solana/spl-token-group": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@solana/spl-token-group/-/spl-token-group-0.0.7.tgz", + "integrity": "sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==", + "license": "Apache-2.0", + "dependencies": { + "@solana/codecs": "2.0.0-rc.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.3" + } + }, + "node_modules/@solana/spl-token-metadata": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.6.tgz", + "integrity": "sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/codecs": "2.0.0-rc.1" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.95.3" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.2", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.2.tgz", + "integrity": "sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz", + "integrity": "sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.15.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz", + "integrity": "sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz", + "integrity": "sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.16.0", + "form-data": "^4.0.5", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bigint-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", + "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "bindings": "^1.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "license": "CC0-1.0", + "peer": true + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rpc-websockets": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.1.1.tgz", + "integrity": "sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA==", + "license": "LGPL-3.0-only", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-mocha": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.1.0.tgz", + "integrity": "sha512-T0C0Xm3/WqCuF2tpa0GNGESTBoKZaiqdUP8guNv4ZY316AFXlyidnrzQ1LUrCT0Wb1i3J0zFTgOh/55Un44WdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yaml": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/shine-solana/shine/package.json b/shine-solana/shine/package.json new file mode 100644 index 0000000..545bfa5 --- /dev/null +++ b/shine-solana/shine/package.json @@ -0,0 +1,27 @@ +{ + "license": "ISC", + "scripts": { + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "@metaplex-foundation/mpl-token-metadata": "^3.4.0", + "@metaplex-foundation/mpl-toolbox": "^0.10.0", + "@metaplex-foundation/umi": "^1.5.1", + "@metaplex-foundation/umi-bundle-defaults": "^1.5.1", + "@metaplex-foundation/umi-web3js-adapters": "^1.5.1", + "@solana/spl-token": "^0.4.14", + "@solana/spl-governance": "^0.3.28" + }, + "devDependencies": { + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "chai": "^4.3.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^5.7.3" + } +} diff --git a/shine-solana/shine/programs/common/Cargo.toml b/shine-solana/shine/programs/common/Cargo.toml new file mode 100644 index 0000000..44c4d21 --- /dev/null +++ b/shine-solana/shine/programs/common/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" + +[dependencies] +anchor-lang = "0.31.1" + + +[features] diff --git a/shine-solana/shine/programs/common/src/deploy_config.rs b/shine-solana/shine/programs/common/src/deploy_config.rs new file mode 100644 index 0000000..54f021c --- /dev/null +++ b/shine-solana/shine/programs/common/src/deploy_config.rs @@ -0,0 +1,43 @@ +//! Единый деплой-конфиг проекта SHINE. +//! Здесь хранятся адреса и параметры, которые зависят от окружения деплоя. + +// ========================= +// Program IDs +// ========================= + +/// `SHINE_PAYMENTS_PROGRAM_ID` — адрес программы `shine_payments` для текущего окружения. +pub const SHINE_PAYMENTS_PROGRAM_ID: &str = "m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"; + +/// `SHINE_USERS_PROGRAM_ID` — адрес программы `shine_users` для текущего окружения. +pub const SHINE_USERS_PROGRAM_ID: &str = "FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm"; + +/// `SHINE_LOGIN_GUARD_PROGRAM_ID` — адрес программы проверки платных логинов. +pub const SHINE_LOGIN_GUARD_PROGRAM_ID: &str = "3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo"; + +// ========================= +// DAO / роли управления +// ========================= + +/// `DAO_AUTHORITY` — кошелек DAO/управления, который имеет право менять защищенные настройки. +pub const DAO_AUTHORITY: &str = "FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P"; + +/// `DAO_TREASURY_WALLET` — кошелек казны DAO для поступления DAO-части выплат в `shine_payments`. +pub const DAO_TREASURY_WALLET: &str = "FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P"; + +// ========================= +// Комиссии / получатели +// ========================= + +/// `REGISTRATION_FEE_RECEIVER` — кошелек получателя комиссии за регистрацию в `shine_users`. +pub const REGISTRATION_FEE_RECEIVER: &str = "9vXFoN9ngfN1gpqQ3HT5n3y9Wp2r7HnSQckirgwVwWwb"; + +// ========================= +// Оракул (Pyth SOL/USD) +// ========================= + +/// `PYTH_SOL_USD_FEED_ID` — feed id Pyth для пары SOL/USD (используется для проверки feed внутри аккаунта). +pub const PYTH_SOL_USD_FEED_ID: &str = + "0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d"; + +/// `PYTH_SOL_USD_ACCOUNT` — адрес Solana-аккаунта обновлений цены Pyth для SOL/USD. +pub const PYTH_SOL_USD_ACCOUNT: &str = "7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE"; diff --git a/shine-solana/shine/programs/common/src/lib.rs b/shine-solana/shine/programs/common/src/lib.rs new file mode 100644 index 0000000..180d185 --- /dev/null +++ b/shine-solana/shine/programs/common/src/lib.rs @@ -0,0 +1,2 @@ +pub mod utils; +pub mod deploy_config; diff --git a/shine-solana/shine/programs/common/src/utils.rs b/shine-solana/shine/programs/common/src/utils.rs new file mode 100644 index 0000000..93f465d --- /dev/null +++ b/shine-solana/shine/programs/common/src/utils.rs @@ -0,0 +1,359 @@ +use anchor_lang::prelude::*; +use anchor_lang::solana_program::{program::invoke_signed, system_instruction}; + +/// сдесь коды всех ошибок + +#[error_code] +pub enum ErrCode { + /// Система уже инициализирована и не может быть инициализирована повторно! + #[msg("Система уже инициализирована и не может быть инициализирована повторно!")] + SystemAlreadyInitialized = 1000, + + #[msg("PDA не содержит данных или не инициализирован")] + EmptyPdaData = 1002, + + #[msg("Пользователь уже зарегистрирован")] + UserAlreadyExists = 1003, + + #[msg("Некорректный логин")] + InvalidLogin = 1004, + + #[msg("Не совпадает PDA адрес")] + InvalidPdaAddress = 1006, + + #[msg("Формат данных не поддерживается")] + UnsupportedFormat = 1011, + + #[msg("Ошибка при десериализации")] + DeserializationError = 1012, + + /// PDA уже существует, создание невозможно + #[msg("PDA-аккаунт уже существует и не может быть создан повторно.")] + PdaAlreadyExists = 1009, + + #[msg("Подписавший не совпадает с ожидаемым пользователем (это потому что пока временно можно регистрировать пользователя с другово аккаунта")] + InvalidSigner = 1005, + + /// Не получилось создат ьпользователя, система уже перегружена, попробуйте поззже!" + #[msg("Не получилось создать пользователя, система уже перегружена, попробуйте поззже!")] + NoSuitableIdPda = 1010, + + #[msg("Невалидная цифровая подпись записи")] + InvalidSignature = 1013, + + #[msg("Невалидный формат записи")] + InvalidRecordFormat = 1014, + + #[msg("Невалидная длина записи")] + InvalidRecordLength = 1015, + + #[msg("Невалидные данные записи")] + InvalidRecordData = 1016, + + #[msg("Невалидный хэш предыдущей версии")] + InvalidPrevHash = 1017, + + #[msg("Попытка изменить неизменяемое поле")] + ImmutableFieldChanged = 1018, + + #[msg("Попытка уменьшить лимит/баланс")] + BalanceDecrease = 1019, + + #[msg("Невалидная версия записи")] + InvalidVersion = 1020, + + #[msg("Размер записи превышает допустимый")] + RecordTooLarge = 1021, + + #[msg("Переполнение при вычислении")] + MathOverflow = 1022, + + #[msg("Неверный адрес получателя комиссии")] + InvalidFeeReceiver = 1023, + + #[msg("Пополнение лимита должно быть кратно шагу")] + InvalidLimitIncrement = 1024, + + #[msg("Невалидная magic-сигнатура записи")] + InvalidRecordMagic = 1025, + + #[msg("Логин относится к платным и требует отдельной покупки через DAO")] + PremiumLogin = 1026, + + #[msg("Некорректный ответ программы проверки логина")] + InvalidLoginGuardResponse = 1027, + + #[msg("Логин использует брендовый термин и требует дополнительной верификации")] + TrademarkLoginRequiresReview = 1028, +} + +///---------------------------------------------------------------------------------------------------------- +/// Базовые функции для работы с PDA +///---------------------------------------------------------------------------------------------------------- + +/// Создаёт PDA аккаунт (если его ещё нет), и записывает в него массив байт. +/// +/// Аргументы: +/// - `pda_account`: аккаунт, куда записываем +/// - `signer`: кто платит за создание (обычно пользователь) +/// - `program_id`: адрес текущей программы +/// - `seeds`: слайс сидов, по которым создавался PDA +/// - `data`: байты для записи +/// - `space`: желаемый размер аккаунта +pub fn create_and_write_pda<'info>( + pda_account: &AccountInfo<'info>, + signer: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + program_id: &Pubkey, + seeds: &[&[u8]], + data: Vec, + space: u64, +) -> Result<()> { + // ─────────────────────────────────────────────── + // 1. Проверяем, создан ли аккаунт (если нет — owner = default) + if pda_account.owner == &Pubkey::default() { + msg!("Создаём PDA с размером {} байт", space); + + let space = space; //+ 128; // Добавляется запас под метаданные + // Вычисляем необходимую арендную плату + let lamports = Rent::get()?.minimum_balance(space as usize); + + // Формируем инструкцию + let create_instr = system_instruction::create_account( + signer.key, + pda_account.key, + lamports, + space, + program_id, + ); + + // Выполняем инструкцию с подписью от PDA + invoke_signed( + &create_instr, + &[signer.clone(), pda_account.clone(), system_program.clone()], + &[&seeds], + )?; + } + + // ─────────────────────────────────────────────── + // 2. Пишем данные в аккаунт + let mut account_data = pda_account.try_borrow_mut_data()?; + + let copy_len = std::cmp::min(account_data.len(), data.len()); + account_data[..copy_len].copy_from_slice(&data[..copy_len]); + + // Если хочешь дополнить оставшееся нулями — раскомментируй: + // for i in copy_len..account_data.len() { + // account_data[i] = 0; + // } + + msg!("Успешно записано {} байт в PDA", copy_len); + Ok(()) +} + +/// Создаёт PDA аккаунт (если его ещё нет). +/// +/// ⚠️ Если аккаунт уже существует, выбрасывается ошибка. +/// Используется внутри инструкций смарт-контракта. +/// +/// Аргументы: +/// - `pda_account`: аккаунт, который хотим создать (PDA) +/// - `signer`: кто оплачивает создание аккаунта (обычно пользователь) +/// - `system_program`: системная программа (`111...111`) +/// - `program_id`: адрес текущей программы (используется для подписи PDA) +/// - `seeds`: массив сидов, по которым вычислялся PDA +/// - `space`: желаемый размер аккаунта в байтах (только данных, без метаданных) +pub fn create_pda<'info>( + pda_account: &AccountInfo<'info>, + signer: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + program_id: &Pubkey, + seeds: &[&[u8]], + space: u64, +) -> Result<()> { + // ─────────────────────────────────────────────── + // 1. Проверяем, существует ли аккаунт + if pda_account.owner != &Pubkey::default() { + // Если владелец не равен Pubkey::default, значит аккаунт уже создан + // Возвращаем ошибку с пояснением + return Err(error!(ErrCode::PdaAlreadyExists)); + } + + // ─────────────────────────────────────────────── + // 2. Логируем, что будем создавать PDA + msg!("Создаём PDA-аккаунт на {} байт", space); + + // Добавляем запас под метаданные Solana (примерно 128 байт) + let full_space = space; + + // Получаем минимальный баланс для аренды (чтобы аккаунт не удалили) + let lamports = Rent::get()?.minimum_balance(full_space as usize); + + // ─────────────────────────────────────────────── + // 3. Создаём инструкцию system_program для создания аккаунта + let create_instr = system_instruction::create_account( + signer.key, // от имени кого + pda_account.key, // для какого PDA + lamports, // сколько лампортов перевести + full_space, // сколько байт выделить + program_id, // кто будет владельцем PDA + ); + + // ─────────────────────────────────────────────── + // 4. Выполняем инструкцию с подписью PDA (через сиды) + invoke_signed( + &create_instr, + &[signer.clone(), pda_account.clone(), system_program.clone()], + &[&seeds], // PDA сиды → для подписи + )?; + + Ok(()) +} + +/// Записывает массив байт в PDA аккаунт (в начало data-секции). +/// +/// ⚠️ Убедись, что PDA был передан как `#[account(mut)]` +/// ⚠️ Эта функция ничего не создаёт, только пишет. +/// +/// Аргументы: +/// - `pda_account`: аккаунт, в который пишем (должен быть mut) +/// - `data`: бинарный массив, который нужно записать +pub fn write_to_pda<'info>(pda_account: &AccountInfo<'info>, data: &[u8]) -> Result<()> { + // ─────────────────────────────────────────────── + // 1. Получаем доступ к данным PDA (на запись) + let mut account_data = pda_account.try_borrow_mut_data()?; + + // ─────────────────────────────────────────────── + // 2. Вычисляем сколько байт реально можно записать + // (на случай, если data длиннее, чем выделено место) + let copy_len = std::cmp::min(account_data.len(), data.len()); + + // ─────────────────────────────────────────────── + // 3. Копируем данные в аккаунт (с самого начала) + account_data[..copy_len].copy_from_slice(&data[..copy_len]); + + // Логируем, сколько байт записано + msg!("Успешно записано {} байт в PDA", copy_len); + + Ok(()) +} + +/// ------------------------------------------------------------------------ +/// safe_read_pda ‒ «безопасное чтение PDA» +/// ------------------------------------------------------------------------ +/// +/// * Принимает: ссылку на `AccountInfo<'info>` PDA-аккаунта. +/// * Возвращает: `Vec` с данными аккаунта. +/// Если аккаунта нет или его данные пусты — возвращается `Vec::new()` +/// длиной 0 байт. +/// +/// Как работает ─────────────────────────────────────────────────────────── +/// 1. Проверяем, что аккаунт **инициализирован**: у не-инициализированного +/// owner = Pubkey::default(). Если owner нулевой — сразу отдаём пустой вектор. +/// 2. Если длина буфера == 0 (Anchor helper `data_is_empty()`), тоже отдаём пустой. +/// 3. Пытаемся безопасно (`try_borrow_data`) получить ссылку на данные. +/// - Успех → копируем их в Vec и возвращаем. +/// - Ошибка (например, конфликт borrow) → логируем и возвращаем пустой Vec. +/// +/// пример использования +/// let raw_bytes = safe_read_pda(&ctx.accounts.readonly_pda); +/// require!(!raw_bytes.is_empty(), ErrCode::EmptyPdaData); +/// msg!("Размер считанных данных: {}", raw_bytes.len()); +/// ------------------------------------------------------------------------ +pub fn safe_read_pda<'info>(pda_account: &AccountInfo<'info>) -> Vec { + // ───────────────────────────────────────────────────────────────────── + // 1) Аккаунт Н*Е* СУЩЕСТВУЕТ или не инициализирован: + // owner == Pubkey::default() (в Solana нулевой owner у пустого счёта) + // ───────────────────────────────────────────────────────────────────── + if pda_account.owner == &Pubkey::default() { + msg!("safe_read_pda: аккаунт не инициализирован ‒ возвращаем пустой массив"); + return Vec::new(); // [] + } + + // ───────────────────────────────────────────────────────────────────── + // 2) У аккаунта нет данных (длина 0) — тоже считаем «пустым» + // ───────────────────────────────────────────────────────────────────── + if pda_account.data_is_empty() { + msg!("safe_read_pda: у аккаунта data_len == 0 ‒ возвращаем пустой массив"); + return Vec::new(); + } + + // ───────────────────────────────────────────────────────────────────── + // 3) Пытаемся безопасно забрать буфер данных; ошибки перехватываем + // ───────────────────────────────────────────────────────────────────── + match pda_account.try_borrow_data() { + Ok(data_ref) => { + // to_vec() копирует bytes → Vec, чтобы дальше работать без borrow-лифа + data_ref.to_vec() + } + Err(e) => { + // Ошибка при borrow (например, уже есть активное мутабельное заимствование) + msg!( + "safe_read_pda: ошибка borrow_data ({:?}) ‒ возвращаем пустой массив", + e + ); + Vec::new() + } + } +} + +/// ------------------------------------------------------------------------ +/// delete_pda_with_assign — закрыть PDA, вернуть ренту и освободить адрес +/// ------------------------------------------------------------------------ +/// +/// Параметры: +/// - `pda_account` : PDA-аккаунт (mut), который закрываем (owned вашей программой) +/// - `recipient` : счёт, на который возвращаем лампорты (обычно пользователь) +/// - `system_program`: системная программа (111...111) +/// - `program_id` : Pubkey вашей программы (проверка владельца) +/// - `seeds` : сиды PDA (в том же порядке, как при создании), чтобы PDA «подписал» assign +/// +/// Делает: +/// 1) Проверяет, что PDA принадлежит вашей программе. +/// 2) Обнуляет данные и сжимает их до 0 байт (realloc(0)). +/// 3) Переводит все лампорты PDA на `recipient`. +/// 4) Делает `assign` владельца на System Program (через `invoke_signed`). +/// +/// Результат: +/// — В конце транзакции аккаунт с lamports=0 и data_len=0 будет удалён рантаймом, +/// владелец = System Program (чисто/ожидаемо). +/// — В следующей транзакции можно снова создать PDA с тем же сидом. +/// ------------------------------------------------------------------------ + +pub fn delete_pda_return_rent<'info>( + pda_account: &AccountInfo<'info>, + recipient: &AccountInfo<'info>, + program_id: &Pubkey, +) -> Result<()> { + // 0) проверки + require!( + pda_account.owner != &Pubkey::default(), + ErrCode::EmptyPdaData + ); + require!(pda_account.owner == program_id, ErrCode::InvalidPdaAddress); + + // 1) Переложить все лампорты с PDA на получателя (мы владелец, это разрешено) + let amount = **pda_account.lamports.borrow(); + if amount > 0 { + **recipient.lamports.borrow_mut() = recipient + .lamports() + .checked_add(amount) + .ok_or(ProgramError::InsufficientFunds)?; + **pda_account.lamports.borrow_mut() = 0; + } + + // 2) Нулим данные (если были) + if !pda_account.data_is_empty() { + let mut data = pda_account.try_borrow_mut_data()?; + for b in data.iter_mut() { + *b = 0; + } + } + + // 3) Сжать до 0 байт + pda_account.realloc(0, false)?; + + // Никаких assign/transfer больше не делаем — это надёжнее. + msg!("PDA закрыт: рента отправлена на {}", recipient.key); + Ok(()) +} diff --git a/shine-solana/shine/programs/shine_login_guard/Cargo.toml b/shine-solana/shine/programs/shine_login_guard/Cargo.toml new file mode 100644 index 0000000..52206b0 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "shine_login_guard" +version = "0.1.0" +description = "Premium login classification program" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "shine_login_guard" +test = false +doctest = false +bench = false + +[dependencies] +anchor-lang = "0.31.1" + +[features] +default = [] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +anchor-debug = [] +custom-heap = [] +custom-panic = [] +cpi = [] +idl-build = ["anchor-lang/idl-build"] diff --git a/shine-solana/shine/programs/shine_login_guard/build.rs b/shine-solana/shine/programs/shine_login_guard/build.rs new file mode 100644 index 0000000..6295646 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/build.rs @@ -0,0 +1,114 @@ +use std::collections::BTreeSet; +use std::collections::HashMap; +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; + +const PREMIUM_DIR: &str = "src/dictionaries/premium"; +const TRADEMARKS_DIR: &str = "src/dictionaries/trademarks"; + +fn normalize_word(word: &str) -> Option { + let w = word.trim().to_ascii_lowercase(); + if w.is_empty() || w.len() > 20 { + return None; + } + if !w.chars().all(|c| c.is_ascii_alphanumeric()) { + return None; + } + Some(w) +} + +fn gather_files(dir: &Path) -> Vec { + let mut files = Vec::new(); + if let Ok(entries) = fs::read_dir(dir) { + for entry in entries.flatten() { + let p = entry.path(); + if p.is_dir() { + files.extend(gather_files(&p)); + } else if p.extension().and_then(|s| s.to_str()) == Some("txt") { + files.push(p); + } + } + } + files.sort(); + files +} + +fn load_word_set(dir: &Path, label: &str) -> BTreeSet { + let mut out = BTreeSet::new(); + let mut seen: HashMap = HashMap::new(); + for file in gather_files(dir) { + println!("cargo:rerun-if-changed={}", file.display()); + let raw = fs::read_to_string(&file).unwrap_or_default(); + for line in raw.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + if let Some(w) = normalize_word(line) { + *seen.entry(w.clone()).or_insert(0) += 1; + out.insert(w); + } + } + } + let mut duplicate_words = 0usize; + let mut duplicate_entries = 0usize; + let mut sample: Vec = Vec::new(); + let mut keys: Vec<_> = seen.keys().cloned().collect(); + keys.sort(); + for k in keys { + if let Some(cnt) = seen.get(&k) { + if *cnt > 1 { + duplicate_words += 1; + duplicate_entries += cnt - 1; + if sample.len() < 40 { + sample.push(format!("{k} x{cnt}")); + } + } + } + } + if duplicate_words > 0 { + println!( + "cargo:warning=[{label}] duplicates found: words={}, extra_entries={}", + duplicate_words, duplicate_entries + ); + println!( + "cargo:warning=[{label}] duplicate samples: {}", + sample.join(", ") + ); + } + out +} + +fn main() { + let premium_dir = Path::new(PREMIUM_DIR); + let trademarks_dir = Path::new(TRADEMARKS_DIR); + println!("cargo:rerun-if-changed={}", premium_dir.display()); + println!("cargo:rerun-if-changed={}", trademarks_dir.display()); + + let premium = load_word_set(premium_dir, "premium"); + let trademarks = load_word_set(trademarks_dir, "trademarks"); + + let premium_words: Vec = premium.into_iter().collect(); + let trademark_words: Vec = trademarks.into_iter().collect(); + let mut out = String::new(); + out.push_str("// @generated by build.rs\n"); + out.push_str("pub static PREMIUM_WORDS: &[&str] = &[\n"); + for w in &premium_words { + out.push_str(" \""); + out.push_str(w); + out.push_str("\",\n"); + } + out.push_str("];\n"); + out.push_str("pub static TRADEMARK_WORDS: &[&str] = &[\n"); + for w in &trademark_words { + out.push_str(" \""); + out.push_str(w); + out.push_str("\",\n"); + } + out.push_str("];\n"); + + let out_dir = env::var("OUT_DIR").expect("OUT_DIR is not set"); + let dst = Path::new(&out_dir).join("generated_dictionary.rs"); + fs::write(dst, out).expect("failed to write generated dictionary"); +} diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/adjectives_core.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/adjectives_core.txt new file mode 100644 index 0000000..5fe17f4 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/adjectives_core.txt @@ -0,0 +1,88 @@ +# Premium dictionary: adjectives / style words +# Премиум-словарь: прилагательные / слова-стили +alpha +arcane +atomic +aurora +bold +brave +bright +calm +clean +cool +cosmic +crazy +crisp +crystal +cyber +dark +daring +deep +divine +electric +elite +epic +fast +final +fluid +fresh +funny +future +giant +global +golden +grand +great +happy +hyper +iconic +infinite +iron +legend +light +lucky +lunar +magic +mega +metal +modern +mystic +nano +neo +new +night +noble +official +omega +prime +pro +pure +quick +rapid +real +royal +sexy +sharp +silent +silver +smart +solid +sonic +special +star +steel +storm +strong +super +swift +top +true +ultra +united +urban +velvet +vivid +vip +wild +young +zen diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nicknames_people.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nicknames_people.txt new file mode 100644 index 0000000..eb5e607 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nicknames_people.txt @@ -0,0 +1,421 @@ +# Premium dictionary: nicknames / persona words +# Премиум-словарь: никнеймы / слова-персоны +ace +agent +alpha +astro +bandit +beast +blaze +bolt +boss +bravo +bro +captain +champ +chief +commander +cosmo +crane +crow +crusher +cypher +dash +delta +diesel +drake +duke +eagle +echo +falcon +flash +fury +ghost +gladiator +hawk +hero +hunter +joker +judge +king +knight +legend +lion +lord +marshal +master +matrix +maverick +ninja +nomad +onyx +phantom +pilot +pirate +predator +prince +pro +queen +ranger +reaper +rex +rider +rookie +samurai +savage +sensei +shadow +shark +silver +skipper +sniper +soldier +sparrow +spartan +spirit +storm +striker +tiger +trailblazer +viking +warrior +whisper +wizard +wolf +wraith +zeus +admiral +afterglow +anvil +arrow +avenger +badger +banshee +baron +basilisk +bear +blackout +boomer +breaker +bronco +bullet +bulldog +butcher +caesar +cannon +cardinal +centurion +cerberus +charger +cheetah +cobra +colossus +comet +corsair +cyclone +daemon +defender +destroyer +dominator +dragon +dragonfly +dynamo +enigma +executor +firebrand +firefly +firestorm +firewolf +fisher +forger +freeman +frontier +frost +frostbite +gambit +general +goliath +griffin +grizzly +gunslinger +harbinger +hercules +hex +hornet +hurricane +hyena +icarus +inferno +jackal +jaguar +javelin +jester +judgex +keeper +killer +kraken +lancer +leviathan +lightning +locksmith +lynx +magnum +mercenary +merlin +mirage +monolith +monster +mustang +nebula +neutron +nightfall +nightfox +nightmare +nitro +obelisk +octane +odin +outlaw +overlord +panther +patriot +pegasus +phoenix +phoenixx +poison +protector +prowler +punisher +pyro +quasar +rampage +raptor +ravager +razor +renegade +revenant +riptide +roadster +ronin +saber +sabertooth +scorpion +sentinel +seraph +serpent +shogun +sidewinder +silencer +sirocco +sledge +specter +sphinx +stallion +starlord +stonewall +sunfire +survivor +talon +tempest +thor +thunder +thunderbolt +titan +tracker +trident +trooper +typhoon +tyrant +undertaker +valkyrie +vanguard +venom +vertex +vortex +warden +warlock +watcher +wildcard +windrunner +wingman +wolfhound +abyss +airstrike +alchemist +ambassador +apex +archer +assassin +atlas +backdraft +barrage +barricade +bastion +behemoth +berserker +bigfoot +blackhawk +blizzard +bloodhound +bluefire +bodyguard +bomber +booster +brick +broadsword +buck +buffalo +bughunter +captor +caretaker +carnage +catapult +cavalier +chargerx +chieftain +cliffhanger +clutch +codebreaker +colt +conqueror +contractor +cougar +crosshair +cryptic +darkstar +daybreak +deepstrike +demolisher +desperado +direwolf +doombringer +dozer +drifter +eclipse +ember +endgame +evoker +falconer +fencer +fierce +firehawk +firestarter +fist +flanker +flint +floodgate +forge +fortress +freefall +fugitive +gale +gamechanger +gatekeeper +gauntlet +glacier +godspeed +grave +gremlin +grim +hammer +hardline +headhunter +hellfire +helix +highlander +hitman +hotshot +iceman +icewind +immortal +incognito +invictus +ironclad +juggernaut +juniper +kamikaze +keymaster +kingpin +longshot +lowlight +madmax +marksman +megatron +midnight +minotaur +moonwalker +mutant +nightbird +nighthawk +nightwind +northstar +obsidian +officer +onslaught +operator +overdrive +paladin +pathfinder +patroller +peacekeeper +pendragon +pinpoint +plasma +poet +polar +raider +rainmaker +riptalon +risker +roadrunner +rocketeer +runeblade +safeguard +scalpel +scar +scout +shade +shellshock +shockwave +showstopper +skyfall +slayer +smokescreen +snowfall +solstice +soulforge +southpaw +spectral +speedster +spellbinder +spike +stargazer +stinger +sunstrike +supernova +tactician +teammate +thrasher +thunderbird +timekeeper +torch +tracer +trailhawk +trigger +troublemaker +twister +undertow +updraft +vanquisher +viper +void +wanderer +warpath +wavebreaker +westwind +whitewolf +wildfire +windstorm +wolfpack +wrangler +zenith diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nouns_core.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nouns_core.txt new file mode 100644 index 0000000..8df3b27 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/nouns_core.txt @@ -0,0 +1,204 @@ +# Premium dictionary: nouns / entities +# Премиум-словарь: существительные / сущности +academy +access +account +agent +air +angel +app +arena +art +atlas +bank +base +beacon +beat +beta +bit +blade +block +board +bot +brand +bridge +buddy +build +buyer +byte +camp +capital +card +cash +center +chain +chat +city +class +club +coin +collective +company +community +connect +core +craft +crew +crown +dao +data +deal +delta +desk +dev +digital +direct +district +dock +domain +dream +drive +drop +edge +engine +exchange +expert +factory +family +farm +field +finance +flow +force +fox +fund +future +game +gate +genesis +ghost +global +gold +group +guard +guild +guru +hall +hero +hub +idea +index +info +infra +jet +joy +key +king +kit +labs +land +leader +league +line +link +list +logic +lounge +machine +maker +market +matrix +media +member +mint +mode +money +moon +network +nexus +node +nova +office +one +open +oracle +orbit +order +origin +owner +party +pay +pilot +planet +platform +play +point +pool +portal +power +project +protocol +pulse +queen +quest +radar +realm +relay +resource +rise +rocket +room +route +runner +safe +sale +scope +service +shop +signal +site +skill +sky +space +sphere +spot +squad +stack +stage +star +state +station +step +stock +store +stream +studio +suite +swap +system +team +tech +terminal +time +token +tower +trade +travel +tribe +trust +union +unit +universe +vault +vector +venture +verse +view +vision +voice +wallet +wave +way +web +world +zone diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/people_names.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/people_names.txt new file mode 100644 index 0000000..d2ab65d --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/people_names.txt @@ -0,0 +1,1221 @@ +# Premium dictionary: common person names (latin) +# Премиум-словарь: распространённые имена людей (латиница) +aaron +adam +adrian +aidar +alan +albert +alec +alex +alexander +alfred +andrew +anthony +anton +arnold +arthur +austin +ben +benjamin +bernard +blake +boris +brad +brandon +brian +bruce +caleb +carl +carter +charles +chris +christian +christopher +clark +cole +colin +connor +dan +daniel +danny +david +denis +dennis +derek +dominic +dylan +edgar +edward +eli +elias +elijah +eric +ethan +evan +felix +frank +gabriel +gary +george +glen +gordon +grant +greg +gregory +harry +henry +howard +hugo +ian +isaac +ivan +jack +jackson +jacob +james +jason +jay +jeff +jeremy +jerry +jesse +joel +john +jon +jonathan +jordan +joseph +josh +joshua +justin +keith +kevin +kyle +leon +leonard +liam +logan +louis +lucas +martin +max +maxim +maxwell +michael +mike +nathan +nicholas +nick +noah +oliver +oscar +owen +paul +peter +philip +ray +richard +robert +roger +ron +ronald +ross +ryan +sam +samuel +scott +sean +sebastian +sergey +simon +stanley +stephen +steve +theo +thomas +tim +timothy +tom +tommy +tony +travis +victor +vincent +vladimir +walter +wayne +will +william +zach +zachary +abby +adele +alexa +alexandra +alice +alina +amanda +amber +amelia +amy +ana +anastasia +andrea +angel +angela +anna +aria +ashley +audrey +aurora +ava +bella +brenda +brianna +camila +carla +caroline +catherine +charlotte +chloe +christina +claire +daniela +daria +diana +dorothy +elena +elisa +elizabeth +ella +emilia +emily +emma +erica +eva +evelyn +faith +fiona +frances +gabriella +gloria +grace +hailey +hannah +helen +irene +isabel +isabella +jackie +jane +jasmin +jennifer +jessica +julia +juliana +karen +kate +katherine +katie +kayla +kim +laura +lena +lillian +linda +lisa +lucy +madison +maya +melissa +mia +michelle +mila +monica +nadia +nancy +natalia +nicole +nina +olivia +paige +pamela +patricia +paula +phoebe +rachel +rebecca +rita +rose +sabrina +samantha +sandra +sara +sarah +selena +sofia +sophia +stella +stephanie +susan +svetlana +tanya +taylor +teresa +tiffany +valeria +valerie +vanessa +vera +victoria +violet +yvonne +zoe +aarav +abdul +abel +abigail +abraham +abram +ada +adaline +adelina +adina +agnes +aidan +aileen +ainsley +akira +alain +alana +alani +alessia +alessio +alexis +alfie +alfonso +ali +alicia +alison +aliyah +alvaro +amelie +anabel +anabela +anastasiia +anatoly +andres +andrey +angelina +anita +ann +annabelle +anne +annette +anthonyx +antonio +april +ariana +ariel +arman +armand +arnav +arthurx +asa +ash +athena +atlasx +august +augusta +avery +ayden +aziz +bailey +barbara +beatrice +becky +belinda +bellaa +beth +bethany +bianca +blair +bonnie +bradley +brady +brendan +brent +brett +brittany +brooke +bryan +bryce +byron +caden +calvin +camden +cameron +camille +candice +carina +carlton +carmen +casey +cassandra +cecilia +cedric +celeste +cesar +chad +charlie +chelsea +chester +ciara +clara +clarence +claudia +clifton +clint +clyde +cody +colette +colby +conrad +corey +courtney +cristina +cynthia +daisy +damian +damien +damon +daphne +darian +darryl +dawson +dean +deanna +debora +declan +delia +demi +devin +devon +dexter +diego +dina +donald +donna +douglas +easton +edith +edmund +edwin +elaine +eleanor +eliot +elise +eliza +eloise +emanuel +enzo +esther +eugene +fabian +farah +federico +finley +flora +franklin +frederick +gavin +georgia +gillian +gino +giovanni +giulia +harold +harrison +harvey +hazel +heidi +holly +horace +howie +hudson +hunterx +imani +ingrid +irina +isla +ivanx +jada +jaime +jared +jasper +javier +jayden +jean +jensen +jerome +jillian +joanna +jocelyn +jonas +jose +josef +josie +joyce +jude +julien +julius +karina +karolina +kendra +kenneth +kenny +kieran +kira +kristen +kristina +kristopher +krystal +lance +lara +larry +lauren +layla +leah +leila +leroy +leslie +levi +liliana +lilly +loren +lorenzo +lorraine +luca +lucian +lydia +mabel +mackenzie +malcolm +manuel +marc +marcel +marco +margaret +margarita +maria +marian +marina +mario +marissa +mark +marley +marlon +marsha +martha +martina +marvin +mary +matilda +matteo +maurice +megan +melanie +melody +meredith +miriam +molly +murphy +naomi +natalie +neil +nelson +neve +noel +norman +octavia +omar +opal +orlando +otis +pablo +parker +pearl +penny +percy +perla +pierce +preston +quinn +rafael +ramon +randall +randy +raul +raven +regina +rene +rhett +rihanna +river +rob +robin +rocco +rodney +roland +romeo +rosa +roxanne +ruby +russell +ruth +ryley +sally +salvador +sasha +saul +scarlett +shane +shannon +shawn +shelby +shirley +sidney +sierra +silvia +skyler +sonia +sonya +spencer +stacy +steven +sylvia +tamara +tania +tara +tegan +terry +theodore +tia +tina +toby +trent +trevor +tristan +ulysses +ursula +valentin +vance +veronica +viola +vivian +wanda +wesley +whitney +willa +wyatt +xander +xenia +yasmin +yuri +zane +zelda +zora +aarushi +abner +adalyn +aditya +aiko +alaina +alecia +alejandro +alena +alenaa +alessandra +alexaia +alia +alin +althea +amina +amir +anaya +anika +annie +anson +arjun +armani +artem +arwen +ashton +atticus +ayana +ayla +barry +benson +bethanyx +bhavna +blakeley +blythe +bohdan +brynn +callie +carinaa +carson +catalina +cecily +channing +chase +cherie +chiara +christy +cillian +clay +clement +clio +coraline +corbin +cordelia +damaris +darcy +darianx +darla +delaney +desmond +diya +dominique +dorian +dulcie +eira +eleonora +elin +elodie +elsie +emerson +emmeline +erik +esme +estella +eugenia +ezekiel +faye +finn +fletcher +freya +gabrielle +gael +gareth +gemma +genevieve +geoffrey +gideon +greta +gwendolyn +hamza +harlow +harper +harriet +hartley +hendrix +hermione +hugh +imaniya +indira +ines +isidora +ivette +izabella +jabari +jacinta +jalen +jamila +janine +jayla +jeanine +johanna +jorge +jovan +kadence +kai +kaia +kamil +kamila +karim +karis +karter +katya +keira +kendall +khalid +khloe +kiara +kian +kingsley +kiraa +kobe +kylie +laila +lainey +lana +lani +laraa +latoya +laurel +lavinia +leandro +leilaa +leighton +leonidas +letty +lexi +lincoln +lisette +livia +lorcan +louisa +lyra +maddox +maeve +maia +maira +malik +malina +marinaa +marisol +marleyx +mateo +matias +maude +maxine +michaela +mika +milena +mina +mira +moira +nadine +naveen +nestor +nicola +nicolette +nikita +noemi +nora +novaa +nyla +odelia +odette +ofelia +olive +orion +oswin +paloma +pascale +piper +polina +priya +quentin +ramona +raphael +rayna +renata +riya +rohan +romina +rosalie +rowan +saanvi +sabina +sadie +sahar +salma +samira +sanjay +santana +satya +selina +serafina +shaun +shay +silas +simeon +soraya +stefan +stefania +suri +sybil +talia +tatum +teo +thalia +thiago +tomas +trinity +ulyana +uriah +veda +verena +viktor +violeta +wade +warren +willow +winston +yana +yasmina +yosef +yvette +zaria +zayn +zoya +abdullah +abelardo +abhinav +abir +achim +adel +adham +adil +adnan +ahmad +ahmed +aiden +ajay +akim +akiraa +aksel +albertina +albin +aleks +aleksandr +aleksandra +alessandro +alfonsox +alfredo +aliya +amalia +amirx +amrita +anais +anastasi +anatoliy +anayaa +andrii +anirudh +anouk +anya +ari +arian +arianaa +arielle +arnavx +arsen +artemiy +asaa +asher +asiya +atharv +aubrey +augustin +avani +aylin +azhar +baha +barnaby +beatrix +belen +benedict +benicio +bentleyx +bernadette +bernie +bert +bilal +blaire +boaz +borislav +bruna +bruno +caio +camilaa +carlota +cassidy +celia +celina +cesare +chantal +chloea +cian +cintia +ciro +clotilde +colton +cosima +cristian +cristiane +damla +danica +danilo +daniyar +dario +darina +davit +deirdre +delilah +demian +desiree +devika +dhruv +dinaa +dmitry +dragan +dusan +ece +eduardo +edvina +efrain +egor +eitan +elif +elina +elvira +emiliano +emine +emiro +eny +erdem +esra +evangelina +ewan +fadil +faiza +fatin +fatma +fiora +firas +francesca +franco +franck +gala +gautam +gennadiy +gianna +giorgio +giulio +gokhan +gonzalo +grazia +grigor +gulnaz +habib +hadi +haidar +hamid +hana +hania +hasan +hatice +hiba +hisham +hokuto +huseyin +ibrahim +ihor +ilia +ilya +iman +inara +inesa +iora +ismail +itzel +ivanna +izhar +jacintaa +jael +jahid +jaleel +jan +janelle +jannat +jaroslav +jasmine +javiera +jenna +joaquim +jolene +jordana +julieta +junaid +kabir +kaden +kael +kallie +kamran +kanan +karan +karinaa +karl +kasia +katerina +katrin +kayden +kerem +kianaa +kimi +konrad +kostya +kris +kuldeep +kylian +laila +lamia +lanaa +larisa +latif +leandra +leonora +leticia +liora +lorena +lorik +lucia +luisa +luka +lyana +mahmud +maika +mairaa +maksim +malika +manel +mansa +marat +mariana +marija +marinaa +marion +markus +mart +maryam +matvey +mauro +mehdi +melina +meriem +mihail +mikko +milan +milen +milica +mirela +miron +mohamed +murat +najib +narine +nasim +nazar +nazli +neha +nejat +nesrin +nihal +nikolai +nil +nino +noura +nur +nuray +nuu +odile +oleksii +olena +onur +orhan +ozan +ozgur +parisa +pavel +petra +radek +raimund +ramin +ramin +ranya +raoul +rawan +reda +reema +remi +rima +rita +riyad +romain +roza +ruben +saba +sabri +safa +sahar +sajid +sakina +salih +samer +samina +samir +sandraa +santiago +sarita +selim +senan +sevil +shadi +shah +shirin +sibel +sima +sinem +soha +stoyan +suhail +suleyman +sumaya +suren +taimur +tariq +tatsiana +tigran +timura +tore +tunahan +tural +uliana +vadim +vahid +venera +veronika +vesna +veta +viktoria +vitaliy +vito +vlad +yana +yaroslav +yegor +yelena +yigit +yulia +zahra +zakaria +zdenka +zelim +zemfira +ziad +zina +zirki diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/prefixes_connectors.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/prefixes_connectors.txt new file mode 100644 index 0000000..0f7e729 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/prefixes_connectors.txt @@ -0,0 +1,45 @@ +# Premium dictionary: prefixes and connectors +# Премиум-словарь: префиксы и слова-соединители +and +anti +best +bio +block +chain +cloud +crypto +dao +de +dr +eco +elite +exo +for +free +geo +global +go +hello +i +io +lab +meta +micro +multi +my +neo +new +no +omni +post +pre +pro +re +super +the +to +ultra +un +vip +web +x diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/web3_finance.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/web3_finance.txt new file mode 100644 index 0000000..270b655 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/premium/web3_finance.txt @@ -0,0 +1,41 @@ +# Premium dictionary: web3 and finance terms +# Премиум-словарь: термины web3 и финансов +airdrop +amm +arb +blockchain +bridge +burn +cex +chainlink +dao +defi +dex +drop +farm +farming +gas +governance +holder +launchpad +liquidity +lp +marketcap +mint +nft +node +oracle +pool +reward +rollup +staking +swap +token +tps +validator +vault +wallet +whale +dao +inc +limited diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/consumer_auto.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/consumer_auto.txt new file mode 100644 index 0000000..de6f066 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/consumer_auto.txt @@ -0,0 +1,193 @@ +# Trademark-sensitive words: consumer and automotive brands +# Брендовый словарь: потребительские и автомобильные бренды +adidas +audi +bmw +burberry +canon +cartier +chanel +cocacola +ferrari +ford +gucci +honda +hyundai +ikea +kia +lacoste +lego +lexus +louisvuitton +mazda +mercedes +nestle +nike +nissan +pepsi +porsche +prada +puma +reebok +rolex +siemens +sony +starbucks +toyota +volkswagen +walmart +zara +acura +alfa +armani +astonmartin +balenciaga +bentley +bugatti +buick +cadillac +calvinklein +chevrolet +chrysler +citroen +daewoo +dior +dodge +fendi +fiat +garnier +gillette +givenchy +heineken +hermes +hugo +jaguar +jeep +kiaa +kiax +lancome +landrover +loewe +maserati +maybach +mini +mitsubishi +mustang +opel +patagonia +pontiac +renault +rimowa +skoda +subaru +tesco +tiffanyco +volvo +abercrombie +airjordan +alpine +aquafina +bacardi +baileys +barbie +benetton +bershka +bic +birkenstock +blackberry +blumarine +bosshugo +breitling +bridgestone +bugaboo +bulgari +campari +casio +champion +chupa +colgate +crocs +dettol +dove +drmartens +ecco +essilor +evian +fanta +fisherprice +fossil +gatorade +geox +gillettevenus +goodyear +guess +haagen +headshoulders +heinz +hitachi +hondaauto +hotwheels +jimmychoo +joop +kenzo +kipling +kodak +konica +kotex +lacosteparis +lanvin +leica +levis +lipton +longines +lotus +lynx +maggi +magnumice +manolo +maybelline +mazdaauto +mcdonalds +milka +minicooper +montblanc +moet +moncler +mopar +nestea +nespresso +newbalance +oreo +panasonic +peugeot +philipsone +polaroid +rayban +redbull +reebokclassic +ribena +rimac +saab +sainsbury +shell +smartcar +smirnoff +sprite +stanley +subway +suzuki +tacobell +target +timberland +tomford +tommyhilfiger +toyotacar +triumph +umbro +unilever +versace +vichy +vogue +waterman +wrangler +yoplait diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/tech_global.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/tech_global.txt new file mode 100644 index 0000000..02feb60 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/tech_global.txt @@ -0,0 +1,364 @@ +# Trademark-sensitive words: global tech and web brands +# Брендовый словарь: глобальные тех- и веб-бренды +adobe +airbnb +alibaba +amazon +amd +android +apple +asus +baidu +binance +discord +dropbox +ebay +facebook +github +gitlab +gmail +google +instagram +intel +linkedin +meta +microsoft +netflix +nintendo +nvidia +openai +oracle +paypal +pinterest +reddit +samsung +shopify +skype +slack +snapchat +spotify +stripe +tencent +tesla +tiktok +twitch +uber +visa +whatsapp +xiaomi +yahoo +youtube +zoom +activision +adobexd +airtable +akamai +algolia +amdadeon +ampex +anthropic +arm +asana +atlassian +autodesk +bitbucket +bitfinex +bitrix +broadcom +canva +cloudflare +coinbase +coursera +databricks +digitalocean +docker +eset +evernote +figma +gopro +grafana +heroku +huggingface +jetbrains +kaspersky +lenovo +mailchimp +mastodon +medium +miro +mozilla +notion +okta +opensea +postman +quora +raspberrypi +salesforce +sap +shazam +skypex +snowflake +soundcloud +stackoverflow +teamviewer +telegram +trello +unity +vercel +vmware +weibo +wordpress +7eleven +adguard +airasia +airpods +airtag +aliexpress +allianz +amdryzen +angrybirds +anker +aol +appstore +audible +aws +azure +bard +beeline +behance +bing +blizzardent +booking +bookingcom +bose +bravebrowser +bybit +capcut +carplay +chatgpt +chromebook +chromeos +claude +copilot +corsair +crunchyroll +dailymotion +deepl +deezer +deliveryhero +disney +disneyplus +dribbble +duolingo +epicgames +etsy +firefox +flickr +fortnite +garmin +gettyimages +giphy +glassdoor +godaddy +googledocs +googlemaps +googlesheets +googleslides +hbo +hbomax +hotstar +hubspot +icloud +imdb +imgur +indeed +ios +ipad +iphone +itunes +jbl +jira +kindle +kik +line +linux +loom +luminar +mariadb +messenger +midjourney +motorola +msn +mysql +nextcloud +office365 +onedrive +openvpn +outlook +paramount +patreon +pixar +playstation +plex +primevideo +protonmail +quicksilver +rakuten +roku +signalapp +sketch +skyscanner +snapseed +soundcloudgo +sourceforge +speedtest +squarespace +steam +swiftui +taobao +teams +teslamotors +thunderbird +tripadvisor +ubisoft +verizon +viber +wechat +wetransfer +wikimedia +wise +wix +xbox +xing +yandex +zendesk +zhihu +zillow +zomato +abb +accenture +acer +adp +airbus +alcatel +alibabaai +amdinstinct +analogdevices +applepay +armholdings +asml +atandt +baidumap +baiducloud +blackmagic +blackrock +bloomberg +boeing +broadcomnet +capgemini +ciena +ciscoios +citrix +crowdstrike +datadog +dell +deloitte +deutschetelekom +dropboxpaper +dxc +elastic +equinix +ericsson +esri +f5networks +foxconn +fujitsu +garminconnect +gehealthcare +genpact +godot +goldmansachs +grubhub +hcl +hikvision +honeywell +hpe +infosys +ingrammicro +intuit +juniper +kioxia +kla +lazada +logitech +lucid +marvell +medtronic +mercadolibre +micron +mulesoft +naspers +nec +newrelic +nokiax +norton +ntt +nutanix +nxp +okx +onsemi +paloalto +palantir +pandora +payoneer +paypalx +paypalme +perplexity +philipshealth +pipedrive +procore +qualcomm +quantum +revolut +riotgames +roblox +robinhood +rubrik +salesloft +saphana +servicenow +seagate +semrush +sharp +siemensnx +splunk +square +sumup +tableau +talkdesk +tata +temu +teradata +texasinstruments +thomsonreuters +tiktokshop +tinder +tiscali +toast +tokopedia +toptal +toshiba +tradingview +trip +twilio +unity3d +ups +veeam +velodyne +vistaprint +vodafone +webex +wipro +workday +xerox +zoho diff --git a/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/top500_marketcap_global.txt b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/top500_marketcap_global.txt new file mode 100644 index 0000000..d17dce1 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/dictionaries/trademarks/top500_marketcap_global.txt @@ -0,0 +1,502 @@ +# Trademark dictionary: top-500 global companies by market cap (source-based import) +# Брендовый словарь: топ-500 глобальных компаний по рыночной капитализации (импорт из источника) +nvidia +alphabetgoogle +apple +microsoft +amazon +tsmc +broadcom +saudiaramco +tesla +metaplatforms +samsung +walmart +berkshirehathaway +skhynix +elililly +microntechnology +jpmorganchase +amd +exxonmobil +visa +intel +asml +johnsonandjohnson +oracle +tencent +costco +cisco +mastercard +caterpillar +chinaconstructionbank +chevron +abbvie +netflix +lamresearch +bankofamerica +cocacola +unitedhealth +appliedmaterials +roche +agriculturalbankofchina +procterandgamble +palantir +alibaba +hsbc +generalelectric +morganstanley +icbc +homedepot +philipmorris +astrazeneca +goldmansachs +novartis +catl +merck +texasinstruments +gevernova +bankofchina +armholdings +lvmh +royalbankofcanada +nestle +petrochina +toyota +kweichowmoutai +shell +kla +chinamobile +raytheontechnologies +linde +siemens +internationalholdingcompany +wellsfargo +loreal +mitsubishiufjfinancial +softbank +qualcomm +citigroup +bhpgroup +sap +ibm +americanexpress +sandisk +tmobileus +totalenergies +pepsico +prosus +paloaltonetworks +novonordisk +verizon +mcdonald +commonwealthbank +hermesinternational +analogdevices +foxconnindustrialinternet +kioxiaholdingscorporation +relianceindustries +abb +nexteraenergy +torontodominionbank +inditex +waltdisney +mediatek +amgen +santander +aristanetworks +tjxcompanies +boeing +att +schneiderelectric +siemensenergy +allianz +seagate +riotinto +thermofisherscientific +deltaelectronics +cnooc +crowdstrike +marvell +blackrock +deutschetelekom +zhongjiinnolight +gileadsciences +applovin +anheuserbuschinbev +intuitivesurgical +westerndigital +unionpacificcorporation +dell +charlesschwab +corning +ubs +welltower +airbus +abbottlaboratories +iberdrola +uber +deerecompany +amphenol +conocophillips +cmbank +eaton +salesforce +pfizer +sumitomomitsuifinancialgroup +southerncopper +hitachi +chinashenhuaenergy +pinganinsurance +blackstonegroup +interactivebrokers +chinalifeinsurance +fastretailing +britishamericantobacco +tokyoelectron +pinduoduo +honeywell +dbs +shopify +safran +rollsroyceholdings +prologis +sony +petrobras +chubb +bbva +hdfcbank +byd +unilever +deltaelectronicsthailand +enbridge +mitsubishicorporation +lowescompanies +spglobal +unicredit +strykercorporation +investorab +altriagroup +advantest +bookingholdings +starbucks +vertivholdings +danaher +lockheedmartin +airliquide +bristolmyerssquibb +bhartiairtel +cambricontechnologies +cvshealth +progressive +keyence +zijinmining +capitalone +compagniefinanciererichemont +bp +hyundai +newmont +bnpparibas +intesasanpaolo +aia +enel +bankofmontreal +mizuhofinancialgroup +accenture +foxconn +vertexpharmaceuticals +zurichinsurancegroup +parkerhannifin +intuit +sanofi +servicenow +quantaservices +alrajhibank +southerncompany +cibc +cmegroup +equinix +howmetaerospace +infineon +sksquare +adobe +glaxosmithkline +canadiannaturalresources +constellationenergy +brookfieldcorporation +mitsuibussan +medtronic +xiaomi +tranetechnologies +sberbank +marriottinternational +scotiabank +equinor +cadencedesignsystems +dukeenergy +chinayangtzepower +synopsys +axa +williamscompanies +fortinet +bnymellon +essilorluxottica +tokiomarine +cummins +dior +fedex +icicibank +generaldynamics +grupomexico +caixabank +statebankofindia +midea +mckesson +sinopec +glencore +spotify +agnicoeaglemines +comcast +westpacbanking +automaticdataprocessing +wastemanagement +hcahealthcare +kohlbergkravisroberts +tataconsultancyservices +itauunibanco +freeportmcmoran +pncfinancialservices +ing +postalsavingsbankofchina +bankofcommunications +elevancehealth +intercontinentalexchange +americantower +itochushoji +schlumberger +csxcorporation +enterpriseproducts +monsterbeverage +usbancorp +nationalgrid +bostonscientific +johnsoncontrols +ups +recruit +mercadolibre +mitsubishiheavyindustries +eoptolinktechnology +nationalaustraliabank +ocbcbank +atlascopco +chugaipharmaceutical +barclays +airbnb +bloomenergy +americamovil +suncorenergy +shinetsuchemical +engie +eni +mondelez +lloydsbankinggroup +vinci +nippontelegraphandtelephone +marshandmclennancompanies +ciena +northropgrumman +nxpsemiconductors +mitsubishielectric +3m +rocketlabusa +moodys +simonproperty +murataseisakusho +brookfieldassetmanagement +canadianpacificrailway +baesystems +oreillyautomotive +monolithicpowersystems +apolloglobalmanagement +nokia +anzbank +smic +sherwinwilliams +datadog +eogresources +marathonpetroleum +valero +cigna +netease +kindermorgan +emerson +cloudflare +hiltonhotels +tcenergy +luxshareprecision +colgatepalmolive +illinoistoolworks +phillips66 +japanpostbank +carvana +munichre +nauratechnologygroup +rossstores +coherent +americanelectricpower +norfolksouthern +doordash +ecolab +vale +canadiannationalrailway +japantobacco +asegroup +energytransferpartners +adnocgas +barrickgold +warnerbrosdiscovery +generalmotors +aon +taqa +cintas +robinhood +digitalrealty +volvo +regeneronpharmaceuticals +royalcaribbean +crh +lumentum +softbankcorp +transdigm +generali +imperialoil +bakerhughes +hongkongexchangesandclearing +motorolasolutions +rheinmetall +nike +macquarie +republicservices +thetravelerscompanies +kddi +meituandianping +comfortsystems +manulifefinancial +citicbank +airproductsandchemicals +maaden +chinatelecom +merckkgaa +cerebrassystems +nordeabank +bochongkong +deutschebank +natwestgroup +lgenergysolution +thesaudinationalbank +vingroupcompany +deutschepost +nuholdings +londonstockexchange +nongfuspring +singtel +wesfarmers +ferrari +creditagricole +rosneft +truistfinancial +sempraenergy +aflac +dominionenergy +btgpactual +nbcbank +relx +teconnectivity +paccar +wwgrainger +bajajfinance +unitedrentals +sauditelecomcompany +occidentalpetroleum +keysight +microstrategy +targaresources +oneok +realtyincome +snowflake +wheatonpreciousmetals +stmicroelectronics +l3harristechnologies +societegenerale +diamondbackenergy +citicsecurities +allstate +cenovusenergy +orange +standardchartered +dsv +autozone +mplx +larsenandtoubro +hoya +kbc +devonenergy +eon +target +coreweave +walmex +mercedesbenzgroup +marubeni +thales +deutscheboerse +angloamerican +industrialbank +teradyne +sumitomo +basf +nintendo +compassgroup +hindustanunilever +publicstorage +alimentationcouchetard +metlife +sea +ebay +ucb +carrier +takedapharmaceutical +corteva +ford +sumitomodenkikogyo +lifeinsurancecorporationofindia +bmw +arthurgallagher +loblawcompanies +infosys +cencora +ametek +autodesk +nucor +greatwestlifeco +volkswagen +entergy +cheniereenergy +lafargeholcim +nasdaq +microchiptechnology +sunhungkaiproperties +antofagasta +firstabudhabibank +electronicarts +jardinematheson +sungrowpowersupply +coinbase +ambev +argenx +lukoil +panasonic +jiangsuhengruimedicine +fastenal +sandvik +wuxiapptec +xcelenergy diff --git a/shine-solana/shine/programs/shine_login_guard/src/lib.rs b/shine-solana/shine/programs/shine_login_guard/src/lib.rs new file mode 100644 index 0000000..506d234 --- /dev/null +++ b/shine-solana/shine/programs/shine_login_guard/src/lib.rs @@ -0,0 +1,105 @@ +use anchor_lang::prelude::*; +use anchor_lang::solana_program::program::set_return_data; + +declare_id!("3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo"); + +mod wordlist { + include!(concat!(env!("OUT_DIR"), "/generated_dictionary.rs")); +} + +const CLASS_FREE: u32 = 0; +const CLASS_PREMIUM: u32 = 1; +const CLASS_TRADEMARK: u32 = 2; +const MAX_WORDS_PER_LOGIN: usize = 3; + +#[program] +pub mod shine_login_guard { + use super::*; + + pub fn classify_login(_ctx: Context, login: String) -> Result<()> { + let class = classify(&login); + set_return_data(&class.to_le_bytes()); + Ok(()) + } +} + +#[derive(Accounts)] +pub struct ClassifyLogin<'info> { + pub signer: Signer<'info>, +} + +fn classify(login: &str) -> u32 { + let Some(normalized) = normalize_login(login) else { + return CLASS_PREMIUM; + }; + if normalized.len() <= 7 { + return CLASS_PREMIUM; + } + match classify_split(&normalized) { + Some(v) => v, + None => CLASS_FREE, + } +} + +fn normalize_login(login: &str) -> Option { + if login.is_empty() || login.len() > 20 { + return None; + } + let mut out = String::with_capacity(login.len()); + for ch in login.chars() { + if ch == '_' { + continue; + } + if !ch.is_ascii_alphanumeric() { + return None; + } + out.push(ch.to_ascii_lowercase()); + } + if out.is_empty() || out.len() > 20 { + return None; + } + Some(out) +} + +fn classify_split(login: &str) -> Option { + fn dfs(rest: &str, depth: usize, has_tm: bool) -> Option { + if rest.is_empty() { + if depth > 0 && depth <= MAX_WORDS_PER_LOGIN { + return Some(if has_tm { CLASS_TRADEMARK } else { CLASS_PREMIUM }); + } + return None; + } + if depth >= MAX_WORDS_PER_LOGIN { + return None; + } + let max_piece = rest.len().min(20); + let mut premium_found = false; + for i in 1..=max_piece { + let candidate = &rest[..i]; + let is_tm = is_trademark_word(candidate); + let is_pr = is_tm || is_premium_word(candidate); + if !is_pr { + continue; + } + match dfs(&rest[i..], depth + 1, has_tm || is_tm) { + Some(CLASS_TRADEMARK) => return Some(CLASS_TRADEMARK), + Some(CLASS_PREMIUM) => premium_found = true, + _ => {} + }; + } + if premium_found { + Some(CLASS_PREMIUM) + } else { + None + } + } + dfs(login, 0, false) +} + +fn is_premium_word(word: &str) -> bool { + wordlist::PREMIUM_WORDS.binary_search(&word).is_ok() +} + +fn is_trademark_word(word: &str) -> bool { + wordlist::TRADEMARK_WORDS.binary_search(&word).is_ok() +} diff --git a/shine-solana/shine/programs/shine_payments/Cargo.toml b/shine-solana/shine/programs/shine_payments/Cargo.toml new file mode 100644 index 0000000..0d37912 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "shine_payments" +version = "0.2.0" +description = "Shine Payments v2 (очереди выплат)" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "shine_payments" +test = false +doctest = false +bench = false + +[dependencies] +anchor-lang = "0.31.1" +common = { path = "../common" } +pyth-solana-receiver-sdk = { path = "../../.vendor/pyth-crosschain/target_chains/solana/pyth_solana_receiver_sdk" } + +[features] +default = [] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +anchor-debug = [] +custom-heap = [] +custom-panic = [] +cpi = [] +idl-build = ["anchor-lang/idl-build"] diff --git a/shine-solana/shine/programs/shine_payments/src/lib.rs b/shine-solana/shine/programs/shine_payments/src/lib.rs new file mode 100644 index 0000000..17abf33 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/src/lib.rs @@ -0,0 +1,1147 @@ +use anchor_lang::prelude::*; +use anchor_lang::solana_program::{program::invoke, system_instruction}; +use common::utils::{create_pda, safe_read_pda, write_to_pda, ErrCode}; +use pyth_solana_receiver_sdk::error::GetPriceError; +use pyth_solana_receiver_sdk::price_update::{get_feed_id_from_hex, Price, PriceUpdateV2}; +use std::str::FromStr; + +pub mod settings; + +declare_id!("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); + +#[program] +pub mod shine_payments { + use super::*; + + pub fn init(ctx: Context) -> Result<()> { + ensure_expected_pdas(ctx.program_id, &ctx.accounts)?; + require!( + ctx.accounts.config_pda.owner == &Pubkey::default(), + ErrCode::SystemAlreadyInitialized + ); + require!( + ctx.accounts.coef_limit_pda.owner == &Pubkey::default(), + ErrCode::SystemAlreadyInitialized + ); + require!( + ctx.accounts.queues_pda.owner == &Pubkey::default(), + ErrCode::SystemAlreadyInitialized + ); + require!( + ctx.accounts.inflow_vault_pda.owner == &Pubkey::default(), + ErrCode::SystemAlreadyInitialized + ); + + let dao_wallet = Pubkey::from_str(settings::DAO_WALLET) + .map_err(|_| error!(PaymentsError::InvalidSettingsWallet))?; + let system_program_ai = ctx.accounts.system_program.to_account_info(); + + let config = ConfigState { + version: 1, + dao_wallet, + inflow_vault: ctx.accounts.inflow_vault_pda.key(), + }; + create_and_store_state( + ctx.program_id, + &ctx.accounts.payer, + &system_program_ai, + &ctx.accounts.config_pda, + settings::CONFIG_SEED, + settings::CONFIG_SPACE, + &config, + )?; + + let coef_limit = CoefLimitState { + version: 1, + coef_ppm: settings::START_COEF_PPM, + limit_usd_cents: settings::START_LIMIT_USD_CENTS, + call_reward_lamports: settings::START_CALL_REWARD_LAMPORTS, + }; + create_and_store_state( + ctx.program_id, + &ctx.accounts.payer, + &system_program_ai, + &ctx.accounts.coef_limit_pda, + settings::COEF_LIMIT_SEED, + settings::COEF_LIMIT_SPACE, + &coef_limit, + )?; + + let queues = QueuesState { + version: 1, + q1_tickets_total: 0, + q1_tickets_paid: 0, + q1_sum_total_usd_cents: 0, + q1_sum_paid_usd_cents: 0, + q2_tickets_total: 0, + q2_tickets_paid: 0, + q2_sum_total_usd_cents: 0, + q2_sum_paid_usd_cents: 0, + }; + create_and_store_state( + ctx.program_id, + &ctx.accounts.payer, + &system_program_ai, + &ctx.accounts.queues_pda, + settings::QUEUES_SEED, + settings::QUEUES_SPACE, + &queues, + )?; + + let vault = VaultState { version: 1 }; + create_and_store_state( + ctx.program_id, + &ctx.accounts.payer, + &system_program_ai, + &ctx.accounts.inflow_vault_pda, + settings::INFLOW_VAULT_SEED, + settings::INFLOW_VAULT_SPACE, + &vault, + )?; + + Ok(()) + } + + pub fn update_coef_limit( + ctx: Context, + args: UpdateCoefLimitArgs, + ) -> Result<()> { + let config = read_state::(&ctx.accounts.config_pda)?; + require_keys_eq!( + config.dao_wallet, + ctx.accounts.signer.key(), + PaymentsError::UnauthorizedDao + ); + require!(args.coef_ppm > 0, PaymentsError::InvalidCoefficient); + require!(args.limit_usd_cents > 0, PaymentsError::InvalidLimit); + require!( + args.call_reward_lamports <= settings::MAX_CALL_REWARD_LAMPORTS, + PaymentsError::InvalidCallReward + ); + + let mut coef_limit = read_state::(&ctx.accounts.coef_limit_pda)?; + coef_limit.coef_ppm = args.coef_ppm; + coef_limit.limit_usd_cents = args.limit_usd_cents; + coef_limit.call_reward_lamports = args.call_reward_lamports; + write_state(&ctx.accounts.coef_limit_pda, &coef_limit)?; + Ok(()) + } + + pub fn grant_manager_limits( + ctx: Context, + args: GrantManagerLimitsArgs, + ) -> Result<()> { + let config = read_state::(&ctx.accounts.config_pda)?; + require_keys_eq!( + config.dao_wallet, + ctx.accounts.signer.key(), + PaymentsError::UnauthorizedDao + ); + require!( + args.add_q1_usd_cents > 0 || args.add_q2_usd_cents > 0, + PaymentsError::InvalidAmount + ); + + let (expected_pda, bump) = find_manager_allowance_pda(ctx.program_id, &args.manager_wallet); + require_keys_eq!( + expected_pda, + ctx.accounts.manager_allowance_pda.key(), + ErrCode::InvalidPdaAddress + ); + + let system_program_ai = ctx.accounts.system_program.to_account_info(); + let mut state = if ctx.accounts.manager_allowance_pda.owner == &Pubkey::default() { + let initial = ManagerAllowanceState { + version: 1, + manager_wallet: args.manager_wallet, + q1_available_usd_cents: 0, + q2_available_usd_cents: 0, + }; + create_state_with_seeds( + ctx.program_id, + &ctx.accounts.signer, + &system_program_ai, + &ctx.accounts.manager_allowance_pda, + &[ + settings::MANAGER_ALLOWANCE_SEED, + args.manager_wallet.as_ref(), + &[bump], + ], + settings::MANAGER_ALLOWANCE_SPACE, + &initial, + )?; + initial + } else { + read_state::(&ctx.accounts.manager_allowance_pda)? + }; + require_keys_eq!( + state.manager_wallet, + args.manager_wallet, + PaymentsError::InvalidManagerWallet + ); + + state.q1_available_usd_cents = state + .q1_available_usd_cents + .checked_add(args.add_q1_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + state.q2_available_usd_cents = state + .q2_available_usd_cents + .checked_add(args.add_q2_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + write_state(&ctx.accounts.manager_allowance_pda, &state)?; + Ok(()) + } + + pub fn buy_ticket(ctx: Context, args: BuyTicketArgs) -> Result<()> { + let sol_usd = read_sol_usd_price( + &ctx.accounts.sol_usd_price_update, + &ctx.accounts.sol_usd_price_update.key(), + )?; + let purchase_usd_cents = lamports_to_usd_cents_floor(args.amount_lamports, &sol_usd)?; + require!(purchase_usd_cents > 0, PaymentsError::InvalidAmount); + buy_ticket_by_purchase_usd( + &ctx, + purchase_usd_cents, + args.amount_lamports, + args.recipient_wallet, + ) + } + + pub fn buy_ticket_usd(ctx: Context, args: BuyTicketUsdArgs) -> Result<()> { + require!(args.amount_usd_cents > 0, PaymentsError::InvalidAmount); + require!(args.max_pay_lamports > 0, PaymentsError::InvalidAmount); + + let sol_usd = read_sol_usd_price( + &ctx.accounts.sol_usd_price_update, + &ctx.accounts.sol_usd_price_update.key(), + )?; + let pay_lamports = usd_cents_to_lamports_ceil(args.amount_usd_cents, &sol_usd)?; + require!(pay_lamports > 0, PaymentsError::InvalidAmount); + require!( + pay_lamports <= args.max_pay_lamports, + PaymentsError::SlippageExceeded + ); + + buy_ticket_by_purchase_usd(&ctx, args.amount_usd_cents, pay_lamports, args.recipient_wallet) + } + + pub fn buy_ticket_sol(ctx: Context, args: BuyTicketSolArgs) -> Result<()> { + require!(args.amount_lamports > 0, PaymentsError::InvalidAmount); + + let sol_usd = read_sol_usd_price( + &ctx.accounts.sol_usd_price_update, + &ctx.accounts.sol_usd_price_update.key(), + )?; + let purchase_usd_cents = lamports_to_usd_cents_floor(args.amount_lamports, &sol_usd)?; + require!(purchase_usd_cents > 0, PaymentsError::InvalidAmount); + require!( + purchase_usd_cents >= args.min_expected_usd_cents, + PaymentsError::SlippageExceeded + ); + + buy_ticket_by_purchase_usd( + &ctx, + purchase_usd_cents, + args.amount_lamports, + args.recipient_wallet, + ) + } + + pub fn manager_add_ticket( + ctx: Context, + args: ManagerAddTicketArgs, + ) -> Result<()> { + require!(args.payout_usd_cents > 0, PaymentsError::InvalidPayoutAmount); + require!( + args.queue_id == 1 || args.queue_id == 2, + PaymentsError::InvalidTicketQueue + ); + + let (expected_manager_pda, _) = + find_manager_allowance_pda(ctx.program_id, ctx.accounts.signer.key); + require_keys_eq!( + expected_manager_pda, + ctx.accounts.manager_allowance_pda.key(), + ErrCode::InvalidPdaAddress + ); + let mut allowance = + read_state::(&ctx.accounts.manager_allowance_pda)?; + require_keys_eq!( + allowance.manager_wallet, + ctx.accounts.signer.key(), + PaymentsError::InvalidManagerWallet + ); + + let mut queues = read_state::(&ctx.accounts.queues_pda)?; + let debt_before_total = if args.queue_id == 1 { + queues.q1_sum_total_usd_cents + } else { + queues.q2_sum_total_usd_cents + }; + + if args.queue_id == 1 { + require!( + allowance.q1_available_usd_cents >= args.payout_usd_cents, + PaymentsError::ManagerLimitExceeded + ); + } else { + require!( + allowance.q2_available_usd_cents >= args.payout_usd_cents, + PaymentsError::ManagerLimitExceeded + ); + } + + let ticket_index = if args.queue_id == 1 { + queues + .q1_tickets_total + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))? + } else { + queues + .q2_tickets_total + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))? + }; + let (expected_ticket_pda, ticket_bump) = + find_ticket_pda(ctx.program_id, args.queue_id, ticket_index); + require_keys_eq!( + expected_ticket_pda, + ctx.accounts.ticket_pda.key(), + ErrCode::InvalidPdaAddress + ); + require!( + ctx.accounts.ticket_pda.owner == &Pubkey::default(), + ErrCode::PdaAlreadyExists + ); + + let ticket = TicketState { + version: 1, + queue_id: args.queue_id, + index: ticket_index, + is_paid: false, + recipient_wallet: args.recipient_wallet, + payout_usd_cents: args.payout_usd_cents, + debt_before_usd_cents: debt_before_total, + }; + let seed_prefix = if args.queue_id == 1 { + settings::Q1_TICKET_SEED + } else { + settings::Q2_TICKET_SEED + }; + create_state_with_seeds( + ctx.program_id, + &ctx.accounts.signer, + &ctx.accounts.system_program.to_account_info(), + &ctx.accounts.ticket_pda, + &[seed_prefix, &ticket_index.to_le_bytes(), &[ticket_bump]], + settings::TICKET_SPACE, + &ticket, + )?; + + if args.queue_id == 1 { + allowance.q1_available_usd_cents = allowance + .q1_available_usd_cents + .checked_sub(args.payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + queues.q1_tickets_total = ticket_index; + queues.q1_sum_total_usd_cents = queues + .q1_sum_total_usd_cents + .checked_add(args.payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + } else { + allowance.q2_available_usd_cents = allowance + .q2_available_usd_cents + .checked_sub(args.payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + queues.q2_tickets_total = ticket_index; + queues.q2_sum_total_usd_cents = queues + .q2_sum_total_usd_cents + .checked_add(args.payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + } + write_state(&ctx.accounts.manager_allowance_pda, &allowance)?; + write_state(&ctx.accounts.queues_pda, &queues)?; + Ok(()) + } + + pub fn step_payout(ctx: Context) -> Result<()> { + let config = read_state::(&ctx.accounts.config_pda)?; + let coef_limit = read_state::(&ctx.accounts.coef_limit_pda)?; + let mut queues = read_state::(&ctx.accounts.queues_pda)?; + let _vault_state = read_state::(&ctx.accounts.inflow_vault_pda)?; + + require_keys_eq!( + ctx.accounts.dao_wallet.key(), + config.dao_wallet, + PaymentsError::InvalidDaoWallet + ); + require_keys_eq!( + ctx.accounts.inflow_vault_pda.key(), + config.inflow_vault, + PaymentsError::InvalidInflowVault + ); + + let q1_pending = queues + .q1_tickets_total + .checked_sub(queues.q1_tickets_paid) + .ok_or(error!(ErrCode::MathOverflow))?; + let q2_pending = queues + .q2_tickets_total + .checked_sub(queues.q2_tickets_paid) + .ok_or(error!(ErrCode::MathOverflow))?; + + if q1_pending == 0 && q2_pending == 0 { + transfer_all_available_to_dao( + &ctx.accounts.inflow_vault_pda, + &ctx.accounts.dao_wallet, + )?; + return Ok(()); + } + + let target_queue = if q1_pending > 0 { 1 } else { 2 }; + let next_index = if target_queue == 1 { + queues + .q1_tickets_paid + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))? + } else { + queues + .q2_tickets_paid + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))? + }; + let (expected_ticket_pda, _) = find_ticket_pda(ctx.program_id, target_queue, next_index); + require_keys_eq!( + expected_ticket_pda, + ctx.accounts.next_ticket_pda.key(), + ErrCode::InvalidPdaAddress + ); + + let mut ticket = read_state::(&ctx.accounts.next_ticket_pda)?; + require!( + ticket.queue_id == target_queue, + PaymentsError::InvalidTicketQueue + ); + require!( + ticket.index == next_index, + PaymentsError::InvalidTicketIndex + ); + require!(!ticket.is_paid, PaymentsError::TicketAlreadyPaid); + require_keys_eq!( + ctx.accounts.ticket_recipient_wallet.key(), + ticket.recipient_wallet, + PaymentsError::InvalidTicketRecipient + ); + + let sol_usd = read_sol_usd_price( + &ctx.accounts.sol_usd_price_update, + &ctx.accounts.sol_usd_price_update.key(), + )?; + let ticket_lamports = usd_cents_to_lamports_ceil(ticket.payout_usd_cents, &sol_usd)?; + let dao_multiplier: u64 = if target_queue == 1 { 1 } else { 2 }; + let dao_usd_cents = ticket + .payout_usd_cents + .checked_mul(dao_multiplier) + .ok_or(error!(ErrCode::MathOverflow))?; + let dao_lamports = usd_cents_to_lamports_ceil(dao_usd_cents, &sol_usd)?; + + let needed = ticket_lamports + .checked_add(dao_lamports) + .and_then(|v| v.checked_add(coef_limit.call_reward_lamports)) + .ok_or(error!(ErrCode::MathOverflow))?; + require!( + available_vault_lamports(&ctx.accounts.inflow_vault_pda)? >= needed, + PaymentsError::NotEnoughInflowForStep + ); + + transfer_from_vault( + &ctx.accounts.inflow_vault_pda, + &ctx.accounts.ticket_recipient_wallet, + ticket_lamports, + )?; + transfer_from_vault( + &ctx.accounts.inflow_vault_pda, + &ctx.accounts.dao_wallet, + dao_lamports, + )?; + transfer_from_vault( + &ctx.accounts.inflow_vault_pda, + &ctx.accounts.signer, + coef_limit.call_reward_lamports, + )?; + + ticket.is_paid = true; + write_state(&ctx.accounts.next_ticket_pda, &ticket)?; + + if target_queue == 1 { + queues.q1_tickets_paid = queues + .q1_tickets_paid + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))?; + queues.q1_sum_paid_usd_cents = queues + .q1_sum_paid_usd_cents + .checked_add(ticket.payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + } else { + queues.q2_tickets_paid = queues + .q2_tickets_paid + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))?; + queues.q2_sum_paid_usd_cents = queues + .q2_sum_paid_usd_cents + .checked_add(ticket.payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + } + write_state(&ctx.accounts.queues_pda, &queues)?; + + Ok(()) + } + + pub fn change_ticket_recipient( + ctx: Context, + args: ChangeTicketRecipientArgs, + ) -> Result<()> { + let queues = read_state::(&ctx.accounts.queues_pda)?; + let mut ticket = read_state::(&ctx.accounts.ticket_pda)?; + + require!(!ticket.is_paid, PaymentsError::TicketAlreadyPaid); + require_keys_eq!( + ctx.accounts.signer.key(), + ticket.recipient_wallet, + PaymentsError::UnauthorizedTicketOwner + ); + + let (expected_ticket_pda, _) = find_ticket_pda(ctx.program_id, ticket.queue_id, ticket.index); + require_keys_eq!( + expected_ticket_pda, + ctx.accounts.ticket_pda.key(), + ErrCode::InvalidPdaAddress + ); + + let q1_pending = queues + .q1_tickets_total + .checked_sub(queues.q1_tickets_paid) + .ok_or(error!(ErrCode::MathOverflow))?; + let q2_pending = queues + .q2_tickets_total + .checked_sub(queues.q2_tickets_paid) + .ok_or(error!(ErrCode::MathOverflow))?; + + if q1_pending > 0 || q2_pending > 0 { + let target_queue = if q1_pending > 0 { 1 } else { 2 }; + let next_index = if target_queue == 1 { + queues + .q1_tickets_paid + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))? + } else { + queues + .q2_tickets_paid + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))? + }; + + require!( + !(ticket.queue_id == target_queue && ticket.index == next_index), + PaymentsError::CannotChangeRecipientForNextPayoutTicket + ); + } + + ticket.recipient_wallet = args.new_recipient_wallet; + write_state(&ctx.accounts.ticket_pda, &ticket)?; + Ok(()) + } +} + +#[derive(Accounts)] +pub struct Init<'info> { + /// CHECK: подписант и плательщик, проверяется атрибутом `signer`. + #[account(mut, signer)] + pub payer: AccountInfo<'info>, + /// CHECK: PDA конфига, адрес проверяется вручную в `ensure_expected_pdas`. + #[account(mut)] + pub config_pda: AccountInfo<'info>, + /// CHECK: PDA коэффициента/лимита, адрес проверяется вручную в `ensure_expected_pdas`. + #[account(mut)] + pub coef_limit_pda: AccountInfo<'info>, + /// CHECK: PDA состояния очередей, адрес проверяется вручную в `ensure_expected_pdas`. + #[account(mut)] + pub queues_pda: AccountInfo<'info>, + /// CHECK: PDA inflow-вольта, адрес проверяется вручную в `ensure_expected_pdas`. + #[account(mut)] + pub inflow_vault_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct UpdateCoefLimit<'info> { + /// CHECK: подписант-DAO, проверяется атрибутом `signer` и сверкой адреса в коде. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA конфига, читается и валидируется вручную. + #[account(mut)] + pub config_pda: AccountInfo<'info>, + /// CHECK: PDA коэффициента/лимита, читается и валидируется вручную. + #[account(mut)] + pub coef_limit_pda: AccountInfo<'info>, +} + +#[derive(Accounts)] +pub struct GrantManagerLimits<'info> { + /// CHECK: подписант DAO, проверяется атрибутом `signer` и сверкой с config.dao_wallet. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA конфига, читается и валидируется вручную. + #[account(mut)] + pub config_pda: AccountInfo<'info>, + /// CHECK: PDA лимитов менеджера, адрес проверяется вручную по manager pubkey. + #[account(mut)] + pub manager_allowance_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct BuyTicket<'info> { + /// CHECK: подписант-покупатель, проверяется атрибутом `signer`. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA конфига, читается и валидируется вручную. + #[account(mut)] + pub config_pda: AccountInfo<'info>, + /// CHECK: PDA коэффициента/лимита, читается и валидируется вручную. + #[account(mut)] + pub coef_limit_pda: AccountInfo<'info>, + /// CHECK: PDA очередей, читается и валидируется вручную. + #[account(mut)] + pub queues_pda: AccountInfo<'info>, + /// CHECK: PDA тикета, адрес и состояние (должен быть пустым) проверяются вручную. + #[account(mut)] + pub ticket_pda: AccountInfo<'info>, + /// CHECK: DAO-кошелек, адрес сверяется с конфигом вручную. + #[account(mut)] + pub dao_wallet: AccountInfo<'info>, + pub sol_usd_price_update: Account<'info, PriceUpdateV2>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct ManagerAddTicket<'info> { + /// CHECK: подписант-менеджер, проверяется атрибутом `signer`. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA лимитов менеджера, адрес сверяется вручную по signer. + #[account(mut)] + pub manager_allowance_pda: AccountInfo<'info>, + /// CHECK: PDA очередей, читается и валидируется вручную. + #[account(mut)] + pub queues_pda: AccountInfo<'info>, + /// CHECK: PDA тикета, адрес и состояние (должен быть пустым) проверяются вручную. + #[account(mut)] + pub ticket_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct StepPayout<'info> { + /// CHECK: подписант-вызвавший шаг выплат, проверяется атрибутом `signer`. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA конфига, читается и валидируется вручную. + #[account(mut)] + pub config_pda: AccountInfo<'info>, + /// CHECK: PDA очередей, читается и валидируется вручную. + #[account(mut)] + pub queues_pda: AccountInfo<'info>, + /// CHECK: PDA коэффициента/лимита/награды, читается и валидируется вручную. + #[account(mut)] + pub coef_limit_pda: AccountInfo<'info>, + /// CHECK: PDA inflow-вольта, адрес сверяется с конфигом вручную. + #[account(mut)] + pub inflow_vault_pda: AccountInfo<'info>, + /// CHECK: PDA следующего тикета, адрес и содержимое валидируются вручную. + #[account(mut)] + pub next_ticket_pda: AccountInfo<'info>, + /// CHECK: кошелек получателя тикета, адрес сверяется с полем тикета вручную. + #[account(mut)] + pub ticket_recipient_wallet: AccountInfo<'info>, + /// CHECK: DAO-кошелек, адрес сверяется с конфигом вручную. + #[account(mut)] + pub dao_wallet: AccountInfo<'info>, + pub sol_usd_price_update: Account<'info, PriceUpdateV2>, +} + +#[derive(Accounts)] +pub struct ChangeTicketRecipient<'info> { + /// CHECK: подписант-владелец текущего recipient тикета. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA очередей, читается вручную. + #[account(mut)] + pub queues_pda: AccountInfo<'info>, + /// CHECK: PDA тикета, читается и валидируется вручную. + #[account(mut)] + pub ticket_pda: AccountInfo<'info>, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct UpdateCoefLimitArgs { + pub coef_ppm: u64, + pub limit_usd_cents: u64, + pub call_reward_lamports: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct GrantManagerLimitsArgs { + pub manager_wallet: Pubkey, + pub add_q1_usd_cents: u64, + pub add_q2_usd_cents: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct BuyTicketArgs { + pub amount_lamports: u64, + pub recipient_wallet: Pubkey, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct BuyTicketUsdArgs { + pub amount_usd_cents: u64, + pub max_pay_lamports: u64, + pub recipient_wallet: Pubkey, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct BuyTicketSolArgs { + pub amount_lamports: u64, + pub min_expected_usd_cents: u64, + pub recipient_wallet: Pubkey, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct ManagerAddTicketArgs { + pub queue_id: u8, + pub recipient_wallet: Pubkey, + pub payout_usd_cents: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct ChangeTicketRecipientArgs { + pub new_recipient_wallet: Pubkey, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct ConfigState { + pub version: u8, + pub dao_wallet: Pubkey, + pub inflow_vault: Pubkey, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct CoefLimitState { + pub version: u8, + pub coef_ppm: u64, + pub limit_usd_cents: u64, + pub call_reward_lamports: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct QueuesState { + pub version: u8, + pub q1_tickets_total: u64, + pub q1_tickets_paid: u64, + pub q1_sum_total_usd_cents: u64, + pub q1_sum_paid_usd_cents: u64, + pub q2_tickets_total: u64, + pub q2_tickets_paid: u64, + pub q2_sum_total_usd_cents: u64, + pub q2_sum_paid_usd_cents: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct TicketState { + pub version: u8, + pub queue_id: u8, + pub index: u64, + pub is_paid: bool, + pub recipient_wallet: Pubkey, + pub payout_usd_cents: u64, + pub debt_before_usd_cents: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct ManagerAllowanceState { + pub version: u8, + pub manager_wallet: Pubkey, + pub q1_available_usd_cents: u64, + pub q2_available_usd_cents: u64, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct VaultState { + pub version: u8, +} + +struct SolUsdPrice { + price_num: u128, + price_den: u128, +} + +#[error_code] +pub enum PaymentsError { + #[msg("Ошибка в адресах кошельков из настроек программы")] + InvalidSettingsWallet, + #[msg("Недостаточно данных PDA")] + EmptyState, + #[msg("Неверный inflow vault")] + InvalidInflowVault, + #[msg("Неверный DAO кошелек")] + InvalidDaoWallet, + #[msg("Управляющий кошелек не авторизован")] + UnauthorizedManager, + #[msg("DAO кошелек не авторизован для этой операции")] + UnauthorizedDao, + #[msg("Некорректный коэффициент")] + InvalidCoefficient, + #[msg("Некорректный лимит")] + InvalidLimit, + #[msg("Некорректная награда за шаг выплаты")] + InvalidCallReward, + #[msg("Некорректная сумма")] + InvalidAmount, + #[msg("Очередь временно приостановлена: достигнут лимит")] + QueueTemporarilyPaused, + #[msg("Некорректная сумма выплаты")] + InvalidPayoutAmount, + #[msg("Недостаточно средств на inflow vault для шага выплаты")] + NotEnoughInflowForStep, + #[msg("Тикет уже выплачен")] + TicketAlreadyPaid, + #[msg("Неверный получатель тикета")] + InvalidTicketRecipient, + #[msg("Неверный номер тикета")] + InvalidTicketIndex, + #[msg("Неверный тип очереди у тикета")] + InvalidTicketQueue, + #[msg("Неверный кошелек менеджера")] + InvalidManagerWallet, + #[msg("Лимит менеджера по выбранной очереди превышен")] + ManagerLimitExceeded, + #[msg("Только текущий получатель тикета может изменить получателя")] + UnauthorizedTicketOwner, + #[msg("Нельзя менять получателя у следующего тикета на выплату")] + CannotChangeRecipientForNextPayoutTicket, + #[msg("Оракул передан неверный")] + InvalidOracleAccount, + #[msg("Некорректный feed id оракула")] + InvalidOracleFeed, + #[msg("Конфигурация оракула в settings некорректна")] + InvalidOracleFeedConfig, + #[msg("Цена оракула устарела")] + OraclePriceTooOld, + #[msg("Цена оракула некорректна")] + InvalidOraclePrice, + #[msg("Защита от проскальзывания: лимит пользователя не проходит")] + SlippageExceeded, +} + +fn ensure_expected_pdas(program_id: &Pubkey, accounts: &Init) -> Result<()> { + let (config, _) = find_single_pda(program_id, settings::CONFIG_SEED); + let (coef, _) = find_single_pda(program_id, settings::COEF_LIMIT_SEED); + let (queues, _) = find_single_pda(program_id, settings::QUEUES_SEED); + let (inflow, _) = find_single_pda(program_id, settings::INFLOW_VAULT_SEED); + require_keys_eq!( + config, + accounts.config_pda.key(), + ErrCode::InvalidPdaAddress + ); + require_keys_eq!( + coef, + accounts.coef_limit_pda.key(), + ErrCode::InvalidPdaAddress + ); + require_keys_eq!( + queues, + accounts.queues_pda.key(), + ErrCode::InvalidPdaAddress + ); + require_keys_eq!( + inflow, + accounts.inflow_vault_pda.key(), + ErrCode::InvalidPdaAddress + ); + Ok(()) +} + +fn find_single_pda(program_id: &Pubkey, seed: &[u8]) -> (Pubkey, u8) { + Pubkey::find_program_address(&[seed], program_id) +} + +fn find_ticket_pda(program_id: &Pubkey, queue_id: u8, index: u64) -> (Pubkey, u8) { + let idx = index.to_le_bytes(); + let seed = if queue_id == 1 { + settings::Q1_TICKET_SEED + } else { + settings::Q2_TICKET_SEED + }; + Pubkey::find_program_address(&[seed, &idx], program_id) +} + +fn find_manager_allowance_pda(program_id: &Pubkey, manager_wallet: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[settings::MANAGER_ALLOWANCE_SEED, manager_wallet.as_ref()], + program_id, + ) +} + +fn buy_ticket_by_purchase_usd( + ctx: &Context, + purchase_usd_cents: u64, + transfer_lamports: u64, + recipient_wallet: Pubkey, +) -> Result<()> { + let config = read_state::(&ctx.accounts.config_pda)?; + let coef_limit = read_state::(&ctx.accounts.coef_limit_pda)?; + let mut queues = read_state::(&ctx.accounts.queues_pda)?; + + require_keys_eq!( + ctx.accounts.dao_wallet.key(), + config.dao_wallet, + PaymentsError::InvalidDaoWallet + ); + + let queue1_sum_total_before = queues.q1_sum_total_usd_cents; + require!( + queue1_sum_total_before < coef_limit.limit_usd_cents, + PaymentsError::QueueTemporarilyPaused + ); + + let ticket_index = queues + .q1_tickets_total + .checked_add(1) + .ok_or(error!(ErrCode::MathOverflow))?; + let (expected_ticket_pda, ticket_bump) = find_ticket_pda(ctx.program_id, 1, ticket_index); + require_keys_eq!( + expected_ticket_pda, + ctx.accounts.ticket_pda.key(), + ErrCode::InvalidPdaAddress + ); + require!( + ctx.accounts.ticket_pda.owner == &Pubkey::default(), + ErrCode::PdaAlreadyExists + ); + + let payout_usd_cents = purchase_usd_cents + .checked_mul(coef_limit.coef_ppm) + .ok_or(error!(ErrCode::MathOverflow))? + / settings::COEF_SCALE_PPM; + require!(payout_usd_cents > 0, PaymentsError::InvalidPayoutAmount); + + transfer_from_signer_to_target( + &ctx.accounts.signer, + &ctx.accounts.dao_wallet, + &ctx.accounts.system_program.to_account_info(), + transfer_lamports, + )?; + + let ticket = TicketState { + version: 1, + queue_id: 1, + index: ticket_index, + is_paid: false, + recipient_wallet, + payout_usd_cents, + debt_before_usd_cents: queue1_sum_total_before, + }; + create_state_with_seeds( + ctx.program_id, + &ctx.accounts.signer, + &ctx.accounts.system_program.to_account_info(), + &ctx.accounts.ticket_pda, + &[ + settings::Q1_TICKET_SEED, + &ticket_index.to_le_bytes(), + &[ticket_bump], + ], + settings::TICKET_SPACE, + &ticket, + )?; + + queues.q1_tickets_total = ticket_index; + queues.q1_sum_total_usd_cents = queues + .q1_sum_total_usd_cents + .checked_add(payout_usd_cents) + .ok_or(error!(ErrCode::MathOverflow))?; + write_state(&ctx.accounts.queues_pda, &queues)?; + Ok(()) +} + +fn transfer_from_signer_to_target<'info>( + signer: &AccountInfo<'info>, + target: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + amount: u64, +) -> Result<()> { + let ix = system_instruction::transfer(signer.key, target.key, amount); + invoke( + &ix, + &[signer.clone(), target.clone(), system_program.clone()], + )?; + Ok(()) +} + +fn read_sol_usd_price(price_update: &Account, key: &Pubkey) -> Result { + let expected_oracle = Pubkey::from_str(settings::PYTH_SOL_USD_ACCOUNT) + .map_err(|_| error!(PaymentsError::InvalidOracleFeedConfig))?; + require_keys_eq!(expected_oracle, *key, PaymentsError::InvalidOracleAccount); + + let feed_id = get_feed_id_from_hex(settings::PYTH_SOL_USD_FEED_ID) + .map_err(|_| error!(PaymentsError::InvalidOracleFeedConfig))?; + let clock = Clock::get()?; + let price = price_update + .get_price_no_older_than(&clock, settings::ORACLE_MAX_AGE_SECS, &feed_id) + .map_err(map_oracle_error)?; + price_to_ratio(price) +} + +fn map_oracle_error(err: GetPriceError) -> anchor_lang::error::Error { + match err { + GetPriceError::PriceTooOld => error!(PaymentsError::OraclePriceTooOld), + GetPriceError::MismatchedFeedId => error!(PaymentsError::InvalidOracleFeed), + GetPriceError::InsufficientVerificationLevel => error!(PaymentsError::InvalidOraclePrice), + GetPriceError::FeedIdMustBe32Bytes | GetPriceError::FeedIdNonHexCharacter => { + error!(PaymentsError::InvalidOracleFeedConfig) + } + _ => error!(PaymentsError::InvalidOraclePrice), + } +} + +fn price_to_ratio(price: Price) -> Result { + require!(price.price > 0, PaymentsError::InvalidOraclePrice); + let mut num = (price.price as u128) + .checked_mul(settings::USD_CENTS_SCALE as u128) + .ok_or(error!(ErrCode::MathOverflow))?; + let mut den: u128 = 1; + + if price.exponent >= 0 { + let pow = 10u128 + .checked_pow(price.exponent as u32) + .ok_or(error!(ErrCode::MathOverflow))?; + num = num.checked_mul(pow).ok_or(error!(ErrCode::MathOverflow))?; + } else { + let pow = 10u128 + .checked_pow((-price.exponent) as u32) + .ok_or(error!(ErrCode::MathOverflow))?; + den = den.checked_mul(pow).ok_or(error!(ErrCode::MathOverflow))?; + } + + require!(num > 0 && den > 0, PaymentsError::InvalidOraclePrice); + Ok(SolUsdPrice { + price_num: num, + price_den: den, + }) +} + +fn lamports_to_usd_cents_floor(lamports: u64, price: &SolUsdPrice) -> Result { + let numerator = (lamports as u128) + .checked_mul(price.price_num) + .ok_or(error!(ErrCode::MathOverflow))?; + let denominator = (settings::LAMPORTS_PER_SOL as u128) + .checked_mul(price.price_den) + .ok_or(error!(ErrCode::MathOverflow))?; + require!(denominator > 0, PaymentsError::InvalidOraclePrice); + let value = numerator / denominator; + u64::try_from(value).map_err(|_| error!(ErrCode::MathOverflow)) +} + +fn usd_cents_to_lamports_ceil(usd_cents: u64, price: &SolUsdPrice) -> Result { + require!(usd_cents > 0, PaymentsError::InvalidAmount); + require!(price.price_num > 0, PaymentsError::InvalidOraclePrice); + + let numerator = (usd_cents as u128) + .checked_mul(settings::LAMPORTS_PER_SOL as u128) + .and_then(|v| v.checked_mul(price.price_den)) + .ok_or(error!(ErrCode::MathOverflow))?; + let adjusted = numerator + .checked_add(price.price_num - 1) + .ok_or(error!(ErrCode::MathOverflow))?; + let value = adjusted / price.price_num; + u64::try_from(value).map_err(|_| error!(ErrCode::MathOverflow)) +} + +fn create_and_store_state<'info, T: AnchorSerialize>( + program_id: &Pubkey, + payer: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + pda: &AccountInfo<'info>, + seed: &[u8], + space: usize, + state: &T, +) -> Result<()> { + let (_, bump) = find_single_pda(program_id, seed); + create_state_with_seeds( + program_id, + payer, + system_program, + pda, + &[seed, &[bump]], + space, + state, + ) +} + +fn create_state_with_seeds<'info, T: AnchorSerialize>( + program_id: &Pubkey, + payer: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + pda: &AccountInfo<'info>, + seeds: &[&[u8]], + space: usize, + state: &T, +) -> Result<()> { + create_pda(pda, payer, system_program, program_id, seeds, space as u64)?; + write_state(pda, state) +} + +fn write_state(pda: &AccountInfo, state: &T) -> Result<()> { + let bytes = state + .try_to_vec() + .map_err(|_| error!(ErrCode::DeserializationError))?; + write_to_pda(pda, &bytes) +} + +fn read_state(pda: &AccountInfo) -> Result { + let raw = safe_read_pda(pda); + require!(!raw.is_empty(), PaymentsError::EmptyState); + let mut slice: &[u8] = &raw; + T::deserialize(&mut slice).map_err(|_| error!(ErrCode::DeserializationError)) +} + +fn available_vault_lamports(vault: &AccountInfo) -> Result { + let total = vault.lamports(); + let rent_min = Rent::get()?.minimum_balance(vault.data_len()); + Ok(total.saturating_sub(rent_min)) +} + +fn transfer_from_vault(vault: &AccountInfo, recipient: &AccountInfo, amount: u64) -> Result<()> { + if amount == 0 { + return Ok(()); + } + let mut vault_lamports = vault.try_borrow_mut_lamports()?; + let mut recipient_lamports = recipient.try_borrow_mut_lamports()?; + require!( + **vault_lamports >= amount, + PaymentsError::NotEnoughInflowForStep + ); + **vault_lamports = vault_lamports + .checked_sub(amount) + .ok_or(error!(ErrCode::MathOverflow))?; + **recipient_lamports = recipient_lamports + .checked_add(amount) + .ok_or(error!(ErrCode::MathOverflow))?; + Ok(()) +} + +fn transfer_all_available_to_dao(vault: &AccountInfo, dao_wallet: &AccountInfo) -> Result<()> { + let available = available_vault_lamports(vault)?; + transfer_from_vault(vault, dao_wallet, available) +} diff --git a/shine-solana/shine/programs/shine_payments/src/settings.rs b/shine-solana/shine/programs/shine_payments/src/settings.rs new file mode 100644 index 0000000..8a9391b --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/src/settings.rs @@ -0,0 +1,54 @@ +use common::deploy_config; + +/// `CONFIG_SEED` — seed PDA основного конфига `shine_payments`. +pub const CONFIG_SEED: &[u8] = b"shine_payments_config"; +/// `COEF_LIMIT_SEED` — seed PDA коэффициента, лимита и награды шага выплат. +pub const COEF_LIMIT_SEED: &[u8] = b"shine_payments_coef_limit"; +/// `QUEUES_SEED` — seed PDA агрегатов очередей выплат. +pub const QUEUES_SEED: &[u8] = b"shine_payments_queues"; +/// `INFLOW_VAULT_SEED` — seed PDA inflow-вольта, откуда исполняются выплаты. +pub const INFLOW_VAULT_SEED: &[u8] = b"shine_payments_inflow_vault"; +/// `Q1_TICKET_SEED` — seed PDA тикетов очереди 1. +pub const Q1_TICKET_SEED: &[u8] = b"shine_payments_q1_ticket"; +/// `Q2_TICKET_SEED` — seed PDA тикетов очереди 2. +pub const Q2_TICKET_SEED: &[u8] = b"shine_payments_q2_ticket"; +/// `MANAGER_ALLOWANCE_SEED` — seed PDA лимитов менеджера. +pub const MANAGER_ALLOWANCE_SEED: &[u8] = b"shine_p_manager_allow"; + +/// `CONFIG_SPACE` — размер (в байтах) PDA `ConfigState`. +pub const CONFIG_SPACE: usize = 8 + 160; +/// `COEF_LIMIT_SPACE` — размер (в байтах) PDA `CoefLimitState`. +pub const COEF_LIMIT_SPACE: usize = 8 + 96; +/// `QUEUES_SPACE` — размер (в байтах) PDA `QueuesState`. +pub const QUEUES_SPACE: usize = 8 + 192; +/// `INFLOW_VAULT_SPACE` — размер (в байтах) PDA `VaultState`. +pub const INFLOW_VAULT_SPACE: usize = 8 + 32; +/// `TICKET_SPACE` — размер (в байтах) PDA `TicketState`. +pub const TICKET_SPACE: usize = 8 + 160; +/// `MANAGER_ALLOWANCE_SPACE` — размер (в байтах) PDA `ManagerAllowanceState`. +pub const MANAGER_ALLOWANCE_SPACE: usize = 8 + 128; + +/// `COEF_SCALE_PPM` — масштаб fixed-point для коэффициента (ppm = parts per million). +pub const COEF_SCALE_PPM: u64 = 1_000_000; +/// `START_COEF_PPM` — стартовый коэффициент выплаты при инициализации (`5_000_000` = 5.0x). +pub const START_COEF_PPM: u64 = 5_000_000; +/// `START_LIMIT_USD_CENTS` — стартовый лимит Q1 в USD-центах (10_000 USD). +pub const START_LIMIT_USD_CENTS: u64 = 10_000 * 100; +/// `START_CALL_REWARD_LAMPORTS` — стартовая награда за вызов `step_payout` (0.008 SOL). +pub const START_CALL_REWARD_LAMPORTS: u64 = 8_000_000; +/// `MAX_CALL_REWARD_LAMPORTS` — верхняя граница награды за шаг выплат (0.01 SOL). +pub const MAX_CALL_REWARD_LAMPORTS: u64 = 10_000_000; +/// `USD_CENTS_SCALE` — масштаб USD-центов (1 USD = 100 центов). +pub const USD_CENTS_SCALE: u64 = 100; +/// `LAMPORTS_PER_SOL` — количество лампортов в 1 SOL. +pub const LAMPORTS_PER_SOL: u64 = 1_000_000_000; + +/// `ORACLE_MAX_AGE_SECS` — максимальный возраст oracle-цены (в секундах), допустимый для расчетов. +pub const ORACLE_MAX_AGE_SECS: u64 = 120; +/// `PYTH_SOL_USD_FEED_ID` — feed id Pyth для пары SOL/USD (берется из общего deploy-конфига). +pub const PYTH_SOL_USD_FEED_ID: &str = deploy_config::PYTH_SOL_USD_FEED_ID; +/// `PYTH_SOL_USD_ACCOUNT` — адрес аккаунта Pyth price update для SOL/USD (берется из общего deploy-конфига). +pub const PYTH_SOL_USD_ACCOUNT: &str = deploy_config::PYTH_SOL_USD_ACCOUNT; + +/// `DAO_WALLET` — адрес кошелька DAO-казны для `shine_payments` (берется из общего deploy-конфига). +pub const DAO_WALLET: &str = deploy_config::DAO_TREASURY_WALLET; diff --git a/shine-solana/shine/programs/shine_payments/web/admin_tools.html b/shine-solana/shine/programs/shine_payments/web/admin_tools.html new file mode 100644 index 0000000..cfb59b0 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/admin_tools.html @@ -0,0 +1,561 @@ + + + + + + Тех. инструменты — Shine Payments Devnet + + + +
+ +

Техническая страница (Devnet)

+
Программа:
+ +
+
+ + + +
+
+
+
+ +
+

Коэффициент, лимит и награда шага выплат

+
Право изменения: загрузка...
+
+ + + + +
+
Лимит покупки Q1 = max(limit_usd_cents - q1_sum_total_usd_cents, 0)
+
Шаг выплаты Q1 = ticket + dao(1x) + reward; Q2 = ticket + dao(2x) + reward
+
+
+ +
+

Shine Users: экономические параметры

+
Право изменения: загрузка...
+
Загрузка...
+
+ + + + + +
+
+
+ +
+

Адреса и агрегаты

+
Загрузка...
+
+ +
+

Очередь 1 (все билеты)

+
+
+
+ +
+

Очередь 2 (все билеты)

+
+
+
+
+ + + + + diff --git a/shine-solana/shine/programs/shine_payments/web/buy_ticket.html b/shine-solana/shine/programs/shine_payments/web/buy_ticket.html new file mode 100644 index 0000000..739ad02 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/buy_ticket.html @@ -0,0 +1,428 @@ + + + + + + Покупка билета — Shine Payments Devnet + + + +
+ +

Покупка билета (Devnet)

+
Программа:
+ +
+
+ + +
+
+
+ +
+

Текущее состояние (очередь 1)

+
Загрузка...
+
+ +
+

Покупка билета в 1-й очереди

+
Можно купить по USD или по SOL. В очередь и лимиты записываются USD-центы. Выплаты по тикетам считаются в USD, а переводятся в SOL по актуальному курсу Pyth в момент шага выплаты.
+
+ + + +
+
+ +
+
+
+ + +
+
Дополнительно к сумме покупки кошелек платит сеть за создание записи тикета (обычно около 0.002 SOL).
+
+
+
+ + + + + diff --git a/shine-solana/shine/programs/shine_payments/web/dao_revoke_vote.html b/shine-solana/shine/programs/shine_payments/web/dao_revoke_vote.html new file mode 100644 index 0000000..7da76fb --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/dao_revoke_vote.html @@ -0,0 +1,342 @@ + + + + + + DAO revoke vote — Shine Payments Devnet + + + +
+ +

DAO: голосование на revoke/burn membership token (Devnet)

+
Governance program:
+ +
+
+ +
+
Кошелек: не подключен
+
+ +
+
+ + + +
+
+ + +
+
+ +
+
+
+ +
+
+ + +
+
+ +
+
Если получите hold-up (`0x20d`) — дождитесь конца voting window/hold-up и повторите execute.
+
+
+
+ + + + diff --git a/shine-solana/shine/programs/shine_payments/web/dao_tools.html b/shine-solana/shine/programs/shine_payments/web/dao_tools.html new file mode 100644 index 0000000..fd56972 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/dao_tools.html @@ -0,0 +1,274 @@ + + + + + + DAO-права менеджеров — Shine Payments Devnet + + + +
+ +

DAO: права менеджеров (Devnet)

+
Программа:
+ +
+
+ Пока реального DAO-голосования нет: роль DAO выполняет тестовый кошелек + FUc28vNixp7F3nnkpGVt6nuJbgvJ4429v4B5wS52Df6P.
+ Позже это заменяется на вызов из настоящего DAO-казначейства/голосования. +
+
+ +
+
+ + +
+
+
+
+ +
+

Выдать/добавить лимиты менеджеру

+
+ + + +
+
+ +
+
+
+ +
+

Текущие лимиты менеджера

+
+ +
+
+
+
+ + + + + diff --git a/shine-solana/shine/programs/shine_payments/web/index.html b/shine-solana/shine/programs/shine_payments/web/index.html new file mode 100644 index 0000000..9ffea67 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/index.html @@ -0,0 +1,90 @@ + + + + + + Главная — Shine Payments Devnet + + + + + + diff --git a/shine-solana/shine/programs/shine_payments/web/logic_overview.html b/shine-solana/shine/programs/shine_payments/web/logic_overview.html new file mode 100644 index 0000000..d7f0d66 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/logic_overview.html @@ -0,0 +1,65 @@ + + + + + + Логика работы — Shine Payments Devnet + + + + +

Логика работы Shine Payments (тестовый этап)

+
+

Система работает в Devnet. Экономика хранится в USD-центах, а реальные переводы происходят в SOL.

+

Курс SOL/USD берётся из Pyth прямо в контракте при покупке и при шаге выплаты. Цена проверяется на актуальность (не старше 120 секунд).

+
+ +
+

1. Очереди и билеты

+

Есть две очереди: очередь 1 и очередь 2. Каждый билет — отдельный PDA с полями: очередь, индекс, получатель, сумма выплаты, флаг выплачен/нет, сумма долга перед билетом.

+
+ +
+

2. Покупка билета

+

Обычная покупка создаёт билет только в очереди 1. Пользователь может ввести сумму в USD или SOL на UI. В контракте сумма переводится по курсу в USD-центы, а выплата билета рассчитывается как purchase_usd_cents * coef.

+
+ +
+

3. Менеджерские билеты

+

DAO может выдать менеджеру лимиты на добавление билетов отдельно в очередь 1 и очередь 2. Менеджер создаёт билеты без денежного перевода, но с уменьшением своего доступного лимита.

+
+ +
+

4. Порядок выплат

+

Приоритет всегда у очереди 1. Если в очереди 1 нет невыплаченных билетов, идут выплаты очереди 2. Если в процессе выплат очереди 2 снова появляется билет в очереди 1, приоритет возвращается к очереди 1.

+

Шаг выплаты: для очереди 1 в DAO уходит 1x от выплаты тикета, для очереди 2 в DAO уходит 2x от выплаты тикета. Дополнительно вызывающий получает награду в SOL.

+

Если обе очереди пустые/выплачены — доступный остаток inflow-вольта переводится в DAO (без награды вызывающему).

+
+ +
+

5. Тестовый режим пополнения выплат

+

Пока регистрация/авто-поток пополнения не завершены, inflow-вольт для выплат пополняется вручную, после чего выполняются шаги выплат.

+
+ +
+ Подробная версия в документе репозитория: shine/doc/SHINE_PAYMENTS_V2.md. +
+ + diff --git a/shine-solana/shine/programs/shine_payments/web/manager_tools.html b/shine-solana/shine/programs/shine_payments/web/manager_tools.html new file mode 100644 index 0000000..04f7243 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/manager_tools.html @@ -0,0 +1,280 @@ + + + + + + Менеджерские билеты — Shine Payments Devnet + + + +
+ +

Менеджер: создание билетов (Devnet)

+
Программа:
+ +
+
+ + +
+
+
+ +
+

Лимиты менеджера

+
Загрузка...
+
+ +
+

Создать билет менеджером

+
+ + + +
+
+ +
+
+
+
+ + + + + diff --git a/shine-solana/shine/programs/shine_payments/web/roadmap_dao.html b/shine-solana/shine/programs/shine_payments/web/roadmap_dao.html new file mode 100644 index 0000000..329f6e8 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/roadmap_dao.html @@ -0,0 +1,45 @@ + + + + + + Что ещё нужно до DAO — Shine Payments Devnet + + + + +

Что ещё нужно до реального DAO

+ +
+

Сейчас роль DAO выполняет обычный кошелёк (тестовый режим Devnet).

+
+ +
+

Что нужно добавить в production:

+
    +
  1. Заменить обычный DAO-кошелёк на DAO-казначейство/голосование.
  2. +
  3. DAO-решения (выдача лимитов менеджерам, изменение параметров) проводить через голосование.
  4. +
  5. Зафиксировать production-источник цены (oracle governance, fallback-политика, мониторинг stale-данных).
  6. +
  7. Ограничить тестовые ключи и закрыть доступ к приватным данным.
  8. +
+
+ +
+

Текущий дизайн уже совместим с DAO-заменой: достаточно сменить авторизацию вызовов на DAO-механику без изменения базовой структуры очередей и билетов.

+
+ + diff --git a/shine-solana/shine/programs/shine_payments/web/test_plan.html b/shine-solana/shine/programs/shine_payments/web/test_plan.html new file mode 100644 index 0000000..f44fd1b --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/test_plan.html @@ -0,0 +1,63 @@ + + + + + + Сценарий тестирования — Shine Payments Devnet + + + + +

Сценарий тестирования Shine Payments (Devnet)

+ +
+

Вариант А: один кошелёк

+
    +
  1. Открыть admin_tools, выполнить init.
  2. +
  3. Открыть buy_ticket, купить несколько билетов (часть через USD, часть через SOL).
  4. +
  5. Открыть dao_tools, выдать лимиты менеджеру (тем же кошельком).
  6. +
  7. Открыть manager_tools, создать билеты в очередь 1 и очередь 2.
  8. +
  9. Пополнить inflow-вольт вручную.
  10. +
  11. Открыть track_ticket, выполнять шаги выплат до погашения очередей.
  12. +
  13. Проверить, что в шагах: Q1 = ticket + DAO(1x) + reward, Q2 = ticket + DAO(2x) + reward.
  14. +
+
+ +
+

Вариант Б: несколько кошельков

+
    +
  1. Кошелёк 1: DAO (выдаёт лимиты менеджерам).
  2. +
  3. Кошелёк 2: менеджер (создаёт билеты в очередь 1/2).
  4. +
  5. Кошельки 3+: покупатели (создают обычные билеты через покупку).
  6. +
  7. Любой кошелёк может запускать шаг выплат.
  8. +
+
+ +
+

Как вернуть средства после тестов

+
    +
  1. Довести выплаты до нужного состояния (или остановить на текущем шаге).
  2. +
  3. Сделать переводы с тестовых кошельков обратно на исходный кошелёк.
  4. +
  5. При необходимости закрыть неиспользуемые program/PDA-аккаунты и вернуть ренту (через CLI).
  6. +
+
+ +
+

Пока DAO-governance не подключена, ключевые действия DAO выполняются обычным тестовым кошельком. В production это заменяется голосованием DAO.

+
+ + diff --git a/shine-solana/shine/programs/shine_payments/web/track_ticket.html b/shine-solana/shine/programs/shine_payments/web/track_ticket.html new file mode 100644 index 0000000..9322026 --- /dev/null +++ b/shine-solana/shine/programs/shine_payments/web/track_ticket.html @@ -0,0 +1,506 @@ + + + + + + Отслеживание билета — Shine Payments Devnet + + + +
+ +

Отслеживание билета (Devnet)

+
Программа:
+ +
+
+ + +
+
+
+ +
+

Поиск билетов

+
+ + + +
+
+
+ +
+

Состояние шага выплат

+
Загрузка...
+
+ +
+
+
Вызывающий шаг выплат платит сетевую комиссию транзакции и получает on-chain награду. Идея в том, что награда делает вызов экономически выгодным, поэтому всегда есть мотивация нажимать кнопку шага выплат.
+
Автоматического таймера в контракте нет: в Solana любая инструкция должна быть инициирована внешним вызовом.
+
+
+ + + + + diff --git a/shine-solana/shine/programs/shine_users/Cargo.toml b/shine-solana/shine/programs/shine_users/Cargo.toml new file mode 100644 index 0000000..87b5c0f --- /dev/null +++ b/shine-solana/shine/programs/shine_users/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "shine_users" +version = "0.1.0" +description = "User registration smart contract" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "shine_users" +test = false +doctest = false +bench = false + +[dependencies] +anchor-lang = "0.31.1" +common = { path = "../common" } +shine_login_guard = { path = "../shine_login_guard", features = ["cpi", "no-entrypoint"] } + + +[features] +default = [] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +anchor-debug = [] +custom-heap = [] +custom-panic = [] +cpi = [] +idl-build = ["anchor-lang/idl-build"] diff --git a/shine-solana/shine/programs/shine_users/src/lib.rs b/shine-solana/shine/programs/shine_users/src/lib.rs new file mode 100644 index 0000000..0ba5e32 --- /dev/null +++ b/shine-solana/shine/programs/shine_users/src/lib.rs @@ -0,0 +1,32 @@ +use anchor_lang::prelude::*; + +pub mod settings; +pub mod users; + +use users::*; + +declare_id!("FZS1YctoeEhCkZ5VTjsysUFAXR8CqxYztcLboXcg2Rpm"); + +#[program] +pub mod shine { + use super::*; + + pub fn init_users_economy_config(ctx: Context) -> Result<()> { + users::init_users_economy_config(ctx) + } + + pub fn update_users_economy_config( + ctx: Context, + args: UpdateUsersEconomyConfigArgs, + ) -> Result<()> { + users::update_users_economy_config(ctx, args) + } + + pub fn create_user_pda(ctx: Context, args: CreateUserPdaArgs) -> Result<()> { + users::create_user_pda(ctx, args) + } + + pub fn update_user_pda(ctx: Context, args: UpdateUserPdaArgs) -> Result<()> { + users::update_user_pda(ctx, args) + } +} diff --git a/shine-solana/shine/programs/shine_users/src/settings.rs b/shine-solana/shine/programs/shine_users/src/settings.rs new file mode 100644 index 0000000..f83d7cd --- /dev/null +++ b/shine-solana/shine/programs/shine_users/src/settings.rs @@ -0,0 +1,30 @@ +use common::deploy_config; + +/// `USER_PDA_SEED_PREFIX` — префикс seed для пользовательского PDA (`login=<...>`). +pub const USER_PDA_SEED_PREFIX: &str = "login="; +/// `USERS_ECONOMY_CONFIG_SEED` — seed PDA с экономическими параметрами программы `shine_users`. +pub const USERS_ECONOMY_CONFIG_SEED: &[u8] = b"shine_users_economy_config"; +/// `USER_PDA_SPACE` — стартовый размер PDA пользователя, дальше запись может расширяться через realloc. +pub const USER_PDA_SPACE: usize = 768; +/// `USERS_ECONOMY_CONFIG_SPACE` — размер PDA с экономическими параметрами `shine_users`. +pub const USERS_ECONOMY_CONFIG_SPACE: usize = 8 + 96; + +/// `DAO_AUTHORITY` — адрес DAO-авторити, который имеет право обновлять economy-конфиг. +pub const DAO_AUTHORITY: &str = deploy_config::DAO_AUTHORITY; + +/// `SHINE_PAYMENTS_PROGRAM_ID` — адрес программы `shine_payments`, от которой вычисляется PDA inflow-вольта. +pub const SHINE_PAYMENTS_PROGRAM_ID: &str = deploy_config::SHINE_PAYMENTS_PROGRAM_ID; +/// `SHINE_PAYMENTS_INFLOW_VAULT_SEED` — seed inflow-вольта в программе `shine_payments` (должен совпадать с payments settings). +pub const SHINE_PAYMENTS_INFLOW_VAULT_SEED: &[u8] = b"shine_payments_inflow_vault"; +/// `SHINE_LOGIN_GUARD_PROGRAM_ID` — адрес отдельной программы проверки премиальности логина. +pub const SHINE_LOGIN_GUARD_PROGRAM_ID: &str = deploy_config::SHINE_LOGIN_GUARD_PROGRAM_ID; +/// `START_REGISTRATION_FEE_LAMPORTS` — стартовая комиссия регистрации (0.01 SOL) для initial economy-конфига. +pub const START_REGISTRATION_FEE_LAMPORTS: u64 = 10_000_000; + +/// `LIMIT_STEP` — шаг пополнения лимита; `additional_limit` должен быть кратен этому значению. +pub const LIMIT_STEP: u64 = 10_000; +/// `START_LAMPORTS_PER_LIMIT_STEP` — стартовая цена одного шага лимита (0.0001 SOL за 10_000 лимита). +pub const START_LAMPORTS_PER_LIMIT_STEP: u64 = 100_000; + +/// `START_BONUS_LIMIT` — стартовый бонус лимита, выдаваемый пользователю при создании записи. +pub const START_BONUS_LIMIT: u64 = 100_000; diff --git a/shine-solana/shine/programs/shine_users/src/users.rs b/shine-solana/shine/programs/shine_users/src/users.rs new file mode 100644 index 0000000..eeca73d --- /dev/null +++ b/shine-solana/shine/programs/shine_users/src/users.rs @@ -0,0 +1,993 @@ +use crate::settings; +use anchor_lang::prelude::*; +use anchor_lang::solana_program::{ + ed25519_program, + hash::hashv, + instruction::Instruction, + program::{get_return_data, invoke}, + system_instruction, + sysvar::instructions::{load_current_index_checked, load_instruction_at_checked}, +}; +use common::utils::{create_pda, safe_read_pda, write_to_pda, ErrCode}; +use std::str::FromStr; + +const MAGIC: &[u8; 5] = b"SHiNE"; +const FORMAT_MAJOR: u8 = 1; +const FORMAT_MINOR: u8 = 0; +const KEY_STATUS_CREATED: u8 = 0; +const MAX_SYNC_SERVERS: usize = 32; +const MAX_AUTO_REALLOC_INCREASE: usize = 10_000; +const RESERVED_BYTES: [u8; 5] = [0, 0, 0, 0, 0]; +const ZERO_HASH: [u8; 32] = [0; 32]; + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct UserMutableFields { + pub blockchain_key: Pubkey, + pub device_key: Pubkey, + pub chain_number: u16, + pub is_server: bool, + pub server_key: Pubkey, + pub server_address: String, + pub sync_servers: Vec, + pub access_servers: Vec, + pub trusted_count: u8, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct CreateUserPdaArgs { + pub login: String, + pub root_key: Pubkey, + pub created_at_ms: u64, + pub additional_limit: u64, + pub fields: UserMutableFields, + pub signature: Vec, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct UpdateUserPdaArgs { + pub login: String, + pub root_key: Pubkey, + pub created_at_ms: u64, + pub updated_at_ms: u64, + pub version: u32, + pub prev_hash: Vec, + pub additional_limit: u64, + pub fields: UserMutableFields, + pub signature: Vec, +} + +pub struct UserRecord { + pub created_at_ms: u64, + pub updated_at_ms: u64, + pub version: u32, + pub prev_hash: [u8; 32], + pub login: String, + pub root_key_status: u8, + pub root_key: Pubkey, + pub blockchain_key_status: u8, + pub blockchain_key: Pubkey, + pub device_key_status: u8, + pub device_key: Pubkey, + pub chain_number: u16, + pub balance: u64, + pub is_server: bool, + pub server_key: Pubkey, + pub server_address: String, + pub sync_servers: Vec, + pub access_servers: Vec, + pub trusted_count: u8, + pub signature: [u8; 64], +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct UsersEconomyConfigState { + pub version: u8, + pub registration_fee_lamports: u64, + pub lamports_per_limit_step: u64, + pub start_bonus_limit: u64, +} + +#[derive(Accounts)] +pub struct CreateUserPda<'info> { + /// CHECK: подписант транзакции, валидируется Anchor как signer и mut. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA пользователя, адрес проверяется вручную через seed в обработчике. + #[account(mut)] + pub user_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, + /// CHECK: inflow-вольт shine_payments, адрес проверяется вручную как PDA. + #[account(mut)] + pub inflow_vault: AccountInfo<'info>, + /// CHECK: sysvar инструкций, нужен для проверки встроенной Ed25519Program инструкции. + pub instructions: AccountInfo<'info>, + /// CHECK: PDA с экономическими настройками пользователей, адрес проверяется вручную. + pub users_economy_config_pda: AccountInfo<'info>, + pub login_guard_program: Program<'info, shine_login_guard::program::ShineLoginGuard>, +} + +#[derive(Accounts)] +pub struct UpdateUserPda<'info> { + /// CHECK: подписант транзакции, валидируется Anchor как signer и mut. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA пользователя, адрес проверяется вручную через seed в обработчике. + #[account(mut)] + pub user_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, + /// CHECK: inflow-вольт shine_payments, адрес проверяется вручную как PDA. + #[account(mut)] + pub inflow_vault: AccountInfo<'info>, + /// CHECK: sysvar инструкций, нужен для проверки встроенной Ed25519Program инструкции. + pub instructions: AccountInfo<'info>, + /// CHECK: PDA с экономическими настройками пользователей, адрес проверяется вручную. + pub users_economy_config_pda: AccountInfo<'info>, +} + +#[derive(Accounts)] +pub struct InitUsersEconomyConfig<'info> { + /// CHECK: подписант и плательщик, валидируется Anchor как signer и mut. + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA с экономическими настройками пользователей, адрес проверяется вручную. + #[account(mut)] + pub users_economy_config_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Accounts)] +pub struct UpdateUsersEconomyConfig<'info> { + /// CHECK: подписант (должен быть DAO authority из settings). + #[account(mut, signer)] + pub signer: AccountInfo<'info>, + /// CHECK: PDA с экономическими настройками пользователей, адрес проверяется вручную. + #[account(mut)] + pub users_economy_config_pda: AccountInfo<'info>, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct UpdateUsersEconomyConfigArgs { + pub registration_fee_lamports: u64, + pub lamports_per_limit_step: u64, + pub start_bonus_limit: u64, +} + +pub fn init_users_economy_config(ctx: Context) -> Result<()> { + let (expected_pda, bump) = find_users_economy_config_pda(ctx.program_id); + require_keys_eq!( + expected_pda, + ctx.accounts.users_economy_config_pda.key(), + ErrCode::InvalidPdaAddress + ); + require!( + ctx.accounts.users_economy_config_pda.owner == &Pubkey::default(), + ErrCode::SystemAlreadyInitialized + ); + + let state = UsersEconomyConfigState { + version: 1, + registration_fee_lamports: settings::START_REGISTRATION_FEE_LAMPORTS, + lamports_per_limit_step: settings::START_LAMPORTS_PER_LIMIT_STEP, + start_bonus_limit: settings::START_BONUS_LIMIT, + }; + let bytes = state + .try_to_vec() + .map_err(|_| error!(ErrCode::DeserializationError))?; + let seeds: &[&[u8]] = &[settings::USERS_ECONOMY_CONFIG_SEED, &[bump]]; + create_pda( + &ctx.accounts.users_economy_config_pda, + &ctx.accounts.signer, + &ctx.accounts.system_program.to_account_info(), + ctx.program_id, + seeds, + settings::USERS_ECONOMY_CONFIG_SPACE as u64, + )?; + write_to_pda(&ctx.accounts.users_economy_config_pda, &bytes)?; + Ok(()) +} + +pub fn update_users_economy_config( + ctx: Context, + args: UpdateUsersEconomyConfigArgs, +) -> Result<()> { + let dao_authority = + Pubkey::from_str(settings::DAO_AUTHORITY).map_err(|_| error!(ErrCode::InvalidSigner))?; + require_keys_eq!(dao_authority, ctx.accounts.signer.key(), ErrCode::InvalidSigner); + + let (expected_pda, _) = find_users_economy_config_pda(ctx.program_id); + require_keys_eq!( + expected_pda, + ctx.accounts.users_economy_config_pda.key(), + ErrCode::InvalidPdaAddress + ); + require!( + ctx.accounts.users_economy_config_pda.owner == ctx.program_id, + ErrCode::InvalidPdaAddress + ); + require!(args.lamports_per_limit_step > 0, ErrCode::InvalidRecordData); + + let mut state = read_users_economy_config(&ctx.accounts.users_economy_config_pda)?; + state.registration_fee_lamports = args.registration_fee_lamports; + state.lamports_per_limit_step = args.lamports_per_limit_step; + state.start_bonus_limit = args.start_bonus_limit; + let bytes = state + .try_to_vec() + .map_err(|_| error!(ErrCode::DeserializationError))?; + write_to_pda(&ctx.accounts.users_economy_config_pda, &bytes)?; + Ok(()) +} + +pub fn create_user_pda(ctx: Context, args: CreateUserPdaArgs) -> Result<()> { + validate_login(&args.login)?; + require_keys_eq!( + ctx.accounts.login_guard_program.key(), + Pubkey::from_str(settings::SHINE_LOGIN_GUARD_PROGRAM_ID) + .map_err(|_| error!(ErrCode::InvalidLoginGuardResponse))?, + ErrCode::InvalidLoginGuardResponse + ); + classify_login_or_fail( + &ctx.accounts.login_guard_program.to_account_info(), + &ctx.accounts.signer, + &args.login, + )?; + validate_fields(&args.fields)?; + validate_inflow_vault(&ctx.accounts.inflow_vault)?; + require!( + args.additional_limit % settings::LIMIT_STEP == 0, + ErrCode::InvalidLimitIncrement + ); + let economy = read_users_economy_config(&ctx.accounts.users_economy_config_pda)?; + + let login_seed = login_seed_normalized(&args.login); + let (expected_pda, bump) = find_user_pda(ctx.program_id, &login_seed); + require_keys_eq!( + expected_pda, + ctx.accounts.user_pda.key(), + ErrCode::InvalidPdaAddress + ); + require!( + ctx.accounts.user_pda.owner == &Pubkey::default(), + ErrCode::UserAlreadyExists + ); + + let start_balance = economy + .start_bonus_limit + .checked_add(args.additional_limit) + .ok_or(error!(ErrCode::MathOverflow))?; + + let mut record = UserRecord { + created_at_ms: args.created_at_ms, + updated_at_ms: args.created_at_ms, + version: 0, + prev_hash: ZERO_HASH, + login: args.login.clone(), + root_key_status: KEY_STATUS_CREATED, + root_key: args.root_key, + blockchain_key_status: KEY_STATUS_CREATED, + blockchain_key: args.fields.blockchain_key, + device_key_status: KEY_STATUS_CREATED, + device_key: args.fields.device_key, + chain_number: args.fields.chain_number, + balance: start_balance, + is_server: args.fields.is_server, + server_key: args.fields.server_key, + server_address: args.fields.server_address.clone(), + sync_servers: args.fields.sync_servers.clone(), + access_servers: args.fields.access_servers.clone(), + trusted_count: args.fields.trusted_count, + signature: [0; 64], + }; + + let unsigned = serialize_unsigned_record(&record)?; + record.signature = verify_record_signature( + &ctx.accounts.instructions, + &record.root_key, + &args.signature, + &unsigned, + )?; + + let serialized = serialize_full_record(&record)?; + require!( + serialized.len() <= settings::USER_PDA_SPACE, + ErrCode::RecordTooLarge + ); + let padded = pad_to_fixed_size(serialized, settings::USER_PDA_SPACE)?; + + let pda_seeds: &[&[u8]] = &[ + settings::USER_PDA_SEED_PREFIX.as_bytes(), + login_seed.as_bytes(), + &[bump], + ]; + create_pda( + &ctx.accounts.user_pda, + &ctx.accounts.signer, + &ctx.accounts.system_program.to_account_info(), + ctx.program_id, + pda_seeds, + settings::USER_PDA_SPACE as u64, + )?; + write_to_pda(&ctx.accounts.user_pda, &padded)?; + + let total_fee = economy + .registration_fee_lamports + .checked_add(limit_fee_lamports(args.additional_limit, economy.lamports_per_limit_step)?) + .ok_or(error!(ErrCode::MathOverflow))?; + transfer_lamports( + &ctx.accounts.signer, + &ctx.accounts.inflow_vault, + &ctx.accounts.system_program.to_account_info(), + total_fee, + )?; + + Ok(()) +} + +fn classify_login_or_fail<'info>( + login_guard_program: &AccountInfo<'info>, + signer: &AccountInfo<'info>, + login: &str, +) -> Result<()> { + let cpi_ctx = CpiContext::new( + login_guard_program.clone(), + shine_login_guard::cpi::accounts::ClassifyLogin { + signer: signer.to_account_info(), + }, + ); + shine_login_guard::cpi::classify_login(cpi_ctx, login.to_string())?; + + let (program_id, raw) = get_return_data().ok_or(error!(ErrCode::InvalidLoginGuardResponse))?; + require_keys_eq!( + program_id, + *login_guard_program.key, + ErrCode::InvalidLoginGuardResponse + ); + require!(raw.len() == 4, ErrCode::InvalidLoginGuardResponse); + let class = u32::from_le_bytes([raw[0], raw[1], raw[2], raw[3]]); + match class { + 0 => Ok(()), + 1 => Err(error!(ErrCode::PremiumLogin)), + 2 => Err(error!(ErrCode::TrademarkLoginRequiresReview)), + _ => Err(error!(ErrCode::InvalidLoginGuardResponse)), + } +} + +pub fn update_user_pda(ctx: Context, args: UpdateUserPdaArgs) -> Result<()> { + validate_login(&args.login)?; + validate_fields(&args.fields)?; + validate_inflow_vault(&ctx.accounts.inflow_vault)?; + require!( + args.additional_limit % settings::LIMIT_STEP == 0, + ErrCode::InvalidLimitIncrement + ); + let economy = read_users_economy_config(&ctx.accounts.users_economy_config_pda)?; + + let login_seed = login_seed_normalized(&args.login); + let (expected_pda, _) = find_user_pda(ctx.program_id, &login_seed); + require_keys_eq!( + expected_pda, + ctx.accounts.user_pda.key(), + ErrCode::InvalidPdaAddress + ); + require!( + ctx.accounts.user_pda.owner == ctx.program_id, + ErrCode::InvalidPdaAddress + ); + + let raw = safe_read_pda(&ctx.accounts.user_pda); + require!(!raw.is_empty(), ErrCode::EmptyPdaData); + let old_record = deserialize_record_from_pda(&raw)?; + + require!( + old_record.login == args.login, + ErrCode::ImmutableFieldChanged + ); + require!( + old_record.created_at_ms == args.created_at_ms, + ErrCode::ImmutableFieldChanged + ); + require_keys_eq!( + old_record.root_key, + args.root_key, + ErrCode::ImmutableFieldChanged + ); + require!( + old_record.root_key_status == KEY_STATUS_CREATED + && old_record.blockchain_key_status == KEY_STATUS_CREATED + && old_record.device_key_status == KEY_STATUS_CREATED, + ErrCode::InvalidRecordData + ); + require!( + args.version == old_record.version.saturating_add(1), + ErrCode::InvalidVersion + ); + + let expected_prev_hash = hash_unsigned_record(&old_record)?; + let provided_prev_hash = vec_to_hash32(&args.prev_hash)?; + require!( + expected_prev_hash == provided_prev_hash, + ErrCode::InvalidPrevHash + ); + + let new_balance = old_record + .balance + .checked_add(args.additional_limit) + .ok_or(error!(ErrCode::MathOverflow))?; + require!(new_balance >= old_record.balance, ErrCode::BalanceDecrease); + + let mut new_record = UserRecord { + created_at_ms: old_record.created_at_ms, + updated_at_ms: args.updated_at_ms, + version: args.version, + prev_hash: provided_prev_hash, + login: old_record.login.clone(), + root_key_status: old_record.root_key_status, + root_key: old_record.root_key, + blockchain_key_status: old_record.blockchain_key_status, + blockchain_key: args.fields.blockchain_key, + device_key_status: old_record.device_key_status, + device_key: args.fields.device_key, + chain_number: args.fields.chain_number, + balance: new_balance, + is_server: args.fields.is_server, + server_key: args.fields.server_key, + server_address: args.fields.server_address.clone(), + sync_servers: args.fields.sync_servers.clone(), + access_servers: args.fields.access_servers.clone(), + trusted_count: args.fields.trusted_count, + signature: [0; 64], + }; + + let unsigned = serialize_unsigned_record(&new_record)?; + new_record.signature = verify_record_signature( + &ctx.accounts.instructions, + &new_record.root_key, + &args.signature, + &unsigned, + )?; + + let serialized = serialize_full_record(&new_record)?; + ensure_pda_size_and_rent( + &ctx.accounts.user_pda, + &ctx.accounts.signer, + &ctx.accounts.system_program.to_account_info(), + serialized.len(), + )?; + write_to_pda(&ctx.accounts.user_pda, &serialized)?; + + let topup_fee = limit_fee_lamports(args.additional_limit, economy.lamports_per_limit_step)?; + if topup_fee > 0 { + transfer_lamports( + &ctx.accounts.signer, + &ctx.accounts.inflow_vault, + &ctx.accounts.system_program.to_account_info(), + topup_fee, + )?; + } + + Ok(()) +} + +fn serialize_unsigned_record(record: &UserRecord) -> Result> { + let login_bytes = record.login.as_bytes(); + require!(login_bytes.len() <= u8::MAX as usize, ErrCode::InvalidLogin); + + let server_address_bytes = record.server_address.as_bytes(); + require!( + server_address_bytes.len() <= u8::MAX as usize, + ErrCode::InvalidRecordData + ); + require!(record.access_servers.len() <= u8::MAX as usize, ErrCode::InvalidRecordData); + + let mut out = Vec::new(); + out.extend_from_slice(MAGIC); + out.push(FORMAT_MAJOR); + out.push(FORMAT_MINOR); + out.extend_from_slice(&0u16.to_le_bytes()); + + out.extend_from_slice(&record.created_at_ms.to_le_bytes()); + out.extend_from_slice(&record.updated_at_ms.to_le_bytes()); + out.extend_from_slice(&record.version.to_le_bytes()); + out.extend_from_slice(&record.prev_hash); + + out.push(login_bytes.len() as u8); + out.extend_from_slice(login_bytes); + + out.push(record.root_key_status); + out.extend_from_slice(record.root_key.as_ref()); + out.push(record.blockchain_key_status); + out.extend_from_slice(record.blockchain_key.as_ref()); + out.push(record.device_key_status); + out.extend_from_slice(record.device_key.as_ref()); + + out.extend_from_slice(&record.chain_number.to_le_bytes()); + out.extend_from_slice(&record.balance.to_le_bytes()); + + out.push(if record.is_server { 1 } else { 0 }); + if record.is_server { + out.extend_from_slice(record.server_key.as_ref()); + out.push(server_address_bytes.len() as u8); + out.extend_from_slice(server_address_bytes); + require!( + record.sync_servers.len() <= MAX_SYNC_SERVERS, + ErrCode::InvalidRecordData + ); + out.push(record.sync_servers.len() as u8); + for login in &record.sync_servers { + let bytes = login.as_bytes(); + require!(bytes.len() <= u8::MAX as usize, ErrCode::InvalidRecordData); + out.push(bytes.len() as u8); + out.extend_from_slice(bytes); + } + } + + out.push(record.access_servers.len() as u8); + for login in &record.access_servers { + let bytes = login.as_bytes(); + require!(bytes.len() <= u8::MAX as usize, ErrCode::InvalidRecordData); + out.push(bytes.len() as u8); + out.extend_from_slice(bytes); + } + + out.push(record.trusted_count); + out.extend_from_slice(&RESERVED_BYTES); + + let record_len = out + .len() + .checked_add(64) + .ok_or(error!(ErrCode::MathOverflow))?; + require!(record_len <= u16::MAX as usize, ErrCode::RecordTooLarge); + let len_bytes = (record_len as u16).to_le_bytes(); + out[7] = len_bytes[0]; + out[8] = len_bytes[1]; + + Ok(out) +} + +fn serialize_full_record(record: &UserRecord) -> Result> { + let mut out = serialize_unsigned_record(record)?; + out.extend_from_slice(&record.signature); + Ok(out) +} + +fn deserialize_record_from_pda(raw: &[u8]) -> Result { + require!(raw.len() >= 9, ErrCode::InvalidRecordData); + require!(&raw[0..5] == MAGIC, ErrCode::InvalidRecordMagic); + require!( + raw[5] == FORMAT_MAJOR && raw[6] == FORMAT_MINOR, + ErrCode::InvalidRecordFormat + ); + + let record_len = u16::from_le_bytes([raw[7], raw[8]]) as usize; + require!(record_len >= 9 + 64, ErrCode::InvalidRecordLength); + require!(record_len <= raw.len(), ErrCode::InvalidRecordLength); + + let useful = &raw[..record_len]; + let mut cursor = 9usize; + + let created_at_ms = read_u64(useful, &mut cursor)?; + let updated_at_ms = read_u64(useful, &mut cursor)?; + let version = read_u32(useful, &mut cursor)?; + let prev_hash = read_fixed_32(useful, &mut cursor)?; + let login = read_len_prefixed_string(useful, &mut cursor)?; + + let root_key_status = read_u8(useful, &mut cursor)?; + let root_key = Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?); + let blockchain_key_status = read_u8(useful, &mut cursor)?; + let blockchain_key = Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?); + let device_key_status = read_u8(useful, &mut cursor)?; + let device_key = Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?); + + let chain_number = read_u16(useful, &mut cursor)?; + let balance = read_u64(useful, &mut cursor)?; + + let is_server = read_u8(useful, &mut cursor)? == 1; + let (server_key, server_address) = if is_server { + ( + Pubkey::new_from_array(read_fixed_32(useful, &mut cursor)?), + read_len_prefixed_string(useful, &mut cursor)?, + ) + } else { + (Pubkey::default(), String::new()) + }; + + let sync_servers = if is_server { + let sync_count = read_u8(useful, &mut cursor)? as usize; + require!(sync_count <= MAX_SYNC_SERVERS, ErrCode::InvalidRecordData); + let mut out = Vec::with_capacity(sync_count); + for _ in 0..sync_count { + out.push(read_len_prefixed_string(useful, &mut cursor)?); + } + out + } else { + Vec::new() + }; + + let access_count = read_u8(useful, &mut cursor)? as usize; + let mut access_servers = Vec::with_capacity(access_count); + for _ in 0..access_count { + access_servers.push(read_len_prefixed_string(useful, &mut cursor)?); + } + + let trusted_count = read_u8(useful, &mut cursor)?; + require!( + useful.get(cursor..cursor + 5) == Some(&RESERVED_BYTES), + ErrCode::InvalidRecordData + ); + cursor += 5; + + let signature = read_fixed_64(useful, &mut cursor)?; + require!(cursor == useful.len(), ErrCode::InvalidRecordLength); + + Ok(UserRecord { + created_at_ms, + updated_at_ms, + version, + prev_hash, + login, + root_key_status, + root_key, + blockchain_key_status, + blockchain_key, + device_key_status, + device_key, + chain_number, + balance, + is_server, + server_key, + server_address, + sync_servers, + access_servers, + trusted_count, + signature, + }) +} + +fn hash_unsigned_record(record: &UserRecord) -> Result<[u8; 32]> { + let unsigned = serialize_unsigned_record(record)?; + let digest = hashv(&[&unsigned]); + let mut out = [0u8; 32]; + out.copy_from_slice(digest.as_ref()); + Ok(out) +} + +fn verify_record_signature( + instructions_sysvar: &AccountInfo, + root_key: &Pubkey, + signature: &[u8], + unsigned: &[u8], +) -> Result<[u8; 64]> { + require_keys_eq!( + *instructions_sysvar.key, + anchor_lang::solana_program::sysvar::instructions::id(), + ErrCode::InvalidSignature + ); + let provided_sig = vec_to_signature(signature)?; + let msg_hash = hashv(&[unsigned]); + + let current_ix_index = load_current_index_checked(instructions_sysvar) + .map_err(|_| error!(ErrCode::InvalidSignature))?; + require!(current_ix_index > 0, ErrCode::InvalidSignature); + let ed_ix = load_instruction_at_checked((current_ix_index - 1) as usize, instructions_sysvar) + .map_err(|_| error!(ErrCode::InvalidSignature))?; + + let parsed = parse_ed25519_ix(&ed_ix)?; + require_keys_eq!(parsed.pubkey, *root_key, ErrCode::InvalidSignature); + require!( + parsed.message == msg_hash.as_ref(), + ErrCode::InvalidSignature + ); + require!(parsed.signature == provided_sig, ErrCode::InvalidSignature); + + Ok(parsed.signature) +} + +struct ParsedEd25519 { + pub pubkey: Pubkey, + pub signature: [u8; 64], + pub message: Vec, +} + +fn parse_ed25519_ix(ix: &Instruction) -> Result { + require_keys_eq!( + ix.program_id, + ed25519_program::id(), + ErrCode::InvalidSignature + ); + + let data = &ix.data; + require!(data.len() >= 16, ErrCode::InvalidSignature); + require!(data[0] == 1, ErrCode::InvalidSignature); // одна подпись + + let signature_offset = le_u16(data, 2)? as usize; + let signature_ix_index = le_u16(data, 4)?; + let pubkey_offset = le_u16(data, 6)? as usize; + let pubkey_ix_index = le_u16(data, 8)?; + let message_offset = le_u16(data, 10)? as usize; + let message_size = le_u16(data, 12)? as usize; + let message_ix_index = le_u16(data, 14)?; + + require!(signature_ix_index == u16::MAX, ErrCode::InvalidSignature); + require!(pubkey_ix_index == u16::MAX, ErrCode::InvalidSignature); + require!(message_ix_index == u16::MAX, ErrCode::InvalidSignature); + + let signature_end = signature_offset + .checked_add(64) + .ok_or(error!(ErrCode::InvalidSignature))?; + let pubkey_end = pubkey_offset + .checked_add(32) + .ok_or(error!(ErrCode::InvalidSignature))?; + let message_end = message_offset + .checked_add(message_size) + .ok_or(error!(ErrCode::InvalidSignature))?; + + let signature_slice = data + .get(signature_offset..signature_end) + .ok_or(error!(ErrCode::InvalidSignature))?; + let pubkey_slice = data + .get(pubkey_offset..pubkey_end) + .ok_or(error!(ErrCode::InvalidSignature))?; + let message = data + .get(message_offset..message_end) + .ok_or(error!(ErrCode::InvalidSignature))? + .to_vec(); + + let mut signature = [0u8; 64]; + signature.copy_from_slice(signature_slice); + let pubkey = Pubkey::new_from_array( + <[u8; 32]>::try_from(pubkey_slice).map_err(|_| error!(ErrCode::InvalidSignature))?, + ); + + Ok(ParsedEd25519 { + pubkey, + signature, + message, + }) +} + +fn le_u16(data: &[u8], offset: usize) -> Result { + let end = offset + .checked_add(2) + .ok_or(error!(ErrCode::InvalidSignature))?; + let s = data + .get(offset..end) + .ok_or(error!(ErrCode::InvalidSignature))?; + Ok(u16::from_le_bytes([s[0], s[1]])) +} + +fn validate_login(login: &str) -> Result<()> { + require!(!login.is_empty(), ErrCode::InvalidLogin); + require!(login.len() <= 20, ErrCode::InvalidLogin); + for ch in login.chars() { + if !(ch.is_ascii_alphabetic() || ch.is_ascii_digit() || ch == '_') { + return Err(error!(ErrCode::InvalidLogin)); + } + } + Ok(()) +} + +fn login_seed_normalized(login: &str) -> String { + login.to_ascii_lowercase() +} + +fn validate_fields(fields: &UserMutableFields) -> Result<()> { + if fields.is_server { + require!( + !fields.server_address.is_empty(), + ErrCode::InvalidRecordData + ); + require!( + fields.server_address.as_bytes().len() <= u8::MAX as usize, + ErrCode::InvalidRecordData + ); + require!( + fields.sync_servers.len() <= MAX_SYNC_SERVERS, + ErrCode::InvalidRecordData + ); + for login in &fields.sync_servers { + require!(!login.is_empty(), ErrCode::InvalidRecordData); + require!( + login.as_bytes().len() <= u8::MAX as usize, + ErrCode::InvalidRecordData + ); + } + } else { + require!(fields.server_address.is_empty(), ErrCode::InvalidRecordData); + require!(fields.sync_servers.is_empty(), ErrCode::InvalidRecordData); + } + require!( + fields.access_servers.len() <= u8::MAX as usize, + ErrCode::InvalidRecordData + ); + for login in &fields.access_servers { + require!(!login.is_empty(), ErrCode::InvalidRecordData); + require!( + login.as_bytes().len() <= u8::MAX as usize, + ErrCode::InvalidRecordData + ); + } + Ok(()) +} + +fn validate_inflow_vault(inflow_vault: &AccountInfo) -> Result<()> { + let payments_program_id = Pubkey::from_str(settings::SHINE_PAYMENTS_PROGRAM_ID) + .map_err(|_| error!(ErrCode::InvalidFeeReceiver))?; + let (expected, _) = Pubkey::find_program_address( + &[settings::SHINE_PAYMENTS_INFLOW_VAULT_SEED], + &payments_program_id, + ); + require_keys_eq!(expected, *inflow_vault.key, ErrCode::InvalidFeeReceiver); + Ok(()) +} + +fn transfer_lamports<'info>( + payer: &AccountInfo<'info>, + recipient: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + lamports: u64, +) -> Result<()> { + if lamports == 0 { + return Ok(()); + } + let ix = system_instruction::transfer(payer.key, recipient.key, lamports); + invoke( + &ix, + &[payer.clone(), recipient.clone(), system_program.clone()], + )?; + Ok(()) +} + +fn ensure_pda_size_and_rent<'info>( + pda: &AccountInfo<'info>, + payer: &AccountInfo<'info>, + system_program: &AccountInfo<'info>, + required_len: usize, +) -> Result<()> { + let current_len = pda.data_len(); + if required_len <= current_len { + return Ok(()); + } + + let increase = required_len + .checked_sub(current_len) + .ok_or(error!(ErrCode::MathOverflow))?; + require!(increase <= MAX_AUTO_REALLOC_INCREASE, ErrCode::RecordTooLarge); + + let rent = Rent::get()?; + let required_lamports = rent.minimum_balance(required_len); + let current_lamports = pda.lamports(); + let top_up = required_lamports.saturating_sub(current_lamports); + if top_up > 0 { + transfer_lamports(payer, pda, system_program, top_up)?; + } + + pda.realloc(required_len, false)?; + Ok(()) +} + +fn limit_fee_lamports(limit_delta: u64, lamports_per_limit_step: u64) -> Result { + let units = limit_delta / settings::LIMIT_STEP; + units + .checked_mul(lamports_per_limit_step) + .ok_or(error!(ErrCode::MathOverflow)) +} + +fn find_user_pda(program_id: &Pubkey, login: &str) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[settings::USER_PDA_SEED_PREFIX.as_bytes(), login.as_bytes()], + program_id, + ) +} + +fn find_users_economy_config_pda(program_id: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(&[settings::USERS_ECONOMY_CONFIG_SEED], program_id) +} + +fn read_users_economy_config(pda: &AccountInfo) -> Result { + let raw = safe_read_pda(pda); + require!(!raw.is_empty(), ErrCode::EmptyPdaData); + let mut slice: &[u8] = &raw; + UsersEconomyConfigState::deserialize(&mut slice) + .map_err(|_| error!(ErrCode::DeserializationError)) +} + +fn pad_to_fixed_size(mut bytes: Vec, target_size: usize) -> Result> { + require!(bytes.len() <= target_size, ErrCode::RecordTooLarge); + bytes.resize(target_size, 0); + Ok(bytes) +} + +fn vec_to_signature(input: &[u8]) -> Result<[u8; 64]> { + require!(input.len() == 64, ErrCode::InvalidSignature); + let mut out = [0u8; 64]; + out.copy_from_slice(input); + Ok(out) +} + +fn vec_to_hash32(input: &[u8]) -> Result<[u8; 32]> { + require!(input.len() == 32, ErrCode::InvalidPrevHash); + let mut out = [0u8; 32]; + out.copy_from_slice(input); + Ok(out) +} + +fn read_u8(data: &[u8], cursor: &mut usize) -> Result { + let v = *data + .get(*cursor) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor += 1; + Ok(v) +} + +fn read_u16(data: &[u8], cursor: &mut usize) -> Result { + let end = cursor + .checked_add(2) + .ok_or(error!(ErrCode::InvalidRecordData))?; + let slice = data + .get(*cursor..end) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor = end; + Ok(u16::from_le_bytes([slice[0], slice[1]])) +} + +fn read_u32(data: &[u8], cursor: &mut usize) -> Result { + let end = cursor + .checked_add(4) + .ok_or(error!(ErrCode::InvalidRecordData))?; + let slice = data + .get(*cursor..end) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor = end; + Ok(u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]])) +} + +fn read_u64(data: &[u8], cursor: &mut usize) -> Result { + let end = cursor + .checked_add(8) + .ok_or(error!(ErrCode::InvalidRecordData))?; + let slice = data + .get(*cursor..end) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor = end; + Ok(u64::from_le_bytes([ + slice[0], slice[1], slice[2], slice[3], slice[4], slice[5], slice[6], slice[7], + ])) +} + +fn read_fixed_32(data: &[u8], cursor: &mut usize) -> Result<[u8; 32]> { + let end = cursor + .checked_add(32) + .ok_or(error!(ErrCode::InvalidRecordData))?; + let slice = data + .get(*cursor..end) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor = end; + let mut out = [0u8; 32]; + out.copy_from_slice(slice); + Ok(out) +} + +fn read_fixed_64(data: &[u8], cursor: &mut usize) -> Result<[u8; 64]> { + let end = cursor + .checked_add(64) + .ok_or(error!(ErrCode::InvalidRecordData))?; + let slice = data + .get(*cursor..end) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor = end; + let mut out = [0u8; 64]; + out.copy_from_slice(slice); + Ok(out) +} + +fn read_len_prefixed_string(data: &[u8], cursor: &mut usize) -> Result { + let len = read_u8(data, cursor)? as usize; + let end = cursor + .checked_add(len) + .ok_or(error!(ErrCode::InvalidRecordData))?; + let slice = data + .get(*cursor..end) + .ok_or(error!(ErrCode::InvalidRecordData))?; + *cursor = end; + let value = std::str::from_utf8(slice).map_err(|_| error!(ErrCode::InvalidRecordData))?; + Ok(value.to_string()) +} diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/00_prepare_voter2_deposit.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/00_prepare_voter2_deposit.js new file mode 100644 index 0000000..6b2e227 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/00_prepare_voter2_deposit.js @@ -0,0 +1,38 @@ +#!/usr/bin/env node +"use strict"; +const path = require("path"); +const BN = require("bn.js"); +const { Connection, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { getAssociatedTokenAddressSync, createAssociatedTokenAccountIdempotentInstruction, createMintToInstruction, TOKEN_PROGRAM_ID } = require("@solana/spl-token"); +const { withDepositGoverningTokens, PROGRAM_VERSION_V3, getTokenOwnerRecordAddress } = require("@solana/spl-governance"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, PublicKey } = require("./js_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const voter2 = loadKeypair(path.resolve(__dirname, cfg.VOTER2_KEYPAIR)); + const realm = new PublicKey(cfg.REALM); + const mint = new PublicKey(cfg.GOVERNING_MINT); + const govPid = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + + const ata = getAssociatedTokenAddressSync(mint, voter2.publicKey, false, TOKEN_PROGRAM_ID); + const ix1 = [ + createAssociatedTokenAccountIdempotentInstruction(main.publicKey, ata, voter2.publicKey, mint, TOKEN_PROGRAM_ID), + createMintToInstruction(mint, ata, main.publicKey, 1n, [], TOKEN_PROGRAM_ID), + ]; + const sigMint = await sendAndConfirmTransaction(conn, new Transaction().add(...ix1), [main], { commitment: "confirmed" }); + + const tor = await getTokenOwnerRecordAddress(govPid, realm, mint, voter2.publicKey); + const ai = await conn.getAccountInfo(tor, "confirmed"); + let sigDeposit = null; + if (!ai) { + const ix2 = []; + await withDepositGoverningTokens(ix2, govPid, PROGRAM_VERSION_V3, realm, ata, mint, voter2.publicKey, main.publicKey, voter2.publicKey, new BN(1), true); + sigDeposit = await sendAndConfirmTransaction(conn, new Transaction().add(...ix2), [main, voter2], { commitment: "confirmed" }); + } + console.log("prepare done"); + console.log("mint tx:", sigMint); + console.log("deposit tx:", sigDeposit || "already exists"); +} +main().catch((e) => { console.error(e?.message || e); process.exit(1); }); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01_create_nft_for_wallet_admin.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01_create_nft_for_wallet_admin.js new file mode 100644 index 0000000..c9af73c --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01_create_nft_for_wallet_admin.js @@ -0,0 +1,56 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const BN = require("bn.js"); +const { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMintInstruction, + createInitializePermanentDelegateInstruction, + createInitializeNonTransferableMintInstruction, + getAssociatedTokenAddressSync, + createAssociatedTokenAccountIdempotentInstruction, + createMintToInstruction, + createSetAuthorityInstruction, + AuthorityType, +} = require("@solana/spl-token"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, nowStamp, PublicKey } = require("./js_common"); + +async function main() { + const target = process.argv[3]; + if (!target) throw new Error("Usage: node 01_create_nft_for_wallet_admin.js "); + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const governance = new PublicKey(cfg.GOVERNANCE); + const targetPk = new PublicKey(target); + const mint = Keypair.generate(); + const mintLen = getMintLen([ExtensionType.NonTransferable, ExtensionType.PermanentDelegate]); + const rentMint = await conn.getMinimumBalanceForRentExemption(mintLen, "confirmed"); + const ata = getAssociatedTokenAddressSync(mint.publicKey, targetPk, false, TOKEN_2022_PROGRAM_ID); + const tx = new Transaction().add( + SystemProgram.createAccount({ fromPubkey: main.publicKey, newAccountPubkey: mint.publicKey, space: mintLen, lamports: rentMint, programId: TOKEN_2022_PROGRAM_ID }), + createInitializeNonTransferableMintInstruction(mint.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializePermanentDelegateInstruction(mint.publicKey, main.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction(mint.publicKey, 0, main.publicKey, main.publicKey, TOKEN_2022_PROGRAM_ID), + createAssociatedTokenAccountIdempotentInstruction(main.publicKey, ata, targetPk, mint.publicKey, TOKEN_2022_PROGRAM_ID), + createMintToInstruction(mint.publicKey, ata, main.publicKey, 1n, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.MintTokens, governance, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.FreezeAccount, governance, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.PermanentDelegate, governance, [], TOKEN_2022_PROGRAM_ID) + ); + const sig = await sendAndConfirmTransaction(conn, tx, [main, mint], { commitment: "confirmed" }); + const runs = path.resolve(__dirname, cfg.RUNS_DIR || "./runs"); + fs.mkdirSync(runs, { recursive: true }); + const report = { createdAt: new Date().toISOString(), mint: mint.publicKey.toBase58(), owner: targetPk.toBase58(), ata: ata.toBase58(), tx: sig }; + const rp = path.join(runs, `${nowStamp()}_admin_create_nft_${targetPk.toBase58().slice(0,8)}.json`); + fs.writeFileSync(rp, JSON.stringify(report, null, 2)); + console.log("NFT created and delegated to governance"); + console.log("mint:", report.mint); + console.log("owner:", report.owner); + console.log("report:", rp); +} +main().catch((e)=>{console.error(e?.message||e);process.exit(1);}); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01b_create_empty_nft_template.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01b_create_empty_nft_template.js new file mode 100644 index 0000000..d43ccef --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/01b_create_empty_nft_template.js @@ -0,0 +1,44 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const { Connection, Keypair, SystemProgram, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { + TOKEN_2022_PROGRAM_ID, + ExtensionType, + getMintLen, + createInitializeMintInstruction, + createInitializePermanentDelegateInstruction, + createInitializeNonTransferableMintInstruction, + createSetAuthorityInstruction, + AuthorityType, +} = require("@solana/spl-token"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, nowStamp, PublicKey } = require("./js_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const governance = new PublicKey(cfg.GOVERNANCE); + const mint = Keypair.generate(); + const mintLen = getMintLen([ExtensionType.NonTransferable, ExtensionType.PermanentDelegate]); + const rentMint = await conn.getMinimumBalanceForRentExemption(mintLen, "confirmed"); + const tx = new Transaction().add( + SystemProgram.createAccount({ fromPubkey: main.publicKey, newAccountPubkey: mint.publicKey, space: mintLen, lamports: rentMint, programId: TOKEN_2022_PROGRAM_ID }), + createInitializeNonTransferableMintInstruction(mint.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializePermanentDelegateInstruction(mint.publicKey, main.publicKey, TOKEN_2022_PROGRAM_ID), + createInitializeMintInstruction(mint.publicKey, 0, main.publicKey, main.publicKey, TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.MintTokens, governance, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.FreezeAccount, governance, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint.publicKey, main.publicKey, AuthorityType.PermanentDelegate, governance, [], TOKEN_2022_PROGRAM_ID) + ); + const sig = await sendAndConfirmTransaction(conn, tx, [main, mint], { commitment: "confirmed" }); + const runs = path.resolve(__dirname, cfg.RUNS_DIR || "./runs"); + fs.mkdirSync(runs, { recursive: true }); + const rp = path.join(runs, `${nowStamp()}_empty_nft_template.json`); + fs.writeFileSync(rp, JSON.stringify({ mint: mint.publicKey.toBase58(), tx: sig, createdAt: new Date().toISOString() }, null, 2)); + console.log("EMPTY NFT template created"); + console.log("mint:", mint.publicKey.toBase58()); + console.log("report:", rp); +} +main().catch((e)=>{console.error(e?.message||e);process.exit(1);}); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/02_propose_vote_mint_nft.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/02_propose_vote_mint_nft.js new file mode 100644 index 0000000..0dbb428 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/02_propose_vote_mint_nft.js @@ -0,0 +1,60 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const BN = require("bn.js"); +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createMintToInstruction } = require("@solana/spl-token"); +const { + PROGRAM_VERSION_V3, Vote, YesNoVote, VoteType, + withCreateProposal, withInsertTransaction, withSignOffProposal, withCastVote, + getTokenOwnerRecordAddress, getProposalTransactionAddress +} = require("@solana/spl-governance"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, nowStamp, toInstructionData } = require("./js_common"); + +async function main() { + const targetWallet = process.argv[3]; + const nftMintStr = process.argv[4]; + if (!targetWallet || !nftMintStr) throw new Error("Usage: node 02_propose_vote_mint_nft.js "); + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const realm = new PublicKey(cfg.REALM); const governance = new PublicKey(cfg.GOVERNANCE); + const governingMint = new PublicKey(cfg.GOVERNING_MINT); const govPid = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const nftMint = new PublicKey(nftMintStr); const target = new PublicKey(targetWallet); + const mainTor = await getTokenOwnerRecordAddress(govPid, realm, governingMint, main.publicKey); + const targetAta = getAssociatedTokenAddressSync(nftMint, target, false, TOKEN_2022_PROGRAM_ID); + const ataExists = (await conn.getAccountInfo(targetAta, "confirmed")) !== null; + if (!ataExists) throw new Error(`Target ATA not found. Create it first: ${targetAta.toBase58()}`); + + const ixCreate = []; + const proposal = await withCreateProposal(ixCreate, govPid, PROGRAM_VERSION_V3, realm, governance, mainTor, `Mint NFT to ${target.toBase58().slice(0,8)}`, "https://arweave.net/", governingMint, main.publicKey, undefined, VoteType.SINGLE_CHOICE, ["Approve"], true, main.publicKey); + const txCreate = await sendAndConfirmTransaction(conn, new Transaction().add(...ixCreate), [main], { commitment: "confirmed" }); + + const mintIx = [createMintToInstruction(nftMint, targetAta, governance, 1n, [], TOKEN_2022_PROGRAM_ID)]; + const insertData = mintIx.map(toInstructionData); + const ixInsert = []; + const proposalTx = await withInsertTransaction(ixInsert, govPid, PROGRAM_VERSION_V3, governance, proposal, mainTor, main.publicKey, 0, 0, 0, insertData, main.publicKey); + const txInsert = await sendAndConfirmTransaction(conn, new Transaction().add(...ixInsert), [main], { commitment: "confirmed" }); + + const ixSign = []; + withSignOffProposal(ixSign, govPid, PROGRAM_VERSION_V3, realm, governance, proposal, main.publicKey, undefined, mainTor); + const txSign = await sendAndConfirmTransaction(conn, new Transaction().add(...ixSign), [main], { commitment: "confirmed" }); + + const vote = Vote.fromYesNoVote(YesNoVote.Yes); + const ixVote1 = []; + await withCastVote(ixVote1, govPid, PROGRAM_VERSION_V3, realm, governance, proposal, mainTor, mainTor, main.publicKey, governingMint, vote, main.publicKey); + const txVote1 = await sendAndConfirmTransaction(conn, new Transaction().add(...ixVote1), [main], { commitment: "confirmed" }); + + const computedTx = await getProposalTransactionAddress(govPid, PROGRAM_VERSION_V3, proposal, 0, 0); + if (!computedTx.equals(proposalTx)) throw new Error("proposal tx mismatch"); + const runs = path.resolve(__dirname, cfg.RUNS_DIR || "./runs"); fs.mkdirSync(runs, { recursive: true }); + const report = { type: "mint_nft", realm: realm.toBase58(), governance: governance.toBase58(), proposal: proposal.toBase58(), proposalTransaction: proposalTx.toBase58(), nftMint: nftMint.toBase58(), targetWallet: target.toBase58(), targetAta: targetAta.toBase58(), txCreate, txInsert, txSign, txVote1 }; + const rp = path.join(runs, `${nowStamp()}_proposal_mint_${target.toBase58().slice(0,8)}.json`); + fs.writeFileSync(rp, JSON.stringify(report, null, 2)); + console.log("proposal mint created and voted"); + console.log("report:", rp); + console.log("execute command:"); + console.log(`node 03_execute_mint_nft.js ${resolveConfigPath(process.argv[2])} ${proposal.toBase58()} ${proposalTx.toBase58()} ${nftMint.toBase58()} ${target.toBase58()}`); +} +main().catch((e)=>{console.error(e?.message||e);process.exit(1);}); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/03_execute_mint_nft.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/03_execute_mint_nft.js new file mode 100644 index 0000000..093565e --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/03_execute_mint_nft.js @@ -0,0 +1,30 @@ +#!/usr/bin/env node +"use strict"; +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createMintToInstruction } = require("@solana/spl-token"); +const { PROGRAM_VERSION_V3, withExecuteTransaction } = require("@solana/spl-governance"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, toInstructionData } = require("./js_common"); +const path = require("path"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const proposal = new PublicKey(process.argv[3]); + const proposalTx = new PublicKey(process.argv[4]); + const nftMint = new PublicKey(process.argv[5]); + const target = new PublicKey(process.argv[6]); + if (!process.argv[6]) throw new Error("Usage: node 03_execute_mint_nft.js "); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const governance = new PublicKey(cfg.GOVERNANCE); const govPid = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const targetAta = getAssociatedTokenAddressSync(nftMint, target, false, TOKEN_2022_PROGRAM_ID); + const ataExists = (await conn.getAccountInfo(targetAta, "confirmed")) !== null; + if (!ataExists) throw new Error(`Target ATA not found. Create it first: ${targetAta.toBase58()}`); + const mintIx = [ + createMintToInstruction(nftMint, targetAta, governance, 1n, [], TOKEN_2022_PROGRAM_ID), + ].map(toInstructionData); + const ix = []; + await withExecuteTransaction(ix, govPid, PROGRAM_VERSION_V3, governance, proposal, proposalTx, mintIx); + const sig = await sendAndConfirmTransaction(conn, new Transaction().add(...ix), [main], { commitment: "confirmed" }); + console.log("execute mint done:", sig); +} +main().catch((e)=>{console.error(e?.message||e);process.exit(1);}); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/04_propose_vote_burn_nft.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/04_propose_vote_burn_nft.js new file mode 100644 index 0000000..f877ad9 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/04_propose_vote_burn_nft.js @@ -0,0 +1,53 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createBurnCheckedInstruction } = require("@solana/spl-token"); +const { + PROGRAM_VERSION_V3, Vote, YesNoVote, VoteType, + withCreateProposal, withInsertTransaction, withSignOffProposal, withCastVote, + getTokenOwnerRecordAddress +} = require("@solana/spl-governance"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, nowStamp, toInstructionData } = require("./js_common"); + +async function main() { + const targetWallet = process.argv[3]; + const nftMintStr = process.argv[4]; + if (!targetWallet || !nftMintStr) throw new Error("Usage: node 04_propose_vote_burn_nft.js "); + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const realm = new PublicKey(cfg.REALM); const governance = new PublicKey(cfg.GOVERNANCE); + const governingMint = new PublicKey(cfg.GOVERNING_MINT); const govPid = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const nftMint = new PublicKey(nftMintStr); const target = new PublicKey(targetWallet); + const mainTor = await getTokenOwnerRecordAddress(govPid, realm, governingMint, main.publicKey); + const sourceAta = getAssociatedTokenAddressSync(nftMint, target, false, TOKEN_2022_PROGRAM_ID); + + const ixCreate = []; + const proposal = await withCreateProposal(ixCreate, govPid, PROGRAM_VERSION_V3, realm, governance, mainTor, `Burn NFT ${nftMint.toBase58().slice(0,8)}`, "https://arweave.net/", governingMint, main.publicKey, undefined, VoteType.SINGLE_CHOICE, ["Approve"], true, main.publicKey); + const txCreate = await sendAndConfirmTransaction(conn, new Transaction().add(...ixCreate), [main], { commitment: "confirmed" }); + + const burnIx = [toInstructionData(createBurnCheckedInstruction(sourceAta, nftMint, governance, 1n, 0, [], TOKEN_2022_PROGRAM_ID))]; + const ixInsert = []; + const proposalTx = await withInsertTransaction(ixInsert, govPid, PROGRAM_VERSION_V3, governance, proposal, mainTor, main.publicKey, 0, 0, 0, burnIx, main.publicKey); + const txInsert = await sendAndConfirmTransaction(conn, new Transaction().add(...ixInsert), [main], { commitment: "confirmed" }); + + const ixSign = []; + withSignOffProposal(ixSign, govPid, PROGRAM_VERSION_V3, realm, governance, proposal, main.publicKey, undefined, mainTor); + const txSign = await sendAndConfirmTransaction(conn, new Transaction().add(...ixSign), [main], { commitment: "confirmed" }); + + const vote = Vote.fromYesNoVote(YesNoVote.Yes); + const ixVote1 = []; + await withCastVote(ixVote1, govPid, PROGRAM_VERSION_V3, realm, governance, proposal, mainTor, mainTor, main.publicKey, governingMint, vote, main.publicKey); + const txVote1 = await sendAndConfirmTransaction(conn, new Transaction().add(...ixVote1), [main], { commitment: "confirmed" }); + const runs = path.resolve(__dirname, cfg.RUNS_DIR || "./runs"); fs.mkdirSync(runs, { recursive: true }); + const report = { type: "burn_nft", realm: realm.toBase58(), governance: governance.toBase58(), proposal: proposal.toBase58(), proposalTransaction: proposalTx.toBase58(), nftMint: nftMint.toBase58(), targetWallet: target.toBase58(), sourceAta: sourceAta.toBase58(), txCreate, txInsert, txSign, txVote1 }; + const rp = path.join(runs, `${nowStamp()}_proposal_burn_${target.toBase58().slice(0,8)}.json`); + fs.writeFileSync(rp, JSON.stringify(report, null, 2)); + console.log("proposal burn created and voted"); + console.log("report:", rp); + console.log("execute command:"); + console.log(`node 05_execute_burn_nft.js ${resolveConfigPath(process.argv[2])} ${proposal.toBase58()} ${proposalTx.toBase58()} ${nftMint.toBase58()} ${target.toBase58()}`); +} +main().catch((e)=>{console.error(e?.message||e);process.exit(1);}); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/05_execute_burn_nft.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/05_execute_burn_nft.js new file mode 100644 index 0000000..e02b739 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/05_execute_burn_nft.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node +"use strict"; +const path = require("path"); +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createBurnCheckedInstruction } = require("@solana/spl-token"); +const { PROGRAM_VERSION_V3, withExecuteTransaction } = require("@solana/spl-governance"); +const { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, toInstructionData } = require("./js_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const proposal = new PublicKey(process.argv[3]); + const proposalTx = new PublicKey(process.argv[4]); + const nftMint = new PublicKey(process.argv[5]); + const target = new PublicKey(process.argv[6]); + if (!process.argv[6]) throw new Error("Usage: node 05_execute_burn_nft.js "); + const conn = new Connection(clusterUrl(cfg.CLUSTER), "confirmed"); + const main = loadKeypair(path.resolve(__dirname, cfg.MAIN_KEYPAIR)); + const governance = new PublicKey(cfg.GOVERNANCE); const govPid = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const sourceAta = getAssociatedTokenAddressSync(nftMint, target, false, TOKEN_2022_PROGRAM_ID); + const burnIx = [toInstructionData(createBurnCheckedInstruction(sourceAta, nftMint, governance, 1n, 0, [], TOKEN_2022_PROGRAM_ID))]; + const ix = []; + await withExecuteTransaction(ix, govPid, PROGRAM_VERSION_V3, governance, proposal, proposalTx, burnIx); + const sig = await sendAndConfirmTransaction(conn, new Transaction().add(...ix), [main], { commitment: "confirmed" }); + console.log("execute burn done:", sig); +} +main().catch((e)=>{console.error(e?.message||e);process.exit(1);}); diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/README.md b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/README.md new file mode 100644 index 0000000..0c101cd --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/README.md @@ -0,0 +1,66 @@ +# CreateGovernmentNFTAndDAO + +## RU + +Скрипты для Devnet, чтобы управлять NFT через DAO (Realms/SPL Governance): +1) создать предложение на выпуск NFT (`mint`) и выполнить его; +2) создать предложение на сжигание NFT (`burn`) и выполнить его. + +### Что лежит в папке + +- `config.env` — параметры кластера, DAO, ключей. +- `keypairs/` — ключи оператора и второго участника. +- `runs/` — отчёты запусков (proposal, tx и т.д.). +- `00_prepare_voter2_deposit.js` — депонирование governance-токена для второго голосующего. +- `01_create_nft_for_wallet_admin.js` — создать NFT на кошелёк и делегировать право governance PDA. +- `01b_create_empty_nft_template.js` — создать пустой NFT mint-шаблон (supply=0) для будущего DAO mint. +- `02_propose_vote_mint_nft.js` — создать+подписать+проголосовать за proposal на mint. +- `03_execute_mint_nft.js` — выполнить proposal mint. +- `04_propose_vote_burn_nft.js` — создать+подписать+проголосовать за proposal на burn. +- `05_execute_burn_nft.js` — выполнить proposal burn. + +### Важно перед запуском + +1. Нужен `node`, `@solana/web3.js`, `@solana/spl-token`, `@solana/spl-governance`. +2. В `config.env` должен быть корректный `REALM`, `GOVERNANCE`, `GOVERNING_MINT`, `MAIN_KEYPAIR`. +3. Для `mint via DAO` целевой ATA должен существовать заранее (скрипт `02` это проверяет). + +### Быстрый полный тест (mint + burn) + +1. Создать NFT-шаблон (куда DAO будет минтить): + - `node 01b_create_empty_nft_template.js ./config.env` +2. Создать ATA для целевого кошелька и этого mint (если ещё нет). +3. Поднять proposal на mint: + - `node 02_propose_vote_mint_nft.js ./config.env ` +4. Выполнить proposal (команду берёшь из консоли шага 3): + - `node 03_execute_mint_nft.js ./config.env ` +5. Создать NFT для burn-теста: + - `node 01_create_nft_for_wallet_admin.js ./config.env ` +6. Поднять proposal на burn: + - `node 04_propose_vote_burn_nft.js ./config.env ` +7. Выполнить proposal burn (команда из шага 6): + - `node 05_execute_burn_nft.js ./config.env ` + +### Как проверить результат + +Смотри JSON-отчёты в `runs/`: там есть `proposal`, `proposalTransaction`, tx подписи и mint/кошельки. + +Для проверки через час: +1) поднимаешь proposal (скрипт `02` или `04`); +2) ждёшь; +3) запускаешь соответствующий `execute` скрипт с параметрами из отчёта. + +### Проверка DAO + +В текущем `config.env`: +- Realm: `2DTh1ivaekAW8kRYzGPsL2taFLJFFkBjEwqPisebxsS7` +- Governance PDA: `EMZ8vmr1xB4HZBDCFL9rHB98m1C5cYrGnRA8ZHayyGwD` +- Governing mint: `F1KctLRvVzqwcBYNGsivnjR39gY8Uvq5U3uyaqEBNASg` + +## EN + +Devnet scripts for DAO-governed NFT flow (Realms/SPL Governance): +- propose/sign/vote/execute NFT mint to a wallet; +- propose/sign/vote/execute NFT burn from a wallet. + +Main idea: first script in each pair creates proposal and vote, second script executes proposal later. diff --git a/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/js_common.js b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/js_common.js new file mode 100644 index 0000000..7f572ea --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentNFTAndDAO/js_common.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const { PublicKey, Keypair, clusterApiUrl } = require("@solana/web3.js"); +const { InstructionData, AccountMetaData } = require("@solana/spl-governance"); + +function parseEnvConfig(configPath) { + const raw = fs.readFileSync(configPath, "utf8"); + const out = {}; + for (const line of raw.split("\n")) { + const t = line.trim(); + if (!t || t.startsWith("#")) continue; + const i = t.indexOf("="); + if (i < 0) continue; + const k = t.slice(0, i).trim(); + let v = t.slice(i + 1).trim(); + if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) v = v.slice(1, -1); + out[k] = v; + } + return out; +} + +function resolveConfigPath(argvPath) { + return argvPath ? path.resolve(argvPath) : path.resolve(__dirname, "config.env"); +} + +function loadKeypair(fp) { + return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(fs.readFileSync(fp, "utf8")))); +} + +function clusterUrl(cluster) { + if (cluster === "devnet" || cluster === "mainnet-beta" || cluster === "testnet") return clusterApiUrl(cluster); + return cluster; +} + +function nowStamp() { + const d = new Date(); const p = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}_${p(d.getHours())}-${p(d.getMinutes())}-${p(d.getSeconds())}`; +} + +function toInstructionData(ix) { + return new InstructionData({ + programId: ix.programId, + accounts: ix.keys.map((k) => new AccountMetaData({ pubkey: k.pubkey, isSigner: !!k.isSigner, isWritable: !!k.isWritable })), + data: Uint8Array.from(ix.data), + }); +} + +module.exports = { parseEnvConfig, resolveConfigPath, loadKeypair, clusterUrl, nowStamp, toInstructionData, PublicKey }; diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/01_create_governance_token.sh b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/01_create_governance_token.sh new file mode 100755 index 0000000..6cb9d12 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/01_create_governance_token.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# +# RU: Создает governance token (Token-2022, NonTransferable + PermanentDelegate) +# с настройками из governance_token.config.env. +# EN: Creates governance token (Token-2022, NonTransferable + PermanentDelegate) +# using settings from governance_token.config.env. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="$SCRIPT_DIR/governance_token.config.env" +node "$SCRIPT_DIR/js/01_create_governance_token_exec.js" "$CONFIG_PATH" diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/02_mint_token_to_wallet.sh b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/02_mint_token_to_wallet.sh new file mode 100755 index 0000000..087b100 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/02_mint_token_to_wallet.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -euo pipefail +# +# RU: Выпускает ровно 1 membership-токен на указанный кошелек. +# Если у кошелька уже есть >=1 токен, скрипт завершится ошибкой. +# EN: Mints exactly 1 membership token to the given wallet. +# If wallet already has >=1 token, script exits with error. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="$SCRIPT_DIR/governance_token.config.env" +WALLET="${1:-}" + +if [[ -z "$WALLET" ]]; then + echo "Использование:" + echo " $0 " + echo "Usage:" + echo " $0 " + exit 1 +fi + +node "$SCRIPT_DIR/js/02_mint_membership_to_wallet_exec.js" "$CONFIG_PATH" "$WALLET" diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/03_force_burn_from_wallet.sh b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/03_force_burn_from_wallet.sh new file mode 100755 index 0000000..b14cbfa --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/03_force_burn_from_wallet.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# +# RU: Принудительно сжигает 1 membership-токен на указанном кошельке. +# EN: Force-burns exactly 1 membership token from the given wallet. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="$SCRIPT_DIR/governance_token.config.env" +WALLET="${1:-}" + +if [[ -z "$WALLET" ]]; then + echo "Использование:" + echo " $0 " + echo "Usage:" + echo " $0 " + exit 1 +fi + +node "$SCRIPT_DIR/js/03_force_burn_from_wallet_exec.js" "$CONFIG_PATH" "$WALLET" diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/04_create_dao.sh b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/04_create_dao.sh new file mode 100755 index 0000000..c5f94b4 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/04_create_dao.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail +# +# RU: Создает DAO (Realm + Governance + Treasury) на уже существующем governance mint. +# EN: Creates DAO (Realm + Governance + Treasury) using existing governance mint. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="$SCRIPT_DIR/governance_token.config.env" + +node "$SCRIPT_DIR/js/05_create_dao_exec.js" "$CONFIG_PATH" diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/05_transfer_rights_to_governance_pda.sh b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/05_transfer_rights_to_governance_pda.sh new file mode 100755 index 0000000..63aea14 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/05_transfer_rights_to_governance_pda.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +# +# RU: Передает права Mint/Freeze/PermanentDelegate на Governance PDA из конфига. +# Перед отправкой транзакции внутри JS будет подтверждение "yes". +# EN: Transfers Mint/Freeze/PermanentDelegate authorities to Governance PDA +# from config. JS script asks for "yes" confirmation before sending. + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="$SCRIPT_DIR/governance_token.config.env" +node "$SCRIPT_DIR/js/04_transfer_rights_to_governance_pda_exec.js" "$CONFIG_PATH" diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/README.md b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/README.md new file mode 100644 index 0000000..e00732a --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/README.md @@ -0,0 +1,74 @@ +# CreateGovernmentTokenAndDAO + +## RU + +Единый набор скриптов для: +1. создания governance token, +2. выдачи/сжигания membership токенов, +3. передачи прав на Governance PDA, +4. создания DAO (Realm/Governance/Treasury). + +### Важная структура ключей + +Используются две папки: +- `keypairs/dao_creator/` — ключ инициатора DAO и плательщика (ровно 1 `*.json`). +- `keypairs/government_token/` — ключ mint governance token (ровно 1 `*.json`). + +Скрипты автоматически берут единственный файл из этих папок. +Если в папке `government_token` 0 файлов или больше 1 — скрипт завершится ошибкой. + +### Скрипты + +```bash +./01_create_governance_token.sh +./02_mint_token_to_wallet.sh +./03_force_burn_from_wallet.sh +./04_create_dao.sh +./05_transfer_rights_to_governance_pda.sh +./grind_vanity_mint.sh [PREFIX] [COUNT] [ignore-case] +``` + +### Базовый порядок + +1. (Опционально) `grind_vanity_mint.sh`, затем ОБЯЗАТЕЛЬНО скопировать выбранный json в `keypairs/government_token/`. + Пример: + ```bash + cp ./runs/.json ./keypairs/government_token/selected_mint.json + ``` +2. `01_create_governance_token.sh` +3. В `governance_token.config.env` указать `GT_MINT_ADDRESS`. +4. `02_mint_token_to_wallet.sh ` +5. `03_force_burn_from_wallet.sh ` +6. `04_create_dao.sh` +7. Внести полученный Governance PDA в `GT_GOVERNANCE_PDA`. +8. `05_transfer_rights_to_governance_pda.sh` + +--- + +## EN + +Unified scripts for: +1. governance token creation, +2. membership mint/burn, +3. authority transfer to Governance PDA, +4. DAO creation (Realm/Governance/Treasury). + +### Required keypair layout + +Two folders are used: +- `keypairs/dao_creator/` — DAO creator/payer keypair (exactly 1 `*.json`). +- `keypairs/government_token/` — governance token mint keypair (exactly 1 `*.json`). + +Scripts auto-detect the single file in each folder. +If `government_token` has 0 files or more than 1 file, script fails with error. + +### Scripts + +```bash +./01_create_governance_token.sh +./02_mint_token_to_wallet.sh +./03_force_burn_from_wallet.sh +./04_create_dao.sh +./05_transfer_rights_to_governance_pda.sh +./grind_vanity_mint.sh [PREFIX] [COUNT] [ignore-case] +``` diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/grind_vanity_mint.sh b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/grind_vanity_mint.sh new file mode 100755 index 0000000..b26c427 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/grind_vanity_mint.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +set -euo pipefail +# +# RU: Подбирает vanity mint keypair через `solana-keygen grind`. +# Параметры: [PREFIX] [COUNT] [ignore-case] +# EN: Finds vanity mint keypair using `solana-keygen grind`. +# Args: [PREFIX] [COUNT] [ignore-case] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="$SCRIPT_DIR/governance_token.config.env" +PREFIX="${1:-}" +COUNT="${2:-1}" +IGNORE_CASE="${3:-}" + +if [[ -n "$PREFIX" ]]; then + node "$SCRIPT_DIR/js/grind_vanity_mint_exec.js" "$CONFIG_PATH" "$PREFIX" "$COUNT" "$IGNORE_CASE" +else + node "$SCRIPT_DIR/js/grind_vanity_mint_exec.js" "$CONFIG_PATH" +fi diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/01_create_governance_token_exec.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/01_create_governance_token_exec.js new file mode 100644 index 0000000..2aba985 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/01_create_governance_token_exec.js @@ -0,0 +1,40 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const { Connection, SystemProgram, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_PROGRAM_ID, getMintLen, createInitializeMintInstruction } = require("@solana/spl-token"); +const { parseEnvConfig, assertRequired, resolveConfigPath, loadKeypair, findSingleJsonFile, saveKeypair, parseCluster, nowStamp, ui, getOperatorKeypairFromConfig } = require("./_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + assertRequired(cfg, "GT_CLUSTER"); assertRequired(cfg, "GT_RUNS_DIR"); + const operator = getOperatorKeypairFromConfig(cfg); + const connection = new Connection(parseCluster(cfg.GT_CLUSTER), "confirmed"); + const gtDir = path.resolve(cfg.GT_GOVERNMENT_TOKEN_KEYPAIR_DIR || path.join(__dirname, "..", "keypairs", "government_token")); + fs.mkdirSync(gtDir, { recursive: true }); + const mintKeypairPath = findSingleJsonFile(gtDir); + const mint = loadKeypair(mintKeypairPath); + const mintLen = getMintLen([]); + const rent = await connection.getMinimumBalanceForRentExemption(mintLen, "confirmed"); + ui.title("=== Создание governance token (SPL classic) / Create governance token (SPL classic) ==="); + const tx = new Transaction().add( + SystemProgram.createAccount({ fromPubkey: operator.publicKey, newAccountPubkey: mint.publicKey, space: mintLen, lamports: rent, programId: TOKEN_PROGRAM_ID }), + createInitializeMintInstruction(mint.publicKey, 0, operator.publicKey, operator.publicKey, TOKEN_PROGRAM_ID) + ); + const sig = await sendAndConfirmTransaction(connection, tx, [operator, mint], { commitment: "confirmed" }); + const runsDir = path.resolve(cfg.GT_RUNS_DIR); fs.mkdirSync(runsDir, { recursive: true }); + const outMintPath = mintKeypairPath; + saveKeypair(outMintPath, mint); + fs.writeFileSync(path.join(runsDir, `${nowStamp()}_create_token.json`), JSON.stringify({ mint: mint.publicKey.toBase58(), txCreateMint: sig }, null, 2)); + ui.ok(`OK: Mint ${mint.publicKey.toBase58()}`); + ui.info(`RU: Использован keypair: ${mintKeypairPath}`); + ui.info(`EN: Used keypair: ${mintKeypairPath}`); + ui.info(`RU: Вставьте этот mint в файл: ${path.resolve(__dirname, "..", "governance_token.config.env")}`); + ui.info(`RU: Строка: GT_MINT_ADDRESS="${mint.publicKey.toBase58()}"`); + ui.info(`EN: Put this mint into file: ${path.resolve(__dirname, "..", "governance_token.config.env")}`); + ui.info(`EN: Line: GT_MINT_ADDRESS="${mint.publicKey.toBase58()}"`); + ui.info(`Mint keypair: ${outMintPath}`); + ui.info(`Tx: ${sig}`); +} +main().catch((e) => { ui.err(`Ошибка / Error: ${e?.message || e}`); process.exit(1); }); diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/02_mint_membership_to_wallet_exec.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/02_mint_membership_to_wallet_exec.js new file mode 100644 index 0000000..a69ea3a --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/02_mint_membership_to_wallet_exec.js @@ -0,0 +1,34 @@ +#!/usr/bin/env node +"use strict"; +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createAssociatedTokenAccountIdempotentInstruction, createMintToInstruction, getAccount } = require("@solana/spl-token"); +const { parseEnvConfig, assertRequired, resolveConfigPath, parseCluster, ui, getMintPublicKeyFromConfig, getOperatorKeypairFromConfig } = require("./_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const receiver = new PublicKey(process.argv[3]); + if (!process.argv[3]) throw new Error("Использование / Usage: node .../02...js "); + assertRequired(cfg, "GT_CLUSTER"); + const mint = getMintPublicKeyFromConfig(cfg); + const operator = getOperatorKeypairFromConfig(cfg); + const connection = new Connection(parseCluster(cfg.GT_CLUSTER), "confirmed"); + const ata = getAssociatedTokenAddressSync(mint, receiver, false, TOKEN_2022_PROGRAM_ID); + const ataInfo = await connection.getAccountInfo(ata, "confirmed"); + if (ataInfo) { + const tokenAcc = await getAccount(connection, ata, "confirmed", TOKEN_2022_PROGRAM_ID); + if (tokenAcc.amount >= 1n) { + throw new Error( + `На кошельке уже есть membership token / Wallet already has membership token. wallet=${receiver.toBase58()} amount=${tokenAcc.amount.toString()}` + ); + } + } + const ix = [ + createAssociatedTokenAccountIdempotentInstruction(operator.publicKey, ata, receiver, mint, TOKEN_2022_PROGRAM_ID), + createMintToInstruction(mint, ata, operator.publicKey, 1n, [], TOKEN_2022_PROGRAM_ID), + ]; + ui.title("=== Выпуск 1 membership токена / Mint 1 membership token ==="); + const sig = await sendAndConfirmTransaction(connection, new Transaction().add(...ix), [operator], { commitment: "confirmed" }); + ui.ok("Успешно / Success"); + ui.info(`Mint: ${mint.toBase58()}`); ui.info(`Wallet: ${receiver.toBase58()}`); ui.info(`Tx: ${sig}`); +} +main().catch((e) => { ui.err(`Ошибка / Error: ${e?.message || e}`); process.exit(1); }); diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/03_force_burn_from_wallet_exec.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/03_force_burn_from_wallet_exec.js new file mode 100644 index 0000000..496afcd --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/03_force_burn_from_wallet_exec.js @@ -0,0 +1,22 @@ +#!/usr/bin/env node +"use strict"; +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, createBurnCheckedInstruction } = require("@solana/spl-token"); +const { parseEnvConfig, assertRequired, resolveConfigPath, parseCluster, ui, getMintPublicKeyFromConfig, getOperatorKeypairFromConfig } = require("./_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const targetOwner = new PublicKey(process.argv[3]); + if (!process.argv[3]) throw new Error("Использование / Usage: node .../03...js "); + assertRequired(cfg, "GT_CLUSTER"); + const mint = getMintPublicKeyFromConfig(cfg); + const operator = getOperatorKeypairFromConfig(cfg); + const connection = new Connection(parseCluster(cfg.GT_CLUSTER), "confirmed"); + const targetAta = getAssociatedTokenAddressSync(mint, targetOwner, false, TOKEN_2022_PROGRAM_ID); + const ix = createBurnCheckedInstruction(targetAta, mint, operator.publicKey, 1n, 0, [], TOKEN_2022_PROGRAM_ID); + ui.title("=== Принудительное сжигание 1 токена / Force burn 1 token ==="); + const sig = await sendAndConfirmTransaction(connection, new Transaction().add(ix), [operator], { commitment: "confirmed" }); + ui.ok("Успешно / Success"); + ui.info(`Mint: ${mint.toBase58()}`); ui.info(`Wallet: ${targetOwner.toBase58()}`); ui.info(`Tx: ${sig}`); +} +main().catch((e) => { ui.err(`Ошибка / Error: ${e?.message || e}`); process.exit(1); }); diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/04_transfer_rights_to_governance_pda_exec.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/04_transfer_rights_to_governance_pda_exec.js new file mode 100644 index 0000000..147a263 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/04_transfer_rights_to_governance_pda_exec.js @@ -0,0 +1,28 @@ +#!/usr/bin/env node +"use strict"; +const { Connection, PublicKey, Transaction, sendAndConfirmTransaction } = require("@solana/web3.js"); +const { TOKEN_2022_PROGRAM_ID, AuthorityType, createSetAuthorityInstruction } = require("@solana/spl-token"); +const { parseEnvConfig, assertRequired, resolveConfigPath, parseCluster, askYes, ui, getMintPublicKeyFromConfig, getOperatorKeypairFromConfig } = require("./_common"); + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + assertRequired(cfg, "GT_CLUSTER"); assertRequired(cfg, "GT_GOVERNANCE_PDA"); + const mint = getMintPublicKeyFromConfig(cfg); + const operator = getOperatorKeypairFromConfig(cfg); + const governancePda = new PublicKey(cfg.GT_GOVERNANCE_PDA); + const connection = new Connection(parseCluster(cfg.GT_CLUSTER), "confirmed"); + ui.title("=== Передача прав DAO / Transfer rights to DAO ==="); + ui.warn(`RU: Будут переданы права Mint/Freeze/PermanentDelegate от ${operator.publicKey.toBase58()} на ${governancePda.toBase58()}`); + ui.warn(`EN: Mint/Freeze/PermanentDelegate authorities will be transferred to governance PDA.`); + const ok = await askYes("Введите yes / Type yes to continue: "); + if (!ok) return ui.warn("Отменено / Cancelled"); + const ixs = [ + createSetAuthorityInstruction(mint, operator.publicKey, AuthorityType.MintTokens, governancePda, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint, operator.publicKey, AuthorityType.FreezeAccount, governancePda, [], TOKEN_2022_PROGRAM_ID), + createSetAuthorityInstruction(mint, operator.publicKey, AuthorityType.PermanentDelegate, governancePda, [], TOKEN_2022_PROGRAM_ID), + ]; + const sig = await sendAndConfirmTransaction(connection, new Transaction().add(...ixs), [operator], { commitment: "confirmed" }); + ui.ok("Успешно / Success"); + ui.info(`Mint: ${mint.toBase58()}`); ui.info(`DAO PDA: ${governancePda.toBase58()}`); ui.info(`Tx: ${sig}`); +} +main().catch((e) => { ui.err(`Ошибка / Error: ${e?.message || e}`); process.exit(1); }); diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/05_create_dao_exec.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/05_create_dao_exec.js new file mode 100644 index 0000000..c8ea748 --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/05_create_dao_exec.js @@ -0,0 +1,191 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const BN = require("bn.js"); +const { + Connection, + PublicKey, + Transaction, + sendAndConfirmTransaction, +} = require("@solana/web3.js"); +const { + getAssociatedTokenAddressSync, + TOKEN_2022_PROGRAM_ID, + TOKEN_PROGRAM_ID, +} = require("@solana/spl-token"); +const { + MintMaxVoteWeightSource, + VoteThreshold, + VoteThresholdType, + VoteTipping, + GovernanceConfig, + PROGRAM_VERSION_V3, + GoverningTokenConfigAccountArgs, + GoverningTokenType, + withCreateRealm, + withDepositGoverningTokens, + withCreateGovernance, + withCreateNativeTreasury, + withSetRealmAuthority, + SetRealmAuthorityAction, +} = require("@solana/spl-governance"); +const { parseEnvConfig, assertRequired, resolveConfigPath, parseCluster, nowStamp, getOperatorKeypairFromConfig, getMintPublicKeyFromConfig, ui } = require("./_common"); + +async function main() { + const configPath = resolveConfigPath(process.argv[2]); + const cfg = parseEnvConfig(configPath); + [ + "GT_CLUSTER", "DAO_REALM_NAME", "SPL_GOVERNANCE_PROGRAM_ID", "DAO_VOTING_TIME_SEC", "DAO_APPROVAL_THRESHOLD_PERCENT" + ].forEach((k) => assertRequired(cfg, k)); + + const cluster = cfg.GT_CLUSTER; + const connection = new Connection(parseCluster(cluster), "confirmed"); + const operator = getOperatorKeypairFromConfig(cfg); + const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const mint = getMintPublicKeyFromConfig(cfg); + const votingTimeSec = Number(cfg.DAO_VOTING_TIME_SEC); + const thresholdPct = Number(cfg.DAO_APPROVAL_THRESHOLD_PERCENT); + const runsDir = path.resolve(cfg.DAO_RUNS_DIR || path.join(__dirname, "runs")); + fs.mkdirSync(runsDir, { recursive: true }); + + const mintAi = await connection.getAccountInfo(mint, "confirmed"); + if (!mintAi) throw new Error(`Governing mint not found: ${mint.toBase58()}`); + if (!mintAi.owner.equals(TOKEN_PROGRAM_ID)) { + throw new Error( + `Этот CreateDAO ожидает governing mint под классическим SPL Token (${TOKEN_PROGRAM_ID.toBase58()}). ` + + `Текущий mint owner: ${mintAi.owner.toBase58()}` + ); + } + + const [realmPda] = PublicKey.findProgramAddressSync( + [Buffer.from("governance"), Buffer.from(cfg.DAO_REALM_NAME, "utf8")], + governanceProgramId + ); + const realmExists = (await connection.getAccountInfo(realmPda)) !== null; + if (realmExists) throw new Error(`Realm already exists: ${realmPda.toBase58()}`); + + const ownerAtaToken2022 = getAssociatedTokenAddressSync(mint, operator.publicKey, false, TOKEN_2022_PROGRAM_ID); + const ownerAtaToken = getAssociatedTokenAddressSync(mint, operator.publicKey, false, TOKEN_PROGRAM_ID); + let ownerAta = ownerAtaToken2022; + let ownerAtaInfo = await connection.getAccountInfo(ownerAtaToken2022, "confirmed"); + let tokenProgramId = TOKEN_2022_PROGRAM_ID; + if (!ownerAtaInfo) { + ownerAta = ownerAtaToken; + ownerAtaInfo = await connection.getAccountInfo(ownerAtaToken, "confirmed"); + tokenProgramId = TOKEN_PROGRAM_ID; + } + if (!ownerAtaInfo) throw new Error("Operator ATA for governing mint not found. Mint at least 1 token to operator first."); + + const programVersion = PROGRAM_VERSION_V3; + const ixRealm = []; + const communityTokenConfig = new GoverningTokenConfigAccountArgs({ + voterWeightAddin: undefined, + maxVoterWeightAddin: undefined, + tokenType: GoverningTokenType.Membership, + }); + const realmPk = await withCreateRealm( + ixRealm, + governanceProgramId, + programVersion, + cfg.DAO_REALM_NAME, + operator.publicKey, + mint, + operator.publicKey, + undefined, + MintMaxVoteWeightSource.FULL_SUPPLY_FRACTION, + new BN(1), + communityTokenConfig, + undefined + ); + const sigRealm = await sendAndConfirmTransaction(connection, new Transaction().add(...ixRealm), [operator], { commitment: "confirmed" }); + + const ixDeposit = []; + const tokenOwnerRecordPk = await withDepositGoverningTokens( + ixDeposit, + governanceProgramId, + programVersion, + realmPk, + ownerAta, + mint, + operator.publicKey, + operator.publicKey, + operator.publicKey, + new BN(1), + true, + tokenProgramId + ); + const sigDeposit = await sendAndConfirmTransaction(connection, new Transaction().add(...ixDeposit), [operator], { commitment: "confirmed" }); + + const governanceConfig = new GovernanceConfig({ + communityVoteThreshold: new VoteThreshold({ type: VoteThresholdType.YesVotePercentage, value: thresholdPct }), + minCommunityTokensToCreateProposal: new BN(1), + minInstructionHoldUpTime: 0, + baseVotingTime: votingTimeSec, + communityVoteTipping: VoteTipping.Early, + minCouncilTokensToCreateProposal: new BN(0), + councilVoteThreshold: new VoteThreshold({ type: VoteThresholdType.Disabled }), + councilVetoVoteThreshold: new VoteThreshold({ type: VoteThresholdType.Disabled }), + communityVetoVoteThreshold: new VoteThreshold({ type: VoteThresholdType.Disabled }), + councilVoteTipping: VoteTipping.Disabled, + votingCoolOffTime: 0, + depositExemptProposalCount: 0, + }); + const ixGov = []; + const governancePk = await withCreateGovernance( + ixGov, + governanceProgramId, + programVersion, + realmPk, + realmPk, + governanceConfig, + tokenOwnerRecordPk, + operator.publicKey, + operator.publicKey + ); + const treasuryPk = await withCreateNativeTreasury(ixGov, governanceProgramId, programVersion, governancePk, operator.publicKey); + const sigGov = await sendAndConfirmTransaction(connection, new Transaction().add(...ixGov), [operator], { commitment: "confirmed" }); + + const ixRealmAuthority = []; + withSetRealmAuthority( + ixRealmAuthority, + governanceProgramId, + programVersion, + realmPk, + operator.publicKey, + governancePk, + SetRealmAuthorityAction.SetChecked + ); + const sigSetRealmAuthority = await sendAndConfirmTransaction(connection, new Transaction().add(...ixRealmAuthority), [operator], { commitment: "confirmed" }); + + const report = { + createdAt: new Date().toISOString(), + cluster, + realmName: cfg.DAO_REALM_NAME, + governanceProgramId: governanceProgramId.toBase58(), + governingMint: mint.toBase58(), + operator: operator.publicKey.toBase58(), + realm: realmPk.toBase58(), + governance: governancePk.toBase58(), + nativeTreasury: treasuryPk.toBase58(), + tokenOwnerRecord: tokenOwnerRecordPk.toBase58(), + txRealm: sigRealm, + txDeposit: sigDeposit, + txGovernanceTreasury: sigGov, + txSetRealmAuthority: sigSetRealmAuthority, + }; + const reportPath = path.join(runsDir, `${nowStamp()}_create_dao.json`); + fs.writeFileSync(reportPath, JSON.stringify(report, null, 2)); + + ui.ok("DAO created successfully / DAO успешно создан"); + ui.info(`Realm: ${realmPk.toBase58()}`); + ui.info(`Governance PDA: ${governancePk.toBase58()}`); + ui.info(`Treasury: ${treasuryPk.toBase58()}`); + ui.info(`Report: ${reportPath}`); +} + +main().catch((e) => { + console.error("CreateDAO error:", e?.message || e); + process.exit(1); +}); diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/_common.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/_common.js new file mode 100644 index 0000000..86e74ed --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/_common.js @@ -0,0 +1,118 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const readline = require("readline"); +const { Keypair, PublicKey, clusterApiUrl } = require("@solana/web3.js"); + +function parseEnvConfig(configPath) { + const raw = fs.readFileSync(configPath, "utf8"); + const out = {}; + for (const line of raw.split("\n")) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq === -1) continue; + const key = trimmed.slice(0, eq).trim(); + let val = trimmed.slice(eq + 1).trim(); + if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) val = val.slice(1, -1); + val = val.replace(/\$HOME/g, process.env.HOME || ""); + out[key] = val; + } + return out; +} + +function assertRequired(cfg, key) { + if (!cfg[key]) throw new Error(`В конфиге отсутствует обязательный параметр / Missing config key: ${key}`); +} + +function resolveConfigPath(argvPath) { + return argvPath ? path.resolve(argvPath) : path.resolve(__dirname, "..", "governance_token.config.env"); +} + +function loadKeypair(filePath) { + const arr = JSON.parse(fs.readFileSync(filePath, "utf8")); + return Keypair.fromSecretKey(Uint8Array.from(arr)); +} + +function findSingleJsonFile(dirPath) { + const abs = path.resolve(dirPath); + if (!fs.existsSync(abs)) throw new Error(`Папка не найдена / Directory not found: ${abs}`); + const files = fs.readdirSync(abs).filter((f) => { + const p = path.join(abs, f); + return fs.statSync(p).isFile() && f.endsWith(".json"); + }); + if (files.length !== 1) { + throw new Error(`В папке должен быть ровно 1 json-файл / Directory must contain exactly 1 json file: ${abs}. Сейчас: ${files.length}`); + } + return path.join(abs, files[0]); +} + +function saveKeypair(filePath, keypair) { + fs.mkdirSync(path.dirname(filePath), { recursive: true }); + fs.writeFileSync(filePath, JSON.stringify(Array.from(keypair.secretKey))); +} + +function parseCluster(cluster) { + if (cluster === "devnet" || cluster === "mainnet-beta" || cluster === "testnet") return clusterApiUrl(cluster); + return cluster; +} + +function nowStamp() { + const d = new Date(); + const p = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}_${p(d.getHours())}-${p(d.getMinutes())}-${p(d.getSeconds())}`; +} + +async function askYes(prompt) { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + const answer = await new Promise((resolve) => rl.question(prompt, resolve)); + rl.close(); + return answer.trim() === "yes"; +} + +function colors(s, code) { return `\x1b[${code}m${s}\x1b[0m`; } +const ui = { + info: (s) => console.log(colors(s, "36")), + ok: (s) => console.log(colors(s, "32")), + warn: (s) => console.log(colors(s, "33")), + err: (s) => console.log(colors(s, "31")), + title: (s) => console.log(colors(s, "1;35")), +}; + +function getMintPublicKeyFromConfig(cfg) { + if (cfg.GT_MINT_ADDRESS && cfg.GT_MINT_ADDRESS.trim()) return new PublicKey(cfg.GT_MINT_ADDRESS.trim()); + if (cfg.GT_GOVERNMENT_TOKEN_KEYPAIR_DIR && cfg.GT_GOVERNMENT_TOKEN_KEYPAIR_DIR.trim()) { + const kpPath = findSingleJsonFile(path.resolve(cfg.GT_GOVERNMENT_TOKEN_KEYPAIR_DIR)); + return loadKeypair(kpPath).publicKey; + } + if (cfg.GT_MINT_KEYPAIR_PATH && cfg.GT_MINT_KEYPAIR_PATH.trim()) return loadKeypair(path.resolve(cfg.GT_MINT_KEYPAIR_PATH)).publicKey; + throw new Error("Не задан mint: укажите GT_MINT_ADDRESS или положите 1 keypair в GT_GOVERNMENT_TOKEN_KEYPAIR_DIR"); +} + +function getOperatorKeypairFromConfig(cfg) { + if (cfg.GT_DAO_CREATOR_KEYPAIR_DIR && cfg.GT_DAO_CREATOR_KEYPAIR_DIR.trim()) { + const kpPath = findSingleJsonFile(path.resolve(cfg.GT_DAO_CREATOR_KEYPAIR_DIR)); + return loadKeypair(kpPath); + } + if (cfg.GT_OPERATOR_KEYPAIR_PATH && cfg.GT_OPERATOR_KEYPAIR_PATH.trim()) { + return loadKeypair(path.resolve(cfg.GT_OPERATOR_KEYPAIR_PATH)); + } + throw new Error("Не задан ключ оператора: укажите GT_DAO_CREATOR_KEYPAIR_DIR или GT_OPERATOR_KEYPAIR_PATH"); +} + +module.exports = { + parseEnvConfig, + assertRequired, + resolveConfigPath, + loadKeypair, + findSingleJsonFile, + saveKeypair, + parseCluster, + nowStamp, + askYes, + ui, + getMintPublicKeyFromConfig, + getOperatorKeypairFromConfig, +}; diff --git a/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/grind_vanity_mint_exec.js b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/grind_vanity_mint_exec.js new file mode 100644 index 0000000..20d44ae --- /dev/null +++ b/shine-solana/shine/scripts/CreateGovernmentTokenAndDAO/js/grind_vanity_mint_exec.js @@ -0,0 +1,36 @@ +#!/usr/bin/env node +"use strict"; +const fs = require("fs"); +const path = require("path"); +const { spawn } = require("child_process"); +const { parseEnvConfig, resolveConfigPath, nowStamp, ui } = require("./_common"); +const DEFAULT_PREFIX = "SHi"; + +async function main() { + const cfg = parseEnvConfig(resolveConfigPath(process.argv[2])); + const runsDir = path.resolve(cfg.GT_RUNS_DIR || path.join(__dirname, "..", "runs")); + fs.mkdirSync(runsDir, { recursive: true }); + const prefix = process.argv[3] || cfg.GT_VANITY_PREFIX || DEFAULT_PREFIX; + if (!/^[1-9A-HJ-NP-Za-km-z]+$/.test(prefix)) throw new Error("Префикс Base58 без 0/O/I/l"); + ui.title("=== Vanity подбор mint keypair / Vanity mint keypair grind ==="); + ui.info(`Prefix: ${prefix}`); + const args = ["grind", "--starts-with", `${prefix}:1`]; + const p = spawn("solana-keygen", args, { cwd: runsDir, stdio: ["ignore", "pipe", "pipe"] }); + const lines = []; + const on = (d) => { + for (const l of String(d).split("\n")) { + const line = l.trim(); if (!line) continue; + lines.push(line); console.log(line); + } + }; + p.stdout.on("data", on); p.stderr.on("data", on); + const code = await new Promise((resolve) => p.on("close", resolve)); + if (code !== 0) throw new Error(`solana-keygen grind exit code ${code}`); + const rp = path.join(runsDir, `${nowStamp()}_vanity_grind_report.json`); + fs.writeFileSync(rp, JSON.stringify({ createdAt: new Date().toISOString(), prefix, command: `solana-keygen ${args.join(" ")}`, outputLog: lines }, null, 2)); + ui.ok("Готово / Done"); + ui.info(`Report: ${rp}`); + ui.info(`RU: Скопируйте выбранный keypair из runs в keypairs/government_token/ (один json-файл).`); + ui.info(`EN: Copy selected keypair from runs to keypairs/government_token/ (single json file).`); +} +main().catch((e) => { ui.err(`Ошибка / Error: ${e?.message || e}`); process.exit(1); }); diff --git a/shine-solana/shine/scripts/dao/README.md b/shine-solana/shine/scripts/dao/README.md new file mode 100644 index 0000000..454fb9a --- /dev/null +++ b/shine-solana/shine/scripts/dao/README.md @@ -0,0 +1,60 @@ +# DAO scripts (актуальные) + +## 1) Проверка конфигурации + +```bash +scripts/dao/create_realm_dao_full_test.sh scripts/dao/dao.config.env +``` + +## 2) Реальное создание FULL DAO + +```bash +node scripts/dao/create_realm_dao_full_build_exec.js scripts/dao/dao.config.env +``` + +Что делает: + +1. Создает governance mint (SPL, decimals=0, supply из конфига). +2. Добавляет on-chain metadata для mint (URI и картинка из Arweave). +3. Создает Realm / Governance / Native Treasury. +4. Депозитит governance токены в Realm. +5. Пишет отчеты в `scripts/dao/runs/*.json` и `*.txt`. + +## 3) Revoke/Burn membership токенов + +### Вариант A (рекомендуется): через DAO голосование + +```bash +node scripts/dao/propose_vote_execute_revoke_full_exec.js \ + scripts/dao/dao.config.env \ + \ + \ + \ + \ + [AMOUNT] +``` + +Скрипт делает полный цикл: + +1. `create proposal` +2. `insert revoke instruction` +3. `sign off` +4. `cast vote` +5. `execute` + +### Вариант B (технический/админский): прямой revoke + +```bash +node scripts/dao/revoke_member_token_full_exec.js \ + scripts/dao/dao.config.env \ + \ + \ + \ + [AMOUNT] +``` + +Важное: + +1. Для `RevokeGoverningTokens` токен должен быть membership-типом (в full-скрипте это уже так). +2. Для сценария “только DAO голосованием” используйте вариант A. +3. Вариант B оставлен как технический инструмент. diff --git a/shine-solana/shine/scripts/dao/create_realm_dao_full_build_exec.js b/shine-solana/shine/scripts/dao/create_realm_dao_full_build_exec.js new file mode 100755 index 0000000..eae52e2 --- /dev/null +++ b/shine-solana/shine/scripts/dao/create_realm_dao_full_build_exec.js @@ -0,0 +1,456 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const readline = require("readline"); +const BN = require("bn.js"); +const { + Connection, + Keypair, + PublicKey, + SystemProgram, + Transaction, + sendAndConfirmTransaction, + clusterApiUrl, +} = require("@solana/web3.js"); +const { + TOKEN_PROGRAM_ID, + AuthorityType, + getMintLen, + createInitializeMintInstruction, + getAssociatedTokenAddressSync, + createAssociatedTokenAccountIdempotentInstruction, + createMintToInstruction, + createSetAuthorityInstruction, +} = require("@solana/spl-token"); +const { + MintMaxVoteWeightSource, + VoteThreshold, + VoteThresholdType, + VoteTipping, + GovernanceConfig, + PROGRAM_VERSION_V3, + GoverningTokenConfigAccountArgs, + GoverningTokenType, + withCreateRealm, + withDepositGoverningTokens, + withCreateGovernance, + withCreateNativeTreasury, + withSetRealmAuthority, + SetRealmAuthorityAction, +} = require("@solana/spl-governance"); +const { createUmi } = require("@metaplex-foundation/umi-bundle-defaults"); +const { + createSignerFromKeypair, + signerIdentity, + percentAmount, + none, + some, +} = require("@metaplex-foundation/umi"); +const { fromWeb3JsKeypair, fromWeb3JsPublicKey } = require("@metaplex-foundation/umi-web3js-adapters"); +const { mplTokenMetadata, createV1, TokenStandard } = require("@metaplex-foundation/mpl-token-metadata"); + +function parseEnvConfig(configPath) { + const raw = fs.readFileSync(configPath, "utf8"); + const out = {}; + for (const line of raw.split("\n")) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq === -1) continue; + const key = trimmed.slice(0, eq).trim(); + let val = trimmed.slice(eq + 1).trim(); + if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) { + val = val.slice(1, -1); + } + val = val.replace(/\$HOME/g, process.env.HOME || ""); + out[key] = val; + } + return out; +} + +function assertRequired(cfg, key) { + if (!cfg[key]) throw new Error(`В конфиге отсутствует обязательный параметр: ${key}`); +} + +function loadKeypair(filePath) { + const arr = JSON.parse(fs.readFileSync(filePath, "utf8")); + return Keypair.fromSecretKey(Uint8Array.from(arr)); +} + +function lamportsToSol(lamports) { + return Number(lamports) / 1_000_000_000; +} + +function nowStamp() { + const d = new Date(); + const p = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}_${p(d.getHours())}-${p( + d.getMinutes() + )}-${p(d.getSeconds())}`; +} + +async function askYes() { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + const answer = await new Promise((resolve) => + rl.question("Введите YES для реального создания ПОЛНОГО DAO: ", resolve) + ); + rl.close(); + return answer.trim() === "YES"; +} + +function ensureArweaveUri(name, uri) { + if (!uri) throw new Error(`${name} пустой`); + if (!(uri.startsWith("https://arweave.net/") || uri.startsWith("ar://"))) { + throw new Error(`${name} должен указывать на Arweave (https://arweave.net/... или ar://...)`); + } +} + +async function attachTokenMetadataViaUmi(cfg, cluster, issuer, mintPubkey, mintKeypair) { + ensureArweaveUri("DAO_GOV_TOKEN_METADATA_URI", cfg.DAO_GOV_TOKEN_METADATA_URI); + ensureArweaveUri("DAO_GOV_TOKEN_IMAGE_URL", cfg.DAO_GOV_TOKEN_IMAGE_URL); + + const umi = createUmi(clusterApiUrl(cluster)); + const umiSigner = createSignerFromKeypair(umi, fromWeb3JsKeypair(issuer)); + const umiMintSigner = createSignerFromKeypair(umi, fromWeb3JsKeypair(mintKeypair)); + umi.use(signerIdentity(umiSigner)); + umi.use(mplTokenMetadata()); + + const builder = createV1(umi, { + mint: umiMintSigner, + authority: umiSigner, + payer: umiSigner, + updateAuthority: umiSigner, + name: cfg.DAO_GOV_NFT_NAME, + symbol: cfg.DAO_GOV_NFT_SYMBOL, + uri: cfg.DAO_GOV_TOKEN_METADATA_URI, + sellerFeeBasisPoints: percentAmount(0), + tokenStandard: TokenStandard.Fungible, + decimals: some(0), + creators: none(), + collection: none(), + uses: none(), + collectionDetails: none(), + ruleSet: none(), + printSupply: none(), + primarySaleHappened: false, + isMutable: true, + isCollection: false, + splTokenProgram: fromWeb3JsPublicKey(TOKEN_PROGRAM_ID), + }); + + const res = await builder.sendAndConfirm(umi); + const sig = Buffer.from(res.signature).toString("base64"); + return sig; +} + +async function main() { + const configPath = process.argv[2] + ? path.resolve(process.argv[2]) + : path.resolve(__dirname, "dao.config.env"); + if (!fs.existsSync(configPath)) throw new Error(`Конфиг не найден: ${configPath}`); + + const cfg = parseEnvConfig(configPath); + [ + "DAO_CLUSTER", + "DAO_REALM_NAME", + "DAO_GOV_NFT_NAME", + "DAO_GOV_NFT_SYMBOL", + "DAO_GOV_NFT_SUPPLY", + "DAO_VOTING_TIME_SEC", + "DAO_APPROVAL_THRESHOLD_PERCENT", + "DAO_ISSUER_KEYPAIR", + "SPL_GOVERNANCE_PROGRAM_ID", + "DAO_GOV_TOKEN_METADATA_URI", + "DAO_GOV_TOKEN_IMAGE_URL", + ].forEach((k) => assertRequired(cfg, k)); + + const cluster = cfg.DAO_CLUSTER; + const connection = new Connection(clusterApiUrl(cluster), "confirmed"); + const issuer = loadKeypair(path.resolve(cfg.DAO_ISSUER_KEYPAIR)); + const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + + const supply = Number(cfg.DAO_GOV_NFT_SUPPLY); + const votingTimeSec = Number(cfg.DAO_VOTING_TIME_SEC); + const thresholdPct = Number(cfg.DAO_APPROVAL_THRESHOLD_PERCENT); + if (!Number.isInteger(supply) || supply <= 0) throw new Error("DAO_GOV_NFT_SUPPLY должен быть целым > 0"); + if (!Number.isInteger(votingTimeSec) || votingTimeSec < 3600) + throw new Error("DAO_VOTING_TIME_SEC должен быть >= 3600 (ограничение Realms)"); + if (!Number.isInteger(thresholdPct) || thresholdPct < 51 || thresholdPct > 100) + throw new Error("DAO_APPROVAL_THRESHOLD_PERCENT должен быть в диапазоне 51..100"); + + const [realmPda] = PublicKey.findProgramAddressSync( + [Buffer.from("governance"), Buffer.from(cfg.DAO_REALM_NAME, "utf8")], + governanceProgramId + ); + const realmExists = (await connection.getAccountInfo(realmPda)) !== null; + if (realmExists) throw new Error(`Realm уже существует: ${realmPda.toBase58()}`); + + const startBalance = await connection.getBalance(issuer.publicKey, "confirmed"); + console.log("============================================================"); + console.log("СОЗДАНИЕ DAO (FULL)"); + console.log("------------------------------------------------------------"); + console.log("Сеть: ", cluster); + console.log("Realm name: ", cfg.DAO_REALM_NAME); + console.log("Realm PDA: ", realmPda.toBase58()); + console.log("Governance program: ", governanceProgramId.toBase58()); + console.log("Issuer: ", issuer.publicKey.toBase58()); + console.log("Баланс до старта: ", `${lamportsToSol(startBalance)} SOL`); + console.log("Token name/symbol: ", `${cfg.DAO_GOV_NFT_NAME} / ${cfg.DAO_GOV_NFT_SYMBOL}`); + console.log("Token supply: ", supply); + console.log("Voting time sec: ", votingTimeSec); + console.log("Threshold %: ", thresholdPct); + console.log("Arweave metadata URI:", cfg.DAO_GOV_TOKEN_METADATA_URI); + console.log("Arweave image URL: ", cfg.DAO_GOV_TOKEN_IMAGE_URL); + console.log("============================================================"); + + const ok = await askYes(); + if (!ok) { + console.log("Отменено пользователем."); + return; + } + + const mintKeypair = Keypair.generate(); + const mintLen = getMintLen([]); + const mintRent = await connection.getMinimumBalanceForRentExemption(mintLen); + const issuerAta = getAssociatedTokenAddressSync(mintKeypair.publicKey, issuer.publicKey, false, TOKEN_PROGRAM_ID); + + const txMint = new Transaction().add( + SystemProgram.createAccount({ + fromPubkey: issuer.publicKey, + newAccountPubkey: mintKeypair.publicKey, + space: mintLen, + lamports: mintRent, + programId: TOKEN_PROGRAM_ID, + }), + createInitializeMintInstruction(mintKeypair.publicKey, 0, issuer.publicKey, issuer.publicKey, TOKEN_PROGRAM_ID), + createAssociatedTokenAccountIdempotentInstruction( + issuer.publicKey, + issuerAta, + issuer.publicKey, + mintKeypair.publicKey, + TOKEN_PROGRAM_ID + ), + createMintToInstruction(mintKeypair.publicKey, issuerAta, issuer.publicKey, supply, [], TOKEN_PROGRAM_ID) + ); + const sigMint = await sendAndConfirmTransaction(connection, txMint, [issuer, mintKeypair], { + commitment: "confirmed", + }); + + const sigMetadata = await attachTokenMetadataViaUmi( + cfg, + cluster, + issuer, + mintKeypair.publicKey, + mintKeypair + ); + + const programVersion = PROGRAM_VERSION_V3; + const ixRealm = []; + const communityTokenConfig = new GoverningTokenConfigAccountArgs({ + voterWeightAddin: undefined, + maxVoterWeightAddin: undefined, + tokenType: GoverningTokenType.Membership, + }); + const realmPk = await withCreateRealm( + ixRealm, + governanceProgramId, + programVersion, + cfg.DAO_REALM_NAME, + issuer.publicKey, + mintKeypair.publicKey, + issuer.publicKey, + undefined, + MintMaxVoteWeightSource.FULL_SUPPLY_FRACTION, + new BN(1), + communityTokenConfig, + undefined + ); + const sigRealm = await sendAndConfirmTransaction(connection, new Transaction().add(...ixRealm), [issuer], { + commitment: "confirmed", + }); + + const ixDeposit = []; + const tokenOwnerRecordPk = await withDepositGoverningTokens( + ixDeposit, + governanceProgramId, + programVersion, + realmPk, + issuerAta, + mintKeypair.publicKey, + issuer.publicKey, + issuer.publicKey, + issuer.publicKey, + new BN(supply), + true + ); + const sigDeposit = await sendAndConfirmTransaction(connection, new Transaction().add(...ixDeposit), [issuer], { + commitment: "confirmed", + }); + + const governanceConfig = new GovernanceConfig({ + communityVoteThreshold: new VoteThreshold({ type: VoteThresholdType.YesVotePercentage, value: thresholdPct }), + minCommunityTokensToCreateProposal: new BN(1), + minInstructionHoldUpTime: 0, + baseVotingTime: votingTimeSec, + communityVoteTipping: VoteTipping.Early, + minCouncilTokensToCreateProposal: new BN(0), + councilVoteThreshold: new VoteThreshold({ type: VoteThresholdType.Disabled }), + councilVetoVoteThreshold: new VoteThreshold({ type: VoteThresholdType.Disabled }), + communityVetoVoteThreshold: new VoteThreshold({ type: VoteThresholdType.Disabled }), + councilVoteTipping: VoteTipping.Disabled, + votingCoolOffTime: 0, + depositExemptProposalCount: 0, + }); + + const ixGov = []; + const governancePk = await withCreateGovernance( + ixGov, + governanceProgramId, + programVersion, + realmPk, + realmPk, + governanceConfig, + tokenOwnerRecordPk, + issuer.publicKey, + issuer.publicKey + ); + const treasuryPk = await withCreateNativeTreasury(ixGov, governanceProgramId, programVersion, governancePk, issuer.publicKey); + const sigGov = await sendAndConfirmTransaction(connection, new Transaction().add(...ixGov), [issuer], { + commitment: "confirmed", + }); + + // Для DAO revoke governing tokens mint authority должен быть у governance PDA. + const ixSetMintAuthority = [ + createSetAuthorityInstruction( + mintKeypair.publicKey, + issuer.publicKey, + AuthorityType.MintTokens, + governancePk, + [], + TOKEN_PROGRAM_ID + ), + ]; + const sigSetMintAuthority = await sendAndConfirmTransaction( + connection, + new Transaction().add(...ixSetMintAuthority), + [issuer], + { commitment: "confirmed" } + ); + + const ixRealmAuthority = []; + withSetRealmAuthority( + ixRealmAuthority, + governanceProgramId, + programVersion, + realmPk, + issuer.publicKey, + governancePk, + SetRealmAuthorityAction.SetChecked + ); + const sigSetRealmAuthority = await sendAndConfirmTransaction( + connection, + new Transaction().add(...ixRealmAuthority), + [issuer], + { commitment: "confirmed" } + ); + + const endBalance = await connection.getBalance(issuer.publicKey, "confirmed"); + const spentLamports = startBalance - endBalance; + const report = { + createdAt: new Date().toISOString(), + cluster, + configPath, + realmName: cfg.DAO_REALM_NAME, + governanceProgramId: governanceProgramId.toBase58(), + issuer: issuer.publicKey.toBase58(), + communityMint: mintKeypair.publicKey.toBase58(), + issuerAta: issuerAta.toBase58(), + realm: realmPk.toBase58(), + tokenOwnerRecord: tokenOwnerRecordPk.toBase58(), + governance: governancePk.toBase58(), + nativeTreasury: treasuryPk.toBase58(), + metadataUri: cfg.DAO_GOV_TOKEN_METADATA_URI, + imageUrl: cfg.DAO_GOV_TOKEN_IMAGE_URL, + txMint: sigMint, + txMetadata: sigMetadata, + txRealm: sigRealm, + txDeposit: sigDeposit, + txGovernanceTreasury: sigGov, + txSetMintAuthorityToGovernance: sigSetMintAuthority, + txSetRealmAuthority: sigSetRealmAuthority, + votingTimeSec, + thresholdPercent: thresholdPct, + tokenSupply: supply, + startBalanceLamports: startBalance, + endBalanceLamports: endBalance, + spentLamports, + startBalanceSol: lamportsToSol(startBalance), + endBalanceSol: lamportsToSol(endBalance), + spentSol: lamportsToSol(spentLamports), + }; + const reportDir = path.resolve(__dirname, "runs"); + fs.mkdirSync(reportDir, { recursive: true }); + const reportBaseName = `${nowStamp()}_${cfg.DAO_REALM_NAME.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 80)}_full`; + const reportJsonPath = path.join(reportDir, `${reportBaseName}.json`); + const reportTxtPath = path.join(reportDir, `${reportBaseName}.txt`); + fs.writeFileSync(reportJsonPath, JSON.stringify(report, null, 2)); + fs.writeFileSync( + reportTxtPath, + [ + `createdAt: ${report.createdAt}`, + `cluster: ${report.cluster}`, + `realmName: ${report.realmName}`, + `governanceProgramId: ${report.governanceProgramId}`, + `issuer: ${report.issuer}`, + `communityMint: ${report.communityMint}`, + `issuerAta: ${report.issuerAta}`, + `realm: ${report.realm}`, + `tokenOwnerRecord: ${report.tokenOwnerRecord}`, + `governance: ${report.governance}`, + `nativeTreasury: ${report.nativeTreasury}`, + `metadataUri: ${report.metadataUri}`, + `imageUrl: ${report.imageUrl}`, + `txMint: ${report.txMint}`, + `txMetadata: ${report.txMetadata}`, + `txRealm: ${report.txRealm}`, + `txDeposit: ${report.txDeposit}`, + `txGovernanceTreasury: ${report.txGovernanceTreasury}`, + `txSetMintAuthorityToGovernance: ${report.txSetMintAuthorityToGovernance}`, + `txSetRealmAuthority: ${report.txSetRealmAuthority}`, + `tokenSupply: ${report.tokenSupply}`, + `votingTimeSec: ${report.votingTimeSec}`, + `thresholdPercent: ${report.thresholdPercent}`, + `startBalanceSol: ${report.startBalanceSol}`, + `endBalanceSol: ${report.endBalanceSol}`, + `spentSol: ${report.spentSol}`, + `configPath: ${report.configPath}`, + ].join("\n") + "\n" + ); + + console.log("============================================================"); + console.log("DAO FULL СОЗДАНО"); + console.log("------------------------------------------------------------"); + console.log("Community mint (SPL + metadata): ", mintKeypair.publicKey.toBase58()); + console.log("Realm: ", realmPk.toBase58()); + console.log("Governance: ", governancePk.toBase58()); + console.log("Native treasury PDA: ", treasuryPk.toBase58()); + console.log("Tx mint: ", sigMint); + console.log("Tx metadata: ", sigMetadata); + console.log("Tx realm: ", sigRealm); + console.log("Tx deposit: ", sigDeposit); + console.log("Tx governance+treasury: ", sigGov); + console.log("Tx set mint authority -> governance: ", sigSetMintAuthority); + console.log("Tx set realm authority -> governance: ", sigSetRealmAuthority); + console.log("Баланс после: ", `${lamportsToSol(endBalance)} SOL`); + console.log("Потрачено: ", `${lamportsToSol(spentLamports)} SOL`); + console.log("Отчёт JSON: ", reportJsonPath); + console.log("Отчёт TXT: ", reportTxtPath); + console.log("============================================================"); +} + +main().catch((e) => { + console.error("Ошибка создания DAO FULL:", e?.message || e); + process.exit(1); +}); diff --git a/shine-solana/shine/scripts/dao/create_realm_dao_full_test.sh b/shine-solana/shine/scripts/dao/create_realm_dao_full_test.sh new file mode 100755 index 0000000..fdec4a0 --- /dev/null +++ b/shine-solana/shine/scripts/dao/create_realm_dao_full_test.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_PATH="${1:-$SCRIPT_DIR/dao.config.env}" + +if [[ ! -f "$CONFIG_PATH" ]]; then + echo "Ошибка: не найден конфиг $CONFIG_PATH" + exit 1 +fi + +# shellcheck disable=SC1090 +source "$CONFIG_PATH" + +require_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "Ошибка: команда '$1' не найдена" + exit 1 + fi +} + +require_cmd solana +require_cmd solana-keygen +require_cmd node + +if [[ -z "${DAO_REALM_NAME:-}" || -z "${DAO_CLUSTER:-}" || -z "${DAO_ISSUER_KEYPAIR:-}" || -z "${SPL_GOVERNANCE_PROGRAM_ID:-}" ]]; then + echo "Ошибка: обязательные поля конфига пустые" + exit 1 +fi + +if [[ ! -f "$DAO_ISSUER_KEYPAIR" ]]; then + echo "Ошибка: keypair не найден: $DAO_ISSUER_KEYPAIR" + exit 1 +fi + +if [[ "${DAO_REALM_NAME}" == *"TEMPLATE"* || "${DAO_REALM_NAME}" == *"CHANGE_ME"* ]]; then + echo "Ошибка: похоже, не заменили тестовое имя DAO_REALM_NAME" + exit 1 +fi + +if ! [[ "${DAO_VOTING_TIME_SEC}" =~ ^[0-9]+$ ]] || ! [[ "${DAO_GOV_NFT_SUPPLY}" =~ ^[0-9]+$ ]] || ! [[ "${DAO_APPROVAL_THRESHOLD_PERCENT}" =~ ^[0-9]+$ ]]; then + echo "Ошибка: числовые параметры заданы некорректно" + exit 1 +fi + +if (( DAO_APPROVAL_THRESHOLD_PERCENT < 51 || DAO_APPROVAL_THRESHOLD_PERCENT > 100 )); then + echo "Ошибка: DAO_APPROVAL_THRESHOLD_PERCENT должен быть в диапазоне 51..100" + exit 1 +fi + +ISSUER_PUBKEY="$(solana-keygen pubkey "$DAO_ISSUER_KEYPAIR")" +ISSUER_BALANCE="$(solana balance "$ISSUER_PUBKEY" --url "$DAO_CLUSTER" 2>/dev/null || true)" + +REALM_PDA="$(node - "$DAO_REALM_NAME" "$SPL_GOVERNANCE_PROGRAM_ID" <<'NODE' +const { PublicKey } = require("@solana/web3.js"); +const realmName = process.argv[2]; +const programId = new PublicKey(process.argv[3]); +const [pda] = PublicKey.findProgramAddressSync( + [Buffer.from("governance"), Buffer.from(realmName, "utf8")], + programId +); +console.log(pda.toBase58()); +NODE +)" + +if [[ -z "$REALM_PDA" ]]; then + echo "Ошибка: не удалось вычислить PDA realm." + exit 1 +fi + +REALM_EXISTS="no" +if solana account "$REALM_PDA" --url "$DAO_CLUSTER" >/dev/null 2>&1; then + REALM_EXISTS="yes" +fi + +cat < + new AccountMetaData({ + pubkey: k.pubkey, + isSigner: !!k.isSigner, + isWritable: !!k.isWritable, + }) + ), + data: Uint8Array.from(ix.data), + }); +} + +async function main() { + const configPath = process.argv[2] ? path.resolve(process.argv[2]) : path.resolve(__dirname, "dao.config.env"); + const realm = new PublicKey(process.argv[3]); + const governance = new PublicKey(process.argv[4]); + const proposal = new PublicKey(process.argv[5]); + const proposalTx = new PublicKey(process.argv[6]); + const mint = new PublicKey(process.argv[7]); + const targetOwner = new PublicKey(process.argv[8]); + const amount = new BN(process.argv[9] || "1"); + if (!process.argv[8]) { + throw new Error( + "Использование: node scripts/dao/execute_revoke_transaction_full_exec.js [amount]" + ); + } + const cfg = parseEnvConfig(configPath); + const cluster = cfg.DAO_CLUSTER || "devnet"; + const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const signer = loadKeypair(path.resolve(cfg.DAO_ISSUER_KEYPAIR)); + const connection = new Connection(clusterApiUrl(cluster), "confirmed"); + + const ixRawRevoke = []; + await withRevokeGoverningTokens( + ixRawRevoke, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + targetOwner, + mint, + governance, + amount + ); + const revokeInstructionData = toGovernanceInstructionData(ixRawRevoke[0]); + + const ixExecute = []; + await withExecuteTransaction( + ixExecute, + governanceProgramId, + PROGRAM_VERSION_V3, + governance, + proposal, + proposalTx, + [revokeInstructionData] + ); + const sig = await sendAndConfirmTransaction(connection, new Transaction().add(...ixExecute), [signer], { + commitment: "confirmed", + }); + console.log("Execute success. Tx:", sig); +} + +main().catch((e) => { + console.error("Ошибка execute revoke:", e?.message || e); + process.exit(1); +}); diff --git a/shine-solana/shine/scripts/dao/propose_vote_execute_revoke_full_exec.js b/shine-solana/shine/scripts/dao/propose_vote_execute_revoke_full_exec.js new file mode 100755 index 0000000..5b3f812 --- /dev/null +++ b/shine-solana/shine/scripts/dao/propose_vote_execute_revoke_full_exec.js @@ -0,0 +1,399 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const readline = require("readline"); +const BN = require("bn.js"); +const { + Connection, + Keypair, + PublicKey, + Transaction, + sendAndConfirmTransaction, + clusterApiUrl, +} = require("@solana/web3.js"); +const { + PROGRAM_VERSION_V3, + Vote, + YesNoVote, + VoteType, + InstructionData, + AccountMetaData, + withRevokeGoverningTokens, + withCreateProposal, + withInsertTransaction, + withSignOffProposal, + withCastVote, + withExecuteTransaction, + withFinalizeVote, + getTokenOwnerRecordAddress, + getProposalTransactionAddress, +} = require("@solana/spl-governance"); + +function parseEnvConfig(configPath) { + const raw = fs.readFileSync(configPath, "utf8"); + const out = {}; + for (const line of raw.split("\n")) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq === -1) continue; + const key = trimmed.slice(0, eq).trim(); + let val = trimmed.slice(eq + 1).trim(); + if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) { + val = val.slice(1, -1); + } + val = val.replace(/\$HOME/g, process.env.HOME || ""); + out[key] = val; + } + return out; +} + +function loadKeypair(filePath) { + const arr = JSON.parse(fs.readFileSync(filePath, "utf8")); + return Keypair.fromSecretKey(Uint8Array.from(arr)); +} + +function nowStamp() { + const d = new Date(); + const p = (n) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}_${p(d.getHours())}-${p( + d.getMinutes() + )}-${p(d.getSeconds())}`; +} + +async function askYes() { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + const answer = await new Promise((resolve) => + rl.question("Введите YES для proposal->vote->execute revoke: ", resolve) + ); + rl.close(); + return answer.trim() === "YES"; +} + +function toGovernanceInstructionData(ix) { + return new InstructionData({ + programId: ix.programId, + accounts: ix.keys.map( + (k) => + new AccountMetaData({ + pubkey: k.pubkey, + isSigner: !!k.isSigner, + isWritable: !!k.isWritable, + }) + ), + data: Uint8Array.from(ix.data), + }); +} + +function classifyExecuteError(msg) { + const s = String(msg || "").toLowerCase(); + if (s.includes("0x20d") || s.includes("hold up time")) { + return "HOLD_UP_TIME"; + } + if (s.includes("0x21d") || s.includes("invalid mint authority")) { + return "INVALID_MINT_AUTHORITY"; + } + return "OTHER"; +} + +async function main() { + const configPath = process.argv[2] + ? path.resolve(process.argv[2]) + : path.resolve(__dirname, "dao.config.env"); + const realmStr = process.argv[3]; + const governanceStr = process.argv[4]; + const mintStr = process.argv[5]; + const targetOwnerStr = process.argv[6]; + const amountStr = process.argv[7] || "1"; + if (!realmStr || !governanceStr || !mintStr || !targetOwnerStr) { + throw new Error( + "Использование: node scripts/dao/propose_vote_execute_revoke_full_exec.js [amount]" + ); + } + + const cfg = parseEnvConfig(configPath); + const cluster = cfg.DAO_CLUSTER || "devnet"; + const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const proposerKpPath = cfg.DAO_ISSUER_KEYPAIR; + if (!proposerKpPath) throw new Error("В конфиге нет DAO_ISSUER_KEYPAIR"); + const proposer = loadKeypair(path.resolve(proposerKpPath)); + + const realm = new PublicKey(realmStr); + const governance = new PublicKey(governanceStr); + const mint = new PublicKey(mintStr); + const targetOwner = new PublicKey(targetOwnerStr); + const amount = new BN(amountStr); + if (amount.lten(0)) throw new Error("amount должен быть > 0"); + + const connection = new Connection(clusterApiUrl(cluster), "confirmed"); + const proposerRecord = await getTokenOwnerRecordAddress( + governanceProgramId, + realm, + mint, + proposer.publicKey + ); + + console.log("============================================================"); + console.log("DAO REVOKE THROUGH VOTE"); + console.log("------------------------------------------------------------"); + console.log("Сеть: ", cluster); + console.log("Governance program: ", governanceProgramId.toBase58()); + console.log("Realm: ", realm.toBase58()); + console.log("Governance: ", governance.toBase58()); + console.log("Mint: ", mint.toBase58()); + console.log("Target owner: ", targetOwner.toBase58()); + console.log("Amount: ", amount.toString()); + console.log("Proposer: ", proposer.publicKey.toBase58()); + console.log("Proposer record: ", proposerRecord.toBase58()); + console.log("============================================================"); + + const ok = await askYes(); + if (!ok) { + console.log("Отменено пользователем."); + return; + } + + const proposalName = `Revoke ${amount.toString()} from ${targetOwner + .toBase58() + .slice(0, 8)}...`; + const proposalDescription = cfg.DAO_REVOKE_PROPOSAL_URI || cfg.DAO_GOV_TOKEN_METADATA_URI || "https://arweave.net/"; + + const ixCreateProposal = []; + const proposalPk = await withCreateProposal( + ixCreateProposal, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + governance, + proposerRecord, + proposalName, + proposalDescription, + mint, + proposer.publicKey, + undefined, + VoteType.SINGLE_CHOICE, + ["Approve"], + true, + proposer.publicKey + ); + const sigCreateProposal = await sendAndConfirmTransaction( + connection, + new Transaction().add(...ixCreateProposal), + [proposer], + { commitment: "confirmed" } + ); + + const ixRawRevoke = []; + await withRevokeGoverningTokens( + ixRawRevoke, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + targetOwner, + mint, + governance, + amount + ); + if (ixRawRevoke.length !== 1) throw new Error("Ожидалась одна инструкция revoke"); + const revokeInstructionData = toGovernanceInstructionData(ixRawRevoke[0]); + + const ixInsert = []; + const proposalTxPk = await withInsertTransaction( + ixInsert, + governanceProgramId, + PROGRAM_VERSION_V3, + governance, + proposalPk, + proposerRecord, + proposer.publicKey, + 0, + 0, + 0, + [revokeInstructionData], + proposer.publicKey + ); + const sigInsert = await sendAndConfirmTransaction(connection, new Transaction().add(...ixInsert), [proposer], { + commitment: "confirmed", + }); + + const ixSignOff = []; + withSignOffProposal( + ixSignOff, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + governance, + proposalPk, + proposer.publicKey, + undefined, + proposerRecord + ); + const sigSignOff = await sendAndConfirmTransaction(connection, new Transaction().add(...ixSignOff), [proposer], { + commitment: "confirmed", + }); + + const ixVote = []; + const vote = Vote.fromYesNoVote(YesNoVote.Yes); + const voteRecordPk = await withCastVote( + ixVote, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + governance, + proposalPk, + proposerRecord, + proposerRecord, + proposer.publicKey, + mint, + vote, + proposer.publicKey + ); + const sigVote = await sendAndConfirmTransaction(connection, new Transaction().add(...ixVote), [proposer], { + commitment: "confirmed", + }); + + const computedProposalTxPk = await getProposalTransactionAddress( + governanceProgramId, + PROGRAM_VERSION_V3, + proposalPk, + 0, + 0 + ); + if (!computedProposalTxPk.equals(proposalTxPk)) { + throw new Error("Несовпадение адреса proposal transaction"); + } + + let sigFinalize = null; + try { + const ixFinalize = []; + await withFinalizeVote( + ixFinalize, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + governance, + proposalPk, + proposerRecord, + mint + ); + sigFinalize = await sendAndConfirmTransaction(connection, new Transaction().add(...ixFinalize), [proposer], { + commitment: "confirmed", + }); + } catch (_) { + // Может быть уже tipped/succeeded без finalize. + } + + let sigExecute = null; + let executeError = null; + let executeErrorKind = null; + try { + const ixExecute = []; + await withExecuteTransaction( + ixExecute, + governanceProgramId, + PROGRAM_VERSION_V3, + governance, + proposalPk, + proposalTxPk, + [revokeInstructionData] + ); + sigExecute = await sendAndConfirmTransaction(connection, new Transaction().add(...ixExecute), [proposer], { + commitment: "confirmed", + }); + } catch (e) { + executeError = e?.message || String(e); + executeErrorKind = classifyExecuteError(executeError); + } + + const report = { + createdAt: new Date().toISOString(), + cluster, + configPath, + governanceProgramId: governanceProgramId.toBase58(), + realm: realm.toBase58(), + governance: governance.toBase58(), + mint: mint.toBase58(), + targetOwner: targetOwner.toBase58(), + amount: amount.toString(), + proposer: proposer.publicKey.toBase58(), + proposerRecord: proposerRecord.toBase58(), + proposal: proposalPk.toBase58(), + proposalTransaction: proposalTxPk.toBase58(), + voteRecord: voteRecordPk.toBase58(), + txCreateProposal: sigCreateProposal, + txInsertTransaction: sigInsert, + txSignOff: sigSignOff, + txVote: sigVote, + txFinalize: sigFinalize, + txExecute: sigExecute, + executeError, + executeErrorKind, + }; + + const reportDir = path.resolve(__dirname, "runs"); + fs.mkdirSync(reportDir, { recursive: true }); + const reportBaseName = `${nowStamp()}_revoke_${targetOwner.toBase58().slice(0, 10)}`; + const reportJsonPath = path.join(reportDir, `${reportBaseName}.json`); + const reportTxtPath = path.join(reportDir, `${reportBaseName}.txt`); + fs.writeFileSync(reportJsonPath, JSON.stringify(report, null, 2)); + fs.writeFileSync( + reportTxtPath, + [ + `createdAt: ${report.createdAt}`, + `cluster: ${report.cluster}`, + `realm: ${report.realm}`, + `governance: ${report.governance}`, + `mint: ${report.mint}`, + `targetOwner: ${report.targetOwner}`, + `amount: ${report.amount}`, + `proposer: ${report.proposer}`, + `proposal: ${report.proposal}`, + `proposalTransaction: ${report.proposalTransaction}`, + `voteRecord: ${report.voteRecord}`, + `txCreateProposal: ${report.txCreateProposal}`, + `txInsertTransaction: ${report.txInsertTransaction}`, + `txSignOff: ${report.txSignOff}`, + `txVote: ${report.txVote}`, + `txFinalize: ${report.txFinalize || "-"}`, + `txExecute: ${report.txExecute || "-"}`, + `executeError: ${report.executeError || "-"}`, + `executeErrorKind: ${report.executeErrorKind || "-"}`, + ].join("\n") + "\n" + ); + + console.log("============================================================"); + console.log("REVOKE ЧЕРЕЗ DAO ГОЛОСОВАНИЕ ВЫПОЛНЕН"); + console.log("------------------------------------------------------------"); + console.log("Proposal: ", proposalPk.toBase58()); + console.log("Proposal Tx: ", proposalTxPk.toBase58()); + console.log("Tx create proposal: ", sigCreateProposal); + console.log("Tx insert revoke instruction: ", sigInsert); + console.log("Tx sign off: ", sigSignOff); + console.log("Tx cast vote: ", sigVote); + if (sigFinalize) console.log("Tx finalize vote: ", sigFinalize); + if (sigExecute) { + console.log("Tx execute: ", sigExecute); + } else { + console.log("Execute сейчас не прошел (ожидание voting/hold-up):"); + console.log("Ошибка execute: ", executeError); + if (executeErrorKind === "HOLD_UP_TIME") { + console.log("Причина: ", "слишком рано для execute (hold-up / окно голосования еще не завершено)"); + } else if (executeErrorKind === "INVALID_MINT_AUTHORITY") { + console.log("Причина: ", "community mint authority не передан на governance PDA при создании DAO"); + } + console.log("Повтор execute через время этой командой:"); + console.log( + `node scripts/dao/execute_revoke_transaction_full_exec.js ${configPath} ${realm.toBase58()} ${governance.toBase58()} ${proposalPk.toBase58()} ${proposalTxPk.toBase58()} ${mint.toBase58()} ${targetOwner.toBase58()} ${amount.toString()}` + ); + } + console.log("Отчёт JSON: ", reportJsonPath); + console.log("Отчёт TXT: ", reportTxtPath); + console.log("============================================================"); +} + +main().catch((e) => { + console.error("Ошибка proposal/vote/execute revoke:", e?.message || e); + process.exit(1); +}); diff --git a/shine-solana/shine/scripts/dao/revoke_member_token_full_exec.js b/shine-solana/shine/scripts/dao/revoke_member_token_full_exec.js new file mode 100755 index 0000000..28bd000 --- /dev/null +++ b/shine-solana/shine/scripts/dao/revoke_member_token_full_exec.js @@ -0,0 +1,111 @@ +#!/usr/bin/env node +"use strict"; + +const fs = require("fs"); +const path = require("path"); +const readline = require("readline"); +const BN = require("bn.js"); +const { Connection, Keypair, PublicKey, Transaction, sendAndConfirmTransaction, clusterApiUrl } = require("@solana/web3.js"); +const { PROGRAM_VERSION_V3, withRevokeGoverningTokens } = require("@solana/spl-governance"); + +function parseEnvConfig(configPath) { + const raw = fs.readFileSync(configPath, "utf8"); + const out = {}; + for (const line of raw.split("\n")) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith("#")) continue; + const eq = trimmed.indexOf("="); + if (eq === -1) continue; + const key = trimmed.slice(0, eq).trim(); + let val = trimmed.slice(eq + 1).trim(); + if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) { + val = val.slice(1, -1); + } + val = val.replace(/\$HOME/g, process.env.HOME || ""); + out[key] = val; + } + return out; +} + +function loadKeypair(filePath) { + const arr = JSON.parse(fs.readFileSync(filePath, "utf8")); + return Keypair.fromSecretKey(Uint8Array.from(arr)); +} + +async function askYes() { + const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); + const answer = await new Promise((resolve) => + rl.question("Введите YES для отзыва (burn/revoke) governance токенов: ", resolve) + ); + rl.close(); + return answer.trim() === "YES"; +} + +async function main() { + const configPath = process.argv[2] + ? path.resolve(process.argv[2]) + : path.resolve(__dirname, "dao.config.env"); + const realmStr = process.argv[3]; + const mintStr = process.argv[4]; + const targetOwnerStr = process.argv[5]; + const amountStr = process.argv[6] || "1"; + if (!realmStr || !mintStr || !targetOwnerStr) { + throw new Error( + "Использование: node scripts/dao/revoke_member_token_full_exec.js [amount]" + ); + } + + const cfg = parseEnvConfig(configPath); + const cluster = cfg.DAO_CLUSTER || "devnet"; + const governanceProgramId = new PublicKey(cfg.SPL_GOVERNANCE_PROGRAM_ID); + const revokeKpPath = cfg.DAO_REVOKE_AUTHORITY_KEYPAIR || cfg.DAO_ISSUER_KEYPAIR; + if (!revokeKpPath) throw new Error("В конфиге нет DAO_REVOKE_AUTHORITY_KEYPAIR и DAO_ISSUER_KEYPAIR"); + const revokeAuthority = loadKeypair(path.resolve(revokeKpPath)); + + const realm = new PublicKey(realmStr); + const mint = new PublicKey(mintStr); + const targetOwner = new PublicKey(targetOwnerStr); + const amount = new BN(amountStr); + if (amount.lten(0)) throw new Error("amount должен быть > 0"); + + console.log("============================================================"); + console.log("REVOKE/BURN GOVERNANCE TOKENS"); + console.log("------------------------------------------------------------"); + console.log("Сеть: ", cluster); + console.log("Governance program: ", governanceProgramId.toBase58()); + console.log("Realm: ", realm.toBase58()); + console.log("Mint: ", mint.toBase58()); + console.log("Target owner: ", targetOwner.toBase58()); + console.log("Amount: ", amount.toString()); + console.log("Revoke authority: ", revokeAuthority.publicKey.toBase58()); + console.log("============================================================"); + + const ok = await askYes(); + if (!ok) { + console.log("Отменено пользователем."); + return; + } + + const connection = new Connection(clusterApiUrl(cluster), "confirmed"); + const ix = []; + await withRevokeGoverningTokens( + ix, + governanceProgramId, + PROGRAM_VERSION_V3, + realm, + targetOwner, + mint, + revokeAuthority.publicKey, + amount + ); + + const sig = await sendAndConfirmTransaction(connection, new Transaction().add(...ix), [revokeAuthority], { + commitment: "confirmed", + }); + console.log("Готово. Tx:", sig); +} + +main().catch((e) => { + console.error("Ошибка revoke:", e?.message || e); + process.exit(1); +}); diff --git a/shine-solana/shine/settings.gradle b/shine-solana/shine/settings.gradle new file mode 100644 index 0000000..0ec8951 --- /dev/null +++ b/shine-solana/shine/settings.gradle @@ -0,0 +1 @@ +rootProject.name = "shine-tools" diff --git a/shine-solana/shine/tests/shine.ts b/shine-solana/shine/tests/shine.ts new file mode 100644 index 0000000..426da8c --- /dev/null +++ b/shine-solana/shine/tests/shine.ts @@ -0,0 +1,328 @@ +import * as anchor from "@coral-xyz/anchor"; +import { Program } from "@coral-xyz/anchor"; +import { + Ed25519Program, + PublicKey, + SYSVAR_INSTRUCTIONS_PUBKEY, + SystemProgram, + Transaction, +} from "@solana/web3.js"; +import { createHash } from "crypto"; +import { expect } from "chai"; +import { Shine } from "../target/types/shine"; + +const MAGIC = Buffer.from("SHiNE", "utf8"); +const FORMAT_MAJOR = 1; +const FORMAT_MINOR = 0; +const RESERVED = Buffer.from([0, 0, 0, 0, 0]); +const ZERO_HASH = Buffer.alloc(32, 0); +const KEY_STATUS_CREATED = 0; + +const LIMIT_STEP = 10_000n; +const START_BONUS_LIMIT = 100_000n; +const USERS_ECONOMY_CONFIG_SEED = "shine_users_economy_config"; +const SHINE_PAYMENTS_PROGRAM_ID = new PublicKey("m48pWRGWrMj3TEHjuU4zsp5Gju4e7ZaPovk8RcVt7kR"); +const SHINE_LOGIN_GUARD_PROGRAM_ID = new PublicKey("3xkopA7cXagxzMFrKdv3NCBfV6BKiRJCk69kr27M2sRo"); +const SHINE_PAYMENTS_INFLOW_VAULT_SEED = "shine_payments_inflow_vault"; + +type MutableFields = { + blockchainKey: PublicKey; + deviceKey: PublicKey; + chainNumber: number; + isServer: boolean; + serverKey: PublicKey; + serverAddress: string; + syncServers: string[]; + accessServers: string[]; + trustedCount: number; +}; + +type UnsignedRecord = { + createdAtMs: bigint; + updatedAtMs: bigint; + version: number; + prevHash: Buffer; + login: string; + rootKeyStatus: number; + rootKey: PublicKey; + blockchainKeyStatus: number; + blockchainKey: PublicKey; + deviceKeyStatus: number; + deviceKey: PublicKey; + chainNumber: number; + balance: bigint; + isServer: boolean; + serverKey: PublicKey; + serverAddress: string; + syncServers: string[]; + accessServers: string[]; + trustedCount: number; +}; + +function u16le(v: number): Buffer { + const b = Buffer.alloc(2); + b.writeUInt16LE(v, 0); + return b; +} + +function u32le(v: number): Buffer { + const b = Buffer.alloc(4); + b.writeUInt32LE(v, 0); + return b; +} + +function u64le(v: bigint): Buffer { + const b = Buffer.alloc(8); + b.writeBigUInt64LE(v, 0); + return b; +} + +function serializeUnsignedRecord(r: UnsignedRecord): Buffer { + const loginBytes = Buffer.from(r.login, "utf8"); + const serverAddressBytes = Buffer.from(r.serverAddress, "utf8"); + + const out: Buffer[] = []; + out.push(MAGIC); + out.push(Buffer.from([FORMAT_MAJOR])); + out.push(Buffer.from([FORMAT_MINOR])); + out.push(Buffer.alloc(2, 0)); // record_len placeholder + + out.push(u64le(r.createdAtMs)); + out.push(u64le(r.updatedAtMs)); + out.push(u32le(r.version)); + out.push(r.prevHash); + + out.push(Buffer.from([loginBytes.length])); + out.push(loginBytes); + + out.push(Buffer.from([r.rootKeyStatus])); + out.push(r.rootKey.toBuffer()); + out.push(Buffer.from([r.blockchainKeyStatus])); + out.push(r.blockchainKey.toBuffer()); + out.push(Buffer.from([r.deviceKeyStatus])); + out.push(r.deviceKey.toBuffer()); + + out.push(u16le(r.chainNumber)); + out.push(u64le(r.balance)); + + out.push(Buffer.from([r.isServer ? 1 : 0])); + if (r.isServer) { + out.push(r.serverKey.toBuffer()); + out.push(Buffer.from([serverAddressBytes.length])); + out.push(serverAddressBytes); + out.push(Buffer.from([r.syncServers.length])); + for (const s of r.syncServers) { + const sb = Buffer.from(s, "utf8"); + out.push(Buffer.from([sb.length])); + out.push(sb); + } + } + + out.push(Buffer.from([r.accessServers.length])); + for (const s of r.accessServers) { + const sb = Buffer.from(s, "utf8"); + out.push(Buffer.from([sb.length])); + out.push(sb); + } + + out.push(Buffer.from([r.trustedCount])); + out.push(RESERVED); + + const unsigned = Buffer.concat(out); + const recordLen = unsigned.length + 64; + unsigned.writeUInt16LE(recordLen, 7); + return unsigned; +} + +function sha256(buf: Buffer): Buffer { + return createHash("sha256").update(buf).digest(); +} + +function extractSigFromEdIx(ixData: Buffer): Buffer { + const signatureOffset = ixData.readUInt16LE(2); + return ixData.subarray(signatureOffset, signatureOffset + 64); +} + +describe("shine_users e2e", () => { + anchor.setProvider(anchor.AnchorProvider.env()); + const provider = anchor.getProvider() as anchor.AnchorProvider; + const program = anchor.workspace.shine as Program; + + it("registers user and updates balance/server data", async () => { + const login = `u${Date.now().toString().slice(-10)}`; + const [userPda] = PublicKey.findProgramAddressSync( + [Buffer.from("login="), Buffer.from(login, "utf8")], + program.programId + ); + const [usersEconomyConfigPda] = PublicKey.findProgramAddressSync( + [Buffer.from(USERS_ECONOMY_CONFIG_SEED, "utf8")], + program.programId + ); + const [inflowVaultPda] = PublicKey.findProgramAddressSync( + [Buffer.from(SHINE_PAYMENTS_INFLOW_VAULT_SEED, "utf8")], + SHINE_PAYMENTS_PROGRAM_ID + ); + + const economyAi = await provider.connection.getAccountInfo(usersEconomyConfigPda); + if (!economyAi) { + await program.methods + .initUsersEconomyConfig() + .accounts({ + signer: provider.wallet.publicKey, + usersEconomyConfigPda, + systemProgram: SystemProgram.programId, + }) + .rpc(); + } + + const root = anchor.web3.Keypair.generate(); + const blockchainKey = anchor.web3.Keypair.generate().publicKey; + const deviceKey = anchor.web3.Keypair.generate().publicKey; + const serverKey1 = anchor.web3.Keypair.generate().publicKey; + const serverKey2 = anchor.web3.Keypair.generate().publicKey; + + const createdAtMs = BigInt(Date.now()); + const additionalLimitCreate = 20_000n; + expect(additionalLimitCreate % LIMIT_STEP).eq(0n); + + const createRecord: UnsignedRecord = { + createdAtMs, + updatedAtMs: createdAtMs, + version: 0, + prevHash: ZERO_HASH, + login, + rootKeyStatus: KEY_STATUS_CREATED, + rootKey: root.publicKey, + blockchainKeyStatus: KEY_STATUS_CREATED, + blockchainKey, + deviceKeyStatus: KEY_STATUS_CREATED, + deviceKey, + chainNumber: 1, + balance: START_BONUS_LIMIT + additionalLimitCreate, + isServer: true, + serverKey: serverKey1, + serverAddress: "https://srv-1.local", + syncServers: ["sync_srv_1", "sync_srv_2"], + accessServers: ["access_srv_1"], + trustedCount: 0, + }; + + const createUnsigned = serializeUnsignedRecord(createRecord); + const createHash = sha256(createUnsigned); + const createEdIx = Ed25519Program.createInstructionWithPrivateKey({ + privateKey: root.secretKey, + message: createHash, + }); + const createSig = extractSigFromEdIx(Buffer.from(createEdIx.data)); + + const createIx = await program.methods + .createUserPda({ + login, + rootKey: root.publicKey, + createdAtMs: new anchor.BN(createdAtMs.toString()), + additionalLimit: new anchor.BN(additionalLimitCreate.toString()), + fields: { + blockchainKey, + deviceKey, + chainNumber: 1, + isServer: true, + serverKey: serverKey1, + serverAddress: "https://srv-1.local", + syncServers: ["sync_srv_1", "sync_srv_2"], + accessServers: ["access_srv_1"], + trustedCount: 0, + }, + signature: createSig, + }) + .accounts({ + signer: provider.wallet.publicKey, + userPda, + systemProgram: SystemProgram.programId, + inflowVault: inflowVaultPda, + instructions: SYSVAR_INSTRUCTIONS_PUBKEY, + usersEconomyConfigPda, + loginGuardProgram: SHINE_LOGIN_GUARD_PROGRAM_ID, + }) + .instruction(); + + await provider.sendAndConfirm(new Transaction().add(createEdIx, createIx), []); + + const createAcc = await provider.connection.getAccountInfo(userPda); + expect(createAcc).not.eq(null); + expect(createAcc!.owner.toBase58()).eq(program.programId.toBase58()); + + const additionalLimitUpdate = 30_000n; + expect(additionalLimitUpdate % LIMIT_STEP).eq(0n); + + const updateRecord: UnsignedRecord = { + createdAtMs, + updatedAtMs: createdAtMs + 1_000n, + version: 1, + prevHash: sha256(createUnsigned), + login, + rootKeyStatus: KEY_STATUS_CREATED, + rootKey: root.publicKey, + blockchainKeyStatus: KEY_STATUS_CREATED, + blockchainKey: anchor.web3.Keypair.generate().publicKey, + deviceKeyStatus: KEY_STATUS_CREATED, + deviceKey: anchor.web3.Keypair.generate().publicKey, + chainNumber: 1, + balance: START_BONUS_LIMIT + additionalLimitCreate + additionalLimitUpdate, + isServer: true, + serverKey: serverKey2, + serverAddress: "https://srv-2.local", + syncServers: ["sync_srv_3"], + accessServers: ["access_srv_2", "access_srv_3"], + trustedCount: 0, + }; + + const updateUnsigned = serializeUnsignedRecord(updateRecord); + const updateHash = sha256(updateUnsigned); + const updateEdIx = Ed25519Program.createInstructionWithPrivateKey({ + privateKey: root.secretKey, + message: updateHash, + }); + const updateSig = extractSigFromEdIx(Buffer.from(updateEdIx.data)); + + const updateIx = await program.methods + .updateUserPda({ + login, + rootKey: root.publicKey, + createdAtMs: new anchor.BN(createdAtMs.toString()), + updatedAtMs: new anchor.BN((createdAtMs + 1_000n).toString()), + version: 1, + prevHash: sha256(createUnsigned), + additionalLimit: new anchor.BN(additionalLimitUpdate.toString()), + fields: { + blockchainKey: updateRecord.blockchainKey, + deviceKey: updateRecord.deviceKey, + chainNumber: 1, + isServer: true, + serverKey: serverKey2, + serverAddress: "https://srv-2.local", + syncServers: ["sync_srv_3"], + accessServers: ["access_srv_2", "access_srv_3"], + trustedCount: 0, + }, + signature: updateSig, + }) + .accounts({ + signer: provider.wallet.publicKey, + userPda, + systemProgram: SystemProgram.programId, + inflowVault: inflowVaultPda, + instructions: SYSVAR_INSTRUCTIONS_PUBKEY, + usersEconomyConfigPda, + }) + .instruction(); + + await provider.sendAndConfirm(new Transaction().add(updateEdIx, updateIx), []); + + const updatedAcc = await provider.connection.getAccountInfo(userPda); + expect(updatedAcc).not.eq(null); + const data = updatedAcc!.data; + expect(data.subarray(0, 5).toString("utf8")).eq("SHiNE"); + expect(data[5]).eq(FORMAT_MAJOR); + expect(data[6]).eq(FORMAT_MINOR); + }); +}); diff --git a/shine-solana/shine/tsconfig.json b/shine-solana/shine/tsconfig.json new file mode 100644 index 0000000..1235e38 --- /dev/null +++ b/shine-solana/shine/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +} diff --git a/shine-solana/shine/yarn.lock b/shine-solana/shine/yarn.lock new file mode 100644 index 0000000..5b329c1 --- /dev/null +++ b/shine-solana/shine/yarn.lock @@ -0,0 +1,1606 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/runtime@^7.25.0": + version "7.27.1" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.1.tgz" + integrity sha512-1x3D2xEk2fRo3PAhwQwu5UubzgiVWSXTBfWpVd2Mx2AzRqJuDJCsgaDVZ7HB5iGzDW1Hl1sWN2mFyKjmR9uAog== + +"@coral-xyz/anchor-errors@^0.31.1": + version "0.31.1" + resolved "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz" + integrity sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ== + +"@coral-xyz/anchor@^0.31.1": + version "0.31.1" + resolved "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.1.tgz" + integrity sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA== + dependencies: + "@coral-xyz/anchor-errors" "^0.31.1" + "@coral-xyz/borsh" "^0.31.1" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.69.0" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + eventemitter3 "^4.0.7" + pako "^2.0.3" + superstruct "^0.15.4" + toml "^3.0.0" + +"@coral-xyz/borsh@^0.31.1": + version "0.31.1" + resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz" + integrity sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@metaplex-foundation/mpl-token-metadata@^3.4.0": + version "3.4.0" + resolved "https://registry.npmjs.org/@metaplex-foundation/mpl-token-metadata/-/mpl-token-metadata-3.4.0.tgz" + integrity sha512-AxBAYCK73JWxY3g9//z/C9krkR0t1orXZDknUPS4+GjwGH2vgPfsk04yfZ31Htka2AdS9YE/3wH7sMUBHKn9Rg== + dependencies: + "@metaplex-foundation/mpl-toolbox" "^0.10.0" + +"@metaplex-foundation/mpl-toolbox@^0.10.0": + version "0.10.0" + resolved "https://registry.npmjs.org/@metaplex-foundation/mpl-toolbox/-/mpl-toolbox-0.10.0.tgz" + integrity sha512-84KD1L5cFyw5xnntHwL4uPwfcrkKSiwuDeypiVr92qCUFuF3ZENa2zlFVPu+pQcjTlod2LmEX3MhBmNjRMpdKg== + +"@metaplex-foundation/umi-bundle-defaults@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-bundle-defaults/-/umi-bundle-defaults-1.5.1.tgz" + integrity sha512-7qoXenAkQbcj468HGAeLZDyg3eEhcS9rWAnGqjnKgWOlL1czL2Qwho0FEtqOv57IHwAJSTpbHbcvABmdpTjjdw== + dependencies: + "@metaplex-foundation/umi-downloader-http" "^1.5.1" + "@metaplex-foundation/umi-eddsa-web3js" "^1.5.1" + "@metaplex-foundation/umi-http-fetch" "^1.5.1" + "@metaplex-foundation/umi-program-repository" "^1.5.1" + "@metaplex-foundation/umi-rpc-chunk-get-accounts" "^1.5.1" + "@metaplex-foundation/umi-rpc-web3js" "^1.5.1" + "@metaplex-foundation/umi-serializer-data-view" "^1.5.1" + "@metaplex-foundation/umi-transaction-factory-web3js" "^1.5.1" + +"@metaplex-foundation/umi-downloader-http@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-downloader-http/-/umi-downloader-http-1.5.1.tgz" + integrity sha512-1s9gSTaDtwELyxBRE6Wmdr3xWeb4Z1uU04dj3Hg8VU+TN6/3wchh93+rIGZT5D3zzdh4+yPxdYV+4ZEr3T5glQ== + +"@metaplex-foundation/umi-eddsa-web3js@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-eddsa-web3js/-/umi-eddsa-web3js-1.5.1.tgz" + integrity sha512-ZlzmXXAa1Ujk00G5TmqXM81J25+k/8sqt0zxBUlLTUSOxzlhxhlUKdErIhpHazbKq+eGck+Onm17oAwVKdKAcw== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "^1.5.1" + "@noble/curves" "^1.0.0" + yaml "^2.7.0" + +"@metaplex-foundation/umi-http-fetch@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-http-fetch/-/umi-http-fetch-1.5.1.tgz" + integrity sha512-AOjZJo3Ua4a2FvgA85x5f0TkMSb+13Ao3uLIQ9FbScV42kqZnDox8KjJ7tKm1ZtYDlCYD0pSFMKPOC9NPDnHDg== + dependencies: + node-fetch "^2.6.7" + +"@metaplex-foundation/umi-options@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-options/-/umi-options-1.5.1.tgz" + integrity sha512-ZE6uXgFA3rElFq4gJxZM2diAqZdFqL65bOnAggwdnnei5XXRzFyNF16wYSqlHnPLvG6ohRHWiXww8d2Mb83xFg== + +"@metaplex-foundation/umi-program-repository@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-program-repository/-/umi-program-repository-1.5.1.tgz" + integrity sha512-E5W0IjwFgDGuBTshISbbEh/s8deqxcOzzEjOOlYdMXnevVsfNLwBBIAY4NPJg3v5vpFlKODwUGB5BxCUVthzJg== + +"@metaplex-foundation/umi-public-keys@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-public-keys/-/umi-public-keys-1.5.1.tgz" + integrity sha512-joTnI1mRtYRfIaTo98uaYRjBPszsdyHuq0vvd6QbSX+MPvu3enkWi+UicuykEc3VXd5tcGdNMiGSx4jgXG6pkw== + dependencies: + "@metaplex-foundation/umi-serializers-encodings" "^1.5.1" + +"@metaplex-foundation/umi-rpc-chunk-get-accounts@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-rpc-chunk-get-accounts/-/umi-rpc-chunk-get-accounts-1.5.1.tgz" + integrity sha512-3dnGobT1Xwul7fXzQr8660UHSnFOCWEed4T449oNekrVsHp2o00fdOqjXwo11DYhS1rjm+gbzRSazRKb62uF2Q== + +"@metaplex-foundation/umi-rpc-web3js@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-rpc-web3js/-/umi-rpc-web3js-1.5.1.tgz" + integrity sha512-CxHyruh2gW2b/ZOwHFFtooOgtu9hBrOJTd3HUMtD/jpaturApa3itsL/zNt4K34tELzVIUL7N78LDjNpzbu9Kw== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "^1.5.1" + +"@metaplex-foundation/umi-serializer-data-view@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-serializer-data-view/-/umi-serializer-data-view-1.5.1.tgz" + integrity sha512-9Wxqk3bGVJ0xNmHhHrOUhdu/90Q1IT3FZRZN4eGckb0sf7Bgls7kBTkFfgXFmUh2VBnE0GnnncXeHKtop5RSFA== + +"@metaplex-foundation/umi-serializers-core@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-serializers-core/-/umi-serializers-core-1.5.1.tgz" + integrity sha512-6nYsbTCLq421x7JT1B3/iNgPpSARj/wL9naoKbOreHrk2ip/4R7vQstVRMl0Gx+Hv2tHnEIbFo3JBtWyC377Qw== + +"@metaplex-foundation/umi-serializers-encodings@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-serializers-encodings/-/umi-serializers-encodings-1.5.1.tgz" + integrity sha512-cVvwWmREE/Pmvjvsd50F18P53HDT0vzZECD6uYWIVzxgwpOiRDFu6r/vGbweomHoWzfTvuU6hiKuKv2KsOoXQA== + dependencies: + "@metaplex-foundation/umi-serializers-core" "^1.5.1" + +"@metaplex-foundation/umi-serializers-numbers@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-serializers-numbers/-/umi-serializers-numbers-1.5.1.tgz" + integrity sha512-7DVF1VJIdT44Pe6qWKaqGu4YVgE10OeLMYpm7C16SujSBgQGB/I2bh8NBifyH2R3oHhoyfE9qgIKB3dgRazN6A== + dependencies: + "@metaplex-foundation/umi-serializers-core" "^1.5.1" + +"@metaplex-foundation/umi-serializers@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-serializers/-/umi-serializers-1.5.1.tgz" + integrity sha512-scXciBylbJ4iwfxOF1Xx2XiBzoYUD8fSKWTsMal5Rj1hMRDe6b2XZcsBOjio61iAr8aTtFPmKpqxeBdLwmQ0ZQ== + dependencies: + "@metaplex-foundation/umi-options" "^1.5.1" + "@metaplex-foundation/umi-public-keys" "^1.5.1" + "@metaplex-foundation/umi-serializers-core" "^1.5.1" + "@metaplex-foundation/umi-serializers-encodings" "^1.5.1" + "@metaplex-foundation/umi-serializers-numbers" "^1.5.1" + +"@metaplex-foundation/umi-transaction-factory-web3js@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-transaction-factory-web3js/-/umi-transaction-factory-web3js-1.5.1.tgz" + integrity sha512-g4NfvtnmXtH1Q/Y9LdCsFtDRHQZmZWW7uKz+N9a+IVsJTTvpWFALMHm66dFDQGa0ExAYxAj7j6uZH2qDn0zarA== + dependencies: + "@metaplex-foundation/umi-web3js-adapters" "^1.5.1" + +"@metaplex-foundation/umi-web3js-adapters@^1.5.1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi-web3js-adapters/-/umi-web3js-adapters-1.5.1.tgz" + integrity sha512-6W3JElD0B0EbgHofVKqk4PbP/JDrUHIKWciM7tEuXTDXbuXbSECDe7qlTU0JZXmVZNfYufI6FHnkCfPys2ZnIQ== + dependencies: + buffer "^6.0.3" + +"@metaplex-foundation/umi@^1.5.1", "@metaplex-foundation/umi@>= 0.8.2 <= 1": + version "1.5.1" + resolved "https://registry.npmjs.org/@metaplex-foundation/umi/-/umi-1.5.1.tgz" + integrity sha512-ONRv5a0kv+23AMlR8oyFBHnjVg3o3N8pUfFcV4gzbg6OgZf87zHsPWBfED3OTJqx267v1bEn6d6DABXNFq9Z3A== + dependencies: + "@metaplex-foundation/umi-options" "^1.5.1" + "@metaplex-foundation/umi-public-keys" "^1.5.1" + "@metaplex-foundation/umi-serializers" "^1.5.1" + +"@noble/curves@^1.0.0", "@noble/curves@^1.4.2": + version "1.9.1" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz" + integrity sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@1.8.0": + version "1.8.0" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@solana/buffer-layout-utils@^0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz" + integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/web3.js" "^1.32.0" + bigint-buffer "^1.1.5" + bignumber.js "^9.0.1" + +"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/codecs-core@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-rc.1.tgz" + integrity sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ== + dependencies: + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-core@2.1.1": + version "2.1.1" + resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.1.1.tgz" + integrity sha512-iPQW3UZ2Vi7QFBo2r9tw0NubtH8EdrhhmZulx6lC8V5a+qjaxovtM/q/UW2BTNpqqHLfO0tIcLyBLrNH4HTWPg== + dependencies: + "@solana/errors" "2.1.1" + +"@solana/codecs-data-structures@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-rc.1.tgz" + integrity sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-numbers@^2.1.0": + version "2.1.1" + resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.1.1.tgz" + integrity sha512-m20IUPJhPUmPkHSlZ2iMAjJ7PaYUvlMtFhCQYzm9BEBSI6OCvXTG3GAPpAnSGRBfg5y+QNqqmKn4QHU3B6zzCQ== + dependencies: + "@solana/codecs-core" "2.1.1" + "@solana/errors" "2.1.1" + +"@solana/codecs-numbers@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-rc.1.tgz" + integrity sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs-strings@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-rc.1.tgz" + integrity sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/codecs@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/codecs/-/codecs-2.0.0-rc.1.tgz" + integrity sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/options" "2.0.0-rc.1" + +"@solana/errors@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/errors/-/errors-2.0.0-rc.1.tgz" + integrity sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ== + dependencies: + chalk "^5.3.0" + commander "^12.1.0" + +"@solana/errors@2.1.1": + version "2.1.1" + resolved "https://registry.npmjs.org/@solana/errors/-/errors-2.1.1.tgz" + integrity sha512-sj6DaWNbSJFvLzT8UZoabMefQUfSW/8tXK7NTiagsDmh+Q87eyQDDC9L3z+mNmx9b6dEf6z660MOIplDD2nfEw== + dependencies: + chalk "^5.4.1" + commander "^13.1.0" + +"@solana/options@2.0.0-rc.1": + version "2.0.0-rc.1" + resolved "https://registry.npmjs.org/@solana/options/-/options-2.0.0-rc.1.tgz" + integrity sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA== + dependencies: + "@solana/codecs-core" "2.0.0-rc.1" + "@solana/codecs-data-structures" "2.0.0-rc.1" + "@solana/codecs-numbers" "2.0.0-rc.1" + "@solana/codecs-strings" "2.0.0-rc.1" + "@solana/errors" "2.0.0-rc.1" + +"@solana/spl-governance@^0.3.28": + version "0.3.28" + resolved "https://registry.npmjs.org/@solana/spl-governance/-/spl-governance-0.3.28.tgz" + integrity sha512-CUi1hMvzId2rAtMFTlxMwOy0EmFeT0VcmiC+iQnDhRBuM8LLLvRrbTYBWZo3xIvtPQW9HfhVBoL7P/XNFIqYVQ== + dependencies: + "@solana/web3.js" "^1.22.0" + axios "^1.1.3" + bignumber.js "^9.0.1" + bn.js "^5.1.3" + borsh "^0.3.1" + bs58 "^4.0.1" + superstruct "^0.15.2" + +"@solana/spl-token-group@^0.0.7": + version "0.0.7" + resolved "https://registry.npmjs.org/@solana/spl-token-group/-/spl-token-group-0.0.7.tgz" + integrity sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + +"@solana/spl-token-metadata@^0.1.6": + version "0.1.6" + resolved "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.6.tgz" + integrity sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA== + dependencies: + "@solana/codecs" "2.0.0-rc.1" + +"@solana/spl-token@^0.4.14": + version "0.4.14" + resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.14.tgz" + integrity sha512-u09zr96UBpX4U685MnvQsNzlvw9TiY005hk1vJmJr7gMJldoPG1eYU5/wNEyOA5lkMLiR/gOi9SFD4MefOYEsA== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-group" "^0.0.7" + "@solana/spl-token-metadata" "^0.1.6" + buffer "^6.0.3" + +"@solana/web3.js@^1.22.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.69.0", "@solana/web3.js@^1.72.0", "@solana/web3.js@^1.95.3", "@solana/web3.js@^1.95.5": + version "1.98.2" + resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.2.tgz" + integrity sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A== + dependencies: + "@babel/runtime" "^7.25.0" + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" + "@solana/buffer-layout" "^4.0.1" + "@solana/codecs-numbers" "^2.1.0" + agentkeepalive "^4.5.0" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.1" + node-fetch "^2.7.0" + rpc-websockets "^9.0.2" + superstruct "^2.0.2" + +"@swc/helpers@^0.5.11": + version "0.5.17" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz" + integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== + dependencies: + tslib "^2.8.0" + +"@types/bn.js@^4.11.5": + version "4.11.6" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + +"@types/bn.js@^5.1.0": + version "5.1.6" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.6.tgz" + integrity sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w== + dependencies: + "@types/node" "*" + +"@types/chai@^4.3.0": + version "4.3.20" + resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz" + integrity sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ== + +"@types/connect@^3.4.33": + version "3.4.38" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/mocha@^9.0.0": + version "9.1.1" + resolved "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz" + integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== + +"@types/node@*": + version "22.15.19" + resolved "https://registry.npmjs.org/@types/node/-/node-22.15.19.tgz" + integrity sha512-3vMNr4TzNQyjHcRZadojpRaD9Ofr6LsonZAoQ+HMUa/9ORTPoxVIw0e0mpqWpdjj8xybyCM+oKOUH2vwFu/oEw== + dependencies: + undici-types "~6.21.0" + +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== + +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@types/ws@^8.2.2": + version "8.18.1" + resolved "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz" + integrity sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg== + dependencies: + "@types/node" "*" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +agentkeepalive@^4.5.0: + version "4.6.0" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== + dependencies: + humanize-ms "^1.2.1" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@^1.1.3: + version "1.16.0" + resolved "https://registry.npmjs.org/axios/-/axios-1.16.0.tgz" + integrity sha512-6hp5CwvTPlN2A31g5dxnwAX0orzM7pmCRDLnZSX772mv8WDqICwFjowHuPs04Mc8deIld1+ejhtaMn5vp6b+1w== + dependencies: + follow-redirects "^1.16.0" + form-data "^4.0.5" + proxy-from-env "^2.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2: + version "3.0.11" + resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz" + integrity sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +bignumber.js@^9.0.1: + version "9.3.1" + resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz" + integrity sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.2" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== + +borsh@^0.3.1: + version "0.3.1" + resolved "https://registry.npmjs.org/borsh/-/borsh-0.3.1.tgz" + integrity sha512-gJoSTnhwLxN/i2+15Y7uprU8h3CKI+Co4YKZKvrGYUy0FwHWM20x5Sx7eU8Xv4HQqV+7rb4r3P7K1cBIQe3q8A== + dependencies: + "@types/bn.js" "^4.11.5" + bn.js "^5.0.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +buffer-from@^1.0.0, buffer-from@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-layout@^1.2.0, buffer-layout@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz" + integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== + +buffer@^6.0.3, buffer@~6.0.3, buffer@6.0.3: + version "6.0.3" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bufferutil@^4.0.1: + version "4.0.9" + resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz" + integrity sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw== + dependencies: + node-gyp-build "^4.3.0" + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +camelcase@^6.0.0, camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chai@^4.3.4: + version "4.5.0" + resolved "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz" + integrity sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.1.0" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^5.3.0: + version "5.6.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz" + integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== + +chalk@^5.4.1: + version "5.4.1" + resolved "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz" + integrity sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w== + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + +commander@^13.1.0: + version "13.1.0" + resolved "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cross-fetch@^3.1.5: + version "3.2.0" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz" + integrity sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q== + dependencies: + node-fetch "^2.7.0" + +debug@4.3.3: + version "4.3.3" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-eql@^4.1.3: + version "4.1.4" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz" + integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg== + dependencies: + type-detect "^4.0.0" + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +diff@^3.1.0: + version "3.5.0" + resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + +fastestsmallesttextencoderdecoder@^1.0.22: + version "1.0.22" + resolved "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz" + integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +follow-redirects@^1.16.0: + version "1.16.0" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz" + integrity sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw== + +form-data@^4.0.5: + version "4.0.5" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-intrinsic@^1.2.6: + version "1.3.0" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz" + integrity sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg== + dependencies: + function-bind "^1.1.2" + +he@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + +jayson@^4.1.1: + version "4.2.0" + resolved "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz" + integrity sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + stream-json "^1.9.1" + uuid "^8.3.2" + ws "^7.5.10" + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +"mocha@^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X || ^11.X.X", mocha@^9.0.3: + version "9.2.2" + resolved "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz" + integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.3" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "4.2.1" + ms "2.1.3" + nanoid "3.3.1" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.2.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@^2.0.0, ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@3.3.1: + version "3.3.1" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +node-fetch@^2.6.7, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.8.4" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz" + integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +pako@^2.0.3: + version "2.1.0" + resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@^2.6.2: + version "2.8.8" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +proxy-from-env@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz" + integrity sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +rpc-websockets@^9.0.2: + version "9.1.1" + resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.1.1.tgz" + integrity sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA== + dependencies: + "@swc/helpers" "^0.5.11" + "@types/uuid" "^8.3.4" + "@types/ws" "^8.2.2" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +stream-chain@^2.2.5: + version "2.2.5" + resolved "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz" + integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA== + +stream-json@^1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz" + integrity sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw== + dependencies: + stream-chain "^2.2.5" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +superstruct@^0.15.2, superstruct@^0.15.4: + version "0.15.5" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz" + integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== + +superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toml@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-mocha@^10.0.0: + version "10.1.0" + resolved "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.1.0.tgz" + integrity sha512-T0C0Xm3/WqCuF2tpa0GNGESTBoKZaiqdUP8guNv4ZY316AFXlyidnrzQ1LUrCT0Wb1i3J0zFTgOh/55Un44WdA== + dependencies: + ts-node "7.0.1" + optionalDependencies: + tsconfig-paths "^3.5.0" + +ts-node@7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tsconfig-paths@^3.5.0: + version "3.15.0" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +type-detect@^4.0.0, type-detect@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== + +typescript@^5.7.3, typescript@>=5, typescript@>=5.3.3: + version "5.8.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +utf-8-validate@^5.0.2, utf-8-validate@>=5.0.2: + version "5.0.10" + resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@6.2.0: + version "6.2.0" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@*, ws@^7.5.10: + version "7.5.10" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + +ws@^8.5.0: + version "8.18.2" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz" + integrity sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yaml@^2.7.0: + version "2.8.4" + resolved "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz" + integrity sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz" + integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==