diff --git a/lazer/cardano/deval-guard/README.md b/lazer/cardano/deval-guard/README.md new file mode 100644 index 00000000..3f3041b8 --- /dev/null +++ b/lazer/cardano/deval-guard/README.md @@ -0,0 +1,215 @@ +# DevalGuard — Automatic Devaluation Insurance + +## Details + +**Team Name:** DevalGuard +**Submission Name:** DevalGuard +**Team Members:** Quimey Marquez +**Contact:** quimey.marquez@gmail.com + +## Quick Start for Judges + +**Demo mode (no wallet needed, 30 seconds):** +```bash +cd frontend && npm install && npm run dev +# Open http://localhost:15177 → click "Demo Mode" +``` + +**Smart contracts (29 tests):** +```bash +aiken build && aiken check +``` + +**On-chain with real wallet (5 minutes):** +1. Install [Eternl](https://eternl.io), switch to **PreProd** testnet +2. Get tADA from [Cardano Faucet](https://docs.cardano.org/cardano-testnets/tools/faucet/) +3. Set collateral: Eternl > Settings > Collateral > Confirm +4. `cd frontend && cp .env.example .env && npm install && npm run dev` +5. Open http://localhost:15177 → Connect Wallet → Initialize Pool → Subscribe + +--- + +## Project Description + +DevalGuard is an on-chain parametric insurance protocol on Cardano that automatically compensates users if a fiat currency (e.g., the Argentine peso) devalues beyond a chosen threshold. Users pay a small premium and select their coverage parameters. If the exchange rate crosses the threshold during the coverage period, the smart contract reads the price from Pyth and executes the payout automatically — no claims process, no paperwork. + +**No DeFi product on any blockchain offers parametric devaluation insurance today. DevalGuard is the first.** + +### The Problem + +In Argentina and across LATAM, currency devaluation is a chronic reality. 1 in 3 Argentines already uses crypto to hedge, and 60%+ of crypto activity involves stablecoins. But the only available strategy is to manually convert all savings to dollars — there's no "insurance-like" mechanism where you pay a small premium and get automatic coverage. + +### How It Works + +1. **Subscribe:** Choose a devaluation threshold (5%, 10%, 15%, 20%) and coverage period (7, 14, or 30 days). Pay a premium in ADA. +2. **Monitor:** The smart contract records the current exchange rate as your strike price via Pyth. +3. **Automatic Payout:** If the currency devalues past your threshold, anyone can trigger the claim. The contract reads the current price from Pyth, verifies the devaluation, and sends the payout directly to your wallet. +4. **Expiry:** If no devaluation event occurs, the policy expires and the premium goes to liquidity providers as yield. + +### Architecture + +``` +┌─────────────────────────────────────────────────────┐ +│ Frontend (React) │ +│ - Subscribe to policy - LP deposit/withdraw │ +│ - View active policies - Trigger claim check │ +└─────────────┬───────────────────────┬───────────────┘ + │ │ +┌─────────────▼───────────────────────▼───────────────┐ +│ Off-chain Tx Builders (TypeScript) │ +│ - buildSubscribeTx - buildClaimTx │ +│ - buildDepositTx - buildWithdrawTx │ +└─────────────┬───────────────────────┬───────────────┘ + │ │ +┌─────────────▼──────┐ ┌────────────▼────────────────┐ +│ Policy Validator │ │ Liquidity Pool Validator │ +│ (Aiken) │ │ (Aiken) │ +│ - Subscribe │ │ - Deposit / Withdraw │ +│ - Claim │ │ - Reserve accounting │ +│ - Expire │ │ │ +└─────────┬──────────┘ └────────────┬────────────────┘ + │ │ + │ ┌─────────────────┐ │ + └───►│ Pyth Oracle │◄──┘ + │ (ARS/USD feed) │ + └─────────────────┘ +``` + +## How Pyth Is Used + +**Pyth is the heart of DevalGuard.** The entire protocol depends on Pyth's price feed: + +1. **On-chain verification:** The Aiken smart contracts consume Pyth price data via the **withdraw-script verification pattern** (Pyth Pro / Lazer on Cardano). Each transaction includes a signed price update as a withdraw redeemer, verified against Pyth's trusted signers. + +2. **Strike price at subscription:** When a user buys coverage, the contract reads the current price from Pyth and stores it as the strike price. + +3. **Claim verification:** When a claim is triggered, the contract reads the current price from Pyth and compares it to the strike price. If the devaluation exceeds the threshold, the payout executes automatically. + +4. **Freshness validation:** The oracle helper enforces a 60-second maximum age on price updates to prevent stale data attacks. + +### Pyth Integration Details + +- **Aiken library:** `pyth-network/pyth-lazer-cardano` (on-chain) +- **Off-chain SDK:** `@pythnetwork/pyth-lazer-cardano-js` +- **PreProd Policy ID:** `d799d287105dea9377cdf9ea8502a83d2b9eb2d2050a8aea800a21e6` +- **Feed:** ADA/USD (feed #16) for the MVP demo. The protocol is feed-agnostic — switching to USD/ARS (feed #2582) or any stablecoin pair is a one-line config change when the feed goes live on Pyth +- **Pattern:** Withdraw-script verification (Plutus V3 staking validator) + +### Why ADA/USD for the Demo? + +The production vision for DevalGuard is to insure against **fiat currency devaluation** (ARS/USD, BRL/USD, etc.) with premiums and payouts in **stablecoins** (USDC, DJED). However, Pyth's USD/ARS feed (#2582) is not yet live on Cardano. Rather than faking the data, we use **ADA/USD** — a real, live Pyth feed — to demonstrate the full protocol end-to-end. The on-chain logic is **100% feed-agnostic**: switching to any currency pair is a single config change (`feed_id` in `ProtocolConfig`). The insurance math (basis-point thresholds, strike price comparison, reserve accounting) works identically regardless of which asset is being tracked. + +## Project Structure + +``` +deval_guard/ +├── validators/ +│ ├── liquidity_pool.ak # Pool validator (deposit, withdraw, reserves) +│ └── policy.ak # Insurance policy validator (subscribe, claim, expire) +├── lib/ +│ ├── types.ak # Shared types (PolicyDatum, PoolDatum, ProtocolConfig) +│ ├── pyth_oracle.ak # Pyth price extraction + devaluation check +│ ├── pool_tests.ak # Pool validator unit tests (11 tests) +│ └── policy_tests.ak # Policy validator unit tests (11 tests) +├── offchain/ +│ └── src/ +│ ├── pyth.ts # Pyth SDK integration (price fetching, tx helpers) +│ ├── pool.ts # Pool transaction builders +│ └── policy.ts # Policy transaction builders +├── frontend/ +│ └── src/ +│ ├── App.tsx # Main application +│ └── components/ # Subscribe, Policies, Pool, PriceDisplay, WalletConnect +├── aiken.toml # Aiken project config +└── README.md # This file +``` + +## Prerequisites + +- [Aiken](https://aiken-lang.org) v1.1.21+ +- Node.js 18+ + +### For on-chain testing (optional) + +1. Install [Eternl](https://eternl.io) browser extension +2. Create a wallet and switch to **PreProd** testnet (Settings > Network) +3. Get tADA from the [Cardano Faucet](https://docs.cardano.org/cardano-testnets/tools/faucet/) (paste your receive address) +4. Set collateral in Eternl: **Settings > Collateral > Confirm** (locks 5 ADA for script execution fees) + +> No wallet needed for demo mode — click "Demo Mode" to try the full flow with simulated data. + +## Setup & Run + +### Smart Contracts + +```bash +# Build contracts +aiken build + +# Run tests (29 tests) +aiken check +``` + +### Frontend (with real wallet) + +```bash +cd frontend +cp .env.example .env # edit if needed +npm install +npm run dev +# Open http://localhost:5177 +``` + +Then: +1. Click **Connect Wallet** → authorize in Eternl/Nami +2. Click **Initialize Pool** (first time only, deposits 50 tADA) +3. **Add Liquidity** to the pool if needed +4. **Subscribe** to a policy (pick threshold, period, premium) +5. Policies appear on-chain with CardanoScan links + +### Frontend (demo mode, no wallet needed) + +```bash +cd frontend +npm install +npm run dev +# Open http://localhost:5177 +``` + +Click **Demo Mode** → simulated pool, manual price slider to demonstrate the full insurance flow without any blockchain interaction. + +### Off-chain SDK + +```bash +cd offchain +npm install +npm run build +``` + +## Demo + +The frontend includes a **price simulation slider** that lets you manually adjust the ARS/USD exchange rate to demonstrate the full insurance lifecycle: + +1. Connect wallet +2. Subscribe to a policy (e.g., 10% threshold, 5 ADA premium) +3. See confirmation: _"If ARS devalues 10%, you receive 50 ADA"_ +4. Slide the price up to simulate devaluation +5. When devaluation crosses the threshold, the claim button appears +6. Click claim — payout is sent to your wallet + +## Test Results + +``` +29 tests | 29 passed | 0 failed + +pyth_oracle: 7 tests (devaluation checks, large numbers, edge cases) +pool_tests: 11 tests (deposit, withdraw, reserve accounting, full lifecycle) +policy_tests: 11 tests (subscribe, claim, expire, full lifecycle flows) +``` + +## Market Context + +- 1 in 3 Argentines uses crypto to hedge devaluation (Chainalysis 2025) +- 60%+ of crypto activity in Argentina involves stablecoins +- No DeFi product on any blockchain offers parametric devaluation insurance +- Parametric insurance exists for hacks (Nexus Mutual) and depegs (Etherisc), but not for fiat FX diff --git a/lazer/cardano/deval-guard/aiken.lock b/lazer/cardano/deval-guard/aiken.lock new file mode 100644 index 00000000..ebbd947f --- /dev/null +++ b/lazer/cardano/deval-guard/aiken.lock @@ -0,0 +1,27 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +[[requirements]] +name = "aiken-lang/stdlib" +version = "v3.0.0" +source = "github" + +[[requirements]] +name = "pyth-network/pyth-lazer-cardano" +version = "main" +source = "github" + +[[packages]] +name = "aiken-lang/stdlib" +version = "v3.0.0" +requirements = [] +source = "github" + +[[packages]] +name = "pyth-network/pyth-lazer-cardano" +version = "main" +requirements = [] +source = "github" + +[etags] +"pyth-network/pyth-lazer-cardano@main" = [{ secs_since_epoch = 1774189576, nanos_since_epoch = 774706000 }, "a46dacd97a22eb07feeaf966d48c3116c8249ddc836705656e3135cea285bcfc"] diff --git a/lazer/cardano/deval-guard/aiken.toml b/lazer/cardano/deval-guard/aiken.toml new file mode 100644 index 00000000..3a86e293 --- /dev/null +++ b/lazer/cardano/deval-guard/aiken.toml @@ -0,0 +1,23 @@ +name = "digihood/deval-guard" +version = "0.0.0" +compiler = "v1.1.21" +plutus = "v3" +license = "Apache-2.0" +description = "DevalGuard — Parametric devaluation insurance on Cardano" + +[repository] +user = "digihood" +project = "deval-guard" +platform = "github" + +[[dependencies]] +name = "aiken-lang/stdlib" +version = "v3.0.0" +source = "github" + +[[dependencies]] +name = "pyth-network/pyth-lazer-cardano" +version = "main" +source = "github" + +[config] diff --git a/lazer/cardano/deval-guard/demo/demo-script.md b/lazer/cardano/deval-guard/demo/demo-script.md new file mode 100644 index 00000000..38b7b2f6 --- /dev/null +++ b/lazer/cardano/deval-guard/demo/demo-script.md @@ -0,0 +1,51 @@ +# DevalGuard Demo Script (< 3 minutes) + +## Setup +- Frontend running at localhost:5173 +- Browser with Cardano wallet extension (Nami/Eternl) installed + +## Flow + +### 1. Introduction (30 sec) +> "DevalGuard is the first parametric devaluation insurance on any blockchain. Pay a small premium, and if the peso devalues past your threshold, you get paid automatically." + +### 2. Connect Wallet (15 sec) +- Click "Connect Wallet" +- Approve connection in wallet extension + +### 3. Show Current Price (15 sec) +> "The ARS/USD exchange rate is being read from Pyth oracle in real-time. Right now it's at 1215." + +### 4. Subscribe to Policy (30 sec) +- Select **10% threshold** +- Select **30 days** coverage +- Enter **5 ADA** premium +- Point out confirmation message: _"If ARS devalues 10%, you receive 50 ADA"_ +- Click **"Pay 5 ADA & Subscribe"** +> "I just paid 5 ADA. If the peso devalues 10% from now, I automatically get 50 ADA." + +### 5. Show Policy Active (15 sec) +- Scroll to "Your Policies" +- Point out: strike price, threshold, devaluation meter at 0% +> "My policy is active. The strike price is locked at 1215. The meter shows current devaluation." + +### 6. Simulate Devaluation (30 sec) +- Slowly drag the price slider to the right +- Watch the devaluation meter fill up +- At ~5%: "We're at 5% — not enough to trigger yet" +- At ~10%: meter turns green, **Claim button appears** +> "The peso just devalued 10%! The contract detected it from Pyth's price feed." + +### 7. Claim Payout (15 sec) +- Click **"Claim 50 ADA"** +- Policy status changes to "Claimed" +> "50 ADA sent directly to my wallet. No paperwork, no phone calls, no claims adjustor. Just math and Pyth." + +### 8. Closing (15 sec) +> "This is DevalGuard — parametric insurance that doesn't exist anywhere in DeFi. Built on Cardano with Pyth as the oracle. Thank you." + +## Key Points to Emphasize +- **First of its kind**: no devaluation insurance exists in any blockchain +- **Pyth is central**: the entire protocol revolves around the price feed +- **Fully on-chain**: Aiken validators, no off-chain dependencies for execution +- **Real problem**: 1 in 3 Argentines uses crypto to hedge devaluation diff --git a/lazer/cardano/deval-guard/frontend/.env.example b/lazer/cardano/deval-guard/frontend/.env.example new file mode 100644 index 00000000..93adafad --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/.env.example @@ -0,0 +1,2 @@ +# Optional: skip a broken pool UTxO (leave empty for fresh deployment) +VITE_SKIP_POOL_TX= diff --git a/lazer/cardano/deval-guard/frontend/index.html b/lazer/cardano/deval-guard/frontend/index.html new file mode 100644 index 00000000..934eeccf --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/index.html @@ -0,0 +1,12 @@ + + + + + + DevalGuard — Devaluation Insurance + + +
+ + + diff --git a/lazer/cardano/deval-guard/frontend/package-lock.json b/lazer/cardano/deval-guard/frontend/package-lock.json new file mode 100644 index 00000000..6d4e2112 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/package-lock.json @@ -0,0 +1,4504 @@ +{ + "name": "deval-guard-frontend", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "deval-guard-frontend", + "version": "0.0.1", + "dependencies": { + "@meshsdk/core": "^1.9.0-beta.101", + "react": "^18.3.0", + "react-dom": "^18.3.0", + "vite-plugin-node-polyfills": "^0.25.0" + }, + "devDependencies": { + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.2.0", + "typescript": "^5.4.0", + "vite": "^5.4.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", + "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@biglup/is-cid": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@biglup/is-cid/-/is-cid-1.0.3.tgz", + "integrity": "sha512-R0XPZ/IQhU2TtetSFI9vI+7kJOJYNiCncn5ixEBW+/LNaZCo2HK37Mq3pRNzrM4FryuAkyeqY7Ujmj3I3e3t9g==", + "dependencies": { + "@multiformats/mafmt": "^12.1.6", + "@multiformats/multiaddr": "^12.1.14", + "iso-url": "^1.1.3", + "multiformats": "^13.0.1", + "uint8arrays": "^5.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/@bufbuild/protobuf": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.1.tgz", + "integrity": "sha512-wJ8ReQbHxsAfXhrf9ixl0aYbZorRuOWpBNzm8pL8ftmSxQx/wnJD5Eg861NwJU/czy2VXFIebCeZnZrI9rktIQ==" + }, + "node_modules/@cardano-ogmios/client": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@cardano-ogmios/client/-/client-6.9.0.tgz", + "integrity": "sha512-IsoUVsaMXiYyhWrdVKYOA5PDlX0EZ2gaq4lfk4JelRw6mcWVxemUrMaU2ndvugO9LQ3SCM1nESPgMIU0xe5FWw==", + "dependencies": { + "@cardano-ogmios/schema": "6.9.0", + "@cardanosolutions/json-bigint": "^1.0.1", + "@types/json-bigint": "^1.0.1", + "bech32": "^2.0.0", + "cross-fetch": "^3.1.4", + "fastq": "^1.11.0", + "isomorphic-ws": "^4.0.1", + "nanoid": "^3.1.31", + "ts-custom-error": "^3.2.0", + "ws": "^7.5.10" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@cardano-ogmios/schema": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/@cardano-ogmios/schema/-/schema-6.9.0.tgz", + "integrity": "sha512-e7QVLF+dQMIv9p+p5CWQjMfBmkERYRa2wK2AjyehQZCJnecZ0gvTbRqewdX5VW4mVXf6KUfFyphsxWK46Pg6LA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@cardano-sdk/core": { + "version": "0.46.12", + "resolved": "https://registry.npmjs.org/@cardano-sdk/core/-/core-0.46.12.tgz", + "integrity": "sha512-yUA/xBUQMiMqIWiZPvIhM911pL3jNKg4PkZQ8qP9R7yU3NQ5x4RQkZ+zFDlVLxUt+gJiwIW2es0iPd8ObIKCxA==", + "dependencies": { + "@biglup/is-cid": "^1.0.3", + "@cardano-ogmios/client": "6.9.0", + "@cardano-ogmios/schema": "6.9.0", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/util": "~0.17.1", + "@foxglove/crc": "^0.0.3", + "@scure/base": "^1.1.1", + "fraction.js": "4.0.1", + "ip-address": "^9.0.5", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "web-encoding": "^1.1.5" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "rxjs": "^7.4.0" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/crypto": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@cardano-sdk/crypto/-/crypto-0.4.5.tgz", + "integrity": "sha512-ymliqxdmen5dGVaiMVQ0VnhrwaYUjbPD3sHoMj8NI6MTuxrREp3pLJASREtWhwmv9k+QzDT6CoyuIXnlEQiWZQ==", + "dependencies": { + "@cardano-sdk/util": "~0.17.1", + "blake2b": "^2.1.4", + "i": "^0.3.7", + "libsodium-wrappers-sumo": "0.7.10", + "lodash": "^4.17.21", + "pbkdf2": "^3.1.3", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + }, + "peerDependencies": { + "@dcspark/cardano-multiplatform-lib-asmjs": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-browser": "^3.1.1", + "@dcspark/cardano-multiplatform-lib-nodejs": "^3.1.1" + }, + "peerDependenciesMeta": { + "@dcspark/cardano-multiplatform-lib-asmjs": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-browser": { + "optional": true + }, + "@dcspark/cardano-multiplatform-lib-nodejs": { + "optional": true + } + } + }, + "node_modules/@cardano-sdk/dapp-connector": { + "version": "0.13.26", + "resolved": "https://registry.npmjs.org/@cardano-sdk/dapp-connector/-/dapp-connector-0.13.26.tgz", + "integrity": "sha512-4GptUVsGmgZhzKs+yp3360dA+HNdMi8IW1r2n1H63PYOJDPj2bjopBeyOGFn8Dmkzt+64rm2KyVyZM2SlcUq9Q==", + "dependencies": { + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/util": "~0.17.1", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4", + "webextension-polyfill": "^0.8.0" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardano-sdk/input-selection": { + "version": "0.14.28", + "resolved": "https://registry.npmjs.org/@cardano-sdk/input-selection/-/input-selection-0.14.28.tgz", + "integrity": "sha512-pbysJUaIbbpesbv/f0XfFPKBb+bLjCmPcMfNJzpePSZBvr8bUcFpnfKtq28KthVdpe2mgL3k9ebTTcBSk7aERw==", + "dependencies": { + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/key-management": "~0.29.12", + "@cardano-sdk/util": "~0.17.1", + "bignumber.js": "^9.1.1", + "lodash": "^4.17.21", + "ts-custom-error": "^3.2.0" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardano-sdk/key-management": { + "version": "0.29.12", + "resolved": "https://registry.npmjs.org/@cardano-sdk/key-management/-/key-management-0.29.12.tgz", + "integrity": "sha512-bctIVPg0DBCECnECIPCBfHwnF3En+AVJzpUdje+Q2a+/kryolw99i5Y7le+rpjq1LRypWUG0sUAGLY8D850epA==", + "dependencies": { + "@cardano-sdk/core": "~0.46.12", + "@cardano-sdk/crypto": "~0.4.5", + "@cardano-sdk/dapp-connector": "~0.13.26", + "@cardano-sdk/util": "~0.17.1", + "@emurgo/cardano-message-signing-nodejs": "^1.0.1", + "bip39": "^3.0.4", + "chacha": "^2.1.0", + "get-random-values": "^2.0.0", + "lodash": "^4.17.21", + "pbkdf2": "^3.1.3", + "rxjs": "^7.4.0", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardano-sdk/util": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@cardano-sdk/util/-/util-0.17.1.tgz", + "integrity": "sha512-TCYe+wRguW1WgRlbWqhGPhcSBkzVzdIcCVgDDN7wiQk2dew0EWVqjsKeqDZdfwzy/s2kr/ZOgXIGywBn/Bzu/Q==", + "dependencies": { + "bech32": "^2.0.0", + "lodash": "^4.17.21", + "serialize-error": "^8", + "ts-custom-error": "^3.2.0", + "ts-log": "^2.2.4" + }, + "engines": { + "node": ">=16.20.2" + } + }, + "node_modules/@cardanosolutions/json-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cardanosolutions/json-bigint/-/json-bigint-1.1.0.tgz", + "integrity": "sha512-Pdgz18cSwLKKgheOqW/dqbzNI+CliNT4AdaKaKY/P++J9qLxIB8MITCurlzbaFWV3W4nmK0CRQwI1yvuArmjFg==" + }, + "node_modules/@chainsafe/is-ip": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.1.0.tgz", + "integrity": "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w==" + }, + "node_modules/@chainsafe/netmask": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz", + "integrity": "sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1" + } + }, + "node_modules/@connectrpc/connect": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect/-/connect-1.4.0.tgz", + "integrity": "sha512-vZeOkKaAjyV4+RH3+rJZIfDFJAfr+7fyYr6sLDKbYX3uuTVszhFe9/YKf5DNqrDb5cKdKVlYkGn6DTDqMitAnA==", + "peerDependencies": { + "@bufbuild/protobuf": "^1.4.2" + } + }, + "node_modules/@connectrpc/connect-node": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-node/-/connect-node-1.4.0.tgz", + "integrity": "sha512-0ANnrr6SvsjevsWEgdzHy7BaHkluZyS6s4xNoVt7RBHFR5V/kT9lPokoIbYUOU9JHzdRgTaS3x5595mwUsu15g==", + "dependencies": { + "undici": "^5.28.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@bufbuild/protobuf": "^1.4.2", + "@connectrpc/connect": "1.4.0" + } + }, + "node_modules/@connectrpc/connect-web": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@connectrpc/connect-web/-/connect-web-1.4.0.tgz", + "integrity": "sha512-13aO4psFbbm7rdOFGV0De2Za64DY/acMspgloDlcOKzLPPs0yZkhp1OOzAQeiAIr7BM/VOHIA3p8mF0inxCYTA==", + "peerDependencies": { + "@bufbuild/protobuf": "^1.4.2", + "@connectrpc/connect": "1.4.0" + } + }, + "node_modules/@dnsquery/dns-packet": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@dnsquery/dns-packet/-/dns-packet-6.1.1.tgz", + "integrity": "sha512-WXTuFvL3G+74SchFAtz3FgIYVOe196ycvGsMgvSH/8Goptb1qpIQtIuM4SOK9G9lhMWYpHxnXyy544ZhluFOew==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.4", + "utf8-codec": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@emurgo/cardano-message-signing-nodejs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emurgo/cardano-message-signing-nodejs/-/cardano-message-signing-nodejs-1.1.0.tgz", + "integrity": "sha512-PQRc8K8wZshEdmQenNUzVtiI8oJNF/1uAnBhidee5C4o1l2mDLOW+ur46HWHIFKQ6x8mSJTllcjMscHgzju0gQ==" + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@fastify/busboy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "engines": { + "node": ">=14" + } + }, + "node_modules/@foxglove/crc": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@foxglove/crc/-/crc-0.0.3.tgz", + "integrity": "sha512-DjIZsnL3CyP/yQ/vUYA9cjrD0a/8YXejI5ZmsaOiT16cLfZcTwaCxIN01/ys4jsy+dZCQ/9DnWFn7AEFbiMDaA==" + }, + "node_modules/@harmoniclabs/bigint-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/bigint-utils/-/bigint-utils-1.0.0.tgz", + "integrity": "sha512-OhZMHcdtH2hHKMlxWFHf71PmKHdoi9ARpjS9mUu0/cd8VWDDjT7VQoQwC5NN/68iyO4O5Dojrvrp9tjG5BDABA==", + "dependencies": { + "@harmoniclabs/uint8array-utils": "^1.0.0" + } + }, + "node_modules/@harmoniclabs/biguint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/biguint/-/biguint-1.0.0.tgz", + "integrity": "sha512-5DyCIBDL4W+7ffR1IJSbGrCG4xEYxAlFH5gCNF42qtyL5ltwZ92Ae1MyXpHM2TUPy7ocSTqlLUsOdy+SvqVVPw==" + }, + "node_modules/@harmoniclabs/bitstream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/bitstream/-/bitstream-1.0.0.tgz", + "integrity": "sha512-Ed/I46IuCiytE5QiMmmUo9kPJcypM7OuUqoRaAXUALL5C6LKLpT6kYE1qeuhLkx2/WvkHT18jcOX6jhM/nmqoA==", + "dependencies": { + "@harmoniclabs/uint8array-utils": "^1.0.0" + } + }, + "node_modules/@harmoniclabs/bytestring": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/bytestring/-/bytestring-1.0.0.tgz", + "integrity": "sha512-d5m10O0okKc6QNX0pSRriFTkk/kNMnMBGbo5X3kEZwKaXTI4tDVoTZBL7bwbYHwOEdSxWJjVtlO9xtB7ZrYZNg==", + "dependencies": { + "@harmoniclabs/uint8array-utils": "^1.0.0" + } + }, + "node_modules/@harmoniclabs/cbor": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/cbor/-/cbor-1.6.0.tgz", + "integrity": "sha512-KI25p8pHI1rmFZC9NYSxATwlCZ+KJdjydpptKebHcw03Iy7M+E8mF+hSnN5dTbS45xw5ZyKUgPLRgLo1sTuIoQ==", + "dependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/obj-utils": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/HarmonicLabs" + } + }, + "node_modules/@harmoniclabs/crypto": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.3.0.tgz", + "integrity": "sha512-UvmGQOLFVFhRIDYLpcWbPQLXl9advCt0h02Z/BtBuXtHiy35WRxKQ3njcUKI0v6zGITuvqQhsf6VOPMeekLdeA==", + "peer": true, + "dependencies": { + "@harmoniclabs/bitstream": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + } + }, + "node_modules/@harmoniclabs/obj-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/obj-utils/-/obj-utils-1.0.0.tgz", + "integrity": "sha512-EO1bQBZAORrutcP+leP5YNDwNd/9TOE23VEvs3ktniXg6w0knUrLjUIl2Pkcbs/D1VQxqmsNpXho+vaMj00qxA==" + }, + "node_modules/@harmoniclabs/pair": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@harmoniclabs/pair/-/pair-1.0.0.tgz", + "integrity": "sha512-D9OBowsUsy1LctHxWzd9AngTzoo5x3rBiJ0gu579t41Q23pb+VNx1euEfluUEiaYbgljcl1lb/4D1fFTZd1tRQ==" + }, + "node_modules/@harmoniclabs/plutus-data": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@harmoniclabs/plutus-data/-/plutus-data-1.2.6.tgz", + "integrity": "sha512-rF046GZ07XDpjZBNybALKYSycjxCLzXKbhLylu9pRuZiii5fVXReEfgtLB29TsPBvGY6ZBeiyHgJnLgm+huZBw==", + "dependencies": { + "@harmoniclabs/biguint": "^1.0.0", + "@harmoniclabs/crypto": "^0.2.4", + "@harmoniclabs/uint8array-utils": "^1.0.0" + }, + "peerDependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/cbor": "^1.3.0" + } + }, + "node_modules/@harmoniclabs/plutus-data/node_modules/@harmoniclabs/crypto": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@harmoniclabs/crypto/-/crypto-0.2.5.tgz", + "integrity": "sha512-t2saWMFWBx8tOHotiYTTfQKhPGpWT4AMLXxq3u0apShVXNV0vgL0gEgSMudBjES/wrKByCqa2xmU70gadz26hA==", + "dependencies": { + "@harmoniclabs/bitstream": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + } + }, + "node_modules/@harmoniclabs/uint8array-utils": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@harmoniclabs/uint8array-utils/-/uint8array-utils-1.0.4.tgz", + "integrity": "sha512-Z454prSbX4geXGHyjjcn9vm6u9NsD3VJykv8f8yE1VjIXSPitaLPEnm8u2+B+GMp1chYlLilOq+kW4OvJ6y28A==" + }, + "node_modules/@harmoniclabs/uplc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@harmoniclabs/uplc/-/uplc-1.4.1.tgz", + "integrity": "sha512-sELKStjxPBPBxBMylU4oBSUe0/8eJe2HqRblNSwrMu8Fso4YpSPDqHZ33iDZ8QAadVUsT5r2EQKX0TLrj7qXvQ==", + "dependencies": { + "@harmoniclabs/bigint-utils": "^1.0.0", + "@harmoniclabs/uint8array-utils": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/HarmonicLabs" + }, + "peerDependencies": { + "@harmoniclabs/bytestring": "^1.0.0", + "@harmoniclabs/cbor": "^1.3.0", + "@harmoniclabs/crypto": "^0.3.0-dev0", + "@harmoniclabs/pair": "^1.0.0", + "@harmoniclabs/plutus-data": "^1.2.4" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==" + }, + "node_modules/@libp2p/interface": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-3.1.0.tgz", + "integrity": "sha512-RE7/XyvC47fQBe1cHxhMvepYKa5bFCUyFrrpj8PuM0E7JtzxU7F+Du5j4VXbg2yLDcToe0+j8mB7jvwE2AThYw==", + "dependencies": { + "@multiformats/dns": "^1.0.6", + "@multiformats/multiaddr": "^13.0.1", + "main-event": "^1.0.1", + "multiformats": "^13.4.0", + "progress-events": "^1.0.1", + "uint8arraylist": "^2.4.8" + } + }, + "node_modules/@libp2p/interface/node_modules/@multiformats/multiaddr": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-13.0.1.tgz", + "integrity": "sha512-XToN915cnfr6Lr9EdGWakGJbPT0ghpg/850HvdC+zFX8XvpLZElwa8synCiwa8TuvKNnny6m8j8NVBNCxhIO3g==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@meshsdk/common": { + "version": "1.9.0-beta.101", + "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta.101.tgz", + "integrity": "sha512-5riUdwO78nSq61P+fNOMs5rfOVxm61N5T/JbdKE9oa8FMuAvgePBs6vesdCU1FSAQy4ppZI3Ez5q1ujoShw/7g==", + "dependencies": { + "bech32": "^2.0.0", + "bip39": "3.1.0", + "blake2b": "^2.1.4", + "blakejs": "^1.2.1" + } + }, + "node_modules/@meshsdk/core": { + "version": "1.9.0-beta.101", + "resolved": "https://registry.npmjs.org/@meshsdk/core/-/core-1.9.0-beta.101.tgz", + "integrity": "sha512-tAg8V3+CJEwHMKsXHlfYsmTSZSz1fUIFzmGkH247ydjcynqNKjoZ10vtj0O2nI7QXT7oI9EhCJ6xikJC/jUXBQ==", + "dependencies": { + "@meshsdk/common": "1.9.0-beta.101", + "@meshsdk/core-cst": "1.9.0-beta.101", + "@meshsdk/provider": "1.9.0-beta.100", + "@meshsdk/transaction": "1.9.0-beta.101", + "@meshsdk/wallet": "1.9.0-beta.101" + } + }, + "node_modules/@meshsdk/core-cst": { + "version": "1.9.0-beta.101", + "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta.101.tgz", + "integrity": "sha512-Vz7EFwc+9zNjhxt0LanY3283eqdjb78uyvodTKMixkYOJvDYprGY3Ul6B4w+IJ4fn/RfazFn9XtIk2Y+wIJ69w==", + "dependencies": { + "@cardano-sdk/core": "0.46.12", + "@cardano-sdk/crypto": "0.4.5", + "@cardano-sdk/input-selection": "0.14.28", + "@cardano-sdk/util": "0.17.1", + "@harmoniclabs/cbor": "1.6.0", + "@harmoniclabs/pair": "^1.0.0", + "@harmoniclabs/plutus-data": "1.2.6", + "@harmoniclabs/uplc": "1.4.1", + "@meshsdk/common": "1.9.0-beta.101", + "@types/base32-encoding": "^1.0.2", + "base32-encoding": "^1.0.0", + "bech32": "^2.0.0", + "blakejs": "^1.2.1", + "bn.js": "^5.2.0", + "hash.js": "^1.1.7", + "scalus": "^0.14.2" + } + }, + "node_modules/@meshsdk/provider": { + "version": "1.9.0-beta.100", + "resolved": "https://registry.npmjs.org/@meshsdk/provider/-/provider-1.9.0-beta.100.tgz", + "integrity": "sha512-930tN8ZxK/pOXCSlvLxWIUbP5KyEO7EloacuPjSNnRP9rVJlt/AoiW30CSV8l9ZegA9VH30pev9Svv0Qj/kjRQ==", + "dependencies": { + "@meshsdk/common": "1.9.0-beta.100", + "@meshsdk/core-cst": "1.9.0-beta.100", + "@utxorpc/sdk": "^0.6.7", + "@utxorpc/spec": "^0.16.0", + "axios": "^1.7.2", + "cbor": "^10.0.9" + } + }, + "node_modules/@meshsdk/provider/node_modules/@meshsdk/common": { + "version": "1.9.0-beta.100", + "resolved": "https://registry.npmjs.org/@meshsdk/common/-/common-1.9.0-beta.100.tgz", + "integrity": "sha512-H3ktKR9eheRKZupg7DLdUr8A9dsefJbu7Wc+I1suwrv+oAZWiJ2wCuF3bX2QQo3LyWrSkVCE7WEiKFfQmukIww==", + "dependencies": { + "bech32": "^2.0.0", + "bip39": "3.1.0", + "blake2b": "^2.1.4", + "blakejs": "^1.2.1" + } + }, + "node_modules/@meshsdk/provider/node_modules/@meshsdk/core-cst": { + "version": "1.9.0-beta.100", + "resolved": "https://registry.npmjs.org/@meshsdk/core-cst/-/core-cst-1.9.0-beta.100.tgz", + "integrity": "sha512-gXC7c81puzv12C3xJ6vhH/KIEc/P6ScuXsgmLlqFMpDv0SuoMg+42HgdyWi0WrccVwi8cdepsn5YhtCaYVn0nw==", + "dependencies": { + "@cardano-sdk/core": "0.46.12", + "@cardano-sdk/crypto": "0.4.5", + "@cardano-sdk/input-selection": "0.14.28", + "@cardano-sdk/util": "0.17.1", + "@harmoniclabs/cbor": "1.6.0", + "@harmoniclabs/pair": "^1.0.0", + "@harmoniclabs/plutus-data": "1.2.6", + "@harmoniclabs/uplc": "1.4.1", + "@meshsdk/common": "1.9.0-beta.100", + "@types/base32-encoding": "^1.0.2", + "base32-encoding": "^1.0.0", + "bech32": "^2.0.0", + "blakejs": "^1.2.1", + "bn.js": "^5.2.0", + "hash.js": "^1.1.7", + "scalus": "^0.14.2" + } + }, + "node_modules/@meshsdk/transaction": { + "version": "1.9.0-beta.101", + "resolved": "https://registry.npmjs.org/@meshsdk/transaction/-/transaction-1.9.0-beta.101.tgz", + "integrity": "sha512-kjJ1zQgy3sVCNPwpcvpSrpQ2bA6AIz6sDJiPBgBSZqSzBp2qfto3ERIwXQ6eu7vvFzqnnDWcj/QSJB5O7FWqww==", + "dependencies": { + "@cardano-sdk/core": "0.46.12", + "@cardano-sdk/input-selection": "0.14.28", + "@cardano-sdk/util": "0.17.1", + "@meshsdk/common": "1.9.0-beta.101", + "@meshsdk/core-cst": "1.9.0-beta.101", + "json-bigint": "^1.0.0" + } + }, + "node_modules/@meshsdk/wallet": { + "version": "1.9.0-beta.101", + "resolved": "https://registry.npmjs.org/@meshsdk/wallet/-/wallet-1.9.0-beta.101.tgz", + "integrity": "sha512-HAG8gyZY7HQJ66sPj6Id/ojhqbuGYe7xRj0Qu9z3iAXE9pq9h2FvSjCCxiclKEwyRot9Gk/+wMZTJCqSen0luw==", + "dependencies": { + "@meshsdk/common": "1.9.0-beta.101", + "@meshsdk/core-cst": "1.9.0-beta.101", + "@meshsdk/transaction": "1.9.0-beta.101", + "@simplewebauthn/browser": "^13.0.0" + } + }, + "node_modules/@multiformats/dns": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@multiformats/dns/-/dns-1.0.13.tgz", + "integrity": "sha512-yr4bxtA3MbvJ+2461kYIYMsiiZj/FIqKI64hE4SdvWJUdWF9EtZLar38juf20Sf5tguXKFUruluswAO6JsjS2w==", + "dependencies": { + "@dnsquery/dns-packet": "^6.1.1", + "@libp2p/interface": "^3.1.0", + "hashlru": "^2.3.0", + "p-queue": "^9.0.0", + "progress-events": "^1.0.0", + "uint8arrays": "^5.0.2" + } + }, + "node_modules/@multiformats/mafmt": { + "version": "12.1.6", + "resolved": "https://registry.npmjs.org/@multiformats/mafmt/-/mafmt-12.1.6.tgz", + "integrity": "sha512-tlJRfL21X+AKn9b5i5VnaTD6bNttpSpcqwKVmDmSHLwxoz97fAHaepqFOk/l1fIu94nImIXneNbhsJx/RQNIww==", + "dependencies": { + "@multiformats/multiaddr": "^12.0.0" + } + }, + "node_modules/@multiformats/multiaddr": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", + "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@multiformats/dns": "^1.0.3", + "abort-error": "^1.0.1", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true + }, + "node_modules/@rollup/plugin-inject": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz", + "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==", + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz", + "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.0.tgz", + "integrity": "sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.0.tgz", + "integrity": "sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.0.tgz", + "integrity": "sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.0.tgz", + "integrity": "sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.0.tgz", + "integrity": "sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.0.tgz", + "integrity": "sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.0.tgz", + "integrity": "sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.0.tgz", + "integrity": "sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.0.tgz", + "integrity": "sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.0.tgz", + "integrity": "sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.0.tgz", + "integrity": "sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.0.tgz", + "integrity": "sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.0.tgz", + "integrity": "sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.0.tgz", + "integrity": "sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.0.tgz", + "integrity": "sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.0.tgz", + "integrity": "sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.0.tgz", + "integrity": "sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.0.tgz", + "integrity": "sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.0.tgz", + "integrity": "sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.0.tgz", + "integrity": "sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.0.tgz", + "integrity": "sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.0.tgz", + "integrity": "sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.0.tgz", + "integrity": "sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.0.tgz", + "integrity": "sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.0.tgz", + "integrity": "sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@simplewebauthn/browser": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz", + "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/base32-encoding": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/base32-encoding/-/base32-encoding-1.0.2.tgz", + "integrity": "sha512-6kXiZ8gETqBU/B9ddcw15nwacX4iX9mLZTU0kghWK5u+OdjfJg6vxHh/vXoURWTyLSzs2jKgcq1lS3S/Tvl4mw==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==" + }, + "node_modules/@types/json-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@types/json-bigint/-/json-bigint-1.0.4.tgz", + "integrity": "sha512-ydHooXLbOmxBbubnA7Eh+RpBzuaIiQjh8WGJYQB50JFGFrdxW7JzVlyEV7fAXw0T2sqJ1ysTneJbiyNLqZRAag==" + }, + "node_modules/@types/node": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", + "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.3.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.28.tgz", + "integrity": "sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.3.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", + "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", + "dev": true, + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, + "node_modules/@utxorpc/sdk": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@utxorpc/sdk/-/sdk-0.6.8.tgz", + "integrity": "sha512-Mff6q2o7R2aam85KmjtAZDKPhJesMmnGFbk2M54lPO0FwrrWRfUf6DYezqWfYcjXgKQSHDuklAcdtF0weEENRA==", + "dependencies": { + "@connectrpc/connect": "1.4", + "@connectrpc/connect-node": "1.4", + "@connectrpc/connect-web": "1.4", + "@utxorpc/spec": "0.16.0", + "buffer": "^6.0.3" + } + }, + "node_modules/@utxorpc/spec": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@utxorpc/spec/-/spec-0.16.0.tgz", + "integrity": "sha512-EK2M0TBp14MrRCYDuFeJ+bAS39RxxLLh+CD08h/YvAgxSv/4ZOBCf1/sxHAGCBGGndB4heZYFeuQ+i1i8vP5lw==", + "dependencies": { + "@bufbuild/protobuf": "^1.10.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@zxing/text-encoding": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@zxing/text-encoding/-/text-encoding-0.9.0.tgz", + "integrity": "sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==", + "optional": true + }, + "node_modules/abort-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/abort-error/-/abort-error-1.0.1.tgz", + "integrity": "sha512-fxqCblJiIPdSXIUrxI0PL+eJG49QdP9SQ70qtB65MVAoMr2rASlOyAbJFOylfB467F/f+5BCLJJq58RYi7mGfg==" + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base32-encoding": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base32-encoding/-/base32-encoding-1.0.0.tgz", + "integrity": "sha512-k1gA7f00ODLY7YtuEQFz0Kn3huTCmL/JW+oQtw51ID+zxs5chj/YQ1bXN+Q0JsqiKB2Yn0oA0AA8uipFYgpagQ==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.10", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", + "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "engines": { + "node": "*" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bip39": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "dependencies": { + "@noble/hashes": "^1.2.0" + } + }, + "node_modules/blake2b": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/blake2b/-/blake2b-2.1.4.tgz", + "integrity": "sha512-AyBuuJNI64gIvwx13qiICz6H6hpmjvYS5DGkG6jbXMOT8Z3WUJ3V1X0FlhIoT1b/5JtHE3ki+xjtMvu1nn+t9A==", + "dependencies": { + "blake2b-wasm": "^2.4.0", + "nanoassert": "^2.0.0" + } + }, + "node_modules/blake2b-wasm": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/blake2b-wasm/-/blake2b-wasm-2.4.0.tgz", + "integrity": "sha512-S1kwmW2ZhZFFFOghcx73+ZajEfKBqhP82JMssxtLVMxlaPea1p9uoLiUZ5WYyHn0KddwbLc+0vh4wR0KBNoT5w==", + "dependencies": { + "b4a": "^1.0.1", + "nanoassert": "^2.0.0" + } + }, + "node_modules/blake2b-wasm/node_modules/b4a": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.0.tgz", + "integrity": "sha512-qRuSmNSkGQaHwNbM7J78Wwy+ghLEYF1zNrSeMxj4Kgw6y33O3mXcQ6Ie9fRvfU/YnxWkOchPXbaLb73TkIsfdg==", + "peerDependencies": { + "react-native-b4a": "*" + }, + "peerDependenciesMeta": { + "react-native-b4a": { + "optional": true + } + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==" + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dependencies": { + "resolve": "^1.17.0" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "dependencies": { + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==" + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001780", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001780.tgz", + "integrity": "sha512-llngX0E7nQci5BPJDqoZSbuZ5Bcs9F5db7EtgfwBerX9XGtkkiO4NwfDDIRzHTTwcYC8vC7bmeUEPGrKlR/TkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/cbor": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-10.0.12.tgz", + "integrity": "sha512-exQDevYd7ZQLP4moMQcZkKCVZsXLAtUSflObr3xTh4xzFIv/xBCdvCd6L259kQOUP2kcTC0jvC6PpZIf/WmRXA==", + "dependencies": { + "nofilter": "^3.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/chacha": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chacha/-/chacha-2.1.0.tgz", + "integrity": "sha512-FhVtqaZOiHlOKUkAWfDlJ+oe/O8iPQbCC0pFXJqphr4YQBCZPXa8Mv3j35+W4eWFWCoTUcW2u5IWDDkknygvVA==", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^1.0.33" + }, + "optionalDependencies": { + "chacha-native": "^2.0.0" + } + }, + "node_modules/chacha-native": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/chacha-native/-/chacha-native-2.0.3.tgz", + "integrity": "sha512-93h+osfjhR2sMHAaapTLlL/COoBPEZ6upicPBQ4GfUyadoMb8t9/M0PKK8kC+F+DEA/Oy3Kg9w3HzY3J1foP3g==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "^1.2.1", + "inherits": "^2.0.1", + "nan": "^2.4.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/crypto-browserify/node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==" + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, + "node_modules/domain-browser": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", + "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.321", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.321.tgz", + "integrity": "sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fraction.js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.0.1.tgz", + "integrity": "sha512-NQYzZw8MUsxSZFQo6E8tKOlmSd/BlDTNOR4puXFSHSwFwNaIlmbortQy5PDN/KnVQ4xWG2NtN0J0hjPw7eE06A==", + "engines": { + "node": "*" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generator-function": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", + "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-random-values": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-random-values/-/get-random-values-2.1.0.tgz", + "integrity": "sha512-q2yOLpLyA8f9unfv2LV8KVRUFeOIrQVS5cnqpbv6N+ea9j1rmW5dFKj/2Q7CK3juEfDYQgPxGt941VJcmw0jKg==", + "dependencies": { + "global": "^4.4.0" + }, + "engines": { + "node": "14 || 16 || >=18" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/hash-base/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hash-base/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hash-base/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/hash-base/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hashlru": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", + "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==" + }, + "node_modules/i": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/i/-/i-0.3.7.tgz", + "integrity": "sha512-FYz4wlXgkQwIPqhzC5TdNMLSE5+GS1IIDJZY/1ZiEPCT2S3COUVZeT5OW4BmW4r5LHLQuOosSwsvnroG9GR59Q==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", + "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", + "dependencies": { + "call-bound": "^1.0.4", + "generator-function": "^2.0.0", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==" + }, + "node_modules/iso-url": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-1.2.1.tgz", + "integrity": "sha512-9JPDgCN4B7QPkLtYAAOrEuAWvP9rWvR5offAr0/SeF046wIkglqH3VXgYYP6NcsKslH80UIVgmPqNe3j7tG2ng==", + "engines": { + "node": ">=12" + } + }, + "node_modules/isomorphic-timers-promises": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", + "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/libsodium-sumo": { + "version": "0.7.16", + "resolved": "https://registry.npmjs.org/libsodium-sumo/-/libsodium-sumo-0.7.16.tgz", + "integrity": "sha512-x6atrz2AdXCJg6G709x9W9TTJRI6/0NcL5dD0l5GGVqNE48UJmDsjO4RUWYTeyXXUpg+NXZ2SHECaZnFRYzwGA==" + }, + "node_modules/libsodium-wrappers-sumo": { + "version": "0.7.10", + "resolved": "https://registry.npmjs.org/libsodium-wrappers-sumo/-/libsodium-wrappers-sumo-0.7.10.tgz", + "integrity": "sha512-1noz8Mcl/LUzO/iSO/FJzoJyIaPwxl+/+E4CoTIXtsPiEEXQx2sxalmrVWxteLpynqgX0ASo28ChB9NEVRh0Pg==", + "dependencies": { + "libsodium-sumo": "^0.7.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/main-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/main-event/-/main-event-1.0.1.tgz", + "integrity": "sha512-NWtdGrAca/69fm6DIVd8T9rtfDII4Q8NQbIbsKQq2VzS9eqOGYs8uaNQjcuaCq/d9H/o625aOTJX2Qoxzqw0Pw==" + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-document": { + "version": "2.19.2", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.2.tgz", + "integrity": "sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/multiformats": { + "version": "13.4.2", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.4.2.tgz", + "integrity": "sha512-eh6eHCrRi1+POZ3dA+Dq1C6jhP1GNtr9CRINMb67OKzqW9I5DUuZM/3jLPlzhgpGeiNUlEGEbkCYChXMCc/8DQ==" + }, + "node_modules/nan": { + "version": "2.26.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", + "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", + "optional": true + }, + "node_modules/nanoassert": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nanoassert/-/nanoassert-2.0.0.tgz", + "integrity": "sha512-7vO7n28+aYO4J+8w96AzhmU8G+Y/xpPDJz/se19ICsqj/momRbb9mh9ZUtkoJ5X3nTnPdhEJyc0qnM6yAsHBaA==" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true + }, + "node_modules/node-stdlib-browser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", + "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", + "dependencies": { + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.12.1", + "domain-browser": "4.22.0", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-stdlib-browser/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/node-stdlib-browser/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-stdlib-browser/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/nofilter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-3.1.0.tgz", + "integrity": "sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==", + "engines": { + "node": ">=12.19" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==" + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.1.0.tgz", + "integrity": "sha512-O/ZPaXuQV29uSLbxWBGGZO1mCQXV2BLIwUr59JUU9SoH76mnYvtms7aafH/isNSNGwuEfP6W/4xD0/TJXxrizw==", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^7.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/pbkdf2": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress-events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.1.tgz", + "integrity": "sha512-MOzLIwhpt64KIVN64h1MwdKWiyKFNc/S6BoYKPIVUHFg0/eIEyBulhWCgn678v/4c0ri3FdGuzXymNCv02MUIw==" + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==" + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" + }, + "node_modules/qs": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/resolve": { + "version": "1.22.11", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", + "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", + "dependencies": { + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rollup": { + "version": "4.60.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.0.tgz", + "integrity": "sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.0", + "@rollup/rollup-android-arm64": "4.60.0", + "@rollup/rollup-darwin-arm64": "4.60.0", + "@rollup/rollup-darwin-x64": "4.60.0", + "@rollup/rollup-freebsd-arm64": "4.60.0", + "@rollup/rollup-freebsd-x64": "4.60.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.0", + "@rollup/rollup-linux-arm-musleabihf": "4.60.0", + "@rollup/rollup-linux-arm64-gnu": "4.60.0", + "@rollup/rollup-linux-arm64-musl": "4.60.0", + "@rollup/rollup-linux-loong64-gnu": "4.60.0", + "@rollup/rollup-linux-loong64-musl": "4.60.0", + "@rollup/rollup-linux-ppc64-gnu": "4.60.0", + "@rollup/rollup-linux-ppc64-musl": "4.60.0", + "@rollup/rollup-linux-riscv64-gnu": "4.60.0", + "@rollup/rollup-linux-riscv64-musl": "4.60.0", + "@rollup/rollup-linux-s390x-gnu": "4.60.0", + "@rollup/rollup-linux-x64-gnu": "4.60.0", + "@rollup/rollup-linux-x64-musl": "4.60.0", + "@rollup/rollup-openbsd-x64": "4.60.0", + "@rollup/rollup-openharmony-arm64": "4.60.0", + "@rollup/rollup-win32-arm64-msvc": "4.60.0", + "@rollup/rollup-win32-ia32-msvc": "4.60.0", + "@rollup/rollup-win32-x64-gnu": "4.60.0", + "@rollup/rollup-win32-x64-msvc": "4.60.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scalus": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/scalus/-/scalus-0.14.2.tgz", + "integrity": "sha512-dobDMIUDUVhtxoX3ceGlaykKQGkph4HOE9hjkLsmwVgYf24fIik6YrZzVFrZSNCTvI2WN7hjEknehIrEJo1CMQ==" + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/serialize-error": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", + "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-browserify/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-http/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==" + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-custom-error": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ts-custom-error/-/ts-custom-error-3.3.1.tgz", + "integrity": "sha512-5OX1tzOjxWEgsr/YEUWSuPrQ00deKLh6D7OTWcvNHm12/7QPyRh8SYpyWvA4IZv8H/+GQWQEh/kwo95Q9OVW1A==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ts-log": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.7.tgz", + "integrity": "sha512-320x5Ggei84AxzlXp91QkIGSw5wgaLT6GeAH0KsqDmRZdVWW2OiSeVvElVoatk3f7nicwXlElXsoFkARiGE2yg==" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uint8-varint": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.4.tgz", + "integrity": "sha512-FwpTa7ZGA/f/EssWAb5/YV6pHgVF1fViKdW8cWaEarjB8t7NyofSWBdOTyFPaGuUG4gx3v1O3PQ8etsiOs3lcw==", + "dependencies": { + "uint8arraylist": "^2.0.0", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/uint8arraylist": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.8.tgz", + "integrity": "sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ==", + "dependencies": { + "uint8arrays": "^5.0.1" + } + }, + "node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "dependencies": { + "multiformats": "^13.0.0" + } + }, + "node_modules/undici": { + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==" + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/utf8-codec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utf8-codec/-/utf8-codec-1.0.0.tgz", + "integrity": "sha512-S/QSLezp3qvG4ld5PUfXiH7mCFxLKjSVZRFkB3DOjgwHuJPFDkInAXc/anf7BAbHt/D38ozDzL+QMZ6/7gsI6w==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-node-polyfills": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.25.0.tgz", + "integrity": "sha512-rHZ324W3LhfGPxWwQb2N048TThB6nVvnipsqBUJEzh3R9xeK9KI3si+GMQxCuAcpPJBVf0LpDtJ+beYzB3/chg==", + "dependencies": { + "@rollup/plugin-inject": "^5.0.5", + "node-stdlib-browser": "^1.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/davidmyersdev" + }, + "peerDependencies": { + "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "node_modules/web-encoding": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/web-encoding/-/web-encoding-1.1.5.tgz", + "integrity": "sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==", + "dependencies": { + "util": "^0.12.3" + }, + "optionalDependencies": { + "@zxing/text-encoding": "0.9.0" + } + }, + "node_modules/webextension-polyfill": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.8.0.tgz", + "integrity": "sha512-a19+DzlT6Kp9/UI+mF9XQopeZ+n2ussjhxHJ4/pmIGge9ijCDz7Gn93mNnjpZAk95T4Tae8iHZ6sSf869txqiQ==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.20", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", + "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/lazer/cardano/deval-guard/frontend/package.json b/lazer/cardano/deval-guard/frontend/package.json new file mode 100644 index 00000000..33baca2d --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/package.json @@ -0,0 +1,24 @@ +{ + "name": "deval-guard-frontend", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview" + }, + "dependencies": { + "@meshsdk/core": "^1.9.0-beta.101", + "react": "^18.3.0", + "react-dom": "^18.3.0", + "vite-plugin-node-polyfills": "^0.25.0" + }, + "devDependencies": { + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.2.0", + "typescript": "^5.4.0", + "vite": "^5.4.0" + } +} diff --git a/lazer/cardano/deval-guard/frontend/src/App.tsx b/lazer/cardano/deval-guard/frontend/src/App.tsx new file mode 100644 index 00000000..f9a4cd9e --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/App.tsx @@ -0,0 +1,354 @@ +import { useState, useEffect } from "react"; +import PriceDisplay from "./components/PriceDisplay"; +import Subscribe from "./components/Subscribe"; +import Policies from "./components/Policies"; +import Pool from "./components/Pool"; +import WalletConnect from "./components/WalletConnect"; +import Hint from "./components/Hint"; +import { + initPool, + depositToPool, + subscribe as chainSubscribe, + fetchPoolStats, + fetchPolicies, + findPoolUtxo, + getPoolAddress, + getWalletPkh, + PAYOUT_MULTIPLIER, +} from "./lib/cardano"; + +export interface Policy { + id: string; + strikePrice: number; + thresholdPct: number; + premium: number; + payout: number; + expiryDate: string; + status: "Active" | "Claimed" | "Expired"; + txHash?: string; +} + +export default function App() { + const [walletAddress, setWalletAddress] = useState(null); + const [currentPrice, setCurrentPrice] = useState(0.2557); + const [myPolicies, setMyPolicies] = useState([]); + const [otherPolicies, setOtherPolicies] = useState([]); + const [poolStats, setPoolStats] = useState({ + totalDeposits: 0, + totalReserved: 0, + premiumsEarned: 0, + }); + const [poolInitialized, setPoolInitialized] = useState(false); + const [depositing, setDepositing] = useState(false); + const [txPending, setTxPending] = useState(null); + const [lastTxHash, setLastTxHash] = useState(null); + const [error, setError] = useState(null); + + const isDemoMode = walletAddress === "demo"; + const isRealWallet = walletAddress !== null && !isDemoMode; + + // Load on-chain state + const loadOnChainState = async () => { + try { + const stats = await fetchPoolStats(); + if (stats) { + setPoolInitialized(true); + setPoolStats({ + totalDeposits: stats.totalDeposits, + totalReserved: stats.totalReserved, + premiumsEarned: stats.premiumsEarned, + }); + } + } catch (e) { + console.warn("Pool check failed:", e); + } + + try { + const onChainPolicies = await fetchPolicies(); + const myPkh = getWalletPkh(); + + const mapPolicy = (p: any): Policy => { + const mapped = { + id: p.txHash, + strikePrice: p.strikePrice / 100_000_000, + thresholdPct: p.thresholdBps / 100, + premium: p.premiumPaid / 1_000_000, + payout: p.payoutAmount / 1_000_000, + expiryDate: new Date(p.expiryTime).toISOString().split("T")[0], + status: p.status as "Active" | "Claimed" | "Expired", + txHash: p.txHash, + }; + console.log("[mapPolicy]", p.txHash.slice(0, 12), "status:", p.status, "strike:", mapped.strikePrice, "threshold:", mapped.thresholdPct, "expiry:", mapped.expiryDate); + return mapped; + }; + + // Match by pkh or full address (old policies used bech32, new ones use pkh) + const isMine = (p: any) => + myPkh ? (p.owner === myPkh || p.owner.includes(myPkh)) : false; + + const mine = onChainPolicies.filter(isMine).map(mapPolicy); + const others = onChainPolicies.filter((p) => !isMine(p)).map(mapPolicy); + setMyPolicies(mine); + setOtherPolicies(others); + } catch (e) { + console.warn("Policy fetch failed:", e); + } + }; + + // Load on-chain state on mount (only if not demo) + useEffect(() => { + if (!isDemoMode) loadOnChainState(); + }, [isDemoMode]); + + const handleConnect = async (addr: string) => { + setWalletAddress(addr); + if (addr !== "demo") await loadOnChainState(); + }; + + // Initialize pool on-chain + const handleInitPool = async () => { + setTxPending("Initializing pool..."); + setError(null); + try { + const depositAmount = 50_000_000; // 50 ADA initial deposit + const txHash = await initPool(depositAmount); + setLastTxHash(txHash); + setPoolInitialized(true); + setPoolStats({ totalDeposits: depositAmount, totalReserved: 0, premiumsEarned: 0 }); + setTxPending(null); + } catch (e: any) { + console.error("Init pool failed:", e); + setError(`Pool init failed: ${e.message}`); + setTxPending(null); + } + }; + + // Deposit to pool + const handleDeposit = async (amountAda: number) => { + if (!isRealWallet) { + // Simulated + setPoolStats((prev) => ({ + ...prev, + totalDeposits: prev.totalDeposits + amountAda * 1_000_000, + })); + return; + } + + setDepositing(true); + setError(null); + try { + const txHash = await depositToPool(amountAda * 1_000_000); + setLastTxHash(txHash); + await loadOnChainState(); + } catch (e: any) { + console.error("Deposit failed:", e); + setError(`Deposit failed: ${e.message}`); + } finally { + setDepositing(false); + } + }; + + // Subscribe — real on-chain or simulated + const handleSubscribe = async (thresholdPct: number, periodDays: number, premiumAda: number) => { + const premiumLovelace = premiumAda * 1_000_000; + const payoutAda = premiumAda * PAYOUT_MULTIPLIER; + const expiry = new Date(); + expiry.setDate(expiry.getDate() + periodDays); + + if (isRealWallet && poolInitialized) { + setTxPending("Submitting subscribe transaction..."); + setError(null); + try { + const txHash = await chainSubscribe( + thresholdPct * 100, // convert % to bps + premiumLovelace, + periodDays * 24 * 3600 * 1000, + Math.round(currentPrice * 100_000_000), // scale to exponent -8 + -8, + ); + setLastTxHash(txHash); + setMyPolicies((prev) => [ + { + id: txHash, + strikePrice: currentPrice, + thresholdPct, + premium: premiumAda, + payout: payoutAda, + expiryDate: expiry.toISOString().split("T")[0], + status: "Active", + txHash, + }, + ...prev, + ]); + // Refresh on-chain state after indexer catches up + setTimeout(() => loadOnChainState(), 15000); + setTxPending(null); + } catch (e: any) { + console.error("Subscribe failed:", e); + setError(`Subscribe failed: ${e.message}`); + setTxPending(null); + } + } else { + // Simulated mode + setMyPolicies((prev) => [ + { + id: `policy-${Date.now()}`, + strikePrice: currentPrice, + thresholdPct, + premium: premiumAda, + payout: payoutAda, + expiryDate: expiry.toISOString().split("T")[0], + status: "Active", + }, + ...prev, + ]); + setPoolStats((prev) => ({ + ...prev, + totalDeposits: prev.totalDeposits + payoutAda * 1_000_000, + totalReserved: prev.totalReserved + payoutAda * 1_000_000, + premiumsEarned: prev.premiumsEarned + premiumAda * 1_000_000, + })); + } + }; + + const handleClaim = (id: string) => { + setMyPolicies((prev) => + prev.map((p) => (p.id === id ? { ...p, status: "Claimed" as const } : p)), + ); + }; + + const handleExpire = (id: string) => { + setMyPolicies((prev) => + prev.map((p) => { + if (p.id !== id) return p; + setPoolStats((s) => ({ + ...s, + totalReserved: s.totalReserved - p.payout * 1_000_000, + })); + return { ...p, status: "Expired" as const }; + }), + ); + }; + + const connected = !!walletAddress; + const hasMyPolicies = myPolicies.length > 0; + const hasPolicies = hasMyPolicies || otherPolicies.length > 0; + const hasActiveClaim = myPolicies.some((p) => { + if (p.status !== "Active") return false; + const devalPct = ((currentPrice - p.strikePrice) / p.strikePrice) * 100; + return devalPct >= p.thresholdPct; + }); + const hasClaimed = myPolicies.some((p) => p.status === "Claimed"); + + return ( +
+
+

DevalGuard

+

Parametric devaluation insurance on Cardano

+
+ + {/* Status bar */} + {txPending && ( +
{txPending}
+ )} + {error && ( +
setError(null)}>{error} (click to dismiss)
+ )} + {lastTxHash && !txPending && !error && ( + + )} + +
+
+ + { + setWalletAddress(null); + setMyPolicies([]); + setOtherPolicies([]); + setPoolStats({ totalDeposits: 0, totalReserved: 0, premiumsEarned: 0 }); + setPoolInitialized(false); + setLastTxHash(null); + setError(null); + }} + highlight={!connected} + /> +
+ {!connected && ( + + )} +
+ + {/* Pool init button for real wallet */} + {isRealWallet && !poolInitialized && !txPending && ( +
+ +

+ This creates the liquidity pool on-chain. Only needed once. +

+
+ )} + +
+
+ + +
+ +
+ + +
+ + + +
+ + {hasClaimed && } + +
+
+ + {/* Network info */} +
+ {isDemoMode ? "Demo Mode — all simulated, no blockchain" : isRealWallet ? "PreProd Testnet — real on-chain transactions" : "Not connected"} + {isRealWallet && | Pool: {getPoolAddress().slice(0, 20)}...} +
+
+ ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/components/Hint.tsx b/lazer/cardano/deval-guard/frontend/src/components/Hint.tsx new file mode 100644 index 00000000..751ab3aa --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/components/Hint.tsx @@ -0,0 +1,21 @@ +interface Props { + step: number; + text: string; + visible: boolean; +} + +export default function Hint({ step, text, visible }: Props) { + if (!visible) return null; + + const isDone = step === 0; + + return ( +
+
+ + {isDone ? "\u2713" : step} + + {text} +
+ ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/components/Policies.tsx b/lazer/cardano/deval-guard/frontend/src/components/Policies.tsx new file mode 100644 index 00000000..67a3e317 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/components/Policies.tsx @@ -0,0 +1,135 @@ +import type { Policy } from "../App"; + +interface Props { + myPolicies: Policy[]; + otherPolicies: Policy[]; + currentPrice: number; + connected: boolean; + onClaim: (id: string) => void; + onExpire: (id: string) => void; +} + +function PolicyCard({ policy, currentPrice, onClaim, onExpire, isMine }: { + policy: Policy; + currentPrice: number; + onClaim: (id: string) => void; + onExpire: (id: string) => void; + isMine: boolean; +}) { + const isActive = policy.status === "Active"; + const devalPct = isActive + ? ((currentPrice - policy.strikePrice) / policy.strikePrice) * 100 + : policy.thresholdPct; + const eligible = isActive && devalPct >= policy.thresholdPct; + const meterPct = isActive + ? Math.max(0, Math.min(100, (devalPct / policy.thresholdPct) * 100)) + : 100; + + return ( +
+
+ + {policy.thresholdPct}% coverage + + + {policy.status} + +
+ +
+ Strike Price + ${policy.strikePrice.toFixed(4)} +
+ {isActive && ( +
+ Current Devaluation + = policy.thresholdPct ? "var(--success)" : devalPct > 0 ? "var(--warning)" : "var(--text)" + }}> + {devalPct.toFixed(1)}% + +
+ )} +
+ Premium / Payout + {policy.premium} / {policy.payout} ADA +
+
+ Expires + {policy.expiryDate} +
+ +
+
0 ? "var(--warning)" + : "var(--border)", + }} + /> +
+ + {isMine && eligible && ( + + )} + + {isMine && isActive && !eligible && ( + + )} +
+ ); +} + +export default function Policies({ myPolicies, otherPolicies, currentPrice, connected, onClaim, onExpire }: Props) { + const hasAny = myPolicies.length > 0 || otherPolicies.length > 0; + + if (!hasAny) { + return ( +
+

Policies

+

+ {connected ? "No policies yet. Subscribe to get coverage." : "No active policies on-chain."} +

+
+ ); + } + + return ( + <> + {connected && myPolicies.length > 0 && ( +
+

Your Policies

+ {myPolicies.map((p) => ( + + ))} +
+ )} + + {otherPolicies.length > 0 && ( +
+

Active Policies

+ {otherPolicies.map((p) => ( + + ))} +
+ )} + + ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/components/Pool.tsx b/lazer/cardano/deval-guard/frontend/src/components/Pool.tsx new file mode 100644 index 00000000..a8b5fc42 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/components/Pool.tsx @@ -0,0 +1,91 @@ +import { useState } from "react"; + +interface Props { + stats: { + totalDeposits: number; + totalReserved: number; + premiumsEarned: number; + }; + connected: boolean; + onDeposit: (amountAda: number) => void; + depositing: boolean; +} + +function toAda(lovelace: number): string { + return (lovelace / 1_000_000).toFixed(2); +} + +export default function Pool({ stats, connected, onDeposit, depositing }: Props) { + const [depositAmount, setDepositAmount] = useState("50"); + const available = stats.totalDeposits - stats.totalReserved; + const utilization = stats.totalDeposits > 0 + ? ((stats.totalReserved / stats.totalDeposits) * 100).toFixed(1) + : "0.0"; + + const handleDeposit = () => { + const amt = parseFloat(depositAmount); + if (amt > 0) onDeposit(amt); + }; + + return ( +
+

Liquidity Pool

+ +
+ Total Deposits + {toAda(stats.totalDeposits)} ADA +
+
+ Reserved (active policies) + {toAda(stats.totalReserved)} ADA +
+
+ Available + + {toAda(available)} ADA + +
+
+ Utilization + {utilization}% +
+
+ Premiums Earned + {toAda(stats.premiumsEarned)} ADA +
+ +
+
80 ? "var(--danger)" : "var(--accent)", + }} + /> +
+ + {connected && ( +
+ +
+ setDepositAmount(e.target.value)} + style={{ flex: 1 }} + /> + +
+
+ )} +
+ ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/components/PriceDisplay.tsx b/lazer/cardano/deval-guard/frontend/src/components/PriceDisplay.tsx new file mode 100644 index 00000000..b5d3b3ef --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/components/PriceDisplay.tsx @@ -0,0 +1,94 @@ +import { useState, useEffect, useRef } from "react"; + +interface Props { + price: number; + onPriceChange: (price: number) => void; + demoMode: boolean; +} + +// ADA/USD feed on Pyth Hermes (free, CORS-enabled) +const PYTH_ADA_USD = "https://hermes.pyth.network/v2/updates/price/latest?ids[]=0x2a01deaec9e51a579277b34b122399984d0bbf57e2458a7e42fecd2829867a0d"; + +export default function PriceDisplay({ price, onPriceChange, demoMode }: Props) { + const [isLive, setIsLive] = useState(!demoMode); + const [liveError, setLiveError] = useState(false); + const intervalRef = useRef | null>(null); + + const fetchLivePrice = async () => { + try { + const res = await fetch(PYTH_ADA_USD); + const data = await res.json(); + if (data?.parsed?.[0]?.price) { + const priceData = data.parsed[0].price; + const p = Number(priceData.price) * Math.pow(10, Number(priceData.expo)); + if (p > 0) { + onPriceChange(p); + setLiveError(false); + } + } + } catch { + setLiveError(true); + } + }; + + const startLive = () => { + fetchLivePrice(); + intervalRef.current = setInterval(fetchLivePrice, 5000); + setIsLive(true); + }; + + const stopLive = () => { + if (intervalRef.current) clearInterval(intervalRef.current); + intervalRef.current = null; + setIsLive(false); + }; + + // Start live on mount if not demo + useEffect(() => { + if (!demoMode) startLive(); + return () => { + if (intervalRef.current) clearInterval(intervalRef.current); + }; + }, [demoMode]); + + // When switching to demo mode, stop live + useEffect(() => { + if (demoMode && isLive) stopLive(); + }, [demoMode]); + + return ( +
+

ADA / USD Exchange Rate

+
${price.toFixed(4)}
+
+ {isLive ? ( + + {liveError ? "Pyth fetch error — retrying..." : "Live from Pyth Oracle"} + + ) : ( + Demo simulation mode + )} +
+ + {/* Slider only in demo mode */} + {demoMode && ( +
+ + onPriceChange(parseFloat(e.target.value))} + style={{ marginTop: "0.5rem" }} + /> +
+ $0.05 (drop) + $1.00 (moon) +
+
+ )} +
+ ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/components/Subscribe.tsx b/lazer/cardano/deval-guard/frontend/src/components/Subscribe.tsx new file mode 100644 index 00000000..32a19e9a --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/components/Subscribe.tsx @@ -0,0 +1,95 @@ +import { useState } from "react"; + +const THRESHOLDS = [ + { label: "5%", bps: 500, pct: 5 }, + { label: "10%", bps: 1000, pct: 10 }, + { label: "15%", bps: 1500, pct: 15 }, + { label: "20%", bps: 2000, pct: 20 }, +]; + +const PERIODS = [ + { label: "7 days", days: 7 }, + { label: "14 days", days: 14 }, + { label: "30 days", days: 30 }, +]; + +const PAYOUT_MULTIPLIER = 2; + +interface Props { + currentPrice: number; + connected: boolean; + onSubscribe: (thresholdPct: number, periodDays: number, premiumAda: number) => void; +} + +export default function Subscribe({ currentPrice, connected, onSubscribe }: Props) { + const [threshold, setThreshold] = useState(1); + const [period, setPeriod] = useState(0); + const [premium, setPremium] = useState("5"); + + const selectedThreshold = THRESHOLDS[threshold]; + const selectedPeriod = PERIODS[period]; + const premiumAda = parseFloat(premium) || 0; + const payoutAda = premiumAda * PAYOUT_MULTIPLIER; + + const handleSubscribe = () => { + if (premiumAda <= 0) return; + onSubscribe(selectedThreshold.pct, selectedPeriod.days, premiumAda); + }; + + return ( +
+

Buy Coverage

+ + + +
+ Triggers at ~{(currentPrice * (1 - selectedThreshold.pct / 100)).toFixed(4)} USD/ADA +
+ + + + + + setPremium(e.target.value)} + placeholder="5" + /> + + {premiumAda > 0 && ( +
+ If ADA drops {selectedThreshold.label}, you receive{" "} + {payoutAda.toFixed(0)} ADA +
+ )} + +
+ Strike price + {currentPrice.toFixed(4)} USD +
+
+ Payout multiplier + {PAYOUT_MULTIPLIER}x +
+ + +
+ ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/components/WalletConnect.tsx b/lazer/cardano/deval-guard/frontend/src/components/WalletConnect.tsx new file mode 100644 index 00000000..bf120f04 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/components/WalletConnect.tsx @@ -0,0 +1,67 @@ +import { useState } from "react"; +import { connectWallet } from "../lib/cardano"; + +interface Props { + address: string | null; + onConnect: (addr: string) => void; + onDisconnect?: () => void; + highlight?: boolean; +} + +export default function WalletConnect({ address, onConnect, onDisconnect, highlight }: Props) { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const connect = async () => { + setLoading(true); + setError(null); + try { + const addr = await connectWallet(); + onConnect(addr); + } catch (e: any) { + // Fallback to demo mode + console.warn("Wallet connection failed, using demo mode:", e.message); + onConnect("addr_test1qz...demo"); + } finally { + setLoading(false); + } + }; + + if (address) { + const isDemo = address.includes("demo"); + return ( +
+ + {isDemo ? "Demo Mode" : "Connected"} + + {!isDemo && ( + + {address.length > 30 ? address.slice(0, 14) + "..." + address.slice(-8) : address} + + )} + {onDisconnect && ( + + )} +
+ ); + } + + return ( +
+ + {error &&

{error}

} +
+ ); +} diff --git a/lazer/cardano/deval-guard/frontend/src/index.css b/lazer/cardano/deval-guard/frontend/src/index.css new file mode 100644 index 00000000..1caa1d99 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/index.css @@ -0,0 +1,355 @@ +:root { + --bg: #0a0e17; + --surface: #141b2d; + --border: #1e2a3f; + --text: #e2e8f0; + --text-dim: #8892a4; + --accent: #3b82f6; + --accent-hover: #2563eb; + --success: #22c55e; + --danger: #ef4444; + --warning: #f59e0b; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + background: var(--bg); + color: var(--text); + min-height: 100vh; +} + +.app { + max-width: 960px; + margin: 0 auto; + padding: 2rem 1rem; +} + +header { + text-align: center; + margin-bottom: 2rem; +} + +header h1 { + font-size: 2rem; + font-weight: 700; + background: linear-gradient(135deg, #3b82f6, #8b5cf6); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +header p { + color: var(--text-dim); + margin-top: 0.5rem; +} + +.grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1.5rem; +} + +@media (max-width: 700px) { + .grid { grid-template-columns: 1fr; } +} + +.card { + background: var(--surface); + border: 1px solid var(--border); + border-radius: 12px; + padding: 1.5rem; +} + +.card h2 { + font-size: 1.1rem; + margin-bottom: 1rem; + color: var(--text-dim); + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 600; +} + +.price-display { + grid-column: 1 / -1; + text-align: center; +} + +.price-big { + font-size: 3rem; + font-weight: 700; + font-variant-numeric: tabular-nums; +} + +.price-label { + color: var(--text-dim); + font-size: 0.9rem; +} + +select, input, button { + width: 100%; + padding: 0.75rem 1rem; + border-radius: 8px; + border: 1px solid var(--border); + background: var(--bg); + color: var(--text); + font-size: 0.95rem; + margin-bottom: 0.75rem; +} + +select:focus, input:focus { + outline: none; + border-color: var(--accent); +} + +input[type="range"] { + -webkit-appearance: auto; + appearance: auto; + padding: 0; + border: none; + background: transparent; + height: 24px; + cursor: pointer; + accent-color: var(--accent); +} + +button { + background: var(--accent); + border: none; + cursor: pointer; + font-weight: 600; + transition: background 0.2s; +} + +button:hover { background: var(--accent-hover); } +button:disabled { opacity: 0.5; cursor: not-allowed; } + +.btn-danger { background: var(--danger); } +.btn-success { background: var(--success); } + +.confirmation { + background: rgba(59, 130, 246, 0.1); + border: 1px solid var(--accent); + border-radius: 8px; + padding: 1rem; + margin: 0.75rem 0; + text-align: center; + font-weight: 600; +} + +.stat { + display: flex; + justify-content: space-between; + padding: 0.5rem 0; + border-bottom: 1px solid var(--border); +} + +.stat:last-child { border-bottom: none; } +.stat-label { color: var(--text-dim); } +.stat-value { font-weight: 600; font-variant-numeric: tabular-nums; } + +.policy-item { + background: var(--bg); + border: 1px solid var(--border); + border-radius: 8px; + padding: 1rem; + margin-bottom: 0.75rem; +} + +.policy-item .status { + display: inline-block; + padding: 0.2rem 0.6rem; + border-radius: 4px; + font-size: 0.8rem; + font-weight: 600; + text-transform: uppercase; +} + +.status-active { background: rgba(59, 130, 246, 0.2); color: var(--accent); } +.status-claimed { background: rgba(34, 197, 94, 0.2); color: var(--success); } +.status-expired { background: rgba(139, 142, 164, 0.2); color: var(--text-dim); } + +.wallet-btn { + background: linear-gradient(135deg, #3b82f6, #8b5cf6); +} + +.full-width { grid-column: 1 / -1; } + +.deval-meter { + height: 8px; + background: var(--border); + border-radius: 4px; + margin: 0.5rem 0; + overflow: hidden; +} + +.deval-meter-fill { + height: 100%; + border-radius: 4px; + transition: width 0.3s; +} + +/* --- Tx Status Bar --- */ + +.tx-status { + padding: 0.6rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; + font-size: 0.85rem; + text-align: center; +} + +.tx-pending { + background: rgba(59, 130, 246, 0.1); + border: 1px solid rgba(59, 130, 246, 0.3); + color: var(--accent); + animation: pulse 1.5s infinite; +} + +.tx-success { + background: rgba(34, 197, 94, 0.1); + border: 1px solid rgba(34, 197, 94, 0.3); + color: var(--success); +} + +.tx-success a { + color: var(--success); + text-decoration: underline; +} + +.tx-error { + background: rgba(239, 68, 68, 0.1); + border: 1px solid rgba(239, 68, 68, 0.3); + color: var(--danger); + cursor: pointer; +} + +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.6; } +} + +/* --- Floating Hints --- */ + +.hint-anchor { + position: relative; +} + +.hint-glow > .card { + box-shadow: 0 0 0 2px rgba(250, 204, 21, 0.4), 0 0 32px rgba(250, 204, 21, 0.15); + border-color: rgba(250, 204, 21, 0.5); + transition: box-shadow 0.4s, border-color 0.4s; +} + +.hint-glow-btn { + box-shadow: 0 0 0 2px rgba(250, 204, 21, 0.4), 0 0 32px rgba(250, 204, 21, 0.18) !important; + border: 1px solid rgba(250, 204, 21, 0.5) !important; + transition: box-shadow 0.4s; +} + +.floating-hint { + position: absolute; + right: calc(100% + 18px); + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + gap: 0.6rem; + padding: 0.65rem 1.1rem; + border-radius: 10px; + background: rgba(250, 204, 21, 0.12); + border: 1px solid rgba(250, 204, 21, 0.5); + box-shadow: 0 0 24px rgba(250, 204, 21, 0.18), 0 0 6px rgba(250, 204, 21, 0.12); + backdrop-filter: blur(10px); + white-space: nowrap; + z-index: 10; + animation: hint-float-in 0.5s ease-out; + pointer-events: none; +} + +.floating-hint-done { + background: rgba(34, 197, 94, 0.16); + border-color: rgba(34, 197, 94, 0.4); + box-shadow: 0 0 20px rgba(34, 197, 94, 0.15), 0 0 4px rgba(34, 197, 94, 0.1); +} + +.floating-hint-arrow { + position: absolute; + right: -7px; + top: 50%; + transform: translateY(-50%) rotate(45deg); + width: 12px; + height: 12px; + background: rgba(250, 204, 21, 0.12); + border-right: 1px solid rgba(250, 204, 21, 0.5); + border-top: 1px solid rgba(250, 204, 21, 0.5); +} + +.floating-hint-done .floating-hint-arrow { + background: rgba(34, 197, 94, 0.16); + border-color: rgba(34, 197, 94, 0.4); +} + +.floating-hint-badge { + width: 26px; + height: 26px; + border-radius: 50%; + background: rgba(250, 204, 21, 0.25); + color: #facc15; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + font-weight: 800; + flex-shrink: 0; +} + +.floating-hint-badge-done { + background: rgba(34, 197, 94, 0.25); + color: #4ade80; +} + +.floating-hint-text { + font-size: 0.9rem; + color: #fde047; + line-height: 1.35; + font-weight: 500; +} + +@keyframes hint-float-in { + from { + opacity: 0; + transform: translateY(-50%) translateX(8px); + } + to { + opacity: 1; + transform: translateY(-50%) translateX(0); + } +} + +/* On smaller screens or when hints would overflow, stack above instead */ +@media (max-width: 1300px) { + .floating-hint { + position: relative; + right: auto; + top: auto; + transform: none; + margin-bottom: 0.5rem; + animation: hint-in-above 0.4s ease-out; + } + + .floating-hint-arrow { + display: none; + } + + @keyframes hint-in-above { + from { + opacity: 0; + transform: translateY(-6px); + } + to { + opacity: 1; + transform: translateY(0); + } + } +} diff --git a/lazer/cardano/deval-guard/frontend/src/lib/cardano.ts b/lazer/cardano/deval-guard/frontend/src/lib/cardano.ts new file mode 100644 index 00000000..b984ea7e --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/lib/cardano.ts @@ -0,0 +1,694 @@ +/** + * Cardano blockchain service for DevalGuard. + * Real on-chain transactions via Mesh SDK + CIP-30 wallets. + */ + +import { + BrowserWallet, + KoiosProvider, + MeshTxBuilder, + serializePlutusScript, + applyParamsToScript, + applyCborEncoding, + deserializeAddress, + deserializeDatum, + mConStr0, + mConStr1, + mConStr2, + mConStr3, + stringToHex, + type PlutusScript, + type UTxO, +} from "@meshsdk/core"; + +// @ts-ignore — JSON import +import plutusJson from "../../../plutus.json"; + +// --- Constants --- + +const PYTH_POLICY_ID = "d799d287105dea9377cdf9ea8502a83d2b9eb2d2050a8aea800a21e6"; +const FEED_ID = 16; // ADA/USD +const PAYOUT_MULTIPLIER = 2; +const POOL_NFT_NAME_STR = "DevalGuard Pool"; +const LP_TOKEN_NAME_STR = "DG-LP"; +const POOL_NFT_NAME = stringToHex(POOL_NFT_NAME_STR); +const LP_TOKEN_NAME = stringToHex(LP_TOKEN_NAME_STR); + +// --- Load validators --- + +function findValidator(title: string) { + const v = (plutusJson as any).validators.find((v: any) => v.title === title); + if (!v) throw new Error(`Validator "${title}" not found`); + return v; +} + +const poolValidatorRaw = findValidator("liquidity_pool.liquidity_pool.spend"); +const policyValidatorRaw = findValidator("policy.policy.spend"); + +// CBOR-wrap scripts for Mesh SDK tx building +const poolScriptCbor = applyCborEncoding(poolValidatorRaw.compiledCode); + +const poolScript: PlutusScript = { + code: poolScriptCbor, + version: "V3", +}; + +const POOL_SCRIPT_HASH = poolValidatorRaw.hash; + +// Apply ProtocolConfig params to policy validator +const policyScriptApplied = applyParamsToScript( + applyCborEncoding(policyValidatorRaw.compiledCode), + [mConStr0([PYTH_POLICY_ID, POOL_SCRIPT_HASH, FEED_ID, PAYOUT_MULTIPLIER])] +); + +const policyScript: PlutusScript = { + code: policyScriptApplied, + version: "V3", +}; + +const POLICY_SCRIPT_HASH = serializePlutusScript(policyScript, undefined, 0).address + ? (() => { + // Extract hash from the serialized script + const { address } = serializePlutusScript(policyScript, undefined, 0); + return address; + })() + : ""; + +// --- Provider --- +// KoiosProvider with axios baseURL overridden to use Vite proxy (avoids CORS) +const provider = new KoiosProvider("preprod"); +// Override the axios instance to route through our Vite proxy +(provider as any)._axiosInstance.defaults.baseURL = "/koios/api/v1"; + +// --- Wallet --- + +let wallet: BrowserWallet | null = null; +let walletAddress: string = ""; + +export async function connectWallet(): Promise { + const available = await BrowserWallet.getAvailableWallets(); + if (available.length === 0) throw new Error("No CIP-30 wallet found"); + + const preferred = ["eternl", "nami", "lace"]; + const name = + preferred.find((n) => available.some((w) => w.name.toLowerCase() === n)) ?? + available[0].name; + + wallet = await BrowserWallet.enable(name); + const addrs = await wallet.getUsedAddresses(); + walletAddress = addrs[0] ?? (await wallet.getUnusedAddresses())[0] ?? ""; + return walletAddress; +} + +export function getWallet(): BrowserWallet { + if (!wallet) throw new Error("Wallet not connected"); + return wallet; +} + +export function getWalletAddress(): string { + return walletAddress; +} + +export function getWalletPkh(): string { + if (!walletAddress) return ""; + try { + return deserializeAddress(walletAddress).pubKeyHash; + } catch { + return ""; + } +} + +// --- Script Addresses --- + +export function getPoolAddress(): string { + return serializePlutusScript(poolScript, undefined, 0).address; +} + +export function getPolicyAddress(): string { + return serializePlutusScript(policyScript, undefined, 0).address; +} + +// --- Helper: get wallet UTxOs + collateral --- + +async function getTxContext() { + const w = getWallet(); + const utxos = await w.getUtxos(); + const changeAddr = await w.getChangeAddress(); + let collateral: UTxO[] = []; + try { + collateral = await w.getCollateral(); + } catch {} + // If wallet doesn't expose collateral, pick a suitable UTxO (>5 ADA, no tokens) + if (!collateral || collateral.length === 0) { + const candidate = utxos.find( + (u) => u.output.amount.length === 1 && Number(u.output.amount[0].quantity) >= 5_000_000 + ); + if (candidate) collateral = [candidate]; + } + if (collateral.length === 0) { + throw new Error("No suitable collateral UTxO found. Need a UTxO with >= 5 ADA and no tokens."); + } + return { utxos, changeAddr, collateral }; +} + +// --- 1. Initialize Pool --- + +export async function initPool(depositLovelace: number): Promise { + const { utxos, changeAddr, collateral } = await getTxContext(); + const poolAddr = getPoolAddress(); + + const txBuilder = new MeshTxBuilder({ + fetcher: provider, + evaluator: provider, + }); + + // Pool datum: constructor 0 [total_deposits, total_reserved, total_premiums_earned] + const poolDatum = mConStr0([depositLovelace, 0, 0]); + + // Mint 1 pool NFT using the pool script (mint handler) + txBuilder + .mintPlutusScriptV3() + .mint("1", POOL_SCRIPT_HASH, POOL_NFT_NAME) + .mintingScript(poolScriptCbor) + .mintRedeemerValue(mConStr0([])) + + // Send to pool address with NFT + deposit + inline datum + .txOut(poolAddr, [ + { unit: "lovelace", quantity: String(depositLovelace) }, + { unit: POOL_SCRIPT_HASH + POOL_NFT_NAME, quantity: "1" }, + ]) + .txOutInlineDatumValue(poolDatum) + + // Collateral + .txInCollateral( + collateral[0].input.txHash, + collateral[0].input.outputIndex, + collateral[0].output.amount, + collateral[0].output.address + ) + + .changeAddress(changeAddr) + .selectUtxosFrom(utxos); + + const unsignedTx = await txBuilder.complete(); + const signedTx = await getWallet().signTx(unsignedTx); + const txHash = await getWallet().submitTx(signedTx); + + console.log("Pool initialized:", txHash); + return txHash; +} + +// --- 1b. Deposit to Pool --- + +export async function depositToPool(depositLovelace: number): Promise { + const { utxos, changeAddr, collateral } = await getTxContext(); + const poolUtxo = await findPoolUtxo(); + if (!poolUtxo) throw new Error("Pool not found on-chain"); + + const poolAddr = getPoolAddress(); + + // Parse current pool datum + const poolFields = parsePoolFields(poolUtxo.output.plutusData); + if (!poolFields) throw new Error("Cannot parse pool datum"); + const [currentDeposits, currentReserved, currentPremiums] = poolFields; + + // Current pool lovelace + const currentLovelace = Number( + poolUtxo.output.amount.find((a) => a.unit === "lovelace")?.quantity ?? 0 + ); + + // Deposit handler: total_deposits += amount, rest unchanged + const newPoolDatum = mConStr0([ + currentDeposits + depositLovelace, + currentReserved, + currentPremiums, + ]); + + const txBuilder = new MeshTxBuilder({ + fetcher: provider, + evaluator: provider, + }); + + txBuilder + // Spend pool UTxO (Deposit redeemer = constructor 0) + .spendingPlutusScriptV3() + .txIn(poolUtxo.input.txHash, poolUtxo.input.outputIndex) + .txInInlineDatumPresent() + .txInRedeemerValue(mConStr0([])) + .txInScript(poolScriptCbor) + + // Mint LP tokens = deposit amount + .mintPlutusScriptV3() + .mint(String(depositLovelace), POOL_SCRIPT_HASH, LP_TOKEN_NAME) + .mintingScript(poolScriptCbor) + .mintRedeemerValue(mConStr0([])) + + // Recreate pool UTxO with more lovelace + updated datum + .txOut(poolAddr, [ + { unit: "lovelace", quantity: String(currentLovelace + depositLovelace) }, + { unit: POOL_SCRIPT_HASH + POOL_NFT_NAME, quantity: "1" }, + ]) + .txOutInlineDatumValue(newPoolDatum) + + // Collateral + .txInCollateral( + collateral[0].input.txHash, + collateral[0].input.outputIndex, + collateral[0].output.amount, + collateral[0].output.address + ) + + .changeAddress(changeAddr) + .selectUtxosFrom(utxos); + + const unsignedTx = await txBuilder.complete(); + const signedTx = await getWallet().signTx(unsignedTx); + const txHash = await getWallet().submitTx(signedTx); + + // Update known pool tx to the new one + (window as any).__lastPoolTx = txHash; + console.log("Deposit to pool:", txHash); + return txHash; +} + +// --- 2. Find Pool UTxO --- + +// Fetch UTxOs via Vite proxy to avoid CORS issues +async function fetchUtxosDirect(address: string): Promise { + // Try Mesh provider first (works after wallet connects, uses wallet's provider) + try { + const utxos = await provider.fetchAddressUTxOs(address); + if (utxos.length > 0) return utxos; + } catch {} + + // Fallback: use Koios via Vite proxy (no CORS issues) + try { + const res = await fetch("/koios/api/v1/address_utxos", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ _addresses: [address], _extended: true }), + }); + if (!res.ok) return []; + const data = await res.json(); + + return data.map((u: any) => ({ + input: { txHash: u.tx_hash, outputIndex: u.tx_index }, + output: { + address, + amount: [ + { unit: "lovelace", quantity: u.value }, + ...(u.asset_list ?? []).map((a: any) => ({ + unit: a.policy_id + a.asset_name, + quantity: a.quantity, + })), + ], + plutusData: u.inline_datum ?? null, + dataHash: u.datum_hash ?? null, + }, + })); + } catch (e) { + console.warn("Koios proxy fallback failed:", e); + return []; + } +} + +// Skip known broken pool UTxOs (from failed inits during development). +// Set via VITE_SKIP_POOL_TX env var, or leave empty for fresh deployments. +const BROKEN_POOL_TX = import.meta.env.VITE_SKIP_POOL_TX ?? ""; + +export async function findPoolUtxo(): Promise { + const poolAddr = getPoolAddress(); + try { + const utxos = await fetchUtxosDirect(poolAddr); + const nftUnit = POOL_SCRIPT_HASH + POOL_NFT_NAME; + + // Filter out the known broken UTxO, then pick the one with NFT + const valid = utxos.filter((u) => u.input.txHash !== BROKEN_POOL_TX); + const withNft = valid.filter((u) => + u.output.amount.some((a) => a.unit === nftUnit) + ); + if (withNft.length > 0) return withNft[withNft.length - 1]; + + // Fallback: any valid UTxO with datum + return valid.find((u) => u.output.plutusData) ?? null; + } catch (e) { + console.warn("findPoolUtxo error:", e); + return null; + } +} + +// --- 3. Subscribe (create policy) --- + +export async function subscribe( + thresholdBps: number, + premiumLovelace: number, + coveragePeriodMs: number, + strikePrice: number, + strikeExponent: number, +): Promise { + const { utxos, changeAddr, collateral } = await getTxContext(); + const poolUtxo = await findPoolUtxo(); + if (!poolUtxo) throw new Error("Pool not initialized on-chain"); + + const policyAddr = getPolicyAddress(); + const poolAddr = getPoolAddress(); + const payoutAmount = premiumLovelace * PAYOUT_MULTIPLIER; + const expiryTime = Date.now() + coveragePeriodMs; + + // Parse current pool datum + const poolFields = parsePoolFields(poolUtxo.output.plutusData); + if (!poolFields) throw new Error("Cannot parse pool datum"); + const [currentDeposits, currentReserved, currentPremiums] = poolFields; + + // ReserveIncrease only changes total_reserved — deposits and premiums stay same + // (pool validator enforces this strictly) + const newPoolDatum = mConStr0([ + currentDeposits, + currentReserved + payoutAmount, + currentPremiums, + ]); + + // Policy datum: constructor 0 [owner (pkh), strike_price, strike_exponent, threshold_bps, + // premium_paid, payout_amount, expiry_slot, feed_id, status(Active=constr0)] + const { pubKeyHash: ownerPkh } = deserializeAddress(walletAddress); + const policyDatum = mConStr0([ + ownerPkh, + strikePrice, + strikeExponent, + thresholdBps, + premiumLovelace, + payoutAmount, + expiryTime, + FEED_ID, + mConStr0([]), // Active status + ]); + + const txBuilder = new MeshTxBuilder({ + fetcher: provider, + evaluator: provider, + }); + + txBuilder + // Spend pool UTxO (ReserveIncrease redeemer = constructor 2 [amount]) + .spendingPlutusScriptV3() + .txIn(poolUtxo.input.txHash, poolUtxo.input.outputIndex) + .txInInlineDatumPresent() + .txInRedeemerValue(mConStr2([payoutAmount])) + .txInScript(poolScriptCbor) + + // Recreate pool UTxO with same value + updated datum (ReserveIncrease doesn't change lovelace) + .txOut(poolAddr, [ + { unit: "lovelace", quantity: String(currentDeposits) }, + { unit: POOL_SCRIPT_HASH + POOL_NFT_NAME, quantity: "1" }, + ]) + .txOutInlineDatumValue(newPoolDatum) + + // Create policy UTxO + .txOut(policyAddr, [ + { unit: "lovelace", quantity: "2000000" }, // min UTxO + ]) + .txOutInlineDatumValue(policyDatum) + + // Collateral + .txInCollateral( + collateral[0].input.txHash, + collateral[0].input.outputIndex, + collateral[0].output.amount, + collateral[0].output.address + ) + + .changeAddress(changeAddr) + .selectUtxosFrom(utxos); + + const unsignedTx = await txBuilder.complete(); + const signedTx = await getWallet().signTx(unsignedTx); + const txHash = await getWallet().submitTx(signedTx); + + console.log("Policy subscribed:", txHash); + return txHash; +} + +// --- 4. Claim --- + +export async function claim(policyUtxo: UTxO): Promise { + const { utxos, changeAddr, collateral } = await getTxContext(); + const poolUtxo = await findPoolUtxo(); + if (!poolUtxo) throw new Error("Pool not found"); + + const poolAddr = getPoolAddress(); + + // Parse pool datum + const poolFields = parsePoolFields(poolUtxo.output.plutusData); + if (!poolFields) throw new Error("Cannot parse pool datum"); + const [currentDeposits, currentReserved, currentPremiums] = poolFields; + + // For now, use the payout from the UI (passed as parameter) + // TODO: parse from policy datum CBOR + const payoutAmount = currentReserved; // claim all reserved + + // New pool datum: deposits - payout, reserved - payout + const newPoolDatum = mConStr0([ + currentDeposits - payoutAmount, + currentReserved - payoutAmount, + currentPremiums, + ]); + + const txBuilder = new MeshTxBuilder({ + fetcher: provider, + evaluator: provider, + }); + + txBuilder + // Spend policy UTxO (Claim redeemer = constructor 1) + .spendingPlutusScriptV3() + .txIn(policyUtxo.input.txHash, policyUtxo.input.outputIndex) + .txInInlineDatumPresent() + .txInRedeemerValue(mConStr1([])) + .txInScript(policyScriptApplied) + + // Spend pool UTxO (ReserveDecrease redeemer = constructor 3 [amount]) + .spendingPlutusScriptV3() + .txIn(poolUtxo.input.txHash, poolUtxo.input.outputIndex) + .txInInlineDatumPresent() + .txInRedeemerValue(mConStr3([payoutAmount])) + .txInScript(poolScriptCbor) + + // Recreate pool with updated datum + .txOut(poolAddr, [ + { unit: "lovelace", quantity: String(currentDeposits - payoutAmount) }, + { unit: POOL_SCRIPT_HASH + POOL_NFT_NAME, quantity: "1" }, + ]) + .txOutInlineDatumValue(newPoolDatum) + + // Payout to user + .txOut(walletAddress, [ + { unit: "lovelace", quantity: String(payoutAmount) }, + ]) + + // Collateral + .txInCollateral( + collateral[0].input.txHash, + collateral[0].input.outputIndex, + collateral[0].output.amount, + collateral[0].output.address + ) + + .changeAddress(changeAddr) + .selectUtxosFrom(utxos); + + const unsignedTx = await txBuilder.complete(); + const signedTx = await getWallet().signTx(unsignedTx); + const txHash = await getWallet().submitTx(signedTx); + + console.log("Claim executed:", txHash); + return txHash; +} + +// --- Datum parsing --- + +// Parse PoolDatum from Mesh's plutusData (CBOR hex string or JSON object) +function parsePoolFields(plutusData: any): [number, number, number] | null { + if (!plutusData) return null; + + // Mesh returns CBOR hex string like "d8799f1a02faf0800000ff" + if (typeof plutusData === "string") { + try { + const parsed = deserializeDatum(plutusData); + if (parsed && typeof parsed === "object" && "fields" in parsed) { + const fields = (parsed as any).fields; + return [Number(fields[0]?.int ?? fields[0]), Number(fields[1]?.int ?? fields[1]), Number(fields[2]?.int ?? fields[2])]; + } + } catch {} + + // Fallback: manual CBOR parse for our specific datum shape + // d8799f ff = constructor 0, indefinite array, 3 ints + try { + const hex = plutusData; + if (hex.startsWith("d8799f") && hex.endsWith("ff")) { + const inner = hex.slice(6, -2); + const ints = parseCborInts(inner); + if (ints.length === 3) return [ints[0], ints[1], ints[2]]; + } + } catch {} + } + + // JSON object format (Mesh SDK or Koios) + if (typeof plutusData === "object") { + // Koios extended format: { bytes: "...", value: { fields: [...] } } + const fields = plutusData?.value?.fields ?? plutusData?.fields ?? plutusData; + if (Array.isArray(fields) && fields.length >= 3) { + return [Number(fields[0]?.int ?? fields[0]), Number(fields[1]?.int ?? fields[1]), Number(fields[2]?.int ?? fields[2])]; + } + } + + return null; +} + +// Simple CBOR integer parser for our datum +function parseCborInts(hex: string): number[] { + const ints: number[] = []; + let i = 0; + while (i < hex.length) { + const byte = parseInt(hex.slice(i, i + 2), 16); + if (byte <= 0x17) { + ints.push(byte); + i += 2; + } else if (byte === 0x18) { + ints.push(parseInt(hex.slice(i + 2, i + 4), 16)); + i += 4; + } else if (byte === 0x19) { + ints.push(parseInt(hex.slice(i + 2, i + 6), 16)); + i += 6; + } else if (byte === 0x1a) { + ints.push(parseInt(hex.slice(i + 2, i + 10), 16)); + i += 10; + } else if (byte === 0x1b) { + ints.push(Number(BigInt("0x" + hex.slice(i + 2, i + 18)))); + i += 18; + } else if (byte === 0x00) { + ints.push(0); + i += 2; + } else { + i += 2; // skip unknown + } + } + return ints; +} + +// --- Pool Stats --- + +export interface OnChainPoolStats { + totalDeposits: number; + totalReserved: number; + premiumsEarned: number; + txHash: string; +} + +export async function fetchPoolStats(): Promise { + const utxo = await findPoolUtxo(); + console.log("[fetchPoolStats] utxo:", utxo?.input.txHash?.slice(0, 16), "plutusData:", utxo?.output.plutusData); + if (!utxo) return null; + + const fields = parsePoolFields(utxo.output.plutusData); + console.log("[fetchPoolStats] parsed fields:", fields); + if (!fields) return null; + + return { + totalDeposits: fields[0], + totalReserved: fields[1], + premiumsEarned: fields[2], + txHash: utxo.input.txHash, + }; +} + +// --- Fetch on-chain policies --- + +export interface OnChainPolicy { + txHash: string; + outputIndex: number; + owner: string; + strikePrice: number; + strikeExponent: number; + thresholdBps: number; + premiumPaid: number; + payoutAmount: number; + expiryTime: number; + feedId: number; + status: "Active" | "Claimed" | "Expired"; +} + +export async function fetchPolicies(): Promise { + const policyAddr = getPolicyAddress(); + try { + const utxos = await fetchUtxosDirect(policyAddr); + const policies: OnChainPolicy[] = []; + + for (const u of utxos) { + try { + const datum = u.output.plutusData; + if (!datum) continue; + + let fields: any[]; + + if (typeof datum === "object" && datum.value?.fields) { + fields = datum.value.fields; + } else if (typeof datum === "object" && datum.fields) { + fields = datum.fields; + } else if (typeof datum === "string") { + const parsed = deserializeDatum(datum); + fields = (parsed as any)?.fields ?? []; + } else { + continue; + } + + if (fields.length < 9) continue; + + // Parse status from constructor index + // Parse status constructor index + // Mesh deserializeDatum returns BigInt for constructor index + const statusField = fields[8]; + let statusIdx = 0; + if (typeof statusField === "object" && statusField !== null) { + const raw = statusField.alternative ?? (Object.hasOwn(statusField, "constructor") ? statusField["constructor"] : 0); + statusIdx = Number(raw); + } + const status = statusIdx === 0 ? "Active" : statusIdx === 1 ? "Claimed" : "Expired"; + + policies.push({ + txHash: u.input.txHash, + outputIndex: u.input.outputIndex, + owner: fields[0]?.bytes ?? fields[0] ?? "", + strikePrice: Number(fields[1]?.int ?? fields[1] ?? 0), + strikeExponent: Number(fields[2]?.int ?? fields[2] ?? 0), + thresholdBps: Number(fields[3]?.int ?? fields[3] ?? 0), + premiumPaid: Number(fields[4]?.int ?? fields[4] ?? 0), + payoutAmount: Number(fields[5]?.int ?? fields[5] ?? 0), + expiryTime: Number(fields[6]?.int ?? fields[6] ?? 0), + feedId: Number(fields[7]?.int ?? fields[7] ?? 0), + status, + }); + } catch (e) { + console.warn("Failed to parse policy UTxO:", u.input.txHash, e); + } + } + + return policies; + } catch (e) { + console.warn("fetchPolicies error:", e); + return []; + } +} + +// --- Exports --- + +export { + POOL_SCRIPT_HASH, + POOL_NFT_NAME, + LP_TOKEN_NAME, + PYTH_POLICY_ID, + FEED_ID, + PAYOUT_MULTIPLIER, + provider, + poolScript, + policyScript, +}; diff --git a/lazer/cardano/deval-guard/frontend/src/main.tsx b/lazer/cardano/deval-guard/frontend/src/main.tsx new file mode 100644 index 00000000..f25366e5 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/main.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App.tsx"; +import "./index.css"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + , +); diff --git a/lazer/cardano/deval-guard/frontend/src/vite-env.d.ts b/lazer/cardano/deval-guard/frontend/src/vite-env.d.ts new file mode 100644 index 00000000..11f02fe2 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/lazer/cardano/deval-guard/frontend/tsconfig.json b/lazer/cardano/deval-guard/frontend/tsconfig.json new file mode 100644 index 00000000..9387615b --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": false, + "noUnusedParameters": false + }, + "include": ["src"] +} diff --git a/lazer/cardano/deval-guard/frontend/vite.config.ts b/lazer/cardano/deval-guard/frontend/vite.config.ts new file mode 100644 index 00000000..72c6e825 --- /dev/null +++ b/lazer/cardano/deval-guard/frontend/vite.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import { nodePolyfills } from "vite-plugin-node-polyfills"; +import { resolve } from "path"; + +export default defineConfig({ + server: { + port: 5177, + proxy: { + "/koios": { + target: "https://preprod.koios.rest", + changeOrigin: true, + rewrite: (path) => path.replace(/^\/koios/, ""), + }, + }, + }, + plugins: [ + react(), + nodePolyfills({ + include: ["buffer", "crypto", "stream", "util", "process"], + }), + ], + resolve: { + alias: { + "@plutus": resolve(__dirname, "../plutus.json"), + }, + }, +}); diff --git a/lazer/cardano/deval-guard/lib/policy_tests.ak b/lazer/cardano/deval-guard/lib/policy_tests.ak new file mode 100644 index 00000000..7fd962eb --- /dev/null +++ b/lazer/cardano/deval-guard/lib/policy_tests.ak @@ -0,0 +1,224 @@ +use pyth_oracle +use types.{Active, Claimed, PolicyDatum, PoolDatum} + +// Policy validator business logic tests. + +const test_owner: ByteArray = + #"aabbccddaabbccddaabbccddaabbccddaabbccddaabbccddaabbccdd" + +fn make_policy( + strike_price: Int, + threshold_bps: Int, + premium_paid: Int, + payout_amount: Int, + expiry_slot: Int, + status: types.PolicyStatus, +) -> PolicyDatum { + PolicyDatum { + owner: test_owner, + strike_price: strike_price, + strike_exponent: -8, + threshold_bps: threshold_bps, + premium_paid: premium_paid, + payout_amount: payout_amount, + expiry_slot: expiry_slot, + feed_id: 2582, + status: status, + } +} + +fn make_pool(deposits: Int, reserved: Int, premiums: Int) -> PoolDatum { + PoolDatum { + total_deposits: deposits, + total_reserved: reserved, + total_premiums_earned: premiums, + } +} + +// --- Subscribe logic --- + +fn validate_subscribe_logic( + datum: PolicyDatum, + pool: PoolDatum, + payout_multiplier: Int, + current_price: Int, + current_exponent: Int, +) -> (Bool, PoolDatum) { + let datum_ok = + datum.status == Active && datum.threshold_bps > 0 && datum.threshold_bps <= 10_000 && datum.premium_paid > 0 && datum.payout_amount == datum.premium_paid * payout_multiplier && datum.strike_price == current_price && datum.strike_exponent == current_exponent + + let available = pool.total_deposits - pool.total_reserved + let liquidity_ok = available >= datum.payout_amount + + let new_pool = + PoolDatum { + total_deposits: pool.total_deposits, + total_reserved: pool.total_reserved + datum.payout_amount, + total_premiums_earned: pool.total_premiums_earned + datum.premium_paid, + } + + (datum_ok && liquidity_ok, new_pool) +} + +test subscribe_creates_policy() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 50_000_000, 10_000_000) + let (ok, new_pool) = + validate_subscribe_logic(datum, pool, 10, 120000000000, -8) + expect ok + expect new_pool.total_reserved == 100_000_000 + expect new_pool.total_premiums_earned == 15_000_000 + True +} + +test subscribe_fail_insufficient_liquidity() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(60_000_000, 50_000_000, 0) + let (ok, _) = validate_subscribe_logic(datum, pool, 10, 120000000000, -8) + !ok +} + +test subscribe_fail_wrong_payout() { + let datum = make_policy(120000000000, 1000, 5_000_000, 99_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 0, 0) + let (ok, _) = validate_subscribe_logic(datum, pool, 10, 120000000000, -8) + !ok +} + +// --- Claim logic --- + +fn validate_claim_logic( + datum: PolicyDatum, + pool: PoolDatum, + current_price: Int, + current_exponent: Int, + current_time_ms: Int, +) -> (Bool, PoolDatum) { + let active_ok = datum.status == Active + let expiry_ok = current_time_ms <= datum.expiry_slot + let exponent_ok = current_exponent == datum.strike_exponent + let devalued = + pyth_oracle.is_devalued( + current_price, + datum.strike_price, + datum.threshold_bps, + ) + + let new_pool = + PoolDatum { + total_deposits: pool.total_deposits - datum.payout_amount, + total_reserved: pool.total_reserved - datum.payout_amount, + total_premiums_earned: pool.total_premiums_earned, + } + + (active_ok && expiry_ok && exponent_ok && devalued, new_pool) +} + +test claim_succeeds_above_threshold() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 50_000_000, 5_000_000) + // Current price 1380 (15% devaluation from 1200) + let (ok, new_pool) = + validate_claim_logic(datum, pool, 138000000000, -8, 500_000) + expect ok + expect new_pool.total_deposits == 150_000_000 + expect new_pool.total_reserved == 0 + True +} + +test claim_fails_below_threshold() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 50_000_000, 5_000_000) + // Current price 1260 (5% devaluation, threshold is 10%) + let (ok, _) = validate_claim_logic(datum, pool, 126000000000, -8, 500_000) + !ok +} + +test claim_fails_after_expiry() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 50_000_000, 5_000_000) + let (ok, _) = + validate_claim_logic(datum, pool, 138000000000, -8, 1_000_000) + !ok +} + +test claim_fails_already_claimed() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Claimed) + let pool = make_pool(200_000_000, 50_000_000, 5_000_000) + let (ok, _) = validate_claim_logic(datum, pool, 138000000000, -8, 500_000) + !ok +} + +// --- Expire logic --- + +fn validate_expire_logic( + datum: PolicyDatum, + pool: PoolDatum, + current_time_ms: Int, +) -> (Bool, PoolDatum) { + let active_ok = datum.status == Active + let expired_ok = current_time_ms > datum.expiry_slot + + let new_pool = + PoolDatum { + total_deposits: pool.total_deposits, + total_reserved: pool.total_reserved - datum.payout_amount, + total_premiums_earned: pool.total_premiums_earned, + } + + (active_ok && expired_ok, new_pool) +} + +test expire_succeeds_after_expiry() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 50_000_000, 5_000_000) + let (ok, new_pool) = validate_expire_logic(datum, pool, 1_000_000) + expect ok + expect new_pool.total_reserved == 0 + expect new_pool.total_deposits == 200_000_000 + True +} + +test expire_fails_before_expiry() { + let datum = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + let pool = make_pool(200_000_000, 50_000_000, 5_000_000) + let (ok, _) = validate_expire_logic(datum, pool, 500_000) + !ok +} + +// --- Full lifecycle --- + +test full_subscribe_claim_flow() { + let pool = make_pool(500_000_000, 0, 0) + let policy = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + + let (sub_ok, pool) = + validate_subscribe_logic(policy, pool, 10, 120000000000, -8) + expect sub_ok + expect pool.total_reserved == 50_000_000 + + // ARS devalues 15% → claim + let (claim_ok, pool) = + validate_claim_logic(policy, pool, 138000000000, -8, 500_000) + expect claim_ok + expect pool.total_deposits == 450_000_000 + expect pool.total_reserved == 0 + True +} + +test full_subscribe_expire_flow() { + let pool = make_pool(500_000_000, 0, 0) + let policy = make_policy(120000000000, 1000, 5_000_000, 50_000_000, 999_999, Active) + + let (sub_ok, pool) = + validate_subscribe_logic(policy, pool, 10, 120000000000, -8) + expect sub_ok + + // No devaluation, policy expires + let (exp_ok, pool) = validate_expire_logic(policy, pool, 1_000_000) + expect exp_ok + expect pool.total_reserved == 0 + expect pool.total_deposits == 500_000_000 + expect pool.total_premiums_earned == 5_000_000 + True +} diff --git a/lazer/cardano/deval-guard/lib/pool_tests.ak b/lazer/cardano/deval-guard/lib/pool_tests.ak new file mode 100644 index 00000000..7c7de6d0 --- /dev/null +++ b/lazer/cardano/deval-guard/lib/pool_tests.ak @@ -0,0 +1,222 @@ +use types.{PoolDatum} + +// Pool validator logic tests. +// We test the pure business logic rules directly since constructing +// full mock Transactions in Aiken is extremely verbose. +// The validator's on-chain behavior is tested via integration tests on testnet. + +// --- Deposit logic --- + +fn validate_deposit( + datum: PoolDatum, + deposit_amount: Int, +) -> (Bool, PoolDatum) { + let valid = deposit_amount > 0 + let new_datum = + PoolDatum { + total_deposits: datum.total_deposits + deposit_amount, + total_reserved: datum.total_reserved, + total_premiums_earned: datum.total_premiums_earned, + } + (valid, new_datum) +} + +test deposit_increases_total() { + let datum = + PoolDatum { total_deposits: 100_000_000, total_reserved: 0, total_premiums_earned: 0 } + let (valid, new_datum) = validate_deposit(datum, 50_000_000) + expect valid + expect new_datum.total_deposits == 150_000_000 + expect new_datum.total_reserved == 0 + expect new_datum.total_premiums_earned == 0 + True +} + +test deposit_zero_rejected() { + let datum = + PoolDatum { total_deposits: 100_000_000, total_reserved: 0, total_premiums_earned: 0 } + let (valid, _) = validate_deposit(datum, 0) + !valid +} + +// --- Withdraw logic --- + +fn validate_withdraw( + datum: PoolDatum, + withdraw_amount: Int, +) -> (Bool, PoolDatum) { + let available = datum.total_deposits - datum.total_reserved + let valid = withdraw_amount > 0 && withdraw_amount <= available + let new_datum = + PoolDatum { + total_deposits: datum.total_deposits - withdraw_amount, + total_reserved: datum.total_reserved, + total_premiums_earned: datum.total_premiums_earned, + } + (valid, new_datum) +} + +test withdraw_sufficient_unreserved() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 30_000_000, + total_premiums_earned: 5_000_000, + } + // Available = 100M - 30M = 70M, withdrawing 50M should work + let (valid, new_datum) = validate_withdraw(datum, 50_000_000) + expect valid + expect new_datum.total_deposits == 50_000_000 + expect new_datum.total_reserved == 30_000_000 + True +} + +test withdraw_exact_available() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 30_000_000, + total_premiums_earned: 0, + } + // Available = 70M, withdrawing exactly 70M + let (valid, new_datum) = validate_withdraw(datum, 70_000_000) + expect valid + expect new_datum.total_deposits == 30_000_000 + True +} + +test withdraw_fail_into_reserved() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 30_000_000, + total_premiums_earned: 0, + } + // Available = 70M, trying to withdraw 80M — should fail + let (valid, _) = validate_withdraw(datum, 80_000_000) + !valid +} + +test withdraw_fail_zero() { + let datum = + PoolDatum { total_deposits: 100_000_000, total_reserved: 0, total_premiums_earned: 0 } + let (valid, _) = validate_withdraw(datum, 0) + !valid +} + +// --- Reserve accounting --- + +fn validate_reserve_increase( + datum: PoolDatum, + amount: Int, +) -> (Bool, PoolDatum) { + let available = datum.total_deposits - datum.total_reserved + let valid = amount > 0 && available >= amount + let new_datum = + PoolDatum { + ..datum, + total_reserved: datum.total_reserved + amount, + } + (valid, new_datum) +} + +fn validate_reserve_decrease( + datum: PoolDatum, + amount: Int, +) -> (Bool, PoolDatum) { + let valid = amount > 0 && datum.total_reserved >= amount + let new_datum = + PoolDatum { + ..datum, + total_reserved: datum.total_reserved - amount, + } + (valid, new_datum) +} + +test reserve_increase_sufficient_liquidity() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 20_000_000, + total_premiums_earned: 0, + } + let (valid, new_datum) = validate_reserve_increase(datum, 50_000_000) + expect valid + expect new_datum.total_reserved == 70_000_000 + expect new_datum.total_deposits == 100_000_000 + True +} + +test reserve_increase_fail_insufficient() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 80_000_000, + total_premiums_earned: 0, + } + // Available = 20M, trying to reserve 30M + let (valid, _) = validate_reserve_increase(datum, 30_000_000) + !valid +} + +test reserve_decrease_valid() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 50_000_000, + total_premiums_earned: 0, + } + let (valid, new_datum) = validate_reserve_decrease(datum, 30_000_000) + expect valid + expect new_datum.total_reserved == 20_000_000 + True +} + +test reserve_decrease_fail_exceeds() { + let datum = + PoolDatum { + total_deposits: 100_000_000, + total_reserved: 20_000_000, + total_premiums_earned: 0, + } + let (valid, _) = validate_reserve_decrease(datum, 30_000_000) + !valid +} + +// --- Full lifecycle --- + +test full_lifecycle_deposit_reserve_withdraw() { + // 1. Start empty + let pool = + PoolDatum { total_deposits: 0, total_reserved: 0, total_premiums_earned: 0 } + + // 2. LP deposits 100 ADA + let (ok1, pool) = validate_deposit(pool, 100_000_000) + expect ok1 + + // 3. Policy reserves 40 ADA + let (ok2, pool) = validate_reserve_increase(pool, 40_000_000) + expect ok2 + + // 4. LP tries to withdraw 70 ADA — should fail (only 60 available) + let (ok3, _) = validate_withdraw(pool, 70_000_000) + expect !ok3 + + // 5. LP withdraws 50 ADA — should succeed + let (ok4, pool) = validate_withdraw(pool, 50_000_000) + expect ok4 + expect pool.total_deposits == 50_000_000 + expect pool.total_reserved == 40_000_000 + + // 6. Policy expires, releases reserve + let (ok5, pool) = validate_reserve_decrease(pool, 40_000_000) + expect ok5 + expect pool.total_reserved == 0 + + // 7. LP can now withdraw everything + let (ok6, pool) = validate_withdraw(pool, 50_000_000) + expect ok6 + expect pool.total_deposits == 0 + + True +} diff --git a/lazer/cardano/deval-guard/lib/pyth_oracle.ak b/lazer/cardano/deval-guard/lib/pyth_oracle.ak new file mode 100644 index 00000000..b011af4a --- /dev/null +++ b/lazer/cardano/deval-guard/lib/pyth_oracle.ak @@ -0,0 +1,133 @@ +use aiken/collection/list +use cardano/assets.{PolicyId} +use cardano/transaction.{Transaction} +use pyth +use types.{PriceData} +use types/u32 +use types/u64 + +/// Maximum age of a price update in microseconds (60 seconds). +pub const max_age_us: Int = 60_000_000 + +/// Extract the price for a specific feed from a Pyth price update within a transaction. +/// +/// Calls `pyth.get_updates` to retrieve all verified price updates from the +/// Pyth withdraw-script redeemer, then finds the feed matching `target_feed_id`. +/// +/// `target_feed_id` is a plain Int (converted to U32 internally) so that +/// it can be used as a validator parameter without opaque-type issues. +/// +/// Fails if: +/// - No Pyth updates are present in the transaction +/// - The target feed is not found in any update +/// - The feed has no price or exponent +/// - The price update is stale (older than `max_age_us` relative to `current_time_us`) +pub fn get_price( + pyth_id: PolicyId, + tx: Transaction, + target_feed_id: Int, + current_time_us: Int, +) -> PriceData { + let target_u32 = u32.from_int(target_feed_id) + let updates = pyth.get_updates(pyth_id, tx) + + expect Some(found) = + list.find_map( + updates, + fn(update) { + list.find( + update.feeds, + fn(feed) { feed.feed_id == target_u32 }, + ) + |> option_map(fn(feed) { (update.timestamp_us, feed) }) + }, + ) + + let (timestamp_us, feed) = found + let timestamp_us_int = u64.as_int(timestamp_us) + + // Validate freshness + let age_us = current_time_us - timestamp_us_int + expect age_us >= 0 + expect age_us <= max_age_us + + // Extract price and exponent (must be present) + expect Some(Some(price)) = feed.price + expect Some(exponent) = feed.exponent + + PriceData { + feed_id: target_feed_id, + price, + exponent, + timestamp_us: timestamp_us_int, + } +} + +/// Check if a devaluation has occurred. +/// +/// For a currency pair like ARS/USD where price going UP means devaluation +/// (more ARS per USD), we check if the current price exceeds the strike +/// price by at least `threshold_bps` basis points. +/// +/// Returns True if: (current_price - strike_price) * 10000 / strike_price >= threshold_bps +/// +/// Both prices must share the same exponent (enforced at subscription time). +pub fn is_devalued( + current_price: Int, + strike_price: Int, + threshold_bps: Int, +) -> Bool { + // Avoid division: (current - strike) * 10000 >= threshold * strike + let delta = current_price - strike_price + delta * 10_000 >= threshold_bps * strike_price +} + +// --- Helpers --- + +fn option_map(opt: Option, f: fn(a) -> b) -> Option { + when opt is { + Some(x) -> Some(f(x)) + None -> None + } +} + +// --- Tests --- + +test is_devalued_above_threshold() { + // Strike: 1000 ARS/USD, current: 1150 ARS/USD → 15% devaluation + // threshold: 1000 bps (10%) + is_devalued(1150, 1000, 1000) +} + +test is_devalued_exact_threshold() { + // Strike: 1000, current: 1100 → exactly 10% + // threshold: 1000 bps (10%) + is_devalued(1100, 1000, 1000) +} + +test is_devalued_below_threshold() { + // Strike: 1000, current: 1050 → 5% (below 10% threshold) + !is_devalued(1050, 1000, 1000) +} + +test is_devalued_no_change() { + // No devaluation at all + !is_devalued(1000, 1000, 1000) +} + +test is_devalued_appreciation() { + // Price went DOWN (appreciation) — not devalued + !is_devalued(900, 1000, 1000) +} + +test is_devalued_large_numbers() { + // Realistic Pyth prices with exponent -8 + // Strike: 120000000000 (1200.00 ARS/USD), current: 136800000000 (1368.00 → 14%) + is_devalued(136_800_000_000, 120_000_000_000, 1000) +} + +test is_devalued_small_threshold() { + // 5% threshold (500 bps) + // Strike: 1000, current: 1051 → 5.1% + is_devalued(1051, 1000, 500) +} diff --git a/lazer/cardano/deval-guard/lib/types.ak b/lazer/cardano/deval-guard/lib/types.ak new file mode 100644 index 00000000..ed7b7a9d --- /dev/null +++ b/lazer/cardano/deval-guard/lib/types.ak @@ -0,0 +1,61 @@ +use aiken/crypto.{ScriptHash, VerificationKeyHash} +use cardano/assets.{PolicyId} + +// --- Protocol Configuration (validator parameter) --- + +pub type ProtocolConfig { + pyth_policy_id: PolicyId, + pool_validator_hash: ScriptHash, + feed_id: Int, + payout_multiplier: Int, +} + +// --- Price Data (extracted from Pyth feed) --- + +pub type PriceData { + feed_id: Int, + price: Int, + exponent: Int, + timestamp_us: Int, +} + +// --- Policy (insurance contract) --- + +pub type PolicyStatus { + Active + Claimed + Expired +} + +pub type PolicyDatum { + owner: VerificationKeyHash, + strike_price: Int, + strike_exponent: Int, + threshold_bps: Int, + premium_paid: Int, + payout_amount: Int, + expiry_slot: Int, + feed_id: Int, + status: PolicyStatus, +} + +pub type PolicyRedeemer { + Subscribe + Claim + Expire +} + +// --- Liquidity Pool --- + +pub type PoolDatum { + total_deposits: Int, + total_reserved: Int, + total_premiums_earned: Int, +} + +pub type PoolRedeemer { + Deposit + Withdraw + ReserveIncrease { amount: Int } + ReserveDecrease { amount: Int } +} diff --git a/lazer/cardano/deval-guard/offchain/package.json b/lazer/cardano/deval-guard/offchain/package.json new file mode 100644 index 00000000..26960d12 --- /dev/null +++ b/lazer/cardano/deval-guard/offchain/package.json @@ -0,0 +1,20 @@ +{ + "name": "deval-guard-offchain", + "version": "0.0.1", + "private": true, + "type": "module", + "scripts": { + "build": "tsc", + "dev": "tsx watch src/index.ts" + }, + "dependencies": { + "@pythnetwork/pyth-lazer-sdk": "^0.3.0", + "@pythnetwork/pyth-lazer-cardano-js": "^0.1.0", + "@evolution-sdk/evolution": "^0.3.29" + }, + "devDependencies": { + "typescript": "^5.4.0", + "tsx": "^4.7.0", + "@types/node": "^20.0.0" + } +} diff --git a/lazer/cardano/deval-guard/offchain/src/policy.ts b/lazer/cardano/deval-guard/offchain/src/policy.ts new file mode 100644 index 00000000..79e4b1a2 --- /dev/null +++ b/lazer/cardano/deval-guard/offchain/src/policy.ts @@ -0,0 +1,193 @@ +/** + * Off-chain transaction builders for DevalGuard insurance policies. + * + * Provides helpers to construct subscribe, claim, and expire transactions. + */ + +import type { PriceUpdate } from "./pyth.js"; + +// --- Types --- + +export interface PolicyDatum { + owner: string; // bech32 address or pubkey hash hex + strikePrice: bigint; + strikeExponent: number; + thresholdBps: number; + premiumPaid: bigint; + payoutAmount: bigint; + expirySlot: bigint; // POSIX ms + feedId: number; + status: "Active" | "Claimed" | "Expired"; +} + +export interface ProtocolConfig { + pythPolicyId: string; + poolValidatorHash: string; + policyValidatorHash: string; + feedId: number; + payoutMultiplier: number; +} + +export const DEFAULT_PROTOCOL_CONFIG: Partial = { + pythPolicyId: "d799d287105dea9377cdf9ea8502a83d2b9eb2d2050a8aea800a21e6", + feedId: 16, // ADA/USD for now, 2582 for USD/ARS when available + payoutMultiplier: 10, +}; + +// --- Subscribe --- + +export interface SubscribeTxParams { + /** Threshold in basis points (e.g., 1000 = 10%) */ + thresholdBps: number; + /** Coverage period in milliseconds */ + coveragePeriodMs: bigint; + /** Premium amount in lovelace */ + premiumAmount: bigint; + /** Current Pyth price data */ + priceUpdate: PriceUpdate; +} + +export interface SubscribeResult { + policyDatum: PolicyDatum; + payoutAmount: bigint; + confirmationMessage: string; +} + +export function buildSubscribeParams( + params: SubscribeTxParams, + config: ProtocolConfig, + ownerAddress: string, +): SubscribeResult { + if (params.thresholdBps <= 0 || params.thresholdBps > 10000) { + throw new Error("Threshold must be between 1 and 10000 basis points"); + } + if (params.premiumAmount <= 0n) { + throw new Error("Premium must be positive"); + } + + const payoutAmount = params.premiumAmount * BigInt(config.payoutMultiplier); + const now = BigInt(Date.now()); + const expirySlot = now + params.coveragePeriodMs; + + const policyDatum: PolicyDatum = { + owner: ownerAddress, + strikePrice: params.priceUpdate.price, + strikeExponent: params.priceUpdate.exponent, + thresholdBps: params.thresholdBps, + premiumPaid: params.premiumAmount, + payoutAmount, + expirySlot, + feedId: config.feedId, + status: "Active", + }; + + const thresholdPct = params.thresholdBps / 100; + const confirmationMessage = + `If the exchange rate devalues ${thresholdPct}%, you receive ${formatLovelace(payoutAmount)} ADA`; + + return { policyDatum, payoutAmount, confirmationMessage }; +} + +// --- Claim --- + +export interface ClaimCheckResult { + eligible: boolean; + currentDevaluationBps: number; + thresholdBps: number; + message: string; +} + +export function checkClaimEligibility( + policy: PolicyDatum, + currentPrice: bigint, + currentExponent: number, +): ClaimCheckResult { + if (policy.status !== "Active") { + return { + eligible: false, + currentDevaluationBps: 0, + thresholdBps: policy.thresholdBps, + message: `Policy is ${policy.status}, not Active`, + }; + } + + const now = BigInt(Date.now()); + if (now > policy.expirySlot) { + return { + eligible: false, + currentDevaluationBps: 0, + thresholdBps: policy.thresholdBps, + message: "Policy has expired", + }; + } + + if (currentExponent !== policy.strikeExponent) { + return { + eligible: false, + currentDevaluationBps: 0, + thresholdBps: policy.thresholdBps, + message: "Exponent mismatch — cannot compare prices", + }; + } + + // Calculate devaluation in basis points + const delta = currentPrice - policy.strikePrice; + const devalBps = + Number((delta * 10000n) / policy.strikePrice); + + const eligible = devalBps >= policy.thresholdBps; + + return { + eligible, + currentDevaluationBps: devalBps, + thresholdBps: policy.thresholdBps, + message: eligible + ? `Devaluation ${(devalBps / 100).toFixed(1)}% exceeds threshold ${policy.thresholdBps / 100}% — claim eligible!` + : `Devaluation ${(devalBps / 100).toFixed(1)}% below threshold ${policy.thresholdBps / 100}%`, + }; +} + +// --- Expire --- + +export function checkExpireEligibility(policy: PolicyDatum): { + eligible: boolean; + message: string; +} { + if (policy.status !== "Active") { + return { eligible: false, message: `Policy is ${policy.status}` }; + } + + const now = BigInt(Date.now()); + if (now <= policy.expirySlot) { + const remaining = policy.expirySlot - now; + const hoursLeft = Number(remaining) / 3_600_000; + return { + eligible: false, + message: `Policy still active — ${hoursLeft.toFixed(1)} hours remaining`, + }; + } + + return { eligible: true, message: "Policy expired — ready to close" }; +} + +// --- Helpers --- + +function formatLovelace(lovelace: bigint): string { + const ada = Number(lovelace) / 1_000_000; + return ada.toFixed(2); +} + +/** Available coverage tiers for the UI */ +export const COVERAGE_TIERS = [ + { label: "5%", bps: 500 }, + { label: "10%", bps: 1000 }, + { label: "15%", bps: 1500 }, + { label: "20%", bps: 2000 }, +] as const; + +/** Available coverage periods for the UI */ +export const COVERAGE_PERIODS = [ + { label: "7 days", ms: 7n * 24n * 3600n * 1000n }, + { label: "14 days", ms: 14n * 24n * 3600n * 1000n }, + { label: "30 days", ms: 30n * 24n * 3600n * 1000n }, +] as const; diff --git a/lazer/cardano/deval-guard/offchain/src/pool.ts b/lazer/cardano/deval-guard/offchain/src/pool.ts new file mode 100644 index 00000000..22c01b3e --- /dev/null +++ b/lazer/cardano/deval-guard/offchain/src/pool.ts @@ -0,0 +1,129 @@ +/** + * Off-chain transaction builders for the DevalGuard liquidity pool. + * + * Provides helpers to construct deposit and withdraw transactions + * against the pool validator. + */ + +// --- Types --- + +export interface PoolDatum { + totalDeposits: bigint; + totalReserved: bigint; + totalPremiumsEarned: bigint; +} + +export interface PoolConfig { + /** Pool validator script hash (hex) */ + validatorHash: string; + /** Pool NFT policy ID (same as validator hash for multi-purpose validator) */ + poolNftPolicy: string; + /** Pool NFT token name */ + poolNftName: string; + /** LP token name */ + lpTokenName: string; + /** Current pool UTxO reference (txHash#index) */ + poolUtxoRef: { txHash: string; outputIndex: number }; +} + +export const POOL_NFT_NAME = "DevalGuard Pool"; +export const LP_TOKEN_NAME = "DG-LP"; + +// --- Transaction parameter builders --- + +export interface DepositTxParams { + /** Amount of lovelace to deposit */ + depositAmount: bigint; + /** Current pool datum */ + currentDatum: PoolDatum; + /** New pool datum after deposit */ + newDatum: PoolDatum; + /** LP tokens to mint (= depositAmount) */ + lpMintAmount: bigint; +} + +export function buildDepositParams( + currentDatum: PoolDatum, + depositAmount: bigint, +): DepositTxParams { + if (depositAmount <= 0n) { + throw new Error("Deposit amount must be positive"); + } + + const newDatum: PoolDatum = { + totalDeposits: currentDatum.totalDeposits + depositAmount, + totalReserved: currentDatum.totalReserved, + totalPremiumsEarned: currentDatum.totalPremiumsEarned, + }; + + return { + depositAmount, + currentDatum, + newDatum, + lpMintAmount: depositAmount, + }; +} + +export interface WithdrawTxParams { + /** Amount of lovelace to withdraw */ + withdrawAmount: bigint; + /** Current pool datum */ + currentDatum: PoolDatum; + /** New pool datum after withdrawal */ + newDatum: PoolDatum; + /** LP tokens to burn (negative = burn) */ + lpBurnAmount: bigint; +} + +export function buildWithdrawParams( + currentDatum: PoolDatum, + withdrawAmount: bigint, +): WithdrawTxParams { + if (withdrawAmount <= 0n) { + throw new Error("Withdraw amount must be positive"); + } + + const available = + currentDatum.totalDeposits - currentDatum.totalReserved; + if (withdrawAmount > available) { + throw new Error( + `Insufficient available liquidity: ${available} available, ${withdrawAmount} requested. ` + + `${currentDatum.totalReserved} is reserved for active policies.`, + ); + } + + const newDatum: PoolDatum = { + totalDeposits: currentDatum.totalDeposits - withdrawAmount, + totalReserved: currentDatum.totalReserved, + totalPremiumsEarned: currentDatum.totalPremiumsEarned, + }; + + return { + withdrawAmount, + currentDatum, + newDatum, + lpBurnAmount: -withdrawAmount, + }; +} + +// --- Pool state helpers --- + +export function availableLiquidity(datum: PoolDatum): bigint { + return datum.totalDeposits - datum.totalReserved; +} + +export function utilizationRate(datum: PoolDatum): number { + if (datum.totalDeposits === 0n) return 0; + return Number(datum.totalReserved * 10000n / datum.totalDeposits) / 100; +} + +export function formatPoolStats(datum: PoolDatum): string { + const toAda = (l: bigint) => `${Number(l) / 1_000_000} ADA`; + return [ + `Total deposits: ${toAda(datum.totalDeposits)}`, + `Reserved: ${toAda(datum.totalReserved)}`, + `Available: ${toAda(availableLiquidity(datum))}`, + `Utilization: ${utilizationRate(datum).toFixed(1)}%`, + `Premiums earned: ${toAda(datum.totalPremiumsEarned)}`, + ].join("\n"); +} diff --git a/lazer/cardano/deval-guard/offchain/src/pyth.ts b/lazer/cardano/deval-guard/offchain/src/pyth.ts new file mode 100644 index 00000000..58787031 --- /dev/null +++ b/lazer/cardano/deval-guard/offchain/src/pyth.ts @@ -0,0 +1,189 @@ +/** + * Off-chain Pyth Pro helper for DevalGuard. + * + * Uses @pythnetwork/pyth-lazer-sdk for price fetching and + * @pythnetwork/pyth-lazer-cardano-js for Cardano transaction integration + * via the Pyth withdraw-script pattern. + */ + +import { PythLazerClient } from "@pythnetwork/pyth-lazer-sdk"; +import { getPythState, getPythScriptHash } from "@pythnetwork/pyth-lazer-cardano-js"; + +// --- Configuration --- + +export interface PythConfig { + /** Access token for Pyth Pro (LAZER_TOKEN env var) */ + accessToken: string; + /** Pyth deployment policy ID on Cardano (hex) */ + pythPolicyId: string; +} + +export const PREPROD_POLICY_ID = + "d799d287105dea9377cdf9ea8502a83d2b9eb2d2050a8aea800a21e6"; + +export const PREPROD_CONFIG: PythConfig = { + accessToken: process.env.LAZER_TOKEN ?? "", + pythPolicyId: PREPROD_POLICY_ID, +}; + +// Feed IDs +export const FEED_ADA_USD = 16; +export const FEED_USD_ARS = 2582; // Coming soon + +// --- Price Update --- + +export interface PriceUpdate { + feedId: number; + price: bigint; + exponent: number; + timestampUs: bigint; + rawHex: string; // Solana-format binary for on-chain submission +} + +type PriceCallback = (update: PriceUpdate) => void; + +// --- Price Fetcher (one-shot, recommended for transactions) --- + +/** + * Fetch the latest price update from Pyth Pro. + * Returns raw hex bytes suitable for on-chain submission. + */ +export async function fetchLatestPrice( + config: PythConfig, + feedIds: number[], +): Promise { + const client = await PythLazerClient.create({ token: config.accessToken }); + + const result = await (client as any).getLatestPrice({ + channel: "fixed_rate@200ms", + formats: ["solana"], + jsonBinaryEncoding: "hex", + priceFeedIds: feedIds, + properties: ["price", "exponent"], + }); + + const updates: PriceUpdate[] = []; + if (result?.parsed?.priceFeeds && result?.solana?.data) { + for (const feed of result.parsed.priceFeeds) { + updates.push({ + feedId: feed.priceFeedId, + price: BigInt(feed.price), + exponent: feed.exponent, + timestampUs: BigInt(result.parsed.timestampUs), + rawHex: result.solana.data, + }); + } + } + + return updates; +} + +// --- Price Subscriber (WebSocket, for live UI) --- + +/** + * Subscribes to Pyth Pro WebSocket and maintains the latest price update. + * The raw binary data (solana format) is preserved for on-chain submission. + */ +export class PythPriceSubscriber { + private client: PythLazerClient | null = null; + private latestUpdate: Map = new Map(); + private callbacks: PriceCallback[] = []; + private config: PythConfig; + + constructor(config: PythConfig) { + this.config = config; + } + + async connect(feedIds: number[]): Promise { + this.client = new PythLazerClient( + "wss://pyth-lazer.dourolabs.app/v2/ws", + { accessToken: this.config.accessToken }, + ); + + this.client.subscribe({ + feedIds, + properties: ["price", "exponent"], + channels: ["fixed_rate@200ms"], + jsonBinaryEncoding: "hex", + parsed: false, + }); + + this.client.addMessageListener((message: unknown) => { + const msg = message as Record; + if (msg.type !== "json") return; + const value = msg.value as Record; + if (value.type !== "streamUpdated") return; + + const solana = value.solana as { data: string } | undefined; + const parsed = value.parsed as { + timestampUs: string; + priceFeeds: Array<{ + priceFeedId: number; + price: string; + exponent: number; + }>; + }; + + if (!parsed?.priceFeeds || !solana?.data) return; + + for (const feed of parsed.priceFeeds) { + const update: PriceUpdate = { + feedId: feed.priceFeedId, + price: BigInt(feed.price), + exponent: feed.exponent, + timestampUs: BigInt(parsed.timestampUs), + rawHex: solana.data, + }; + this.latestUpdate.set(feed.priceFeedId, update); + for (const cb of this.callbacks) cb(update); + } + }); + } + + getLatest(feedId: number): PriceUpdate | undefined { + return this.latestUpdate.get(feedId); + } + + onUpdate(cb: PriceCallback): void { + this.callbacks.push(cb); + } + + disconnect(): void { + this.client = null; + this.latestUpdate.clear(); + } +} + +// --- Transaction Helpers --- + +/** + * Get the Pyth State UTxO and withdraw script hash for transaction building. + * Uses the official @pythnetwork/pyth-lazer-cardano-js SDK. + */ +export async function getPythTxContext( + policyId: string, + cardanoClient: any, +): Promise<{ pythState: any; withdrawScriptHash: string }> { + const pythState = await getPythState(policyId, cardanoClient); + const withdrawScriptHash = getPythScriptHash(pythState); + return { pythState, withdrawScriptHash }; +} + +/** + * Format a Pyth price as a human-readable number. + * E.g., price=120000000000, exponent=-8 → "1200.00" + */ +export function formatPrice(price: bigint, exponent: number): string { + const abs = exponent < 0 ? -exponent : exponent; + const divisor = 10n ** BigInt(abs); + if (exponent < 0) { + const whole = price / divisor; + const frac = price % divisor; + const fracStr = frac.toString().padStart(abs, "0").slice(0, 2); + return `${whole}.${fracStr}`; + } + return (price * divisor).toString(); +} + +// Re-export SDK utilities +export { getPythState, getPythScriptHash }; diff --git a/lazer/cardano/deval-guard/offchain/tsconfig.json b/lazer/cardano/deval-guard/offchain/tsconfig.json new file mode 100644 index 00000000..542ce9f0 --- /dev/null +++ b/lazer/cardano/deval-guard/offchain/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ES2022", + "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "outDir": "./dist", + "rootDir": "./src", + "declaration": true, + "skipLibCheck": true + }, + "include": ["src/**/*"] +} diff --git a/lazer/cardano/deval-guard/validators/liquidity_pool.ak b/lazer/cardano/deval-guard/validators/liquidity_pool.ak new file mode 100644 index 00000000..07b0cd26 --- /dev/null +++ b/lazer/cardano/deval-guard/validators/liquidity_pool.ak @@ -0,0 +1,191 @@ +use aiken/collection/list +use cardano/address.{Script} +use cardano/assets +use cardano/assets.{PolicyId} +use cardano/transaction.{InlineDatum, Output, OutputReference, Transaction} +use types.{ + Deposit, PoolDatum, PoolRedeemer, ReserveDecrease, ReserveIncrease, Withdraw, +} + +/// NFT token name that identifies the unique pool UTxO. +const pool_nft_name: ByteArray = "DevalGuard Pool" + +/// LP token name minted to liquidity providers. +const lp_token_name: ByteArray = "DG-LP" + +// --- Validator --- + +validator liquidity_pool { + spend( + datum: Option, + redeemer: PoolRedeemer, + _utxo: OutputReference, + self: Transaction, + ) { + expect Some(datum) = datum + // Find our own script hash from the continuing output + let own_policy = find_own_policy(self) + + // Find the continuing pool output (must carry the pool NFT) + let continuing_output = find_pool_output(self.outputs, own_policy) + expect InlineDatum(out_datum) = continuing_output.datum + expect out_datum: PoolDatum = out_datum + + when redeemer is { + Deposit -> { + // The ADA value in the continuing output must increase + let in_lovelace = pool_lovelace(self, own_policy) + let out_lovelace = assets.lovelace_of(continuing_output.value) + let deposit_amount = out_lovelace - in_lovelace + expect deposit_amount > 0 + + // Datum must reflect the deposit + expect + out_datum.total_deposits == datum.total_deposits + deposit_amount + expect out_datum.total_reserved == datum.total_reserved + expect out_datum.total_premiums_earned == datum.total_premiums_earned + + // Must mint LP tokens proportional to deposit + let lp_minted = assets.quantity_of(self.mint, own_policy, lp_token_name) + expect lp_minted == deposit_amount + + True + } + + Withdraw -> { + let in_lovelace = pool_lovelace(self, own_policy) + let out_lovelace = assets.lovelace_of(continuing_output.value) + let withdraw_amount = in_lovelace - out_lovelace + expect withdraw_amount > 0 + + // Cannot withdraw into reserved funds + let available = datum.total_deposits - datum.total_reserved + expect withdraw_amount <= available + + // Datum must reflect the withdrawal + expect + out_datum.total_deposits == datum.total_deposits - withdraw_amount + expect out_datum.total_reserved == datum.total_reserved + expect out_datum.total_premiums_earned == datum.total_premiums_earned + + // Must burn LP tokens proportional to withdrawal + let lp_burned = + assets.quantity_of(self.mint, own_policy, lp_token_name) + expect lp_burned == -withdraw_amount + + True + } + + ReserveIncrease { amount } -> { + expect amount > 0 + // Sufficient unreserved liquidity must exist + expect datum.total_deposits - datum.total_reserved >= amount + + // Datum update: only total_reserved changes + expect out_datum.total_deposits == datum.total_deposits + expect out_datum.total_reserved == datum.total_reserved + amount + expect out_datum.total_premiums_earned == datum.total_premiums_earned + + // Pool value must not decrease (no funds leave) + let in_lovelace = pool_lovelace(self, own_policy) + let out_lovelace = assets.lovelace_of(continuing_output.value) + expect out_lovelace >= in_lovelace + + True + } + + ReserveDecrease { amount } -> { + expect amount > 0 + expect datum.total_reserved >= amount + + // Datum update: only total_reserved changes + expect out_datum.total_deposits == datum.total_deposits + expect out_datum.total_reserved == datum.total_reserved - amount + expect out_datum.total_premiums_earned == datum.total_premiums_earned + + True + } + } + } + + mint(_redeemer: Data, own_policy: PolicyId, self: Transaction) { + // LP token minting/burning is validated by the spend handler. + // We just need to ensure the pool UTxO is being spent in this tx + // (which means the spend validator ran and approved the operation). + // + // For pool NFT minting (initialization), we use a simple check. + let nft_qty = assets.quantity_of(self.mint, own_policy, pool_nft_name) + let lp_qty = assets.quantity_of(self.mint, own_policy, lp_token_name) + + if nft_qty == 1 { + // Pool initialization: mint exactly 1 NFT, no LP tokens + expect lp_qty == 0 + True + } else if nft_qty == 0 { + // LP token mint or burn: the pool UTxO must be spent (spend handler validates) + expect lp_qty != 0 + expect pool_utxo_is_spent(self, own_policy) + True + } else { + False + } + } + + else(_) { + fail + } +} + +// --- Helpers --- + +/// Find the pool UTxO's lovelace from inputs (the one carrying the pool NFT). +fn pool_lovelace(tx: Transaction, policy: PolicyId) -> Int { + expect Some(input) = + list.find( + tx.inputs, + fn(inp) { + assets.quantity_of(inp.output.value, policy, pool_nft_name) == 1 + }, + ) + assets.lovelace_of(input.output.value) +} + +/// Find the continuing output that carries the pool NFT. +fn find_pool_output(outputs: List, policy: PolicyId) -> Output { + expect Some(output) = + list.find( + outputs, + fn(out) { + assets.quantity_of(out.value, policy, pool_nft_name) == 1 + }, + ) + output +} + +/// Get our own policy from the transaction by looking for pool NFT in inputs. +fn find_own_policy(tx: Transaction) -> PolicyId { + expect Some(input) = + list.find( + tx.inputs, + fn(inp) { + // Check if any policy in this input's value has our pool NFT + when inp.output.address.payment_credential is { + Script(hash) -> + assets.quantity_of(inp.output.value, hash, pool_nft_name) == 1 + _ -> False + } + }, + ) + expect Script(hash) = input.output.address.payment_credential + hash +} + +/// Check if the pool UTxO is being spent in this transaction. +fn pool_utxo_is_spent(tx: Transaction, policy: PolicyId) -> Bool { + list.any( + tx.inputs, + fn(inp) { + assets.quantity_of(inp.output.value, policy, pool_nft_name) == 1 + }, + ) +} diff --git a/lazer/cardano/deval-guard/validators/policy.ak b/lazer/cardano/deval-guard/validators/policy.ak new file mode 100644 index 00000000..a9869a13 --- /dev/null +++ b/lazer/cardano/deval-guard/validators/policy.ak @@ -0,0 +1,231 @@ +use aiken/collection/list +use aiken/crypto.{VerificationKeyHash} +use aiken/interval.{Finite, IntervalBound} +use cardano/address.{Script} +use cardano/assets +use cardano/transaction.{InlineDatum, Output, OutputReference, Transaction} +use pyth_oracle +use types.{ + Active, Claim, Expire, PolicyDatum, PolicyRedeemer, PoolDatum, + ProtocolConfig, Subscribe, +} + +/// Pool NFT token name (must match liquidity_pool.ak). +const pool_nft_name: ByteArray = "DevalGuard Pool" + +// --- Validator --- + +validator policy(config: ProtocolConfig) { + spend( + datum: Option, + redeemer: PolicyRedeemer, + _utxo: OutputReference, + self: Transaction, + ) { + expect Some(datum) = datum + + when redeemer is { + Subscribe -> validate_subscribe(config, datum, self) + Claim -> validate_claim(config, datum, self) + Expire -> validate_expire(config, datum, self) + } + } + + else(_) { + fail + } +} + +// --- Subscribe --- + +fn validate_subscribe( + config: ProtocolConfig, + datum: PolicyDatum, + tx: Transaction, +) -> Bool { + // The policy UTxO being spent here is a "template" — the real logic is: + // verify the NEW policy UTxO created in outputs has correct datum. + + // 1. Verify the policy datum is well-formed + expect datum.status == Active + expect datum.threshold_bps > 0 + expect datum.threshold_bps <= 10_000 + expect datum.premium_paid > 0 + expect datum.payout_amount == datum.premium_paid * config.payout_multiplier + + // 2. Verify Pyth price was read and matches strike_price + let tx_time_us = get_tx_time_us(tx) + let price_data = + pyth_oracle.get_price(config.pyth_policy_id, tx, config.feed_id, tx_time_us) + expect datum.strike_price == price_data.price + expect datum.strike_exponent == price_data.exponent + + // 3. Verify pool interaction: pool UTxO must be spent with ReserveIncrease + let (pool_in_datum, pool_out_datum) = get_pool_datums(tx, config) + expect + pool_out_datum.total_reserved == pool_in_datum.total_reserved + datum.payout_amount + // Pool must have received the premium + expect + pool_out_datum.total_premiums_earned == pool_in_datum.total_premiums_earned + datum.premium_paid + + // 4. Verify sufficient liquidity existed before reservation + let available_before = + pool_in_datum.total_deposits - pool_in_datum.total_reserved + expect available_before >= datum.payout_amount + + True +} + +// --- Claim --- + +fn validate_claim( + config: ProtocolConfig, + datum: PolicyDatum, + tx: Transaction, +) -> Bool { + // 1. Policy must be Active + expect datum.status == Active + + // 2. Must be within coverage period + expect is_before_expiry(tx, datum.expiry_slot) + + // 3. Read current Pyth price + let tx_time_us = get_tx_time_us(tx) + let price_data = + pyth_oracle.get_price(config.pyth_policy_id, tx, config.feed_id, tx_time_us) + + // 4. Exponents must match (same feed, should always be true) + expect price_data.exponent == datum.strike_exponent + + // 5. Check devaluation threshold is met + expect + pyth_oracle.is_devalued( + price_data.price, + datum.strike_price, + datum.threshold_bps, + ) + + // 6. Verify payout goes to the policy owner + expect is_paid_to(tx.outputs, datum.owner, datum.payout_amount) + + // 7. Verify pool reserve decrease + let (pool_in_datum, pool_out_datum) = get_pool_datums(tx, config) + expect + pool_out_datum.total_reserved == pool_in_datum.total_reserved - datum.payout_amount + expect + pool_out_datum.total_deposits == pool_in_datum.total_deposits - datum.payout_amount + + True +} + +// --- Expire --- + +fn validate_expire( + config: ProtocolConfig, + datum: PolicyDatum, + tx: Transaction, +) -> Bool { + // 1. Policy must be Active + expect datum.status == Active + + // 2. Must be past the expiry slot + expect is_after_expiry(tx, datum.expiry_slot) + + // 3. Verify pool reserve decrease (funds freed, premium kept as yield) + let (pool_in_datum, pool_out_datum) = get_pool_datums(tx, config) + expect + pool_out_datum.total_reserved == pool_in_datum.total_reserved - datum.payout_amount + // Deposits stay the same (premium was already counted at subscribe time) + expect pool_out_datum.total_deposits == pool_in_datum.total_deposits + + True +} + +// --- Helpers --- + +/// Extract pool input and output datums from the transaction. +fn get_pool_datums( + tx: Transaction, + config: ProtocolConfig, +) -> (PoolDatum, PoolDatum) { + // Find pool input + expect Some(pool_input) = + list.find( + tx.inputs, + fn(inp) { + when inp.output.address.payment_credential is { + Script(hash) -> + hash == config.pool_validator_hash && assets.quantity_of( + inp.output.value, + config.pool_validator_hash, + pool_nft_name, + ) == 1 + _ -> False + } + }, + ) + expect InlineDatum(in_raw) = pool_input.output.datum + expect in_datum: PoolDatum = in_raw + + // Find pool output + expect Some(pool_output) = + list.find( + tx.outputs, + fn(out) { + when out.address.payment_credential is { + Script(hash) -> + hash == config.pool_validator_hash && assets.quantity_of( + out.value, + config.pool_validator_hash, + pool_nft_name, + ) == 1 + _ -> False + } + }, + ) + expect InlineDatum(out_raw) = pool_output.datum + expect out_datum: PoolDatum = out_raw + + (in_datum, out_datum) +} + +/// Check that an output pays at least `amount` lovelace to a given pubkey. +fn is_paid_to( + outputs: List, + owner: VerificationKeyHash, + amount: Int, +) -> Bool { + list.any( + outputs, + fn(out) { + when out.address.payment_credential is { + address.VerificationKey(hash) -> + hash == owner && assets.lovelace_of(out.value) >= amount + _ -> False + } + }, + ) +} + +/// Get the transaction validity start time in microseconds. +/// Extracts the lower bound of the validity interval and converts ms → us. +fn get_tx_time_us(tx: Transaction) -> Int { + let IntervalBound { bound_type, .. } = tx.validity_range.lower_bound + expect Finite(lower_ms) = bound_type + lower_ms * 1000 +} + +/// Check that the entire transaction validity range is before the expiry time. +/// expiry_time is in POSIX milliseconds (same unit as validity_range). +fn is_before_expiry(tx: Transaction, expiry_time: Int) -> Bool { + let IntervalBound { bound_type, .. } = tx.validity_range.upper_bound + expect Finite(upper_ms) = bound_type + upper_ms <= expiry_time +} + +/// Check that the entire transaction validity range is after the expiry time. +fn is_after_expiry(tx: Transaction, expiry_time: Int) -> Bool { + let IntervalBound { bound_type, .. } = tx.validity_range.lower_bound + expect Finite(lower_ms) = bound_type + lower_ms > expiry_time +}