diff --git a/smart-updown.tar.gz b/smart-updown.tar.gz deleted file mode 100644 index a1dc3d9..0000000 Binary files a/smart-updown.tar.gz and /dev/null differ diff --git a/smart-updown/README.md b/smart-updown/README.md new file mode 100644 index 0000000..3001262 --- /dev/null +++ b/smart-updown/README.md @@ -0,0 +1,136 @@ +# Smart-Updown — пакет развёртывания (localnet) + +Бинарная игра UP/DOWN на цену SOL. Пользователь ставит на направление (UP/DOWN) +на 15 секунд; при выигрыше получает ставку + 30% (1.3x). Дом (контракт) — оппонент. +Цена берётся off-chain релеером (он же админ) с вашей БД; SOL хранится в ваулте (PDA `global`). + +Программа: **Anchor v2 (fork `otter-sec/anchor`, ветка `anchor-next`)**, Solana, Rust. + +--- + +## Состав пакета + +``` +smart-updown/ +├── deploy/ +│ ├── smart_updown.so # скомпилированная программа (SBF-байткод, кроссплатформенный) +│ └── smart_updown-keypair.json # authority-ключар программы (ID = E7Hg55...) +├── idl/ +│ ├── smart_updown.json # IDL (для клиента) +│ └── smart_updown.ts # типы TypeScript для клиента +├── relayer/ # off-chain релеер (админ + закрытие ставок) +│ ├── package.json +│ ├── tsconfig.json +│ ├── .env.example +│ ├── idl/ # копия IDL для клиента +│ └── src/ +│ ├── index.ts # главный цикл +│ ├── ops.ts # initialize / createBet / closeBet / fundVault +│ ├── pda.ts # вывод PDA +│ ├── program.ts # клиент из IDL +│ ├── priceSource.ts # ЗАГЛУШКА цены SOL (вставить свой запрос к БД) +│ └── frontStub.ts # ЗАГЛУШКА фронта (откуда приходит выбор пользователя) +├── program/ # исходники контракта (опционально, для пересборки) +│ ├── Anchor.toml +│ ├── Cargo.toml / Cargo.lock +│ ├── rust-toolchain.toml # пинит Rust 1.89.0 +│ └── programs/smart-updown/{src,tests} +├── deploy-localnet.sh # развёртывание на localnet +└── README.md +``` + +--- + +## 1. Требования (Linux x86_64) + +- **Solana CLI (Agave)** — даёт `solana-test-validator`, `solana program deploy`, + `cargo build-sbf`, `solana-keygen`. Установка: + `sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)"` +- **Node.js 18+ / npm** — для relayer. +- (опционально) **Rust 1.89.0** через rustup — только если пересобираете программу. + +> **Важно про `.so`**: это SBF-байткод и он не зависит от архитектуры хоста, +> поэтому `deploy/smart_updown.so`, собранный на macOS, **работает на Linux-валидаторе** +> как есть — пересобирать не нужно. + +## 2. Развёртывание (localnet) + +```bash +chmod +x deploy-localnet.sh +./deploy-localnet.sh +``` + +Скрипт: +1. переключает `solana config` на `http://127.0.0.1:8899`; +2. запускает `solana-test-validator` с программой (`--bpf-program E7Hg55...`); +3. проверяет, что программа поднята под ID `E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3`. + +Подытог — программа доступна на localnet под тем же адресом, что зашит в IDL. + +## 3. Relayer (админ + закрытие ставок) + +```bash +cd relayer +npm install +cp .env.example .env # при желании поправить значения +# инициализация контракта (ваулт/Global): +npm run init +# один прогон ставки: +npm run run +# непрерывный цикл: +npm run loop +``` + +`init` создаёт `Global` (админ + релеер = keypair из `SMART_ADMIN_KEYPAIR`, +по умолчанию `~/.config/solana/id.json`). На localnet скрипт сам делает airDrop +bettor'ам и догружает ваулт банка. На mainnet airDrop выключите +(`SMART_ALLOW_AIRDROP=0`) и пополняйте ваулт переводами с админа. + +> AirDrop на localnet выполняется от keypair, настроенного в `solana config`. +> Убедитесь, что он существует и имеет SOL (в скрипте деплоя это `id.json`, +> см. `solana config get`). + +## 4. Заглушки — куда вставить реальное + +- `relayer/src/priceSource.ts` — функция `getPrice()`. **Замените** на запрос цены + SOL из вашей БД. Единицы любые, главное согласованность между entry и exit. +- `relayer/src/frontStub.ts` — функция `nextBetRequest()`. **Замените** на приём + со стороны фронта: направление (UP/DOWN) и сумма, которые выбрал пользователь. + +## 5. Деплой в новом окружении (если уже есть валидатор, без перезапуска) + +```bash +solana config set --url http://127.0.0.1:8899 +solana program deploy --program-id deploy/smart_updown-keypair.json deploy/smart_updown.so +``` + +## 6. (Опционально) Пересборка программы из исходников + тесты + +Та же команда, что использовалась для сборки: + +```bash +cd program +rustup toolchain install 1.89.0 # если нет +# собрать .so: +cargo build-sbf --manifest-path programs/smart-updown/Cargo.toml +# артефакт появится в program/target/deploy/smart_updown.so +# интеграционные тесты (LiteSVM), без валидатора: +cargo test -p smart-updown +``` + +Если пересобираете, IDL не меняется, пока не меняете layout аккаунтов/инструкций. +После изменения контракта: пересоберите `.so`, перегенерируйте IDL +(`anchor build`, при наличии anchor-cli 2.0.0-rc.1) и обновите `relayer/idl/` +и `idl/`. + +## 7. Переменные окружения relayer (см. .env.example) + +| Переменная | По умолчанию | Описание | +|---|---|---| +| `SMART_RPC_URL` | `http://127.0.0.1:8899` | RPC кластера | +| `SMART_ALLOW_AIRDROP` | `1` | airDrop bettors/ваулта (localnet) | +| `SMART_ADMIN_KEYPAIR` | `~/.config/solana/id.json` | keypair админа/релеера | +| `SMART_MIN_AMOUNT` | `100000000` | мин. ставка (лампорты) | +| `SMART_MAX_AMOUNT` | `10000000000` | макс. ставка (лампорты) | +| `SMART_MULTIPLIER_BPS` | `13000` | выплата 1.3x (bps) | +| `SMART_EXPIRY_SECONDS` | `15` | экспирация (сек) | diff --git a/smart-updown/deploy-localnet.sh b/smart-updown/deploy-localnet.sh new file mode 100755 index 0000000..0b75d50 --- /dev/null +++ b/smart-updown/deploy-localnet.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# Развёртывание smart-updown на localnet (solana-test-validator). +# Использование: ./deploy-localnet.sh +# +# Требования: Solana CLI (solana-test-validator, solana program deploy). +# Если нужно пересобрать программу из исходников, см. README (опционально). +set -euo pipefail + +HERE="$(cd "$(dirname "$0")" && pwd)" +PROGRAM_SO="$HERE/deploy/smart_updown.so" +PROGRAM_KEYPAIR="$HERE/deploy/smart_updown-keypair.json" +PROGRAM_ID="E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3" +RPC_URL="http://127.0.0.1:8899" + +# 1. Настройка CLI на localhost +solana config set --url "$RPC_URL" +solana-keygen pubkey "$PROGRAM_KEYPAIR" >/dev/null 2>&1 || { + echo "Ошибка: нет deploy/smart_updown-keypair.json" + exit 1 +} + +# 2. Запуск валидатора с предзагруженной программой (если ещё не запущен) +if ! solana cluster-version >/dev/null 2>&1; then + echo ">>> Стартую solana-test-validator с программой $PROGRAM_ID" + solana-test-validator --reset \ + --bpf-program "$PROGRAM_ID" "$PROGRAM_SO" \ + >test-ledger.log 2>&1 & + sleep 6 +fi +solana cluster-version + +# 3. Убеждаемся, что программа на месте +if ! solana program show "$PROGRAM_ID" >/dev/null 2>&1; then + echo ">>> Деплою программу" + solana program deploy --program-id "$PROGRAM_KEYPAIR" "$PROGRAM_SO" +else + echo ">>> Программа уже задеплоена: $PROGRAM_ID" +fi +solana program show "$PROGRAM_ID" | head -12 + +echo +echo "Готово. Vault/Global инициализируется первым запуском relayer: npm run init" +echo "Дальше: npm run loop (непрерывно) или npm run run (один прогон)." +echo diff --git a/smart-updown/deploy/smart_updown-keypair.json b/smart-updown/deploy/smart_updown-keypair.json new file mode 100644 index 0000000..15706e6 --- /dev/null +++ b/smart-updown/deploy/smart_updown-keypair.json @@ -0,0 +1 @@ +[39,64,110,209,237,123,147,255,190,74,164,207,160,225,89,109,119,197,167,34,86,233,138,227,63,17,57,104,123,10,58,140,194,196,68,144,108,208,236,142,221,255,163,163,238,139,47,184,50,184,127,42,175,209,36,41,202,28,56,58,98,37,116,204] \ No newline at end of file diff --git a/smart-updown/deploy/smart_updown.so b/smart-updown/deploy/smart_updown.so new file mode 100755 index 0000000..47bcdad Binary files /dev/null and b/smart-updown/deploy/smart_updown.so differ diff --git a/smart-updown/idl/smart_updown.json b/smart-updown/idl/smart_updown.json new file mode 100644 index 0000000..0c72abb --- /dev/null +++ b/smart-updown/idl/smart_updown.json @@ -0,0 +1,546 @@ +{ + "address": "E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3", + "metadata": { + "name": "smart_updown", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "close_bet", + "discriminator": [ + 2 + ], + "accounts": [ + { + "name": "relayer", + "signer": true + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bettor", + "docs": [ + "CHECK: recipient must be the bet's bettor and is validated in the handler." + ], + "writable": true + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "exit_price", + "type": "u64" + } + ] + }, + { + "name": "create_bet", + "discriminator": [ + 1 + ], + "accounts": [ + { + "name": "bettor", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "entry_price", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 0 + ], + "accounts": [ + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "min_amount", + "type": "u64" + }, + { + "name": "max_amount", + "type": "u64" + }, + { + "name": "multiplier_bps", + "type": "u64" + }, + { + "name": "expiry_seconds", + "type": "i64" + } + ] + }, + { + "name": "update", + "discriminator": [ + 3 + ], + "accounts": [ + { + "name": "admin", + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + } + ], + "args": [ + { + "name": "new_relayer", + "type": "pubkey" + }, + { + "name": "min_amount", + "type": "u64" + }, + { + "name": "max_amount", + "type": "u64" + }, + { + "name": "multiplier_bps", + "type": "u64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "expiry_seconds", + "type": "i64" + } + ] + } + ], + "accounts": [ + { + "name": "Bet", + "discriminator": [ + 147, + 23, + 35, + 59, + 15, + 75, + 155, + 32 + ] + }, + { + "name": "Global", + "discriminator": [ + 167, + 232, + 232, + 177, + 200, + 108, + 114, + 127 + ] + } + ], + "events": [ + { + "name": "BetClosed", + "discriminator": [ + 122, + 20, + 157, + 254, + 221, + 0, + 39, + 129 + ] + }, + { + "name": "BetCreated", + "discriminator": [ + 32, + 153, + 105, + 71, + 188, + 72, + 107, + 114 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "Paused", + "msg": "Operation is paused" + }, + { + "code": 6001, + "name": "NotAdmin", + "msg": "Only the admin can perform this action" + }, + { + "code": 6002, + "name": "NotRelayer", + "msg": "Only the relayer is allowed to close bets" + }, + { + "code": 6003, + "name": "AmountBelowMin", + "msg": "Amount below the allowed minimum" + }, + { + "code": 6004, + "name": "AmountAboveMax", + "msg": "Amount above the allowed maximum" + }, + { + "code": 6005, + "name": "InvalidSide", + "msg": "Invalid side value" + }, + { + "code": 6006, + "name": "BetAlreadyFinalized", + "msg": "Bet is already finalized" + }, + { + "code": 6007, + "name": "NotExpired", + "msg": "Bet cannot be closed before expiry" + }, + { + "code": 6008, + "name": "BetIdMismatch", + "msg": "Bet id mismatch" + }, + { + "code": 6009, + "name": "InsufficientVault", + "msg": "Payout exceeds vault solvency" + } + ], + "types": [ + { + "name": "Bet", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "bet_time", + "type": "i64" + }, + { + "name": "expire_time", + "type": "i64" + }, + { + "name": "entry_price", + "type": "u64" + }, + { + "name": "exit_price", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + }, + { + "name": "bettor", + "type": "pubkey" + } + ] + } + }, + { + "name": "BetClosed", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "exit_price", + "type": "u64" + }, + { + "name": "user_won", + "type": "bool" + }, + { + "name": "payout", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + } + ] + } + }, + { + "name": "BetCreated", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "bettor", + "type": "pubkey" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "bet_time", + "type": "i64" + }, + { + "name": "expire_time", + "type": "i64" + }, + { + "name": "entry_price", + "type": "u64" + } + ] + } + }, + { + "name": "Global", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "counter", + "type": "u64" + }, + { + "name": "min_amount", + "type": "u64" + }, + { + "name": "max_amount", + "type": "u64" + }, + { + "name": "multiplier_bps", + "type": "u64" + }, + { + "name": "expiry_seconds", + "type": "i64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "relayer", + "type": "pubkey" + } + ] + } + } + ], + "constants": [ + { + "name": "BET_SEED", + "type": "bytes", + "value": "[98, 101, 116]" + }, + { + "name": "GLOBAL_SEED", + "type": "bytes", + "value": "[103, 108, 111, 98, 97, 108]" + } + ] +} \ No newline at end of file diff --git a/smart-updown/idl/smart_updown.ts b/smart-updown/idl/smart_updown.ts new file mode 100644 index 0000000..544568f --- /dev/null +++ b/smart-updown/idl/smart_updown.ts @@ -0,0 +1,552 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/smart_updown.json`. + */ +export type SmartUpdown = { + "address": "E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3", + "metadata": { + "name": "smartUpdown", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "closeBet", + "discriminator": [ + 2 + ], + "accounts": [ + { + "name": "relayer", + "signer": true + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bettor", + "docs": [ + "CHECK: recipient must be the bet's bettor and is validated in the handler." + ], + "writable": true + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "exitPrice", + "type": "u64" + } + ] + }, + { + "name": "createBet", + "discriminator": [ + 1 + ], + "accounts": [ + { + "name": "bettor", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "entryPrice", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 0 + ], + "accounts": [ + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "minAmount", + "type": "u64" + }, + { + "name": "maxAmount", + "type": "u64" + }, + { + "name": "multiplierBps", + "type": "u64" + }, + { + "name": "expirySeconds", + "type": "i64" + } + ] + }, + { + "name": "update", + "discriminator": [ + 3 + ], + "accounts": [ + { + "name": "admin", + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + } + ], + "args": [ + { + "name": "newRelayer", + "type": "pubkey" + }, + { + "name": "minAmount", + "type": "u64" + }, + { + "name": "maxAmount", + "type": "u64" + }, + { + "name": "multiplierBps", + "type": "u64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "expirySeconds", + "type": "i64" + } + ] + } + ], + "accounts": [ + { + "name": "bet", + "discriminator": [ + 147, + 23, + 35, + 59, + 15, + 75, + 155, + 32 + ] + }, + { + "name": "global", + "discriminator": [ + 167, + 232, + 232, + 177, + 200, + 108, + 114, + 127 + ] + } + ], + "events": [ + { + "name": "betClosed", + "discriminator": [ + 122, + 20, + 157, + 254, + 221, + 0, + 39, + 129 + ] + }, + { + "name": "betCreated", + "discriminator": [ + 32, + 153, + 105, + 71, + 188, + 72, + 107, + 114 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "paused", + "msg": "Operation is paused" + }, + { + "code": 6001, + "name": "notAdmin", + "msg": "Only the admin can perform this action" + }, + { + "code": 6002, + "name": "notRelayer", + "msg": "Only the relayer is allowed to close bets" + }, + { + "code": 6003, + "name": "amountBelowMin", + "msg": "Amount below the allowed minimum" + }, + { + "code": 6004, + "name": "amountAboveMax", + "msg": "Amount above the allowed maximum" + }, + { + "code": 6005, + "name": "invalidSide", + "msg": "Invalid side value" + }, + { + "code": 6006, + "name": "betAlreadyFinalized", + "msg": "Bet is already finalized" + }, + { + "code": 6007, + "name": "notExpired", + "msg": "Bet cannot be closed before expiry" + }, + { + "code": 6008, + "name": "betIdMismatch", + "msg": "Bet id mismatch" + }, + { + "code": 6009, + "name": "insufficientVault", + "msg": "Payout exceeds vault solvency" + } + ], + "types": [ + { + "name": "bet", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "betTime", + "type": "i64" + }, + { + "name": "expireTime", + "type": "i64" + }, + { + "name": "entryPrice", + "type": "u64" + }, + { + "name": "exitPrice", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + }, + { + "name": "bettor", + "type": "pubkey" + } + ] + } + }, + { + "name": "betClosed", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "exitPrice", + "type": "u64" + }, + { + "name": "userWon", + "type": "bool" + }, + { + "name": "payout", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + } + ] + } + }, + { + "name": "betCreated", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "bettor", + "type": "pubkey" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "betTime", + "type": "i64" + }, + { + "name": "expireTime", + "type": "i64" + }, + { + "name": "entryPrice", + "type": "u64" + } + ] + } + }, + { + "name": "global", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "counter", + "type": "u64" + }, + { + "name": "minAmount", + "type": "u64" + }, + { + "name": "maxAmount", + "type": "u64" + }, + { + "name": "multiplierBps", + "type": "u64" + }, + { + "name": "expirySeconds", + "type": "i64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "relayer", + "type": "pubkey" + } + ] + } + } + ], + "constants": [ + { + "name": "betSeed", + "type": "bytes", + "value": "[98, 101, 116]" + }, + { + "name": "globalSeed", + "type": "bytes", + "value": "[103, 108, 111, 98, 97, 108]" + } + ] +}; diff --git a/smart-updown/program/.gitignore b/smart-updown/program/.gitignore new file mode 100644 index 0000000..58466dc --- /dev/null +++ b/smart-updown/program/.gitignore @@ -0,0 +1,8 @@ +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn +.surfpool diff --git a/smart-updown/program/Anchor.toml b/smart-updown/program/Anchor.toml new file mode 100644 index 0000000..6da4f68 --- /dev/null +++ b/smart-updown/program/Anchor.toml @@ -0,0 +1,20 @@ +skip_local_validator = true + +[toolchain] +package_manager = "npm" + +[features] +resolution = true +skip-lint = false + +[programs.localnet] +smart_updown = "E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3" + +[provider] +cluster = "localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +test = "cargo test" + +[hooks] diff --git a/smart-updown/program/Cargo.lock b/smart-updown/program/Cargo.lock new file mode 100644 index 0000000..79dd138 --- /dev/null +++ b/smart-updown/program/Cargo.lock @@ -0,0 +1,4041 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common 0.1.7", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures 0.2.17", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "agave-bls12-381" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "210b1ef312273aa81ccb4c52687d96e3cf07621f3619a7998be20eb9741b08e3" +dependencies = [ + "blst", + "blstrs", + "bytemuck", + "bytemuck_derive", + "group", + "pairing", +] + +[[package]] +name = "agave-feature-set" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dde74a2d1f2f99a3ea59938d1533c7973c344e47d24c1b645ee81e958c54226a" +dependencies = [ + "ahash", + "solana-epoch-schedule", + "solana-hash 4.2.0", + "solana-keypair", + "solana-pubkey 4.1.0", + "solana-sha256-hasher", + "solana-svm-feature-set", +] + +[[package]] +name = "agave-reserved-account-keys" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "798e559c514af005950ea81586a3856f9297ecb80a7359057c19bf6717f5f537" +dependencies = [ + "agave-feature-set", + "solana-pubkey 4.1.0", + "solana-sdk-ids", +] + +[[package]] +name = "agave-syscalls" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84debd4abe0cbab5a6aac2ee50e3969ef0e0961f7dff7e8f96bda0be7998bca2" +dependencies = [ + "agave-bls12-381", + "bincode", + "libsecp256k1", + "num-traits", + "solana-account", + "solana-account-info", + "solana-big-mod-exp", + "solana-blake3-hasher", + "solana-bn254", + "solana-clock", + "solana-cpi", + "solana-curve25519", + "solana-hash 4.2.0", + "solana-instruction", + "solana-keccak-hasher", + "solana-loader-v3-interface", + "solana-poseidon", + "solana-program-entrypoint", + "solana-program-runtime", + "solana-pubkey 4.1.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-sha256-hasher", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-type-overrides", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.20", +] + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anchor-derive-accounts" +version = "2.0.0-rc.1" +source = "git+https://github.com/otter-sec/anchor.git?branch=anchor-next#dbdc31fa415ff36e80dbe861c1a2008f72c8b38e" +dependencies = [ + "anchor-lang-idl", + "bs58", + "curve25519-dalek", + "proc-macro2", + "quote", + "serde_json", + "sha2 0.10.9", + "solana-address 2.7.0", + "syn 2.0.119", +] + +[[package]] +name = "anchor-lang" +version = "2.0.0-rc.1" +source = "git+https://github.com/otter-sec/anchor.git?branch=anchor-next#dbdc31fa415ff36e80dbe861c1a2008f72c8b38e" +dependencies = [ + "anchor-derive-accounts", + "bytemuck", + "pinocchio", + "pinocchio-system", + "sha2 0.10.9", + "solana-address 2.7.0", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-program-memory", + "solana-sha256-hasher", + "solana-system-interface 2.0.0", + "solana-sysvar", + "wincode 0.6.1", +] + +[[package]] +name = "anchor-lang-idl" +version = "0.2.0" +source = "git+https://github.com/otter-sec/anchor.git?branch=anchor-next#dbdc31fa415ff36e80dbe861c1a2008f72c8b38e" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck", + "serde", + "serde_json", + "sha2 0.10.9", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +source = "git+https://github.com/otter-sec/anchor.git?branch=anchor-next#dbdc31fa415ff36e80dbe861c1a2008f72c8b38e" +dependencies = [ + "anyhow", + "serde", +] + +[[package]] +name = "anchor-v2-testing" +version = "0.1.0" +source = "git+https://github.com/otter-sec/anchor.git?branch=anchor-next#dbdc31fa415ff36e80dbe861c1a2008f72c8b38e" +dependencies = [ + "litesvm", + "solana-keypair", + "solana-message", + "solana-program-runtime", + "solana-signer", + "solana-transaction", + "solana-transaction-context", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint 0.4.8", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.8", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.8", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive 0.4.2", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.8", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.8", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.8", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "autocfg" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" + +[[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.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 = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.1", + "digest 0.11.3", +] + +[[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 = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "blst" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20659f9bbee16cbbd2f7393e40ab6309f5a98f76a2eb57a995ec508b72387fe" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "borsh" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553c5d846a6ba5150c65e3b1b8ec073bcf1abc20f9b7220de384a4443ea4e20a" +dependencies = [ + "borsh-derive", + "bytes", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cdfe656708a01f89b451a7d36466e6fe6c414de0aa18fc54f864f6f9ca9f56" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[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 = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytemuck" +version = "1.25.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0e56a716f1e132ff6bf4bdac1c944a3fcdc1cae65f70a4a2a1ac3b401d2d1f" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" + +[[package]] +name = "cc" +version = "1.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad534f4357a5264cce5019c989cf66a4f0dc4e0d1b1d15f8aacec0ff7360273" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" + +[[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.119", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common 0.1.7", + "inout", +] + +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[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.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "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.119", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.119", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.119", +] + +[[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 = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[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 0.1.7", + "subtle", +] + +[[package]] +name = "digest" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" +dependencies = [ + "block-buffer 0.12.1", + "crypto-common 0.2.2", + "ctutils", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[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", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "either" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" + +[[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 = "enum-iterator" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4549325971814bda7a44061bf3fe7e487d447cba01e4220a4b454d630d7a016" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[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 = [ + "bitvec", + "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 = "find-msvc-tools" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" + +[[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 = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "gdbstub" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e02bf1b1a624d96925c608f1b268d82a76cbc587ce9e59f7c755e9ea11c75c" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "log", + "managed", + "num-traits", + "paste", +] + +[[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 = "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.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "glob" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand 0.8.8", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[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" + +[[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 = "hybrid-array" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b" +dependencies = [ + "typenum", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07aa2048142242915a31d35844fb311e0e53fcca590c3a0a40dcf1b841fa09eb" +dependencies = [ + "equivalent", + "hashbrown 0.17.1", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[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", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures 0.2.17", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.189" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" + +[[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", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", +] + +[[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-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ff 0.4.2", + "num-bigint 0.4.8", + "thiserror 1.0.69", +] + +[[package]] +name = "light-poseidon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a1ccadd0bb5a32c196da536fd72c59183de24a055f6bf0513bf845fefab862" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ff 0.5.0", + "num-bigint 0.4.8", + "thiserror 1.0.69", +] + +[[package]] +name = "litesvm" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1e00083aad2a7aa9d6900454604f7776da40be57304e5119f09222a1e9b105a" +dependencies = [ + "agave-feature-set", + "agave-reserved-account-keys", + "agave-syscalls", + "ansi_term", + "bincode", + "hex", + "indexmap", + "itertools 0.14.0", + "log", + "nom", + "serde", + "sha2 0.10.9", + "solana-account", + "solana-address 2.7.0", + "solana-address-lookup-table-interface", + "solana-bpf-loader-program", + "solana-builtins", + "solana-clock", + "solana-compute-budget", + "solana-compute-budget-instruction", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-fee", + "solana-fee-structure", + "solana-hash 4.2.0", + "solana-instruction", + "solana-instruction-error", + "solana-instructions-sysvar", + "solana-keypair", + "solana-last-restart-slot", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-loader-v4-program", + "solana-message", + "solana-native-token", + "solana-nonce", + "solana-nonce-account", + "solana-precompile-error", + "solana-program-error", + "solana-program-runtime", + "solana-rent 3.1.0", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-log-collector", + "solana-svm-timings", + "solana-svm-transaction", + "solana-system-interface 3.1.0", + "solana-system-program", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.20", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" + +[[package]] +name = "managed" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca88d725a0a943b096803bd34e73a4437208b6077654cc4ecb2947a5f91618d" + +[[package]] +name = "memchr" +version = "2.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[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", + "num-integer", + "num-iter", + "num-rational", + "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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" +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-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "num-integer" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" +dependencies = [ + "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-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 = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pastey" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4" + +[[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 = "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", +] + +[[package]] +name = "pinocchio" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cababcb62a2e739c7078ae16eda02789a6e3edd21bbdded864e85c38a7914d" +dependencies = [ + "solana-account-view", + "solana-address 2.7.0", + "solana-define-syscall 5.2.0", + "solana-instruction-view", + "solana-program-error", +] + +[[package]] +name = "pinocchio-system" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ae2ee67b42e2ac797dd88312da473c895660e270d8093e0ba2749b885b5778" +dependencies = [ + "pinocchio", + "solana-address 2.7.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +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 = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + +[[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.17", +] + +[[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_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.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.13.1", +] + +[[package]] +name = "regex" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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 = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "serde" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" +dependencies = [ + "serde_core", + "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.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.229" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "serde_json" +version = "1.0.151" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_with" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee78f1fbe43ac4a0e47aadb3dbd357b69eb0d3793e948624cd03dd2750ab1c0a" +dependencies = [ + "serde_core", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "3.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8705578779c2b6bd90d84d66eb2e206b708b1a4d7b9f17641b293545bf1c7e46" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[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 0.2.17", + "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 0.2.17", + "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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[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 = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "smart-updown" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "anchor-v2-testing", + "solana-clock", + "solana-program-log", + "solana-pubkey 3.0.0", + "wincode 0.5.5", +] + +[[package]] +name = "solana-account" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc0ed36decb689413b9da5d57f2be49eea5bebb3cf7897015167b0c4336e731" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-sysvar", +] + +[[package]] +name = "solana-account-info" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9cf16495d9eb53e3d04e72366a33bb1c20c24e78c171d8b8f5978357b63ae95" +dependencies = [ + "solana-address 2.7.0", + "solana-program-error", + "solana-program-memory", +] + +[[package]] +name = "solana-account-view" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc141b940560430425ebaadb7645496c45f6a10fad9911d719bd03eab7f4d422" +dependencies = [ + "solana-address 2.7.0", + "solana-program-error", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.7.0", +] + +[[package]] +name = "solana-address" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01332a01c0a3098404d55a724c8d9a92aed4a50fe40a7dd0c7a51e29274c14de" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8", + "five8_const", + "serde", + "serde_derive", + "sha2-const-stable", + "solana-atomic-u64", + "solana-define-syscall 5.2.0", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", + "wincode 0.6.1", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e8df0b083c10ce32490410f3795016b1b5d9b4d094658c0a5e496753645b7cd" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[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 = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" +dependencies = [ + "num-bigint 0.4.8", + "num-traits", + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-bincode" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278a1a5bad62cd9da89ac8d4b7ec444e83caa8ae96aa656dfc27684b28d49a5d" +dependencies = [ + "bincode", + "serde_core", + "solana-instruction-error", +] + +[[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.2.0", +] + +[[package]] +name = "solana-bls-signatures" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3d8a6e1a009bddbdbfe13ee6ff206c16afa9f8fae7d04612d779ac2254ad5f" +dependencies = [ + "base64 0.22.1", + "blst", + "blstrs", + "cfg_eval", + "ff", + "group", + "pairing", + "rand 0.8.8", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.20", +] + +[[package]] +name = "solana-bn254" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ff13a8867fcc7b0f1114764e1bf6191b4551dcaf93729ddc676cd4ec6abc9f" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "bytemuck", + "solana-define-syscall 5.2.0", + "thiserror 2.0.20", +] + +[[package]] +name = "solana-borsh" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04abbae16f57178a163125805637b8a076175bb5c0002fb04f4792bea901cf7" +dependencies = [ + "borsh", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219bfba64973ac9e64aa181f03fd56ac319e2d50d8a23d16c54bbd7fa9807a47" +dependencies = [ + "agave-syscalls", + "bincode", + "qualifier_attr", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-instruction", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-packet", + "solana-program-entrypoint", + "solana-program-runtime", + "solana-pubkey 4.1.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-type-overrides", + "solana-system-interface 3.1.0", + "solana-transaction-context", +] + +[[package]] +name = "solana-builtins" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda9d147935c741533496edf72c5b712885d4793a0bca13a21bd75d8f5dc30e9" +dependencies = [ + "agave-feature-set", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-hash 4.2.0", + "solana-loader-v4-program", + "solana-program-runtime", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-system-program", + "solana-vote-program", + "solana-zk-elgamal-proof-program", + "solana-zk-token-proof-program", +] + +[[package]] +name = "solana-builtins-default-costs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3167997e8ac0fe100c4ed54503568d22204aeda56f4d3549e0c09a700b609aa8" +dependencies = [ + "agave-feature-set", + "ahash", + "log", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-loader-v4-program", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-system-program", + "solana-vote-program", +] + +[[package]] +name = "solana-clock" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7708bdb262fd9c257c3a56d4289297b10a3e821b8cba3f7cf42b49c40201ab9" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-compute-budget" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b591fbaed6d9ab4cba6a5a82eb5df208072ced2e5b74c59e9d309ff87af0615f" +dependencies = [ + "solana-fee-structure", + "solana-program-runtime", +] + +[[package]] +name = "solana-compute-budget-instruction" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006d9b6a34f9d7b719100653317990ed55e572107702104c054133b40f587306" +dependencies = [ + "agave-feature-set", + "log", + "solana-borsh", + "solana-builtins-default-costs", + "solana-compute-budget", + "solana-compute-budget-interface", + "solana-instruction", + "solana-packet", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-svm-transaction", + "solana-transaction-error", + "thiserror 2.0.20", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8292c436b269ad23cecc8b24f7da3ab07ca111661e25e00ce0e1d22771951ab9" +dependencies = [ + "borsh", + "solana-instruction", + "solana-sdk-ids", +] + +[[package]] +name = "solana-compute-budget-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22bcf5088ebe5cb2aa548580d0a466de813032b425707a7745a2a63a7764cdc" +dependencies = [ + "solana-program-runtime", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.1.0", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b4d2a4bf0d0b0a86c22111917e86e8bd39a7b31420fb2c7d73eb83761fc7af" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall 5.2.0", + "subtle", + "thiserror 2.0.20", +] + +[[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.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf8209ece2bd9f1450e672858ffc0e5c8c786ff6916d2a862b126dd0128f380f" + +[[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-rewards" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e7b0ba210593ba8ddd39d6d234d81795d1671cebf3026baa10d5dc23ac42f0" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 4.2.0", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[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", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ca9b5cbb6f500f7fd73db5bd95640f71a83f04d6121a0e59a43b202dca2731" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.1.0", + "solana-rent 4.4.0", + "solana-sdk-ids", + "solana-system-interface 3.1.0", +] + +[[package]] +name = "solana-fee" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e506f6ec94e5733b0f2114b43bd8a2abac33a0256e19c65e1d119de008981339" +dependencies = [ + "agave-feature-set", + "solana-fee-structure", + "solana-svm-transaction", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef67f01cc6a0c72e99a08d0d484683f995de4c80e9568728fa77d1537f9b7e09" +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" + +[[package]] +name = "solana-get-sysvar" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef3bc859fc036ed490146793557386cbfae614ebba4adc704c37d94350824ed4" +dependencies = [ + "solana-address 2.7.0", + "solana-define-syscall 5.2.0", + "solana-program-error", +] + +[[package]] +name = "solana-hash" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" +dependencies = [ + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-hash" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8064ea1d591ec791be95245058ca40f4f5345d390c200069d0f79bbf55bfae55" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "five8", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", +] + +[[package]] +name = "solana-instruction" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6a6d22d0a6fdf345be294bb9afdcd40c296cdc095e64e7ceaa3bb3c2f608c1c" +dependencies = [ + "bincode", + "borsh", + "serde", + "serde_derive", + "solana-define-syscall 5.2.0", + "solana-instruction-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3d048edaaeef5a3dc8c01853e585539a74417e4c2d43a9e2c161270045b838" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error", +] + +[[package]] +name = "solana-instruction-view" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab7a27d0c4214b9f7389c3dd00b68c93093a67f1dcc5b7893aebe299bbcbb47" +dependencies = [ + "solana-account-view", + "solana-address 2.7.0", + "solana-define-syscall 5.2.0", + "solana-program-error", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" +dependencies = [ + "bitflags 2.13.1", + "solana-account-info", + "solana-instruction", + "solana-instruction-error", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[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.2.0", +] + +[[package]] +name = "solana-keypair" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "263d614c12aa267a3278703175fd6440552ca61bc960b5a02a4482720c53438b" +dependencies = [ + "ed25519-dalek", + "five8", + "five8_core", + "rand 0.9.5", + "solana-address 2.7.0", + "solana-seed-phrase", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5099e736c3c06c451b307a60637d69eb65b3144143ebeed899e2fd1134f4fc35" +dependencies = [ + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee44c9b1328c5c712c68966fb8de07b47f3e7bac006e74ddd1bb053d3e46e5d" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c948b33ff81fa89699911b207059e493defdba9647eaf18f23abdf3674e0fb" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-loader-v4-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b5191cd34f04e4ec9fd5f2ac8a431ba9ffd6c827511fd35f2cae0256a0c6b12" +dependencies = [ + "log", + "solana-account", + "solana-bincode", + "solana-bpf-loader-program", + "solana-instruction", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 4.1.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-type-overrides", + "solana-transaction-context", +] + +[[package]] +name = "solana-message" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-address 2.7.0", + "solana-hash 4.2.0", + "solana-instruction", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-transaction-error", +] + +[[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.2.0", +] + +[[package]] +name = "solana-native-token" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" + +[[package]] +name = "solana-nonce" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc469152a63284ef959b80c59cda015262a021da55d3b8fe42171d89c4b64f8" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash 4.2.0", + "solana-pubkey 4.1.0", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-nonce-account" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805fd25b29e5a1a0e6c3dd6320c9da80f275fbe4ff6e392617c303a2085c435e" +dependencies = [ + "solana-account", + "solana-hash 3.1.0", + "solana-nonce", + "solana-sdk-ids", +] + +[[package]] +name = "solana-packet" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad62e1045c2347a0c0e219a6ceb0abfe904be622920996bfcac8d116fabe3c7" +dependencies = [ + "bitflags 2.13.1", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-poseidon" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "737b8ab25bf4cc8e618f80f1fe40709b2ace708bc764a36b8a4c81eea8c07034" +dependencies = [ + "ark-bn254 0.4.0", + "ark-bn254 0.5.0", + "light-poseidon 0.2.0", + "light-poseidon 0.4.0", + "solana-define-syscall 4.0.1", + "thiserror 2.0.20", +] + +[[package]] +name = "solana-precompile-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" +dependencies = [ + "num-traits", +] + +[[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", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f04fa578707b3612b095f0c8e19b66a1233f7c42ca8082fcb3b745afcc0add6" + +[[package]] +name = "solana-program-log" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd48ddef444e6db138fb11bdb9ab8117bb830a78cef051a453454de5613039b" +dependencies = [ + "solana-define-syscall 5.2.0", + "solana-program-log-macro", +] + +[[package]] +name = "solana-program-log-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b234f83b71ba6b5d3236b69ba42ccb639907cb724bf58e94ce8398b51ac87c" +dependencies = [ + "quote", + "regex", + "syn 2.0.119", +] + +[[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-runtime" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6c7f89c89d5ff25f64a41c8cb00478b1d62f941f14a7dd8537c9e50bb2acc92" +dependencies = [ + "base64 0.22.1", + "bincode", + "cfg-if", + "itertools 0.14.0", + "log", + "percentage", + "rand 0.9.5", + "serde", + "solana-account", + "solana-account-info", + "solana-clock", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-structure", + "solana-hash 4.2.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-loader-v3-interface", + "solana-program-entrypoint", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface 3.1.0", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.20", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b06bd918d60111ee1f97de817113e2040ca0cedb740099ee8d646233f6b906c" +dependencies = [ + "solana-address 2.7.0", +] + +[[package]] +name = "solana-rent" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-rent" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc016b348926395ba01f8288cdf5da25fc30f5a0806028b32d5e5b3147b10bf9" +dependencies = [ + "solana-sdk-macro", +] + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sbpf" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733b3657a0fab205102b799dbe17f85d3972cf984232c1b0b108fa6ba438e382" +dependencies = [ + "byteorder", + "combine", + "gdbstub", + "hash32", + "libc", + "log", + "rand 0.8.8", + "rustc-demangle", + "thiserror 2.0.20", + "winapi", +] + +[[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.7.0", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8765316242300c48242d84a41614cb3388229ec353ba464f6fe62a733e41806f" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0d2e8d53946f04e789476d6c407e4997b7fb412483df5fc10c075c65cb2edf" +dependencies = [ + "k256", + "solana-define-syscall 5.2.0", + "thiserror 2.0.20", +] + +[[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 = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" +dependencies = [ + "hmac", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-serde-varint" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950e5b83e839dc0f92c66afc124bb8f40e89bc90f0579e8ec5499296d27f54e3" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7cc401931d178472358e6b78dc72d031dc08f752d7410f0e8bd259dd6f02fa" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sanitize", +] + +[[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.2.0", +] + +[[package]] +name = "solana-short-vec" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75782529cc4521114c1ecd71c7e2cdebd41a6fe9844b5d088fd36ef08c57c36" +dependencies = [ + "serde_core", +] + +[[package]] +name = "solana-signature" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "132a93134f1262aa832f1849b83bec6c9945669b866da18661a427943b9e801e" +dependencies = [ + "ed25519-dalek", + "five8", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize", + "wincode 0.4.9", +] + +[[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", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2585f70191623887329dfb5078da3a00e15e3980ea67f42c2e10b07028419f43" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 4.2.0", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4560fde841a6f2001aedc33b74fe99840ee3d56a71fe9b98ee332303b8597900" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-get-sysvar", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f6a291ba063a37780af29e7db14bdd3dc447584d8ba5b3fc4b88e2bbc982fa" +dependencies = [ + "solana-instruction", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-stake-interface" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9bc26191b533f9a6e5a14cca05174119819ced680a80febff2f5051a713f0db" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-sysvar-id", +] + +[[package]] +name = "solana-svm-callback" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4006b0da7e50cba514ced6b47bcf8f9591552458200e361fd4bdef4068cb2fed" +dependencies = [ + "solana-account", + "solana-clock", + "solana-precompile-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-svm-feature-set" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ea15c0d91403375e3d017cc09780cf138b629abba4ccaaa7cf66b1afea1059" + +[[package]] +name = "solana-svm-log-collector" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efb7d3ccd3a51b85807ff16b2f513069e8b55e220b280774a3e9b899bcb81987" +dependencies = [ + "log", +] + +[[package]] +name = "solana-svm-measure" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d70c9972c1f03cb2bbc64d23dc2079419a66d89b49d6b44f79206530551ddc8c" + +[[package]] +name = "solana-svm-timings" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f3d66aa88c9001a076362108f7967d6a00d121ba38428e56928935566ed5bd" +dependencies = [ + "eager", + "enum-iterator", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-svm-transaction" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "067861db805d135a6fbe489bf2b74d701f270df8d03afd3257f7d51a2ff3467e" +dependencies = [ + "solana-hash 4.2.0", + "solana-message", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-signature", + "solana-transaction", +] + +[[package]] +name = "solana-svm-type-overrides" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e41661ebf0edcc296b15251c08fee0ad2da3257e6ab86cea2a0a8f6fba642c6" +dependencies = [ + "rand 0.9.5", +] + +[[package]] +name = "solana-system-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-system-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a95a6f2e23ed861d6444ad4a6d6896c418d7d101b960787e65a8e33157cee81b" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-address 2.7.0", + "solana-instruction", + "solana-msg", + "solana-program-error", +] + +[[package]] +name = "solana-system-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "450479004fee3396c88cc4aa2f9b2b8db9c77be42ee7c1c53e6fac9eaec5fd51" +dependencies = [ + "bincode", + "log", + "serde", + "solana-account", + "solana-bincode", + "solana-fee-calculator", + "solana-instruction", + "solana-nonce", + "solana-nonce-account", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-svm-log-collector", + "solana-svm-type-overrides", + "solana-system-interface 3.1.0", + "solana-sysvar", + "solana-transaction-context", +] + +[[package]] +name = "solana-sysvar" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall 4.0.1", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash 4.2.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-sysvar-id", +] + +[[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.7.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-address 2.7.0", + "solana-hash 4.2.0", + "solana-instruction", + "solana-instruction-error", + "solana-message", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction-error", +] + +[[package]] +name = "solana-transaction-context" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecefe8b30e334e2891ca82da35becd9a3f4c16021d9ca782e2a82adf31084fa3" +dependencies = [ + "bincode", + "serde", + "solana-account", + "solana-instruction", + "solana-instructions-sysvar", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", + "solana-sbpf", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8396904805b0b385b9de115a652fe80fd01e5b98ce0513f4fcd8184ada9bb792" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction-error", + "solana-sanitize", +] + +[[package]] +name = "solana-vote-interface" +version = "5.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d444ce30b6b4f9c281ba06061ea96638d063b53c2171b1e41ba02ebff79ed28f" +dependencies = [ + "bincode", + "cfg_eval", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "serde_with", + "solana-clock", + "solana-hash 4.2.0", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-rent 4.4.0", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface 3.1.0", +] + +[[package]] +name = "solana-vote-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4537fd6efe65f53ccd28d54d2ad43275b024834a4a8ca4dfa4babfa01e6d11ab" +dependencies = [ + "agave-feature-set", + "bincode", + "log", + "num-derive", + "num-traits", + "serde", + "solana-account", + "solana-bincode", + "solana-bls-signatures", + "solana-clock", + "solana-epoch-schedule", + "solana-hash 4.2.0", + "solana-instruction", + "solana-keypair", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", + "solana-sdk-ids", + "solana-signer", + "solana-slot-hashes", + "solana-system-interface 3.1.0", + "solana-transaction", + "solana-transaction-context", + "solana-vote-interface", + "thiserror 2.0.20", +] + +[[package]] +name = "solana-zk-elgamal-proof-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf97ec816e8c6d45b5f05e21381bcc4b856cb3c89b69e465ee20972368b4c31" +dependencies = [ + "agave-feature-set", + "bytemuck", + "num-derive", + "num-traits", + "solana-instruction", + "solana-program-runtime", + "solana-sdk-ids", + "solana-svm-log-collector", + "solana-zk-sdk", +] + +[[package]] +name = "solana-zk-sdk" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09670ff59f60e6ddc2209c2e4353992a9b9f01d4e244f3e9d67bd5146e33d388" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "itertools 0.14.0", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.8", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-address 2.7.0", + "solana-derivation-path", + "solana-instruction", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.20", + "zeroize", +] + +[[package]] +name = "solana-zk-token-proof-program" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f08a8be7008cec95d74c0ded5ae10b6869bd06bd9761c800e7e098bd45097e6" +dependencies = [ + "solana-program-runtime", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[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.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6275cddf4610d1775e6d1fe9469b2e77d0f39fd98fb7450901b821e0c53649f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" +dependencies = [ + "thiserror-impl 2.0.20", +] + +[[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.119", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.4", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tinyvec" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" +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 = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.25.13+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.1.3+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" +dependencies = [ + "winnow", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common 0.1.7", + "subtle", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[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 = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[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.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wincode" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "657690780ce23e6f66576a782ffd88eb353512381817029cc1d7a99154bb6d1f" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.20", + "wincode-derive 0.4.6", +] + +[[package]] +name = "wincode" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d967db7705dc29120bb6e8ce5b5a2e27734ed5976d1c904e95bd238d1c3c5a" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.20", + "wincode-derive 0.4.6", +] + +[[package]] +name = "wincode" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfc6339f1ba427bf7ad7c42403b28e524832ba2ddb5eef1bb2cc3b85db6b7b75" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.20", + "wincode-derive 0.5.1", +] + +[[package]] +name = "wincode-derive" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15ab90b719560d0fda79c74550ad1c948d17b118765942838055ebaf34d67071" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "wincode-derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d582d9fc9d813264407a9e16bfa16846ccf15ef032f9bbcd700741bdc00255" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zeroize" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.119", +] + +[[package]] +name = "zmij" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" diff --git a/smart-updown/program/Cargo.toml b/smart-updown/program/Cargo.toml new file mode 100644 index 0000000..0999ea4 --- /dev/null +++ b/smart-updown/program/Cargo.toml @@ -0,0 +1,18 @@ +[workspace] +members = [ + "programs/*" +] +resolver = "2" + +[workspace.package] +edition = "2021" +rust-version = "1.89.0" + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/smart-updown/program/programs/smart-updown/Cargo.toml b/smart-updown/program/programs/smart-updown/Cargo.toml new file mode 100644 index 0000000..ba4adf3 --- /dev/null +++ b/smart-updown/program/programs/smart-updown/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "smart-updown" +version = "0.1.0" +description = "Created with Anchor" +edition.workspace = true +rust-version.workspace = true + +[lib] +crate-type = ["cdylib", "lib"] +name = "smart_updown" + +[features] +default = [] +cpi = ["no-entrypoint"] +no-entrypoint = [] +no-log-ix-name = [] +idl-build = [] +profile = ["anchor-v2-testing/profile"] + +[dependencies] +# Once anchor-lang is published to crates.io, swap to: anchor-lang = "2.0.0-rc.1" +anchor-lang = { git = "https://github.com/otter-sec/anchor.git", branch = "anchor-next" } +solana-program-log = { version = "1.1", features = ["macro"] } +wincode = { version = "0.5", features = ["derive"] } + +[dev-dependencies] +anchor-v2-testing = { git = "https://github.com/otter-sec/anchor.git", branch = "anchor-next" } +solana-clock = "3.0.1" +solana-pubkey = "3.0.0" + + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = ['cfg(target_os, values("solana"))'] } diff --git a/smart-updown/program/programs/smart-updown/src/constants.rs b/smart-updown/program/programs/smart-updown/src/constants.rs new file mode 100644 index 0000000..7e493df --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/constants.rs @@ -0,0 +1,16 @@ +use anchor_lang::prelude::*; + +#[constant] +pub const GLOBAL_SEED: &[u8] = b"global"; + +#[constant] +pub const BET_SEED: &[u8] = b"bet"; + +pub const SIDE_UP: u64 = 0; +pub const SIDE_DOWN: u64 = 1; + +pub const STATUS_OPEN: u64 = 0; +pub const STATUS_PAYOUT_DONE: u64 = 1; +pub const STATUS_HOUSE_WON: u64 = 2; + +pub const BPS_DIVISOR: u64 = 10_000; diff --git a/smart-updown/program/programs/smart-updown/src/error.rs b/smart-updown/program/programs/smart-updown/src/error.rs new file mode 100644 index 0000000..884660d --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/error.rs @@ -0,0 +1,34 @@ +use anchor_lang::prelude::*; + +#[error_code] +pub enum SmartUpdownError { + #[msg("Operation is paused")] + Paused, + + #[msg("Only the admin can perform this action")] + NotAdmin, + + #[msg("Only the relayer is allowed to close bets")] + NotRelayer, + + #[msg("Amount below the allowed minimum")] + AmountBelowMin, + + #[msg("Amount above the allowed maximum")] + AmountAboveMax, + + #[msg("Invalid side value")] + InvalidSide, + + #[msg("Bet is already finalized")] + BetAlreadyFinalized, + + #[msg("Bet cannot be closed before expiry")] + NotExpired, + + #[msg("Bet id mismatch")] + BetIdMismatch, + + #[msg("Payout exceeds vault solvency")] + InsufficientVault, +} diff --git a/smart-updown/program/programs/smart-updown/src/events.rs b/smart-updown/program/programs/smart-updown/src/events.rs new file mode 100644 index 0000000..89c51e7 --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/events.rs @@ -0,0 +1,21 @@ +use anchor_lang::prelude::*; + +#[event] +pub struct BetCreated { + pub bet: Address, + pub bettor: Address, + pub side: u64, + pub amount: u64, + pub bet_time: i64, + pub expire_time: i64, + pub entry_price: u64, +} + +#[event] +pub struct BetClosed { + pub bet: Address, + pub exit_price: u64, + pub user_won: bool, + pub payout: u64, + pub status: u64, +} diff --git a/smart-updown/program/programs/smart-updown/src/instructions.rs b/smart-updown/program/programs/smart-updown/src/instructions.rs new file mode 100644 index 0000000..2caac14 --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/instructions.rs @@ -0,0 +1,10 @@ +pub mod close_bet; +pub mod create_bet; +pub mod initialize; +pub mod update; + +#[allow(ambiguous_glob_reexports)] +pub use close_bet::*; +pub use create_bet::*; +pub use initialize::*; +pub use update::*; diff --git a/smart-updown/program/programs/smart-updown/src/instructions/close_bet.rs b/smart-updown/program/programs/smart-updown/src/instructions/close_bet.rs new file mode 100644 index 0000000..11d7a1b --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/instructions/close_bet.rs @@ -0,0 +1,95 @@ +use anchor_lang::{prelude::*, Lamports}; + +use crate::{ + constants::{ + BPS_DIVISOR, BET_SEED, GLOBAL_SEED, SIDE_DOWN, SIDE_UP, STATUS_HOUSE_WON, + STATUS_PAYOUT_DONE, STATUS_OPEN, + }, + error::SmartUpdownError, + events::BetClosed, + state::{Bet, Global}, +}; + +#[derive(Accounts)] +#[instruction(id: u64, exit_price: u64)] +pub struct CloseBet { + pub relayer: Signer, + #[account( + mut, + seeds = [BET_SEED, id.to_le_bytes()], + bump + )] + pub bet: Account, + #[account( + mut, + seeds = [GLOBAL_SEED], + bump + )] + pub global: Account, + /// CHECK: recipient must be the bet's bettor and is validated in the handler. + #[account(mut)] + pub bettor: SystemAccount, + pub clock: Sysvar, +} + +pub fn handler(ctx: &mut Context, id: u64, exit_price: u64) -> Result<()> { + require!( + anchor_lang::address_eq(ctx.accounts.relayer.address(), &ctx.accounts.global.relayer), + SmartUpdownError::NotRelayer + ); + require!( + anchor_lang::address_eq(ctx.accounts.bettor.address(), &ctx.accounts.bet.bettor), + SmartUpdownError::NotRelayer + ); + require!( + ctx.accounts.bet.status == STATUS_OPEN, + SmartUpdownError::BetAlreadyFinalized + ); + let now = ctx.accounts.clock.unix_timestamp; + require!(now >= ctx.accounts.bet.expire_time, SmartUpdownError::NotExpired); + + let entry = ctx.accounts.bet.entry_price; + let side = ctx.accounts.bet.side; + let amount = ctx.accounts.bet.amount; + + if exit_price == entry { + return Ok(()); + } + + let user_won = (side == SIDE_UP && exit_price > entry) + || (side == SIDE_DOWN && exit_price < entry); + + let payout; + if user_won { + let multiplier = ctx.accounts.global.multiplier_bps; + let payout_amount = + (amount as u128) + .checked_mul(multiplier as u128) + .unwrap() + .checked_div(BPS_DIVISOR as u128) + .unwrap() as u64; + require!( + ctx.accounts.global.view().lamports() >= payout_amount, + SmartUpdownError::InsufficientVault + ); + payout = payout_amount; + ctx.accounts.global.sub_lamports(payout)?; + ctx.accounts.bettor.add_lamports(payout)?; + ctx.accounts.bet.status = STATUS_PAYOUT_DONE; + } else { + payout = 0; + ctx.accounts.bet.status = STATUS_HOUSE_WON; + } + + ctx.accounts.bet.exit_price = exit_price; + + emit!(BetClosed { + bet: *ctx.accounts.bet.address(), + exit_price, + user_won, + payout, + status: ctx.accounts.bet.status, + }); + + Ok(()) +} diff --git a/smart-updown/program/programs/smart-updown/src/instructions/create_bet.rs b/smart-updown/program/programs/smart-updown/src/instructions/create_bet.rs new file mode 100644 index 0000000..4db75ef --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/instructions/create_bet.rs @@ -0,0 +1,93 @@ +use anchor_lang::prelude::*; + +use crate::{ + constants::{BET_SEED, GLOBAL_SEED, SIDE_DOWN, SIDE_UP, STATUS_OPEN}, + error::SmartUpdownError, + events::BetCreated, + state::{Bet, Global}, +}; + +#[derive(Accounts)] +#[instruction(id: u64, side: u64, amount: u64, entry_price: u64)] +pub struct CreateBet { + #[account(mut)] + pub bettor: Signer, + #[account( + mut, + seeds = [GLOBAL_SEED], + bump + )] + pub global: Account, + #[account( + init, + payer = bettor, + seeds = [BET_SEED, id.to_le_bytes()], + bump + )] + pub bet: Account, + pub clock: Sysvar, + pub system_program: Program, +} + +pub fn handler( + ctx: &mut Context, + id: u64, + side: u64, + amount: u64, + entry_price: u64, +) -> Result<()> { + require!(ctx.accounts.global.paused == 0, SmartUpdownError::Paused); + require!(side == SIDE_UP || side == SIDE_DOWN, SmartUpdownError::InvalidSide); + require!( + amount >= ctx.accounts.global.min_amount, + SmartUpdownError::AmountBelowMin + ); + require!( + amount <= ctx.accounts.global.max_amount, + SmartUpdownError::AmountAboveMax + ); + require!( + id == ctx.accounts.global.counter, + SmartUpdownError::BetIdMismatch + ); + + let now = ctx.accounts.clock.unix_timestamp; + let bettor_address = *ctx.accounts.bettor.address(); + let bet_address = *ctx.accounts.bet.address(); + let expiry_seconds = ctx.accounts.global.expiry_seconds; + + { + let bet = &mut ctx.accounts.bet; + bet.bettor = bettor_address; + bet.side = side; + bet.amount = amount; + bet.bet_time = now; + bet.expire_time = now + expiry_seconds; + bet.entry_price = entry_price; + bet.exit_price = 0; + bet.status = STATUS_OPEN; + } + + ctx.accounts.global.counter = ctx.accounts.global.counter.checked_add(1).unwrap(); + + { + let cpi_accounts = system_program::Transfer { + from: ctx.accounts.bettor.cpi_handle_mut(), + to: ctx.accounts.global.cpi_handle_mut(), + }; + let cpi_ctx = CpiContext::new(ctx.accounts.system_program.address(), cpi_accounts); + system_program::transfer(cpi_ctx, amount)?; + } + + emit!(BetCreated { + bet: bet_address, + bettor: bettor_address, + side, + amount, + bet_time: now, + expire_time: now + expiry_seconds, + entry_price, + }); + + Ok(()) +} diff --git a/smart-updown/program/programs/smart-updown/src/instructions/initialize.rs b/smart-updown/program/programs/smart-updown/src/instructions/initialize.rs new file mode 100644 index 0000000..801995b --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/instructions/initialize.rs @@ -0,0 +1,36 @@ +use anchor_lang::prelude::*; + +use crate::{constants::GLOBAL_SEED, state::Global}; + +#[derive(Accounts)] +pub struct Initialize { + #[account(mut)] + pub admin: Signer, + #[account( + init, + payer = admin, + seeds = [GLOBAL_SEED], + bump + )] + pub global: Account, + pub system_program: Program, +} + +pub fn handler( + ctx: &mut Context, + min_amount: u64, + max_amount: u64, + multiplier_bps: u64, + expiry_seconds: i64, +) -> Result<()> { + let global = &mut ctx.accounts.global; + global.admin = *ctx.accounts.admin.address(); + global.relayer = *ctx.accounts.admin.address(); + global.counter = 0; + global.min_amount = min_amount; + global.max_amount = max_amount; + global.multiplier_bps = multiplier_bps; + global.paused = 0; + global.expiry_seconds = expiry_seconds; + Ok(()) +} diff --git a/smart-updown/program/programs/smart-updown/src/instructions/update.rs b/smart-updown/program/programs/smart-updown/src/instructions/update.rs new file mode 100644 index 0000000..25f59c2 --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/instructions/update.rs @@ -0,0 +1,41 @@ +use anchor_lang::prelude::*; + +use crate::{ + constants::GLOBAL_SEED, + error::SmartUpdownError, + state::Global, +}; + +#[derive(Accounts)] +pub struct Update { + pub admin: Signer, + #[account( + mut, + seeds = [GLOBAL_SEED], + bump + )] + pub global: Account, +} + +pub fn handler( + ctx: &mut Context, + new_relayer: Address, + min_amount: u64, + max_amount: u64, + multiplier_bps: u64, + paused: u64, + expiry_seconds: i64, +) -> Result<()> { + require!( + anchor_lang::address_eq(ctx.accounts.admin.address(), &ctx.accounts.global.admin), + SmartUpdownError::NotAdmin + ); + let global = &mut ctx.accounts.global; + global.relayer = new_relayer; + global.min_amount = min_amount; + global.max_amount = max_amount; + global.multiplier_bps = multiplier_bps; + global.paused = paused; + global.expiry_seconds = expiry_seconds; + Ok(()) +} diff --git a/smart-updown/program/programs/smart-updown/src/lib.rs b/smart-updown/program/programs/smart-updown/src/lib.rs new file mode 100644 index 0000000..3afedca --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/lib.rs @@ -0,0 +1,68 @@ +pub mod constants; +pub mod error; +pub mod events; +pub mod instructions; +pub mod state; + +use anchor_lang::prelude::*; + +pub use instructions::*; + +declare_id!("E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3"); + +#[program] +pub mod smart_updown { + use super::*; + + #[discrim = 0] + pub fn initialize( + ctx: &mut Context, + min_amount: u64, + max_amount: u64, + multiplier_bps: u64, + expiry_seconds: i64, + ) -> Result<()> { + initialize::handler(ctx, min_amount, max_amount, multiplier_bps, expiry_seconds) + } + + #[discrim = 1] + pub fn create_bet( + ctx: &mut Context, + id: u64, + side: u64, + amount: u64, + entry_price: u64, + ) -> Result<()> { + create_bet::handler(ctx, id, side, amount, entry_price) + } + + #[discrim = 2] + pub fn close_bet( + ctx: &mut Context, + id: u64, + exit_price: u64, + ) -> Result<()> { + close_bet::handler(ctx, id, exit_price) + } + + #[discrim = 3] + pub fn update( + ctx: &mut Context, + new_relayer: Address, + min_amount: u64, + max_amount: u64, + multiplier_bps: u64, + paused: u64, + expiry_seconds: i64, + ) -> Result<()> { + update::handler( + ctx, + new_relayer, + min_amount, + max_amount, + multiplier_bps, + paused, + expiry_seconds, + ) + } +} diff --git a/smart-updown/program/programs/smart-updown/src/state.rs b/smart-updown/program/programs/smart-updown/src/state.rs new file mode 100644 index 0000000..09befeb --- /dev/null +++ b/smart-updown/program/programs/smart-updown/src/state.rs @@ -0,0 +1,25 @@ +use anchor_lang::prelude::*; + +#[account] +pub struct Global { + pub counter: u64, + pub min_amount: u64, + pub max_amount: u64, + pub multiplier_bps: u64, + pub expiry_seconds: i64, + pub paused: u64, + pub admin: Address, + pub relayer: Address, +} + +#[account] +pub struct Bet { + pub amount: u64, + pub bet_time: i64, + pub expire_time: i64, + pub entry_price: u64, + pub exit_price: u64, + pub side: u64, + pub status: u64, + pub bettor: Address, +} diff --git a/smart-updown/program/programs/smart-updown/tests/test_smart_updown.rs b/smart-updown/program/programs/smart-updown/tests/test_smart_updown.rs new file mode 100644 index 0000000..d798760 --- /dev/null +++ b/smart-updown/program/programs/smart-updown/tests/test_smart_updown.rs @@ -0,0 +1,283 @@ +use { + anchor_lang::{ + bytemuck, cpi::find_program_address, solana_program::instruction::Instruction, Id, + InstructionData, ToAccountMetas, + }, + anchor_v2_testing::{Keypair, LiteSVM, Message, Signer, VersionedMessage, VersionedTransaction}, + smart_updown::state::{Bet, Global}, +}; + +const CLOCK_ADDR: &str = "SysvarC1ock11111111111111111111111111111111"; +const SYSTEM_ADDR: &str = "11111111111111111111111111111111"; +const MIN_AMOUNT: u64 = 1_000_000_000; // 1 SOL +const MULTIPLIER_BPS: u64 = 13_000; // 1.3x +const EXPIRY_SECONDS: i64 = 15; + +type Addr = anchor_lang::prelude::Address; + +fn pid() -> Addr { + smart_updown::id() +} + +fn global_pda() -> Addr { + find_program_address(&[b"global"], &pid()).0 +} + +fn bet_pda(id: u64) -> Addr { + find_program_address(&[b"bet", &id.to_le_bytes()], &pid()).0 +} + +fn setup() -> (LiteSVM, Keypair) { + let mut svm = LiteSVM::new(); + let bytes = include_bytes!("../../../target/deploy/smart_updown.so"); + svm.add_program(pid(), bytes).expect("deploy program"); + let payer = Keypair::new(); + svm.airdrop(&payer.pubkey(), 100_000_000_000).unwrap(); + (svm, payer) +} + +fn send(svm: &mut LiteSVM, signers: &[&Keypair], instruction: Instruction) -> Result<(), String> { + let blockhash = svm.latest_blockhash(); + let msg = Message::new_with_blockhash(&[instruction], Some(&signers[0].pubkey()), &blockhash); + let tx = VersionedTransaction::try_new(VersionedMessage::Legacy(msg), signers).unwrap(); + let res = svm.send_transaction(tx); + res.map(|_| ()).map_err(|e| format!("{:?}", e)) +} + +fn initialize(svm: &mut LiteSVM, admin: &Keypair) { + let ix = Instruction::new_with_bytes( + pid(), + &smart_updown::instruction::Initialize { + min_amount: MIN_AMOUNT, + max_amount: 1_000_000_000_000, + multiplier_bps: MULTIPLIER_BPS, + expiry_seconds: EXPIRY_SECONDS, + } + .data(), + smart_updown::accounts::Initialize { + admin: admin.pubkey(), + global: global_pda(), + system_program: SYSTEM_ADDR.parse().unwrap(), + } + .to_account_metas(None), + ); + send(svm, &[admin], ix).expect("initialize"); +} + +fn set_clock(svm: &mut LiteSVM, unix: i64) { + use solana_clock::Clock; + let mut clk = svm.get_sysvar::(); + clk.unix_timestamp = unix; + svm.set_sysvar(&clk); +} + +fn fund_vault(svm: &mut LiteSVM, lamports: u64) { + svm.airdrop(&global_pda(), lamports).unwrap(); +} + +fn read_global(svm: &LiteSVM) -> Global { + let acc = svm.get_account(&global_pda()).expect("global account"); + *bytemuck::from_bytes::(&acc.data[8..]) +} + +fn read_bet(svm: &LiteSVM, id: u64) -> Bet { + let acc = svm.get_account(&bet_pda(id)).expect("bet account"); + *bytemuck::from_bytes::(&acc.data[8..]) +} + +fn make_create_ix(id: u64, side: u64, amount: u64, entry_price: u64, bettor: Addr) -> Instruction { + Instruction::new_with_bytes( + pid(), + &smart_updown::instruction::CreateBet { + id, + side, + amount, + entry_price, + } + .data(), + smart_updown::accounts::CreateBet { + bettor, + global: global_pda(), + bet: bet_pda(id), + clock: CLOCK_ADDR.parse().unwrap(), + system_program: SYSTEM_ADDR.parse().unwrap(), + } + .to_account_metas(None), + ) +} + +fn make_close_ix(id: u64, exit_price: u64, relayer: Addr, bettor: Addr) -> Instruction { + Instruction::new_with_bytes( + pid(), + &smart_updown::instruction::CloseBet { id, exit_price }.data(), + smart_updown::accounts::CloseBet { + relayer, + bet: bet_pda(id), + global: global_pda(), + bettor, + clock: CLOCK_ADDR.parse().unwrap(), + } + .to_account_metas(None), + ) +} + +fn create_up_bet(svm: &mut LiteSVM, admin: &Keypair, side: u64) -> (Keypair, u64, u64) { + let bettor = Keypair::new(); + svm.airdrop(&bettor.pubkey(), 100_000_000_000).unwrap(); + set_clock(svm, 1_700_000_000); + let amount = MIN_AMOUNT; + let entry_price = 100_000_000u64; + let create_ix = make_create_ix(0, side, amount, entry_price, bettor.pubkey()); + send(svm, &[&bettor], create_ix).expect("create_bet"); + (bettor, amount, entry_price) +} + +#[test] +fn initialize_creates_global() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let g = read_global(&svm); + assert_eq!(g.admin, admin.pubkey()); + assert_eq!(g.relayer, admin.pubkey()); + assert_eq!(g.counter, 0); + assert_eq!(g.multiplier_bps, MULTIPLIER_BPS); + assert_eq!(g.expiry_seconds, EXPIRY_SECONDS); + assert_eq!(g.paused, 0); +} + +#[test] +fn create_bet_escrows_sol() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, amount, entry_price) = create_up_bet(&mut svm, &admin, 0); + + let vault_balance = svm.get_balance(&global_pda()).unwrap(); + assert!(vault_balance >= amount); + let b = read_bet(&svm, 0); + assert_eq!(b.bettor, bettor.pubkey()); + assert_eq!(b.side, 0); + assert_eq!(b.amount, amount); + assert_eq!(b.entry_price, entry_price); + assert_eq!(b.bet_time, 1_700_000_000); + assert_eq!(b.expire_time, 1_700_000_000 + EXPIRY_SECONDS); + assert_eq!(b.status, 0); + assert_eq!(read_global(&svm).counter, 1); +} + +#[test] +fn close_bet_user_wins_up() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, amount, entry_price) = create_up_bet(&mut svm, &admin, 0); + + set_clock(&mut svm, 1_700_000_000 + EXPIRY_SECONDS + 1); + let exit_price = entry_price + 1_000; + let before = svm.get_balance(&bettor.pubkey()).unwrap(); + let payout = amount * MULTIPLIER_BPS / 10_000; + fund_vault(&mut svm, 10 * amount); + + let close_ix = make_close_ix(0, exit_price, admin.pubkey(), bettor.pubkey()); + send(&mut svm, &[&admin], close_ix).expect("close_bet"); + + assert_eq!(svm.get_balance(&bettor.pubkey()).unwrap(), before + payout); + let b = read_bet(&svm, 0); + assert_eq!(b.status, 1); + assert_eq!(b.exit_price, exit_price); +} + +#[test] +fn close_bet_house_wins_down() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, _amount, entry_price) = create_up_bet(&mut svm, &admin, 1); + + set_clock(&mut svm, 1_700_000_000 + EXPIRY_SECONDS + 1); + let exit_price = entry_price + 1_000; // side=DOWN but price rose -> lose + let before = svm.get_balance(&bettor.pubkey()).unwrap(); + + let close_ix = make_close_ix(0, exit_price, admin.pubkey(), bettor.pubkey()); + send(&mut svm, &[&admin], close_ix).expect("close_bet"); + + assert_eq!(svm.get_balance(&bettor.pubkey()).unwrap(), before); + assert_eq!(read_bet(&svm, 0).status, 2); +} + +#[test] +fn close_bet_equal_price_stays_open() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, amount, entry_price) = create_up_bet(&mut svm, &admin, 0); + + set_clock(&mut svm, 1_700_000_000 + EXPIRY_SECONDS + 1); + let before = svm.get_balance(&bettor.pubkey()).unwrap(); + let payout = amount * MULTIPLIER_BPS / 10_000; + fund_vault(&mut svm, 10 * amount); + + let equal_ix = make_close_ix(0, entry_price, admin.pubkey(), bettor.pubkey()); + send(&mut svm, &[&admin], equal_ix).expect("equal close"); + assert_eq!(read_bet(&svm, 0).status, 0); + assert_eq!(svm.get_balance(&bettor.pubkey()).unwrap(), before); + + let exit_price = entry_price + 1_000; + let second_ix = make_close_ix(0, exit_price, admin.pubkey(), bettor.pubkey()); + send(&mut svm, &[&admin], second_ix).expect("second close"); + assert_eq!( + svm.get_balance(&bettor.pubkey()).unwrap(), + before + payout + ); + assert_eq!(read_bet(&svm, 0).status, 1); +} + +#[test] +fn close_bet_before_expiry_rejected() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, _amount, entry_price) = create_up_bet(&mut svm, &admin, 0); + + let close_ix = make_close_ix(0, entry_price + 500, admin.pubkey(), bettor.pubkey()); + let res = send(&mut svm, &[&admin], close_ix); + assert!(res.is_err(), "expected premature close to be rejected"); + assert_eq!(read_bet(&svm, 0).status, 0); +} + +#[test] +fn close_bet_wrong_relayer_rejected() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, _amount, entry_price) = create_up_bet(&mut svm, &admin, 0); + let attacker = Keypair::new(); + svm.airdrop(&attacker.pubkey(), 100_000_000_000).unwrap(); + + set_clock(&mut svm, 1_700_000_000 + EXPIRY_SECONDS + 1); + let close_ix = make_close_ix(0, entry_price + 500, attacker.pubkey(), bettor.pubkey()); + let res = send(&mut svm, &[&attacker], close_ix); + assert!(res.is_err(), "expected wrong relayer to be rejected"); + assert_eq!(read_bet(&svm, 0).status, 0); +} + +#[test] +fn close_bet_replay_rejected() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let (bettor, _amount, entry_price) = create_up_bet(&mut svm, &admin, 0); + + set_clock(&mut svm, 1_700_000_000 + EXPIRY_SECONDS + 1); + fund_vault(&mut svm, 10 * MIN_AMOUNT); + let close_ix = make_close_ix(0, entry_price + 500, admin.pubkey(), bettor.pubkey()); + send(&mut svm, &[&admin], close_ix).expect("first close"); + let res = send(&mut svm, &[&admin], make_close_ix(0, entry_price + 500, admin.pubkey(), bettor.pubkey())); + assert!(res.is_err(), "expected replay close to be rejected"); +} + +#[test] +fn create_bet_rejects_out_of_range() { + let (mut svm, admin) = setup(); + initialize(&mut svm, &admin); + let bettor = Keypair::new(); + svm.airdrop(&bettor.pubkey(), 100_000_000_000).unwrap(); + set_clock(&mut svm, 1_700_000_000); + + let ix = make_create_ix(0, 0, 1, 100_000_000u64, bettor.pubkey()); + let res = send(&mut svm, &[&bettor], ix); + assert!(res.is_err(), "expected below-min bet to be rejected"); +} diff --git a/smart-updown/program/rust-toolchain.toml b/smart-updown/program/rust-toolchain.toml new file mode 100644 index 0000000..cb684c0 --- /dev/null +++ b/smart-updown/program/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "1.89.0" +components = ["rustfmt","clippy"] +profile = "minimal" diff --git a/smart-updown/relayer/.env.example b/smart-updown/relayer/.env.example new file mode 100644 index 0000000..6beb0e0 --- /dev/null +++ b/smart-updown/relayer/.env.example @@ -0,0 +1,14 @@ +# RPC эндпоинт кластера (localnet = запущенный solana-test-validator) +SMART_RPC_URL=http://127.0.0.1:8899 + +# Разрешить airDrop на localnet (bettor'ам и ваулту). На mainnet выключить. +SMART_ALLOW_AIRDROP=1 + +# Путь к keypair админа/релеера (тот же ключ = admin и relayer) +SMART_ADMIN_KEYPAIR=~/.config/solana/id.json + +# Параметры контракта (должны совпадать со значениями при initialize) +SMART_MIN_AMOUNT=100000000 # 0.1 SOL в лампортах +SMART_MAX_AMOUNT=10000000000 # 10 SOL в лампортах +SMART_MULTIPLIER_BPS=13000 # 1.3x выплата в базисных пунктах +SMART_EXPIRY_SECONDS=15 # экспирация ставки (секунды) diff --git a/smart-updown/relayer/idl/smart_updown.json b/smart-updown/relayer/idl/smart_updown.json new file mode 100644 index 0000000..0c72abb --- /dev/null +++ b/smart-updown/relayer/idl/smart_updown.json @@ -0,0 +1,546 @@ +{ + "address": "E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3", + "metadata": { + "name": "smart_updown", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "close_bet", + "discriminator": [ + 2 + ], + "accounts": [ + { + "name": "relayer", + "signer": true + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bettor", + "docs": [ + "CHECK: recipient must be the bet's bettor and is validated in the handler." + ], + "writable": true + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "exit_price", + "type": "u64" + } + ] + }, + { + "name": "create_bet", + "discriminator": [ + 1 + ], + "accounts": [ + { + "name": "bettor", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "entry_price", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 0 + ], + "accounts": [ + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "min_amount", + "type": "u64" + }, + { + "name": "max_amount", + "type": "u64" + }, + { + "name": "multiplier_bps", + "type": "u64" + }, + { + "name": "expiry_seconds", + "type": "i64" + } + ] + }, + { + "name": "update", + "discriminator": [ + 3 + ], + "accounts": [ + { + "name": "admin", + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + } + ], + "args": [ + { + "name": "new_relayer", + "type": "pubkey" + }, + { + "name": "min_amount", + "type": "u64" + }, + { + "name": "max_amount", + "type": "u64" + }, + { + "name": "multiplier_bps", + "type": "u64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "expiry_seconds", + "type": "i64" + } + ] + } + ], + "accounts": [ + { + "name": "Bet", + "discriminator": [ + 147, + 23, + 35, + 59, + 15, + 75, + 155, + 32 + ] + }, + { + "name": "Global", + "discriminator": [ + 167, + 232, + 232, + 177, + 200, + 108, + 114, + 127 + ] + } + ], + "events": [ + { + "name": "BetClosed", + "discriminator": [ + 122, + 20, + 157, + 254, + 221, + 0, + 39, + 129 + ] + }, + { + "name": "BetCreated", + "discriminator": [ + 32, + 153, + 105, + 71, + 188, + 72, + 107, + 114 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "Paused", + "msg": "Operation is paused" + }, + { + "code": 6001, + "name": "NotAdmin", + "msg": "Only the admin can perform this action" + }, + { + "code": 6002, + "name": "NotRelayer", + "msg": "Only the relayer is allowed to close bets" + }, + { + "code": 6003, + "name": "AmountBelowMin", + "msg": "Amount below the allowed minimum" + }, + { + "code": 6004, + "name": "AmountAboveMax", + "msg": "Amount above the allowed maximum" + }, + { + "code": 6005, + "name": "InvalidSide", + "msg": "Invalid side value" + }, + { + "code": 6006, + "name": "BetAlreadyFinalized", + "msg": "Bet is already finalized" + }, + { + "code": 6007, + "name": "NotExpired", + "msg": "Bet cannot be closed before expiry" + }, + { + "code": 6008, + "name": "BetIdMismatch", + "msg": "Bet id mismatch" + }, + { + "code": 6009, + "name": "InsufficientVault", + "msg": "Payout exceeds vault solvency" + } + ], + "types": [ + { + "name": "Bet", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "bet_time", + "type": "i64" + }, + { + "name": "expire_time", + "type": "i64" + }, + { + "name": "entry_price", + "type": "u64" + }, + { + "name": "exit_price", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + }, + { + "name": "bettor", + "type": "pubkey" + } + ] + } + }, + { + "name": "BetClosed", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "exit_price", + "type": "u64" + }, + { + "name": "user_won", + "type": "bool" + }, + { + "name": "payout", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + } + ] + } + }, + { + "name": "BetCreated", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "bettor", + "type": "pubkey" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "bet_time", + "type": "i64" + }, + { + "name": "expire_time", + "type": "i64" + }, + { + "name": "entry_price", + "type": "u64" + } + ] + } + }, + { + "name": "Global", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "counter", + "type": "u64" + }, + { + "name": "min_amount", + "type": "u64" + }, + { + "name": "max_amount", + "type": "u64" + }, + { + "name": "multiplier_bps", + "type": "u64" + }, + { + "name": "expiry_seconds", + "type": "i64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "relayer", + "type": "pubkey" + } + ] + } + } + ], + "constants": [ + { + "name": "BET_SEED", + "type": "bytes", + "value": "[98, 101, 116]" + }, + { + "name": "GLOBAL_SEED", + "type": "bytes", + "value": "[103, 108, 111, 98, 97, 108]" + } + ] +} \ No newline at end of file diff --git a/smart-updown/relayer/idl/smart_updown.ts b/smart-updown/relayer/idl/smart_updown.ts new file mode 100644 index 0000000..544568f --- /dev/null +++ b/smart-updown/relayer/idl/smart_updown.ts @@ -0,0 +1,552 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/smart_updown.json`. + */ +export type SmartUpdown = { + "address": "E7Hg55ywRDKRZJ35rDMJGC3YFThQbh6nAK9GDayG4sr3", + "metadata": { + "name": "smartUpdown", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "closeBet", + "discriminator": [ + 2 + ], + "accounts": [ + { + "name": "relayer", + "signer": true + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bettor", + "docs": [ + "CHECK: recipient must be the bet's bettor and is validated in the handler." + ], + "writable": true + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "exitPrice", + "type": "u64" + } + ] + }, + { + "name": "createBet", + "discriminator": [ + 1 + ], + "accounts": [ + { + "name": "bettor", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "bet", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 98, + 101, + 116 + ] + }, + { + "kind": "arg", + "path": "id" + } + ] + } + }, + { + "name": "clock", + "address": "SysvarC1ock11111111111111111111111111111111" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "id", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "entryPrice", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 0 + ], + "accounts": [ + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "minAmount", + "type": "u64" + }, + { + "name": "maxAmount", + "type": "u64" + }, + { + "name": "multiplierBps", + "type": "u64" + }, + { + "name": "expirySeconds", + "type": "i64" + } + ] + }, + { + "name": "update", + "discriminator": [ + 3 + ], + "accounts": [ + { + "name": "admin", + "signer": true + }, + { + "name": "global", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 103, + 108, + 111, + 98, + 97, + 108 + ] + } + ] + } + } + ], + "args": [ + { + "name": "newRelayer", + "type": "pubkey" + }, + { + "name": "minAmount", + "type": "u64" + }, + { + "name": "maxAmount", + "type": "u64" + }, + { + "name": "multiplierBps", + "type": "u64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "expirySeconds", + "type": "i64" + } + ] + } + ], + "accounts": [ + { + "name": "bet", + "discriminator": [ + 147, + 23, + 35, + 59, + 15, + 75, + 155, + 32 + ] + }, + { + "name": "global", + "discriminator": [ + 167, + 232, + 232, + 177, + 200, + 108, + 114, + 127 + ] + } + ], + "events": [ + { + "name": "betClosed", + "discriminator": [ + 122, + 20, + 157, + 254, + 221, + 0, + 39, + 129 + ] + }, + { + "name": "betCreated", + "discriminator": [ + 32, + 153, + 105, + 71, + 188, + 72, + 107, + 114 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "paused", + "msg": "Operation is paused" + }, + { + "code": 6001, + "name": "notAdmin", + "msg": "Only the admin can perform this action" + }, + { + "code": 6002, + "name": "notRelayer", + "msg": "Only the relayer is allowed to close bets" + }, + { + "code": 6003, + "name": "amountBelowMin", + "msg": "Amount below the allowed minimum" + }, + { + "code": 6004, + "name": "amountAboveMax", + "msg": "Amount above the allowed maximum" + }, + { + "code": 6005, + "name": "invalidSide", + "msg": "Invalid side value" + }, + { + "code": 6006, + "name": "betAlreadyFinalized", + "msg": "Bet is already finalized" + }, + { + "code": 6007, + "name": "notExpired", + "msg": "Bet cannot be closed before expiry" + }, + { + "code": 6008, + "name": "betIdMismatch", + "msg": "Bet id mismatch" + }, + { + "code": 6009, + "name": "insufficientVault", + "msg": "Payout exceeds vault solvency" + } + ], + "types": [ + { + "name": "bet", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "betTime", + "type": "i64" + }, + { + "name": "expireTime", + "type": "i64" + }, + { + "name": "entryPrice", + "type": "u64" + }, + { + "name": "exitPrice", + "type": "u64" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + }, + { + "name": "bettor", + "type": "pubkey" + } + ] + } + }, + { + "name": "betClosed", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "exitPrice", + "type": "u64" + }, + { + "name": "userWon", + "type": "bool" + }, + { + "name": "payout", + "type": "u64" + }, + { + "name": "status", + "type": "u64" + } + ] + } + }, + { + "name": "betCreated", + "type": { + "kind": "struct", + "fields": [ + { + "name": "bet", + "type": "pubkey" + }, + { + "name": "bettor", + "type": "pubkey" + }, + { + "name": "side", + "type": "u64" + }, + { + "name": "amount", + "type": "u64" + }, + { + "name": "betTime", + "type": "i64" + }, + { + "name": "expireTime", + "type": "i64" + }, + { + "name": "entryPrice", + "type": "u64" + } + ] + } + }, + { + "name": "global", + "serialization": "bytemuck", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "counter", + "type": "u64" + }, + { + "name": "minAmount", + "type": "u64" + }, + { + "name": "maxAmount", + "type": "u64" + }, + { + "name": "multiplierBps", + "type": "u64" + }, + { + "name": "expirySeconds", + "type": "i64" + }, + { + "name": "paused", + "type": "u64" + }, + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "relayer", + "type": "pubkey" + } + ] + } + } + ], + "constants": [ + { + "name": "betSeed", + "type": "bytes", + "value": "[98, 101, 116]" + }, + { + "name": "globalSeed", + "type": "bytes", + "value": "[103, 108, 111, 98, 97, 108]" + } + ] +}; diff --git a/smart-updown/relayer/package.json b/smart-updown/relayer/package.json new file mode 100644 index 0000000..a06805b --- /dev/null +++ b/smart-updown/relayer/package.json @@ -0,0 +1,23 @@ +{ + "name": "smart-updown-relayer", + "version": "0.1.0", + "private": true, + "license": "ISC", + "scripts": { + "typecheck": "tsc -p tsconfig.json --noEmit", + "init": "ts-node src/index.ts --init --once", + "run": "ts-node src/index.ts --once", + "loop": "ts-node src/index.ts" + }, + "dependencies": { + "@anchor-lang/core": "^1.0.0", + "@solana/web3.js": "^1.98.0", + "bn.js": "^5.2.0" + }, + "devDependencies": { + "@types/bn.js": "^5.2.0", + "@types/node": "^25.0.0", + "ts-node": "^10.9.2", + "typescript": "^5.9.3" + } +} diff --git a/smart-updown/relayer/src/config.ts b/smart-updown/relayer/src/config.ts new file mode 100644 index 0000000..f536ae1 --- /dev/null +++ b/smart-updown/relayer/src/config.ts @@ -0,0 +1,65 @@ +import { Connection, clusterApiUrl, Keypair, PublicKey } from "@solana/web3.js"; +import * as fs from "fs"; +import * as os from "os"; +import * as path from "path"; + +export const SIDE_UP = 0; +export const SIDE_DOWN = 1; + +/** + * Runtime configuration. Everything can be overridden via environment + * variables; defaults target the local validator. + */ +export interface Config { + /** RPC endpoint of the cluster (localnet by default). */ + rpcUrl: string; + /** Localnet allows naive airdrops (to bettors and the house vault). */ + allowAirdrop: boolean; + /** Program id. Defaults to the value embedded in the IDL. */ + programId: PublicKey; + /** House admin/relayer keypair file path. */ + adminKeypairPath: string; + /** Initial parameters used by `init` (must match on-chain constants). */ + minAmountLamports: number; + maxAmountLamports: number; + multiplierBps: number; + expirySeconds: number; +} + +function env(name: string, fallback: string): string { + return process.env[name] ?? fallback; +} + +function envNum(name: string, fallback: number): number { + const raw = process.env[name]; + if (!raw) return fallback; + const n = Number(raw); + if (!Number.isFinite(n)) throw new Error(`Invalid number for env ${name}: ${raw}`); + return n; +} + +export function loadConfig(): Config { + const rpcUrl = env("SMART_RPC_URL", "http://127.0.0.1:8899"); + const allowAirdrop = env("SMART_ALLOW_AIRDROP", "1") === "1"; + const adminKeypairPath = + env("SMART_ADMIN_KEYPAIR", path.join(os.homedir(), ".config/solana/id.json")); + + return { + rpcUrl, + allowAirdrop, + programId: PublicKey.default, // placeholder; real value read from the IDL below + adminKeypairPath, + minAmountLamports: envNum("SMART_MIN_AMOUNT", 100_000_000), // 0.1 SOL + maxAmountLamports: envNum("SMART_MAX_AMOUNT", 10_000_000_000), // 10 SOL + multiplierBps: envNum("SMART_MULTIPLIER_BPS", 13_000), // 1.3x + expirySeconds: envNum("SMART_EXPIRY_SECONDS", 15), + }; +} + +export function loadKeypair(pathOrJson: string): Keypair { + const resolved = pathOrJson.startsWith("~") + ? path.join(os.homedir(), pathOrJson.slice(1)) + : path.resolve(pathOrJson); + const raw = fs.readFileSync(resolved, "utf8"); + return Keypair.fromSecretKey(Uint8Array.from(JSON.parse(raw))); +} diff --git a/smart-updown/relayer/src/frontStub.ts b/smart-updown/relayer/src/frontStub.ts new file mode 100644 index 0000000..b511219 --- /dev/null +++ b/smart-updown/relayer/src/frontStub.ts @@ -0,0 +1,24 @@ +import { Keypair } from "@solana/web3.js"; +import { SIDE_DOWN, SIDE_UP } from "./config"; + +/** + * STUB — «фронт»: от пользователя приходят параметры ставки. + * + * В реальной системе это сообщение присылает фронтенд (или твоя БД) после + * того, как пользователь выбрал направление и сумму. Здесь мы эмулируем + * входящую очередь: случайный UP/DOWN и случайную сумму в заданном диапазоне. + */ +export interface BetRequest { + bettor: Keypair; + side: number; // SIDE_UP | SIDE_DOWN + amountLamports: number; +} + +/** Очередь входящих ставок. В заглушке наполняем случайными значениями. */ +export function nextBetRequest(minAmount: number, maxAmount: number): BetRequest { + const bettor = Keypair.generate(); + const side = Math.random() < 0.5 ? SIDE_UP : SIDE_DOWN; + const amount = + minAmount + Math.floor(Math.random() * (maxAmount - minAmount + 1)); + return { bettor, side, amountLamports: amount }; +} diff --git a/smart-updown/relayer/src/index.ts b/smart-updown/relayer/src/index.ts new file mode 100644 index 0000000..59fc019 --- /dev/null +++ b/smart-updown/relayer/src/index.ts @@ -0,0 +1,136 @@ +import { LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; +import { Program } from "@anchor-lang/core"; +import { loadConfig, loadKeypair, SIDE_UP } from "./config"; +import { getPrice } from "./priceSource"; +import { nextBetRequest } from "./frontStub"; +import { + initialize, + createBet, + closeBet, + readGlobal, + ensureVaultFunded, +} from "./ops"; +import { betPda } from "./pda"; +import { makeConnection, makeProgram } from "./program"; + +import type { SmartUpdown } from "../idl/smart_updown"; + +const LAMPORTS_PER_SOL_NUM = Number(LAMPORTS_PER_SOL); + +const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms)); + +const STATUS_OPEN = 0; +async function fundBettor(connection: any, bettorPubkey: PublicKey): Promise { + const bal = await connection.getBalance(bettorPubkey); + if (bal < 2 * LAMPORTS_PER_SOL_NUM) { + await connection.requestAirdrop(bettorPubkey, 5 * LAMPORTS_PER_SOL_NUM); + await sleep(800); + console.log(`bettor funded ${bettorPubkey.toBase58()} (+5 SOL)`); + } +} + +/** Закрывает ставку, повторяя при «equal price» (exit==entry) пока не зафиналится. */ +async function settleBet( + program: Program, + id: any, + entryPrice: number, + relayer: any, + bettor: PublicKey +): Promise { + for (let attempt = 1; ; attempt++) { + const exitPrice = await getPrice(); + if (exitPrice === entryPrice) { + console.log(`attempt ${attempt}: exit==entry (${exitPrice}), жду движение...`); + await sleep(2000); + continue; + } + const sig = await closeBet(program, id, exitPrice, relayer, bettor); + console.log(`close_bet #${id} exit=${exitPrice} (attempt ${attempt}) tx=${sig}`); + + const status = await getStatus(program, id); + if (status === STATUS_OPEN) { + console.log(`ставка ещё open (equal price), повторяю close...`); + await sleep(2000); + continue; + } + return; + } +} + +async function getStatus(program: Program, id: any): Promise { + const bet = await program.account.bet.fetchNullable(betPda(program.programId, id)); + return bet ? bet.status.toNumber() : -1; +} + +async function main(): Promise { + const cfg = loadConfig(); + const admin = loadKeypair(cfg.adminKeypairPath); + const connection = makeConnection(cfg.rpcUrl); + const program = makeProgram(connection, admin); + + console.log(`RPC: ${cfg.rpcUrl}`); + console.log(`Admin/relayer: ${admin.publicKey.toBase58()}`); + + const global = await readGlobal(program, program.programId); + if (!global) { + if (!process.argv.includes("--init")) { + throw new Error( + "Контракт не инициализирован. Запусти с флагом --init (или init+run)." + ); + } + await initialize(program, { + minAmount: cfg.minAmountLamports, + maxAmount: cfg.maxAmountLamports, + multiplierBps: cfg.multiplierBps, + expirySeconds: cfg.expirySeconds, + }, admin); + console.log("Контракт инициализирован."); + } else { + console.log( + `Global: counter=${global.counter} vault=${(global.lamports / LAMPORTS_PER_SOL_NUM).toFixed(2)} SOL ` + + `expiry=${global.expirySeconds}s paused=${global.paused}` + ); + } + + if (cfg.allowAirdrop) { + await ensureVaultFunded(connection, program, 10 * LAMPORTS_PER_SOL_NUM); + } + + const loops = process.argv.includes("--once") ? 1 : Infinity; + let n = 0; + + while (n < loops) { + n++; + const req = nextBetRequest(cfg.minAmountLamports, cfg.maxAmountLamports); + await fundBettor(connection, req.bettor.publicKey); + + const entryPrice = await getPrice(); + await createBet(program, req.bettor, { + side: req.side, + amount: req.amountLamports, + entryPrice, + }); + + console.log( + `ставка ${req.side === SIDE_UP ? "UP" : "DOWN"} на ${(req.amountLamports / LAMPORTS_PER_SOL_NUM).toFixed(3)} SOL, жду ${cfg.expirySeconds}s...` + ); + await sleep((cfg.expirySeconds + 1) * 1000); + + const g0 = await readGlobal(program, program.programId); + const id = g0!.counter.subn(1); + await settleBet(program, id, entryPrice, admin, req.bettor.publicKey); + + const outcome = await program.account.bet.fetchNullable(betPda(program.programId, id)); + console.log( + outcome!.status.toNumber() === 1 + ? `>> результат #${id}: ПОЛЬЗОВАТЕЛЬ ВЫИГРАЛ (payout 1.3x)` + : `>> результат #${id}: ВЫИГРАЛ ДОМ (user lost)` + ); + } + console.log("Готово."); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/smart-updown/relayer/src/ops.ts b/smart-updown/relayer/src/ops.ts new file mode 100644 index 0000000..3660f3e --- /dev/null +++ b/smart-updown/relayer/src/ops.ts @@ -0,0 +1,131 @@ +import { Connection, Keypair, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js"; +import BN from "bn.js"; +import { Program } from "@anchor-lang/core"; +import { SIDE_UP } from "./config"; +import { globalPda } from "./pda"; + +import type { SmartUpdown } from "../idl/smart_updown"; + +const LAMPORTS_PER_SOL_NUM = Number(LAMPORTS_PER_SOL); + +/** Считывает account Global (ваулт). Возвращает null, если ещё не инициализирован. */ +export async function readGlobal( + program: Program, + programId: PublicKey +): Promise<{ + counter: BN; + minAmount: BN; + maxAmount: BN; + multiplierBps: BN; + expirySeconds: BN; + paused: BN; + admin: PublicKey; + relayer: PublicKey; + lamports: number; +} | null> { + const global = globalPda(programId); + const raw = await program.account.global.fetchNullable(global); + if (!raw) return null; + const lamports = await program.provider.connection.getBalance(global); + return { + counter: raw.counter, + minAmount: raw.minAmount, + maxAmount: raw.maxAmount, + multiplierBps: raw.multiplierBps, + expirySeconds: raw.expirySeconds, + paused: raw.paused, + admin: raw.admin, + relayer: raw.relayer, + lamports, + }; +} + +/** Одноразовая инициализация контракта (вызывается admin'ом до приёма ставок). */ +export async function initialize( + program: Program, + args: { + minAmount: number; + maxAmount: number; + multiplierBps: number; + expirySeconds: number; + }, + admin: Keypair +): Promise { + const sig = await program.methods + .initialize( + new BN(args.minAmount), + new BN(args.maxAmount), + new BN(args.multiplierBps), + new BN(args.expirySeconds) + ) + .accounts({ + admin: admin.publicKey, + }) + .signers([admin]) + .rpc(); + return sig; +} + +/** Создаёт ставку от имени пользователя. Возвращает фактический id (== counter). */ +export async function createBet( + program: Program, + bettor: Keypair, + args: { side: number; amount: number; entryPrice: number } +): Promise { + const global = await readGlobal(program, program.programId); + if (!global) throw new Error("Contract not initialized"); + const id = global.counter; + + const sig = await program.methods + .createBet(new BN(id), new BN(args.side), new BN(args.amount), new BN(args.entryPrice)) + .accounts({ + bettor: bettor.publicKey, + }) + .signers([bettor]) + .rpc(); + + console.log(`create_bet #${id} side=${args.side === SIDE_UP ? "UP" : "DOWN"} ` + + `amount=${(args.amount / LAMPORTS_PER_SOL_NUM).toFixed(3)} SOL entry=${args.entryPrice} tx=${sig}`); + return id; +} + +/** + * Закрывает ставку после экспирации. + * Если exit_price == entry_price, контракт не финализирует ставку — тогда + * ждём первое движение цены и повторяем close (см. обработку в main loop). + */ +export async function closeBet( + program: Program, + id: BN, + exitPrice: number, + relayer: Keypair, + bettor: PublicKey +): Promise { + return program.methods + .closeBet(new BN(id), new BN(exitPrice)) + .accounts({ + relayer: relayer.publicKey, + bettor, + }) + .signers([relayer]) + .rpc(); +} + +/** + * Догружает ваулт (house bankroll), чтобы хватило на выплаты 1.3x. + * На localnet используем airDrop на PDA ваулта; на mainnet воздух не накапает — + * там нужно переводить SOL с админа (off-chain, вне этого CLI). + */ +export async function ensureVaultFunded( + connection: Connection, + program: Program, + amountLamports: number +): Promise { + const global = globalPda(program.programId); + const current = await connection.getBalance(global); + const needed = amountLamports; // будущая выплата (до 1.3x), запасаем с запасом + if (current >= needed) return; + const topUp = needed - current + 5 * LAMPORTS_PER_SOL_NUM; // +5 SOL запаса + await connection.requestAirdrop(global, topUp); + console.log(`vault funded +${(topUp / LAMPORTS_PER_SOL_NUM).toFixed(2)} SOL`); +} diff --git a/smart-updown/relayer/src/pda.ts b/smart-updown/relayer/src/pda.ts new file mode 100644 index 0000000..06dcce3 --- /dev/null +++ b/smart-updown/relayer/src/pda.ts @@ -0,0 +1,16 @@ +import { PublicKey } from "@solana/web3.js"; +import BN from "bn.js"; + +/** Seeds, согласованные с контрактом (см. constants.rs). */ +export const GLOBAL_SEED = Buffer.from("global"); +export const BET_SEED = Buffer.from("bet"); + +export function globalPda(programId: PublicKey): PublicKey { + return PublicKey.findProgramAddressSync([GLOBAL_SEED], programId)[0]; +} + +export function betPda(programId: PublicKey, id: BN): PublicKey { + const idLE = Buffer.alloc(8); + idLE.writeBigUInt64LE(BigInt(id.toString(10))); + return PublicKey.findProgramAddressSync([BET_SEED, idLE], programId)[0]; +} diff --git a/smart-updown/relayer/src/priceSource.ts b/smart-updown/relayer/src/priceSource.ts new file mode 100644 index 0000000..3a5b007 --- /dev/null +++ b/smart-updown/relayer/src/priceSource.ts @@ -0,0 +1,22 @@ +/** + * STUB — SOL price source. + * + * TODO(пользователь): замени `getPrice` на реальный запрос к своей БД. + * Договоримся, что функция возвращает цену SOL как целое число в «центах» + * (то же юнит-пространство, что у веса entry/exit на контракте). Контракт + * сравнивает тол ько «больше/меньше/равно», поэтому само юнит-пространство + * не критично — главное, чтобы оно было согласовано между entry и exit. + */ +let simulated = 100_000_000; + +/** Цена SOL сейчас (заглушка — детерминированно «гуляет»). */ +export async function getPrice(): Promise { + const drift = Math.round(Math.random() * 200_000); // ±0.2% движка + simulated += Math.random() < 0.5 ? drift : -drift; + return simulated; +} + +/** Управляемая заглушка: вернуть ровно `value` (полезна для теста «equal price»). */ +export function setPriceOverride(value: number | undefined): void { + simulated = value ?? 100_000_000; +} diff --git a/smart-updown/relayer/src/program.ts b/smart-updown/relayer/src/program.ts new file mode 100644 index 0000000..0f82f4d --- /dev/null +++ b/smart-updown/relayer/src/program.ts @@ -0,0 +1,27 @@ +import { Connection } from "@solana/web3.js"; +import { AnchorProvider, Program, Wallet } from "@anchor-lang/core"; +import { Keypair } from "@solana/web3.js"; +import idl from "../idl/smart_updown.json"; + +import type { SmartUpdown } from "../idl/smart_updown"; + +/** + * Создаёт готовый клиент программы: Connection + AnchorProvider (подпись админа- + * релеера) + типизированный Program, собранный из IDL. + */ +export function makeProgram( + connection: Connection, + admin: Keypair +): Program { + const provider = new AnchorProvider( + connection, + new Wallet(admin), + { commitment: "confirmed", preflightCommitment: "confirmed" } + ); + // IDL.address задаёт programId в рантайме. + return new Program(idl as unknown as SmartUpdown, provider); +} + +export function makeConnection(rpcUrl: string): Connection { + return new Connection(rpcUrl, "confirmed"); +} diff --git a/smart-updown/relayer/tsconfig.json b/smart-updown/relayer/tsconfig.json new file mode 100644 index 0000000..acc1fad --- /dev/null +++ b/smart-updown/relayer/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "lib": ["es2020"], + "module": "commonjs", + "target": "es2020", + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + "strict": true, + "skipLibCheck": true, + "outDir": "dist" + }, + "include": ["src/**/*", "idl/**/*"] +}