From 4652a2d0dbcc403b020f7307c61462fa92566717 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Sat, 29 Nov 2025 23:52:36 -0300 Subject: [PATCH 1/9] feat(frontend): add React frontend for Golden Bridge dApp Implement complete frontend application for the Golden Bridge gold-backed tokenization platform with the following features: - Wallet connection using Reown AppKit (WalletConnect) - GoldToken operations: mint, burn, and transfer GLD tokens - Lottery participation and reward claiming interface - Cross-chain bridge for token transfers via Chainlink CCIP - Admin panel for contract owners with pause/unpause and upgrade controls - Network easy switch between Sepolia and BSC Testnet - Responsive UI with educational tooltips and step indicators Tech stack: React 19, TypeScript, Vite, ethers.js v6, CSS Modules --- frontend/.env.example | 23 + frontend/.gitignore | 8 + frontend/README.md | 90 + frontend/abi/goldToken/goldTokenAbi.json | 722 ++ frontend/abi/goldToken/iGoldTokenAbi.json | 286 + frontend/abi/lotterie/iLotterieAbi.json | 468 ++ frontend/abi/lotterie/lotterieAbi.json | 854 ++ frontend/abi/tokenBridge/iTokenBridgeAbi.json | 399 + frontend/abi/tokenBridge/tokenBridgeAbi.json | 795 ++ frontend/eslint.config.js | 30 + frontend/index.html | 13 + frontend/package-lock.json | 7380 +++++++++++++++++ frontend/package.json | 32 + frontend/src/App.tsx | 39 + .../components/Admin/AdminPanel.module.css | 360 + frontend/src/components/Admin/AdminPanel.tsx | 565 ++ frontend/src/components/Admin/index.ts | 1 + .../components/Dashboard/Dashboard.module.css | 269 + .../src/components/Dashboard/Dashboard.tsx | 354 + .../GoldToken/GoldTokenCard.module.css | 165 + .../components/GoldToken/GoldTokenCard.tsx | 505 ++ .../Lotterie/LotterieCard.module.css | 108 + .../src/components/Lotterie/LotterieCard.tsx | 275 + .../src/components/NetworkSwitcher.module.css | 84 + frontend/src/components/NetworkSwitcher.tsx | 116 + .../TokenBridge/TokenBridgeCard.module.css | 175 + .../TokenBridge/TokenBridgeCard.tsx | 350 + frontend/src/components/WalletConnect.tsx | 22 + frontend/src/components/Web3Provider.tsx | 11 + frontend/src/components/ui/Alert.module.css | 64 + frontend/src/components/ui/Alert.tsx | 39 + frontend/src/components/ui/Badge.module.css | 47 + frontend/src/components/ui/Badge.tsx | 20 + frontend/src/components/ui/Button.module.css | 89 + frontend/src/components/ui/Button.tsx | 45 + frontend/src/components/ui/Card.module.css | 50 + frontend/src/components/ui/Card.tsx | 45 + .../src/components/ui/InfoCard.module.css | 163 + frontend/src/components/ui/InfoCard.tsx | 94 + frontend/src/components/ui/Input.module.css | 75 + frontend/src/components/ui/Input.tsx | 50 + frontend/src/components/ui/Modal.module.css | 84 + frontend/src/components/ui/Modal.tsx | 48 + frontend/src/components/ui/Spinner.module.css | 53 + frontend/src/components/ui/Spinner.tsx | 24 + .../components/ui/StepIndicator.module.css | 190 + frontend/src/components/ui/StepIndicator.tsx | 132 + frontend/src/components/ui/Tooltip.module.css | 136 + frontend/src/components/ui/Tooltip.tsx | 59 + frontend/src/components/ui/index.ts | 13 + frontend/src/config/contracts.ts | 25 + frontend/src/config/env.ts | 40 + frontend/src/config/index.ts | 4 + frontend/src/config/networks.ts | 52 + frontend/src/config/reown.ts | 49 + frontend/src/hooks/index.ts | 5 + frontend/src/hooks/useAdmin.ts | 175 + frontend/src/hooks/useGoldToken.ts | 319 + frontend/src/hooks/useLotterie.ts | 388 + frontend/src/hooks/useNetwork.ts | 39 + frontend/src/hooks/useTokenBridge.ts | 296 + frontend/src/main.tsx | 12 + frontend/src/styles/globals.css | 262 + frontend/src/types/goldToken.ts | 51 + frontend/src/types/index.ts | 11 + frontend/src/types/lotterie.ts | 61 + frontend/src/types/tokenBridge.ts | 85 + frontend/src/vite-env.d.ts | 21 + frontend/tsconfig.app.json | 27 + frontend/tsconfig.json | 7 + frontend/tsconfig.node.json | 13 + frontend/vite.config.ts | 7 + 72 files changed, 17968 insertions(+) create mode 100644 frontend/.env.example create mode 100644 frontend/.gitignore create mode 100644 frontend/README.md create mode 100644 frontend/abi/goldToken/goldTokenAbi.json create mode 100644 frontend/abi/goldToken/iGoldTokenAbi.json create mode 100644 frontend/abi/lotterie/iLotterieAbi.json create mode 100644 frontend/abi/lotterie/lotterieAbi.json create mode 100644 frontend/abi/tokenBridge/iTokenBridgeAbi.json create mode 100644 frontend/abi/tokenBridge/tokenBridgeAbi.json create mode 100644 frontend/eslint.config.js create mode 100644 frontend/index.html create mode 100644 frontend/package-lock.json create mode 100644 frontend/package.json create mode 100644 frontend/src/App.tsx create mode 100644 frontend/src/components/Admin/AdminPanel.module.css create mode 100644 frontend/src/components/Admin/AdminPanel.tsx create mode 100644 frontend/src/components/Admin/index.ts create mode 100644 frontend/src/components/Dashboard/Dashboard.module.css create mode 100644 frontend/src/components/Dashboard/Dashboard.tsx create mode 100644 frontend/src/components/GoldToken/GoldTokenCard.module.css create mode 100644 frontend/src/components/GoldToken/GoldTokenCard.tsx create mode 100644 frontend/src/components/Lotterie/LotterieCard.module.css create mode 100644 frontend/src/components/Lotterie/LotterieCard.tsx create mode 100644 frontend/src/components/NetworkSwitcher.module.css create mode 100644 frontend/src/components/NetworkSwitcher.tsx create mode 100644 frontend/src/components/TokenBridge/TokenBridgeCard.module.css create mode 100644 frontend/src/components/TokenBridge/TokenBridgeCard.tsx create mode 100644 frontend/src/components/WalletConnect.tsx create mode 100644 frontend/src/components/Web3Provider.tsx create mode 100644 frontend/src/components/ui/Alert.module.css create mode 100644 frontend/src/components/ui/Alert.tsx create mode 100644 frontend/src/components/ui/Badge.module.css create mode 100644 frontend/src/components/ui/Badge.tsx create mode 100644 frontend/src/components/ui/Button.module.css create mode 100644 frontend/src/components/ui/Button.tsx create mode 100644 frontend/src/components/ui/Card.module.css create mode 100644 frontend/src/components/ui/Card.tsx create mode 100644 frontend/src/components/ui/InfoCard.module.css create mode 100644 frontend/src/components/ui/InfoCard.tsx create mode 100644 frontend/src/components/ui/Input.module.css create mode 100644 frontend/src/components/ui/Input.tsx create mode 100644 frontend/src/components/ui/Modal.module.css create mode 100644 frontend/src/components/ui/Modal.tsx create mode 100644 frontend/src/components/ui/Spinner.module.css create mode 100644 frontend/src/components/ui/Spinner.tsx create mode 100644 frontend/src/components/ui/StepIndicator.module.css create mode 100644 frontend/src/components/ui/StepIndicator.tsx create mode 100644 frontend/src/components/ui/Tooltip.module.css create mode 100644 frontend/src/components/ui/Tooltip.tsx create mode 100644 frontend/src/components/ui/index.ts create mode 100644 frontend/src/config/contracts.ts create mode 100644 frontend/src/config/env.ts create mode 100644 frontend/src/config/index.ts create mode 100644 frontend/src/config/networks.ts create mode 100644 frontend/src/config/reown.ts create mode 100644 frontend/src/hooks/index.ts create mode 100644 frontend/src/hooks/useAdmin.ts create mode 100644 frontend/src/hooks/useGoldToken.ts create mode 100644 frontend/src/hooks/useLotterie.ts create mode 100644 frontend/src/hooks/useNetwork.ts create mode 100644 frontend/src/hooks/useTokenBridge.ts create mode 100644 frontend/src/main.tsx create mode 100644 frontend/src/styles/globals.css create mode 100644 frontend/src/types/goldToken.ts create mode 100644 frontend/src/types/index.ts create mode 100644 frontend/src/types/lotterie.ts create mode 100644 frontend/src/types/tokenBridge.ts create mode 100644 frontend/src/vite-env.d.ts create mode 100644 frontend/tsconfig.app.json create mode 100644 frontend/tsconfig.json create mode 100644 frontend/tsconfig.node.json create mode 100644 frontend/vite.config.ts diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..7327744 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1,23 @@ +# Reown (WalletConnect) Project ID +# Get one at https://cloud.reown.com +VITE_REOWN_PROJECT_ID="" + +# Contract Addresses - Sepolia +VITE_CONTRACT_ADDRESS_SEPOLIA_GOLD_TOKEN="0x19ad15A55D28B59775934be8913389F23b38fC34" +VITE_CONTRACT_ADDRESS_SEPOLIA_LOTTERIE="0xa44599409aDb9D9E69f5e262a9Cc17658D306565" +VITE_CONTRACT_ADDRESS_SEPOLIA_TOKEN_BRIDGE="0x1AF470D6e52A8aA3b1328Bb74D93967E0DC0F721" + +# Contract Addresses - BSC Testnet +VITE_CONTRACT_ADDRESS_BSC_TESTNET_GOLD_TOKEN="0xaDA54cF66fe2aA440C2c230346a7B7621B61DF31" +VITE_CONTRACT_ADDRESS_BSC_TESTNET_LOTTERIE="0x0B0970beDa533276435bDcdD45DF9cE2875E6d78" +VITE_CONTRACT_ADDRESS_BSC_TESTNET_TOKEN_BRIDGE="0x4380FDA9f42BE8aEcda15CC5e6D67C87b20EcA6a" + +# RPC URLs +VITE_RPC_URL_SEPOLIA="" +VITE_RPC_URL_BSC_TESTNET="" + +# Site Metadata +VITE_SITE_NAME="Golden Bridge" +VITE_SITE_DESCRIPTION="Gold-backed tokenization with lottery rewards" +VITE_SITE_URL="http://localhost:5173" +VITE_SITE_ICON="https://assets.reown.com/reown-profile-pic.png" diff --git a/frontend/.gitignore b/frontend/.gitignore new file mode 100644 index 0000000..641e30c --- /dev/null +++ b/frontend/.gitignore @@ -0,0 +1,8 @@ +# Node modules +node_modules/ + +# Dist folder +dist/ + +# Environment variables +.env \ No newline at end of file diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..fde8d9c --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,90 @@ +# Golden Bridge Frontend + +This is the frontend application for the Golden Bridge project, a gold-backed tokenization platform with lottery rewards and cross-chain bridging capabilities. + +## Project Description + +The Golden Bridge frontend allows users to: + +- Connect their wallet (MetaMask, WalletConnect, etc.) +- Mint and burn Gold Tokens (GLD) +- Participate in the daily lottery +- Bridge tokens between Ethereum Sepolia and BSC Testnet +- View their token balance and transaction history + +## Setup Instructions + +1. **Prerequisites:** + + - Node.js (v18 or later) + - npm or yarn + +2. **Installation:** + + ```bash + cd frontend + npm install + ``` + +3. **Environment Configuration:** + + - Copy `.env.example` to `.env`: + ```bash + cp .env.example .env + ``` + - Update the `.env` file with your specific configuration values (RPC URLs, Project ID, etc.). + +4. **Running the Application:** + ```bash + npm run dev + ``` + The application will be available at `http://localhost:5173`. + +## Environment Variables + +The following environment variables are required in the `.env` file: + +- `VITE_REOWN_PROJECT_ID`: Your Reown (ex WalletConnect) Project ID +- `VITE_CONTRACT_ADDRESS_SEPOLIA_GOLD_TOKEN`: Gold Token contract address on Ethereum Sepolia +- `VITE_CONTRACT_ADDRESS_SEPOLIA_LOTTERIE`: Lotterie contract address on Ethereum Sepolia +- `VITE_CONTRACT_ADDRESS_SEPOLIA_TOKEN_BRIDGE`: Token Bridge contract address on Ethereum Sepolia +- `VITE_CONTRACT_ADDRESS_BSC_TESTNET_GOLD_TOKEN`: Gold Token contract address on BSC Testnet +- `VITE_CONTRACT_ADDRESS_BSC_TESTNET_LOTTERIE`: Lotterie contract address on BSC Testnet +- `VITE_CONTRACT_ADDRESS_BSC_TESTNET_TOKEN_BRIDGE`: Token Bridge contract address on BSC Testnet +- `VITE_RPC_URL_SEPOLIA`: RPC URL for Ethereum Sepolia +- `VITE_RPC_URL_BSC_TESTNET`: RPC URL for BSC Testnet +- `VITE_SITE_NAME`: Name of the site (default: "Golden Bridge") +- `VITE_SITE_DESCRIPTION`: Description of the site +- `VITE_SITE_URL`: URL of the site +- `VITE_SITE_ICON`: URL of the site icon + +## Available Scripts + +- `npm run dev`: Starts the development server +- `npm run build`: Builds the application for production +- `npm run preview`: Previews the production build locally +- `npm run lint`: Runs ESLint to check for code quality issues + +## Project Structure + +- `src/components`: React components + - `Dashboard`: Main dashboard component + - `GoldToken`: Components related to Gold Token operations + - `Lotterie`: Components related to the lottery + - `TokenBridge`: Components related to the bridge + - `ui`: Reusable UI components +- `src/config`: Configuration files (contracts, networks, etc.) +- `src/hooks`: Custom React hooks +- `src/styles`: Global styles and CSS modules +- `src/types`: TypeScript type definitions +- `src/utils`: Utility functions +- `abi`: Smart contract ABIs + +## Technologies Used + +- React +- TypeScript +- Vite +- ethers.js +- Reown AppKit (WalletConnect) +- CSS Modules diff --git a/frontend/abi/goldToken/goldTokenAbi.json b/frontend/abi/goldToken/goldTokenAbi.json new file mode 100644 index 0000000..0597a29 --- /dev/null +++ b/frontend/abi/goldToken/goldTokenAbi.json @@ -0,0 +1,722 @@ +{ + "abi": [ + { "type": "constructor", "inputs": [], "stateMutability": "nonpayable" }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OWNER_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "addOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "allowance", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "spender", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { "name": "spender", "type": "address", "internalType": "address" }, + { "name": "value", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claimEth", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "decimals", + "inputs": [], + "outputs": [{ "name": "", "type": "uint8", "internalType": "uint8" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFees", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFeesAddress", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGoldPriceInEth", + "inputs": [], + "outputs": [{ "name": "", "type": "int256", "internalType": "int256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getTimestamps", + "inputs": [], + "outputs": [ + { "name": "", "type": "address[]", "internalType": "address[]" }, + { "name": "", "type": "uint256[]", "internalType": "uint256[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUsers", + "inputs": [], + "outputs": [ + { "name": "", "type": "address[]", "internalType": "address[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasOwnerRole", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { + "name": "dataFeedGoldAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "dataFeedEthAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "name", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "removeOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFeesAddress", + "inputs": [ + { "name": "feesAddress", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLotterieAddress", + "inputs": [ + { + "name": "lotterieAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { "name": "interfaceId", "type": "bytes4", "internalType": "bytes4" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "symbol", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { "name": "to", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { "name": "from", "type": "address", "internalType": "address" }, + { "name": "to", "type": "address", "internalType": "address" }, + { "name": "value", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "FeesAddressUpdated", + "inputs": [ + { + "name": "previousFeesAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newFeesAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GoldTokenInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "dataFeedGold", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "dataFeedEth", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LotterieAddressUpdated", + "inputs": [ + { + "name": "previousLotterieAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newLotterieAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Mint", + "inputs": [ + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserAdded", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserRemoved", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { "type": "error", "name": "AccessControlBadConfirmation", "inputs": [] }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" }, + { "name": "neededRole", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { "name": "target", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "AmountMustBeGreaterThanZero", "inputs": [] }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { "type": "error", "name": "ERC1967NonPayable", "inputs": [] }, + { + "type": "error", + "name": "ERC20InsufficientAllowance", + "inputs": [ + { "name": "spender", "type": "address", "internalType": "address" }, + { "name": "allowance", "type": "uint256", "internalType": "uint256" }, + { "name": "needed", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "type": "error", + "name": "ERC20InsufficientBalance", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" }, + { "name": "balance", "type": "uint256", "internalType": "uint256" }, + { "name": "needed", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "type": "error", + "name": "ERC20InvalidApprover", + "inputs": [ + { "name": "approver", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "ERC20InvalidReceiver", + "inputs": [ + { "name": "receiver", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "ERC20InvalidSender", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "ERC20InvalidSpender", + "inputs": [ + { "name": "spender", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "EnforcedPause", "inputs": [] }, + { "type": "error", "name": "EthTransferFailed", "inputs": [] }, + { "type": "error", "name": "ExpectedPause", "inputs": [] }, + { "type": "error", "name": "FailedCall", "inputs": [] }, + { "type": "error", "name": "InvalidGoldPrice", "inputs": [] }, + { "type": "error", "name": "InvalidInitialization", "inputs": [] }, + { "type": "error", "name": "NotInitializing", "inputs": [] }, + { "type": "error", "name": "ReentrancyGuardReentrantCall", "inputs": [] }, + { "type": "error", "name": "UUPSUnauthorizedCallContext", "inputs": [] }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { "name": "slot", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { "type": "error", "name": "ValueMustBeGreaterThanZero", "inputs": [] } + ] +} diff --git a/frontend/abi/goldToken/iGoldTokenAbi.json b/frontend/abi/goldToken/iGoldTokenAbi.json new file mode 100644 index 0000000..844c19c --- /dev/null +++ b/frontend/abi/goldToken/iGoldTokenAbi.json @@ -0,0 +1,286 @@ +{ + "abi": [ + { + "type": "function", + "name": "addOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "burn", + "inputs": [ + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claimEth", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getFees", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getFeesAddress", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGoldPriceInEth", + "inputs": [], + "outputs": [{ "name": "", "type": "int256", "internalType": "int256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getTimestamps", + "inputs": [], + "outputs": [ + { "name": "", "type": "address[]", "internalType": "address[]" }, + { "name": "", "type": "uint256[]", "internalType": "uint256[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getUsers", + "inputs": [], + "outputs": [ + { "name": "", "type": "address[]", "internalType": "address[]" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasOwnerRole", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { + "name": "dataFeedGoldAddress", + "type": "address", + "internalType": "address" + }, + { + "name": "dataFeedEthAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "mint", + "inputs": [], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setFeesAddress", + "inputs": [ + { "name": "feesAddress", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setLotterieAddress", + "inputs": [ + { + "name": "lotterieAddress", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { "name": "to", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "FeesAddressUpdated", + "inputs": [ + { + "name": "previousFeesAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newFeesAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GoldTokenInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "dataFeedGold", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "dataFeedEth", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LotterieAddressUpdated", + "inputs": [ + { + "name": "previousLotterieAddress", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newLotterieAddress", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Mint", + "inputs": [ + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserAdded", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "timestamp", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "UserRemoved", + "inputs": [ + { + "name": "user", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { "type": "error", "name": "AmountMustBeGreaterThanZero", "inputs": [] }, + { "type": "error", "name": "EthTransferFailed", "inputs": [] }, + { "type": "error", "name": "InvalidGoldPrice", "inputs": [] }, + { "type": "error", "name": "ValueMustBeGreaterThanZero", "inputs": [] } + ] +} diff --git a/frontend/abi/lotterie/iLotterieAbi.json b/frontend/abi/lotterie/iLotterieAbi.json new file mode 100644 index 0000000..c8fdff0 --- /dev/null +++ b/frontend/abi/lotterie/iLotterieAbi.json @@ -0,0 +1,468 @@ +{ + "abi": [ + { + "type": "function", + "name": "addOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claim", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getCallbackGasLimit", + "inputs": [], + "outputs": [{ "name": "", "type": "uint32", "internalType": "uint32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGains", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGoldToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getKeyHash", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLastRequestId", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNumWords", + "inputs": [], + "outputs": [{ "name": "", "type": "uint32", "internalType": "uint32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRequestConfirmations", + "inputs": [], + "outputs": [{ "name": "", "type": "uint16", "internalType": "uint16" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getResults", + "inputs": [ + { "name": "requestId", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getVrfCoordinator", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getVrfSubscriptionId", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasOwnerRole", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { + "name": "vrfSubscriptionId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "vrfCoordinator", + "type": "address", + "internalType": "address" + }, + { "name": "keyHash", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "callbackGasLimit", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "requestConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { "name": "numWords", "type": "uint32", "internalType": "uint32" }, + { "name": "goldToken", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "randomDraw", + "inputs": [], + "outputs": [ + { "name": "requestId", "type": "uint256", "internalType": "uint256" } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setCallbackGasLimit", + "inputs": [ + { + "name": "callbackGasLimit", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setGoldToken", + "inputs": [ + { "name": "goldToken", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setKeyHash", + "inputs": [ + { "name": "keyHash", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setNumWords", + "inputs": [ + { "name": "numWords", "type": "uint32", "internalType": "uint32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setRequestConfirmations", + "inputs": [ + { + "name": "requestConfirmations", + "type": "uint16", + "internalType": "uint16" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setVrfCoordinator", + "inputs": [ + { + "name": "vrfCoordinator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setVrfSubscriptionId", + "inputs": [ + { + "name": "vrfSubscriptionId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "CallbackGasLimitUpdated", + "inputs": [ + { + "name": "previousGasLimit", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + }, + { + "name": "newGasLimit", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GainClaimed", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GoldTokenUpdated", + "inputs": [ + { + "name": "previousGoldToken", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newGoldToken", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "KeyHashUpdated", + "inputs": [ + { + "name": "previousKeyHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newKeyHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LotterieInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "vrfCoordinator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "goldToken", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "vrfSubscriptionId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "keyHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "callbackGasLimit", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + }, + { + "name": "requestConfirmations", + "type": "uint16", + "indexed": false, + "internalType": "uint16" + }, + { + "name": "numWords", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NumWordsUpdated", + "inputs": [ + { + "name": "previousNumWords", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + }, + { + "name": "newNumWords", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RandomDrawed", + "inputs": [ + { + "name": "requestId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RequestConfirmationsUpdated", + "inputs": [ + { + "name": "previousConfirmations", + "type": "uint16", + "indexed": true, + "internalType": "uint16" + }, + { + "name": "newConfirmations", + "type": "uint16", + "indexed": true, + "internalType": "uint16" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "VrfCoordinatorUpdated", + "inputs": [ + { + "name": "previousCoordinator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newCoordinator", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "VrfSubscriptionUpdated", + "inputs": [ + { + "name": "previousSubscriptionId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "newSubscriptionId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Winner", + "inputs": [ + { + "name": "winner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { "type": "error", "name": "NoGainToClaim", "inputs": [] }, + { "type": "error", "name": "OneRandomDrawPerDay", "inputs": [] }, + { "type": "error", "name": "TransferFailed", "inputs": [] } + ] +} diff --git a/frontend/abi/lotterie/lotterieAbi.json b/frontend/abi/lotterie/lotterieAbi.json new file mode 100644 index 0000000..ec24e37 --- /dev/null +++ b/frontend/abi/lotterie/lotterieAbi.json @@ -0,0 +1,854 @@ +{ + "abi": [ + { + "type": "constructor", + "inputs": [ + { + "name": "vrfCoordinator", + "type": "address", + "internalType": "address" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OWNER_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "acceptOwnership", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "addOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "claim", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "getCallbackGasLimit", + "inputs": [], + "outputs": [{ "name": "", "type": "uint32", "internalType": "uint32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGains", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGoldToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getKeyHash", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLastRequestId", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getNumWords", + "inputs": [], + "outputs": [{ "name": "", "type": "uint32", "internalType": "uint32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRequestConfirmations", + "inputs": [], + "outputs": [{ "name": "", "type": "uint16", "internalType": "uint16" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getResults", + "inputs": [ + { "name": "requestId", "type": "uint256", "internalType": "uint256" } + ], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getVrfCoordinator", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getVrfSubscriptionId", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasOwnerRole", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { + "name": "vrfSubscriptionId", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "vrfCoordinator", + "type": "address", + "internalType": "address" + }, + { "name": "keyHash", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "callbackGasLimit", + "type": "uint32", + "internalType": "uint32" + }, + { + "name": "requestConfirmations", + "type": "uint16", + "internalType": "uint16" + }, + { "name": "numWords", "type": "uint32", "internalType": "uint32" }, + { "name": "goldToken", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "owner", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "randomDraw", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "rawFulfillRandomWords", + "inputs": [ + { "name": "requestId", "type": "uint256", "internalType": "uint256" }, + { + "name": "randomWords", + "type": "uint256[]", + "internalType": "uint256[]" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "removeOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "s_vrfCoordinator", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "address", + "internalType": "contract IVRFCoordinatorV2Plus" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setCallbackGasLimit", + "inputs": [ + { + "name": "callbackGasLimit", + "type": "uint32", + "internalType": "uint32" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setCoordinator", + "inputs": [ + { + "name": "_vrfCoordinator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setGoldToken", + "inputs": [ + { "name": "goldToken", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setKeyHash", + "inputs": [ + { "name": "keyHash", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setNumWords", + "inputs": [ + { "name": "numWords", "type": "uint32", "internalType": "uint32" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setRequestConfirmations", + "inputs": [ + { + "name": "requestConfirmations", + "type": "uint16", + "internalType": "uint16" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setVrfCoordinator", + "inputs": [ + { + "name": "vrfCoordinator", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setVrfSubscriptionId", + "inputs": [ + { + "name": "vrfSubscriptionId", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { "name": "interfaceId", "type": "bytes4", "internalType": "bytes4" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transferOwnership", + "inputs": [ + { "name": "to", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "event", + "name": "CallbackGasLimitUpdated", + "inputs": [ + { + "name": "previousGasLimit", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + }, + { + "name": "newGasLimit", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "CoordinatorSet", + "inputs": [ + { + "name": "vrfCoordinator", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GainClaimed", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "GoldTokenUpdated", + "inputs": [ + { + "name": "previousGoldToken", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newGoldToken", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "KeyHashUpdated", + "inputs": [ + { + "name": "previousKeyHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newKeyHash", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "LotterieInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "vrfCoordinator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "goldToken", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "vrfSubscriptionId", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "keyHash", + "type": "bytes32", + "indexed": false, + "internalType": "bytes32" + }, + { + "name": "callbackGasLimit", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + }, + { + "name": "requestConfirmations", + "type": "uint16", + "indexed": false, + "internalType": "uint16" + }, + { + "name": "numWords", + "type": "uint32", + "indexed": false, + "internalType": "uint32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "NumWordsUpdated", + "inputs": [ + { + "name": "previousNumWords", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + }, + { + "name": "newNumWords", + "type": "uint32", + "indexed": true, + "internalType": "uint32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferRequested", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "OwnershipTransferred", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RandomDrawed", + "inputs": [ + { + "name": "requestId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RequestConfirmationsUpdated", + "inputs": [ + { + "name": "previousConfirmations", + "type": "uint16", + "indexed": true, + "internalType": "uint16" + }, + { + "name": "newConfirmations", + "type": "uint16", + "indexed": true, + "internalType": "uint16" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "VrfCoordinatorUpdated", + "inputs": [ + { + "name": "previousCoordinator", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "newCoordinator", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "VrfSubscriptionUpdated", + "inputs": [ + { + "name": "previousSubscriptionId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + }, + { + "name": "newSubscriptionId", + "type": "uint256", + "indexed": true, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Winner", + "inputs": [ + { + "name": "winner", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { "type": "error", "name": "AccessControlBadConfirmation", "inputs": [] }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" }, + { "name": "neededRole", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { "name": "target", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { "type": "error", "name": "ERC1967NonPayable", "inputs": [] }, + { "type": "error", "name": "FailedCall", "inputs": [] }, + { "type": "error", "name": "InvalidInitialization", "inputs": [] }, + { "type": "error", "name": "NoGainToClaim", "inputs": [] }, + { "type": "error", "name": "NotInitializing", "inputs": [] }, + { "type": "error", "name": "OneRandomDrawPerDay", "inputs": [] }, + { + "type": "error", + "name": "OnlyCoordinatorCanFulfill", + "inputs": [ + { "name": "have", "type": "address", "internalType": "address" }, + { "name": "want", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "OnlyOwnerOrCoordinator", + "inputs": [ + { "name": "have", "type": "address", "internalType": "address" }, + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "coordinator", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "ReentrancyGuardReentrantCall", "inputs": [] }, + { "type": "error", "name": "TransferFailed", "inputs": [] }, + { "type": "error", "name": "UUPSUnauthorizedCallContext", "inputs": [] }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { "name": "slot", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { "type": "error", "name": "ZeroAddress", "inputs": [] } + ] +} \ No newline at end of file diff --git a/frontend/abi/tokenBridge/iTokenBridgeAbi.json b/frontend/abi/tokenBridge/iTokenBridgeAbi.json new file mode 100644 index 0000000..a04eece --- /dev/null +++ b/frontend/abi/tokenBridge/iTokenBridgeAbi.json @@ -0,0 +1,399 @@ +{ + "abi": [ + { + "type": "function", + "name": "bridgeTokens", + "inputs": [ + { "name": "receiver", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" }, + { + "name": "payFeesIn", + "type": "uint8", + "internalType": "enum ITokenBridge.PayFeesIn" + } + ], + "outputs": [ + { "name": "messageId", "type": "bytes32", "internalType": "bytes32" } + ], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "destinationChainSelector", + "inputs": [], + "outputs": [{ "name": "", "type": "uint64", "internalType": "uint64" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGoldTokenBalance", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLinkBalance", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "goldToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "_link", "type": "address", "internalType": "address" }, + { "name": "_goldToken", "type": "address", "internalType": "address" }, + { + "name": "_destinationChainSelector", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "link", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "processedMessages", + "inputs": [ + { "name": "messageId", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "setWhitelistedChain", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" }, + { "name": "enabled", "type": "bool", "internalType": "bool" }, + { "name": "ccipExtraArgs", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setWhitelistedSender", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" }, + { "name": "enabled", "type": "bool", "internalType": "bool" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "whitelistedChains", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "whitelistedSenders", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { "name": "beneficiary", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawToken", + "inputs": [ + { "name": "beneficiary", "type": "address", "internalType": "address" }, + { "name": "token", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ChainRemoved", + "inputs": [ + { + "name": "chainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ChainWhitelisted", + "inputs": [ + { + "name": "chainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MessageProcessedWithoutToken", + "inputs": [ + { + "name": "messageId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "sourceChainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SenderRemoved", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SenderWhitelisted", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenBridgeInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "link", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "goldToken", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "destinationChainSelector", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokensBridged", + "inputs": [ + { + "name": "messageId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "destinationChainSelector", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "feeToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "fees", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokensReceived", + "inputs": [ + { + "name": "messageId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "sourceChainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "error", + "name": "ChainNotWhitelisted", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" } + ] + }, + { + "type": "error", + "name": "FailedToWithdrawEth", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "target", "type": "address", "internalType": "address" }, + { "name": "value", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "type": "error", + "name": "InvalidAmount", + "inputs": [ + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "type": "error", + "name": "InvalidChainSelector", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" } + ] + }, + { + "type": "error", + "name": "InvalidSender", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "InvalidSourceChain", + "inputs": [ + { + "name": "sourceChainSelector", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "MessageAlreadyProcessed", + "inputs": [ + { "name": "messageId", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { + "type": "error", + "name": "NotEnoughBalance", + "inputs": [ + { + "name": "currentBalance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "calculatedFees", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { + "type": "error", + "name": "SenderNotWhitelisted", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ] + } + ] +} diff --git a/frontend/abi/tokenBridge/tokenBridgeAbi.json b/frontend/abi/tokenBridge/tokenBridgeAbi.json new file mode 100644 index 0000000..bfa93b7 --- /dev/null +++ b/frontend/abi/tokenBridge/tokenBridgeAbi.json @@ -0,0 +1,795 @@ +{ + "abi": [ + { + "type": "constructor", + "inputs": [ + { "name": "_router", "type": "address", "internalType": "address" } + ], + "stateMutability": "nonpayable" + }, + { "type": "receive", "stateMutability": "payable" }, + { + "type": "function", + "name": "DEFAULT_ADMIN_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "OWNER_ROLE", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "UPGRADE_INTERFACE_VERSION", + "inputs": [], + "outputs": [{ "name": "", "type": "string", "internalType": "string" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "addOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "bridgeTokens", + "inputs": [ + { "name": "receiver", "type": "address", "internalType": "address" }, + { "name": "amount", "type": "uint256", "internalType": "uint256" }, + { + "name": "payFeesIn", + "type": "uint8", + "internalType": "enum ITokenBridge.PayFeesIn" + } + ], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "ccipReceive", + "inputs": [ + { + "name": "message", + "type": "tuple", + "internalType": "struct Client.Any2EVMMessage", + "components": [ + { + "name": "messageId", + "type": "bytes32", + "internalType": "bytes32" + }, + { + "name": "sourceChainSelector", + "type": "uint64", + "internalType": "uint64" + }, + { "name": "sender", "type": "bytes", "internalType": "bytes" }, + { "name": "data", "type": "bytes", "internalType": "bytes" }, + { + "name": "destTokenAmounts", + "type": "tuple[]", + "internalType": "struct Client.EVMTokenAmount[]", + "components": [ + { + "name": "token", + "type": "address", + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "internalType": "uint256" + } + ] + } + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "destinationChainSelector", + "inputs": [], + "outputs": [{ "name": "", "type": "uint64", "internalType": "uint64" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getGoldTokenBalance", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getLinkBalance", + "inputs": [], + "outputs": [{ "name": "", "type": "uint256", "internalType": "uint256" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRoleAdmin", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "getRouter", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "goldToken", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "grantRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "hasOwnerRole", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "hasRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "initialize", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "_link", "type": "address", "internalType": "address" }, + { "name": "_goldToken", "type": "address", "internalType": "address" }, + { + "name": "_destinationChainSelector", + "type": "uint64", + "internalType": "uint64" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "link", + "inputs": [], + "outputs": [{ "name": "", "type": "address", "internalType": "address" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "pause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "paused", + "inputs": [], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "processedMessages", + "inputs": [ + { "name": "messageId", "type": "bytes32", "internalType": "bytes32" } + ], + "outputs": [ + { "name": "wasProcessed", "type": "bool", "internalType": "bool" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "proxiableUUID", + "inputs": [], + "outputs": [{ "name": "", "type": "bytes32", "internalType": "bytes32" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "removeOwner", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "renounceRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { + "name": "callerConfirmation", + "type": "address", + "internalType": "address" + } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "revokeRole", + "inputs": [ + { "name": "role", "type": "bytes32", "internalType": "bytes32" }, + { "name": "account", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setWhitelistedChain", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" }, + { "name": "enabled", "type": "bool", "internalType": "bool" }, + { "name": "ccipExtraArgs", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "setWhitelistedSender", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" }, + { "name": "enabled", "type": "bool", "internalType": "bool" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "supportsInterface", + "inputs": [ + { "name": "interfaceId", "type": "bytes4", "internalType": "bytes4" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "unpause", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "upgradeToAndCall", + "inputs": [ + { + "name": "newImplementation", + "type": "address", + "internalType": "address" + }, + { "name": "data", "type": "bytes", "internalType": "bytes" } + ], + "outputs": [], + "stateMutability": "payable" + }, + { + "type": "function", + "name": "whitelistedChains", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" } + ], + "outputs": [{ "name": "", "type": "bool", "internalType": "bool" }], + "stateMutability": "view" + }, + { + "type": "function", + "name": "whitelistedSenders", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ], + "outputs": [ + { "name": "allowed", "type": "bool", "internalType": "bool" } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "withdraw", + "inputs": [ + { "name": "beneficiary", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "withdrawToken", + "inputs": [ + { "name": "beneficiary", "type": "address", "internalType": "address" }, + { "name": "token", "type": "address", "internalType": "address" } + ], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ChainRemoved", + "inputs": [ + { + "name": "chainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "ChainWhitelisted", + "inputs": [ + { + "name": "chainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Initialized", + "inputs": [ + { + "name": "version", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "MessageProcessedWithoutToken", + "inputs": [ + { + "name": "messageId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "sourceChainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Paused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleAdminChanged", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "previousAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "newAdminRole", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleGranted", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "RoleRevoked", + "inputs": [ + { + "name": "role", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SenderRemoved", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "SenderWhitelisted", + "inputs": [ + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokenBridgeInitialized", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "link", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "goldToken", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "destinationChainSelector", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokensBridged", + "inputs": [ + { + "name": "messageId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "sender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "destinationChainSelector", + "type": "uint64", + "indexed": false, + "internalType": "uint64" + }, + { + "name": "feeToken", + "type": "address", + "indexed": false, + "internalType": "address" + }, + { + "name": "fees", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "TokensReceived", + "inputs": [ + { + "name": "messageId", + "type": "bytes32", + "indexed": true, + "internalType": "bytes32" + }, + { + "name": "receiver", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "amount", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + }, + { + "name": "sourceChainSelector", + "type": "uint64", + "indexed": true, + "internalType": "uint64" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Unpaused", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": false, + "internalType": "address" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Upgraded", + "inputs": [ + { + "name": "implementation", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + }, + { "type": "error", "name": "AccessControlBadConfirmation", "inputs": [] }, + { + "type": "error", + "name": "AccessControlUnauthorizedAccount", + "inputs": [ + { "name": "account", "type": "address", "internalType": "address" }, + { "name": "neededRole", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { + "type": "error", + "name": "AddressEmptyCode", + "inputs": [ + { "name": "target", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "ChainNotWhitelisted", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" } + ] + }, + { + "type": "error", + "name": "ERC1967InvalidImplementation", + "inputs": [ + { + "name": "implementation", + "type": "address", + "internalType": "address" + } + ] + }, + { "type": "error", "name": "ERC1967NonPayable", "inputs": [] }, + { "type": "error", "name": "EnforcedPause", "inputs": [] }, + { "type": "error", "name": "ExpectedPause", "inputs": [] }, + { "type": "error", "name": "FailedCall", "inputs": [] }, + { + "type": "error", + "name": "FailedToWithdrawEth", + "inputs": [ + { "name": "owner", "type": "address", "internalType": "address" }, + { "name": "target", "type": "address", "internalType": "address" }, + { "name": "value", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "type": "error", + "name": "InvalidAmount", + "inputs": [ + { "name": "amount", "type": "uint256", "internalType": "uint256" } + ] + }, + { + "type": "error", + "name": "InvalidChainSelector", + "inputs": [ + { "name": "chainSelector", "type": "uint64", "internalType": "uint64" } + ] + }, + { "type": "error", "name": "InvalidInitialization", "inputs": [] }, + { + "type": "error", + "name": "InvalidRouter", + "inputs": [ + { "name": "router", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "InvalidSender", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "InvalidSourceChain", + "inputs": [ + { + "name": "sourceChainSelector", + "type": "uint64", + "internalType": "uint64" + } + ] + }, + { + "type": "error", + "name": "MessageAlreadyProcessed", + "inputs": [ + { "name": "messageId", "type": "bytes32", "internalType": "bytes32" } + ] + }, + { + "type": "error", + "name": "NotEnoughBalance", + "inputs": [ + { + "name": "currentBalance", + "type": "uint256", + "internalType": "uint256" + }, + { + "name": "calculatedFees", + "type": "uint256", + "internalType": "uint256" + } + ] + }, + { "type": "error", "name": "NotInitializing", "inputs": [] }, + { "type": "error", "name": "ReentrancyGuardReentrantCall", "inputs": [] }, + { + "type": "error", + "name": "SafeERC20FailedOperation", + "inputs": [ + { "name": "token", "type": "address", "internalType": "address" } + ] + }, + { + "type": "error", + "name": "SenderNotWhitelisted", + "inputs": [ + { "name": "sender", "type": "address", "internalType": "address" } + ] + }, + { "type": "error", "name": "UUPSUnauthorizedCallContext", "inputs": [] }, + { + "type": "error", + "name": "UUPSUnsupportedProxiableUUID", + "inputs": [ + { "name": "slot", "type": "bytes32", "internalType": "bytes32" } + ] + } + ] +} diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js new file mode 100644 index 0000000..116f84c --- /dev/null +++ b/frontend/eslint.config.js @@ -0,0 +1,30 @@ +import js from "@eslint/js"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { ignores: ["dist"] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/ban-ts-comment": "warn", + }, + } +); diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 0000000..b642a85 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,13 @@ + + + + + + + Golden Bridge + + +
+ + + \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000..bf9b015 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,7380 @@ +{ + "name": "golden-bridge-frontend", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "golden-bridge-frontend", + "version": "0.0.0", + "dependencies": { + "@reown/appkit": "^1.8.14", + "@reown/appkit-adapter-ethers": "^1.8.14", + "ethers": "^6.15.0", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@eslint/js": "^9.39.1", + "@types/react": "^19.2.7", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.1.1", + "eslint": "^9.39.1", + "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-refresh": "^0.4.24", + "globals": "^16.5.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.48.0", + "vite": "^7.2.4" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", + "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", + "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", + "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.28.3", + "@babel/helpers": "^7.28.4", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5", + "@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/core/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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "@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.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@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-compilation-targets/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, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", + "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.28.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", + "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.5" + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@base-org/account": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@base-org/account/-/account-2.4.0.tgz", + "integrity": "sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@coinbase/cdp-sdk": "^1.0.0", + "@noble/hashes": "1.4.0", + "clsx": "1.2.1", + "eventemitter3": "5.0.1", + "idb-keyval": "6.2.1", + "ox": "0.6.9", + "preact": "10.24.2", + "viem": "^2.31.7", + "zustand": "5.0.3" + } + }, + "node_modules/@coinbase/cdp-sdk": { + "version": "1.38.6", + "resolved": "https://registry.npmjs.org/@coinbase/cdp-sdk/-/cdp-sdk-1.38.6.tgz", + "integrity": "sha512-l9gGGZqhCryuD3nfqB4Y+i8kfBtsnPJoKB5jxx5lKgXhVJw7/BPhgscKkVhP81115Srq3bFegD1IBwUkJ0JFMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana-program/system": "^0.8.0", + "@solana-program/token": "^0.6.0", + "@solana/kit": "^3.0.3", + "@solana/web3.js": "^1.98.1", + "abitype": "1.0.6", + "axios": "^1.12.2", + "axios-retry": "^4.5.0", + "jose": "^6.0.8", + "md5": "^2.3.0", + "uncrypto": "^0.1.3", + "viem": "^2.21.26", + "zod": "^3.24.4" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", + "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", + "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/sha2": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@lit-labs/ssr-dom-shim": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.4.0.tgz", + "integrity": "sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==", + "license": "BSD-3-Clause" + }, + "node_modules/@lit/react": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@lit/react/-/react-1.0.8.tgz", + "integrity": "sha512-p2+YcF+JE67SRX3mMlJ1TKCSTsgyOVdAwd/nxp3NuV1+Cb6MWALbN6nT7Ld4tpmYofcE5kcaSY1YBB9erY+6fw==", + "license": "BSD-3-Clause", + "optional": true, + "peerDependencies": { + "@types/react": "17 || 18 || 19" + } + }, + "node_modules/@lit/reactive-element": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-2.1.1.tgz", + "integrity": "sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0" + } + }, + "node_modules/@msgpack/msgpack": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@msgpack/msgpack/-/msgpack-3.1.2.tgz", + "integrity": "sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==", + "license": "ISC", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@phosphor-icons/webcomponents": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@phosphor-icons/webcomponents/-/webcomponents-2.1.5.tgz", + "integrity": "sha512-JcvQkZxvcX2jK+QCclm8+e8HXqtdFW9xV4/kk2aL9Y3dJA2oQVt+pzbv1orkumz3rfx4K9mn9fDoMr1He1yr7Q==", + "license": "MIT", + "dependencies": { + "lit": "^3" + } + }, + "node_modules/@reown/appkit": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit/-/appkit-1.8.14.tgz", + "integrity": "sha512-y+Gl5SJ/iqh7QVrNkgtwsWyXnmSlodv5ICP5wWl5zdrAWO49kfopa5sULnKq9U1s/BgupHZAqhZFgqCTIrbaHQ==", + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.14", + "@reown/appkit-controllers": "1.8.14", + "@reown/appkit-pay": "1.8.14", + "@reown/appkit-polyfills": "1.8.14", + "@reown/appkit-scaffold-ui": "1.8.14", + "@reown/appkit-ui": "1.8.14", + "@reown/appkit-utils": "1.8.14", + "@reown/appkit-wallet": "1.8.14", + "@walletconnect/universal-provider": "2.23.0", + "bs58": "6.0.0", + "semver": "7.7.2", + "valtio": "2.1.7", + "viem": ">=2.37.9" + }, + "optionalDependencies": { + "@lit/react": "1.0.8" + } + }, + "node_modules/@reown/appkit-adapter-ethers": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-adapter-ethers/-/appkit-adapter-ethers-1.8.14.tgz", + "integrity": "sha512-eXdYeWf8OHd2rCldDVEh8ULxK7lktISD0kE8milegmCm7RU0lU6nyDrURUr8T2K9rcYqYjHXHOWXciAckHcWIg==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit": "1.8.14", + "@reown/appkit-common": "1.8.14", + "@reown/appkit-controllers": "1.8.14", + "@reown/appkit-polyfills": "1.8.14", + "@reown/appkit-scaffold-ui": "1.8.14", + "@reown/appkit-utils": "1.8.14", + "@reown/appkit-wallet": "1.8.14", + "@walletconnect/universal-provider": "2.23.0", + "valtio": "2.1.7" + }, + "peerDependencies": { + "@ethersproject/sha2": "5.8.0", + "ethers": ">=6" + } + }, + "node_modules/@reown/appkit-common": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-common/-/appkit-common-1.8.14.tgz", + "integrity": "sha512-0dRNtmy2e7f89Vvx3NCA09PD24DFT6S0nO6a/MBeFOj7SlvkvIh4SjBWG2x2F4L8KxCSCtQ5x6dWREmTONZjMA==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "big.js": "6.2.2", + "dayjs": "1.11.13", + "viem": ">=2.37.9" + } + }, + "node_modules/@reown/appkit-controllers": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-controllers/-/appkit-controllers-1.8.14.tgz", + "integrity": "sha512-1EF3xzwMwNfzZp1yd2InwA01EEDSylwHfX6MuGa1t5M6HevY4p1QnbnZISpYAQxN1xklCQsT3Zq5pQh6Ofg+Cg==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.14", + "@reown/appkit-wallet": "1.8.14", + "@walletconnect/universal-provider": "2.23.0", + "valtio": "2.1.7", + "viem": ">=2.37.9" + } + }, + "node_modules/@reown/appkit-pay": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-pay/-/appkit-pay-1.8.14.tgz", + "integrity": "sha512-6ReXMGV47quXax8v1RQ8wFgclSd6M7MhX/WHJGwsjNHjFttQ6xWbPlYmjZxKgZ+k+K2TG/wo7oU0pF5Qu/L7Tw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.14", + "@reown/appkit-controllers": "1.8.14", + "@reown/appkit-ui": "1.8.14", + "@reown/appkit-utils": "1.8.14", + "lit": "3.3.0", + "valtio": "2.1.7" + } + }, + "node_modules/@reown/appkit-polyfills": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-polyfills/-/appkit-polyfills-1.8.14.tgz", + "integrity": "sha512-bMMdJpzxni6+FQpMqQomKvXoDy+t9uCunswuKCN33fMRXtXX0A3ui0WMGUFbQ4BKGmQcyUSt/MWid9hZ6KG8Fw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/@reown/appkit-scaffold-ui": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-scaffold-ui/-/appkit-scaffold-ui-1.8.14.tgz", + "integrity": "sha512-dhD9vodp1xsVs0yWP2V+b3XkcksHEHNzjNQvXBmTrfDDDpUYiScBTvjKmMRu/MgUxYRrFdxoMDIfAzjYUAwZuw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.14", + "@reown/appkit-controllers": "1.8.14", + "@reown/appkit-ui": "1.8.14", + "@reown/appkit-utils": "1.8.14", + "@reown/appkit-wallet": "1.8.14", + "lit": "3.3.0" + } + }, + "node_modules/@reown/appkit-ui": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-ui/-/appkit-ui-1.8.14.tgz", + "integrity": "sha512-vExTPCA8QghLaUG3mM2ghUN7IvTGy/dUbVxGYbCrIG/Y7Srshqp8O/vwnWk5RhktRwMNQuOXCRGXf2lWPiuNWQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@phosphor-icons/webcomponents": "2.1.5", + "@reown/appkit-common": "1.8.14", + "@reown/appkit-controllers": "1.8.14", + "@reown/appkit-wallet": "1.8.14", + "lit": "3.3.0", + "qrcode": "1.5.3" + } + }, + "node_modules/@reown/appkit-utils": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-utils/-/appkit-utils-1.8.14.tgz", + "integrity": "sha512-SuXtX2pr8yilaAdTq7nEj2/ulKMUJAKUbtldAcsl3/acsqfD4oKHi13VJEKsHcGx/43sb1uDXA9yB60/g2+NAQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.14", + "@reown/appkit-controllers": "1.8.14", + "@reown/appkit-polyfills": "1.8.14", + "@reown/appkit-wallet": "1.8.14", + "@wallet-standard/wallet": "1.1.0", + "@walletconnect/logger": "3.0.0", + "@walletconnect/universal-provider": "2.23.0", + "valtio": "2.1.7", + "viem": ">=2.37.9" + }, + "optionalDependencies": { + "@base-org/account": "2.4.0", + "@safe-global/safe-apps-provider": "0.18.6", + "@safe-global/safe-apps-sdk": "9.1.0" + }, + "peerDependencies": { + "valtio": "2.1.7" + } + }, + "node_modules/@reown/appkit-wallet": { + "version": "1.8.14", + "resolved": "https://registry.npmjs.org/@reown/appkit-wallet/-/appkit-wallet-1.8.14.tgz", + "integrity": "sha512-p+BgGniq5tSIe98MIUxu1dYPKaccPN/OyYBf4n1M+TgItCrbxDUr7pkbBEqHb3KdyK+EQeTwz3wOJpPQFwHcEQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@reown/appkit-common": "1.8.14", + "@reown/appkit-polyfills": "1.8.14", + "@walletconnect/logger": "3.0.0", + "zod": "3.22.4" + } + }, + "node_modules/@reown/appkit-wallet/node_modules/zod": { + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.47", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz", + "integrity": "sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", + "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", + "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", + "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", + "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", + "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", + "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", + "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", + "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", + "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", + "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", + "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", + "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", + "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", + "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", + "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", + "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", + "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", + "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", + "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", + "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", + "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", + "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@safe-global/safe-apps-provider": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-provider/-/safe-apps-provider-0.18.6.tgz", + "integrity": "sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@safe-global/safe-apps-sdk": "^9.1.0", + "events": "^3.3.0" + } + }, + "node_modules/@safe-global/safe-apps-sdk": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@safe-global/safe-apps-sdk/-/safe-apps-sdk-9.1.0.tgz", + "integrity": "sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@safe-global/safe-gateway-typescript-sdk": "^3.5.3", + "viem": "^2.1.1" + } + }, + "node_modules/@safe-global/safe-gateway-typescript-sdk": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/@safe-global/safe-gateway-typescript-sdk/-/safe-gateway-typescript-sdk-3.23.1.tgz", + "integrity": "sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=16" + } + }, + "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==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana-program/system": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@solana-program/system/-/system-0.8.1.tgz", + "integrity": "sha512-71U9Mzdpw8HQtfgfJSL5xKZbLMRnza2Llsfk7gGnmg2waqK+o8MMH4YNma8xXS1UmOBptXIiNvoZ3p7cmOVktg==", + "license": "Apache-2.0", + "optional": true, + "peerDependencies": { + "@solana/kit": "^3.0" + } + }, + "node_modules/@solana-program/token": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@solana-program/token/-/token-0.6.0.tgz", + "integrity": "sha512-omkZh4Tt9rre4wzWHNOhOEHyenXQku3xyc/UrKvShexA/Qlhza67q7uRwmwEDUs4QqoDBidSZPooOmepnA/jig==", + "license": "Apache-2.0", + "optional": true, + "peerDependencies": { + "@solana/kit": "^3.0" + } + }, + "node_modules/@solana/accounts": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/accounts/-/accounts-3.0.3.tgz", + "integrity": "sha512-KqlePrlZaHXfu8YQTCxN204ZuVm9o68CCcUr6l27MG2cuRUtEM1Ta0iR8JFkRUAEfZJC4Cu0ZDjK/v49loXjZQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/rpc-spec": "3.0.3", + "@solana/rpc-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/addresses": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/addresses/-/addresses-3.0.3.tgz", + "integrity": "sha512-AuMwKhJI89ANqiuJ/fawcwxNKkSeHH9CApZd2xelQQLS7X8uxAOovpcmEgiObQuiVP944s9ScGUT62Bdul9qYg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/assertions": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/nominal-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/assertions": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/assertions/-/assertions-3.0.3.tgz", + "integrity": "sha512-2qspxdbWp2y62dfCIlqeWQr4g+hE8FYSSwcaP6itwMwGRb8393yDGCJfI/znuzJh6m/XVWhMHIgFgsBwnevCmg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/codecs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/codecs/-/codecs-3.0.3.tgz", + "integrity": "sha512-GOHwTlIQsCoJx9Ryr6cEf0FHKAQ7pY4aO4xgncAftrv0lveTQ1rPP2inQ1QT0gJllsIa8nwbfXAADs9nNJxQDA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "3.0.3", + "@solana/codecs-data-structures": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/options": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-core": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-3.0.3.tgz", + "integrity": "sha512-emKykJ3h1DmnDOY29Uv9eJXP8E/FHzvlUBJ6te+5EbKdFjj7vdlKYPfDxOI6iGdXTY+YC/ELtbNBh6QwF2uEDQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-data-structures": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-3.0.3.tgz", + "integrity": "sha512-R15cLp8riJvToXziW8lP6AMSwsztGhEnwgyGmll32Mo0Yjq+hduW2/fJrA/TJs6tA/OgTzMQjlxgk009EqZHCw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-3.0.3.tgz", + "integrity": "sha512-pfXkH9J0glrM8qj6389GAn30+cJOxzXLR2FsPOHCUMXrqLhGjMMZAWhsQkpOQ37SGc/7EiQsT/gmyGC7gxHqJQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "3.0.3", + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-3.0.3.tgz", + "integrity": "sha512-VHBXnnTVtcQ1j+7Vrz+qSYo38no+jiHRdGnhFspRXEHNJbllzwKqgBE7YN3qoIXH+MKxgJUcwO5KHmdzf8Wn2A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/errors": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-3.0.3.tgz", + "integrity": "sha512-1l84xJlHNva6io62PcYfUamwWlc0eM95nHgCrKX0g0cLoC6D6QHYPCEbEVkR+C5UtP9JDgyQM8MFiv+Ei5tO9Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "chalk": "5.6.2", + "commander": "14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/fast-stable-stringify": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/fast-stable-stringify/-/fast-stable-stringify-3.0.3.tgz", + "integrity": "sha512-ED0pxB6lSEYvg+vOd5hcuQrgzEDnOrURFgp1ZOY+lQhJkQU6xo+P829NcJZQVP1rdU2/YQPAKJKEseyfe9VMIw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/functional": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/functional/-/functional-3.0.3.tgz", + "integrity": "sha512-2qX1kKANn8995vOOh5S9AmF4ItGZcfbny0w28Eqy8AFh+GMnSDN4gqpmV2LvxBI9HibXZptGH3RVOMk82h1Mpw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/instruction-plans": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/instruction-plans/-/instruction-plans-3.0.3.tgz", + "integrity": "sha512-eqoaPtWtmLTTpdvbt4BZF5H6FIlJtXi9H7qLOM1dLYonkOX2Ncezx5NDCZ9tMb2qxVMF4IocYsQnNSnMfjQF1w==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/instructions": "3.0.3", + "@solana/promises": "3.0.3", + "@solana/transaction-messages": "3.0.3", + "@solana/transactions": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/instructions": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/instructions/-/instructions-3.0.3.tgz", + "integrity": "sha512-4csIi8YUDb5j/J+gDzmYtOvq7ZWLbCxj4t0xKn+fPrBk/FD2pK29KVT3Fu7j4Lh1/ojunQUP9X4NHwUexY3PnA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "3.0.3", + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/keys": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/keys/-/keys-3.0.3.tgz", + "integrity": "sha512-tp8oK9tMadtSIc4vF4aXXWkPd4oU5XPW8nf28NgrGDWGt25fUHIydKjkf2hPtMt9i1WfRyQZ33B5P3dnsNqcPQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/assertions": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/nominal-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/nominal-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/nominal-types/-/nominal-types-3.0.3.tgz", + "integrity": "sha512-aZavCiexeUAoMHRQg4s1AHkH3wscbOb70diyfjhwZVgFz1uUsFez7csPp9tNFkNolnadVb2gky7yBk3IImQJ6A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/options": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-3.0.3.tgz", + "integrity": "sha512-jarsmnQ63RN0JPC5j9sgUat07NrL9PC71XU7pUItd6LOHtu4+wJMio3l5mT0DHVfkfbFLL6iI6+QmXSVhTNF3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "3.0.3", + "@solana/codecs-data-structures": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/programs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/programs/-/programs-3.0.3.tgz", + "integrity": "sha512-JZlVE3/AeSNDuH3aEzCZoDu8GTXkMpGXxf93zXLzbxfxhiQ/kHrReN4XE/JWZ/uGWbaFZGR5B3UtdN2QsoZL7w==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/promises": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/promises/-/promises-3.0.3.tgz", + "integrity": "sha512-K+UflGBVxj30XQMHTylHHZJdKH5QG3oj5k2s42GrZ/Wbu72oapVJySMBgpK45+p90t8/LEqV6rRPyTXlet9J+Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc/-/rpc-3.0.3.tgz", + "integrity": "sha512-3oukAaLK78GegkKcm6iNmRnO4mFeNz+BMvA8T56oizoBNKiRVEq/6DFzVX/LkmZ+wvD601pAB3uCdrTPcC0YKQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/fast-stable-stringify": "3.0.3", + "@solana/functional": "3.0.3", + "@solana/rpc-api": "3.0.3", + "@solana/rpc-spec": "3.0.3", + "@solana/rpc-spec-types": "3.0.3", + "@solana/rpc-transformers": "3.0.3", + "@solana/rpc-transport-http": "3.0.3", + "@solana/rpc-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-api": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-api/-/rpc-api-3.0.3.tgz", + "integrity": "sha512-Yym9/Ama62OY69rAZgbOCAy1QlqaWAyb0VlqFuwSaZV1pkFCCFSwWEJEsiN1n8pb2ZP+RtwNvmYixvWizx9yvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/keys": "3.0.3", + "@solana/rpc-parsed-types": "3.0.3", + "@solana/rpc-spec": "3.0.3", + "@solana/rpc-transformers": "3.0.3", + "@solana/rpc-types": "3.0.3", + "@solana/transaction-messages": "3.0.3", + "@solana/transactions": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-parsed-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-parsed-types/-/rpc-parsed-types-3.0.3.tgz", + "integrity": "sha512-/koM05IM2fU91kYDQxXil3VBNlOfcP+gXE0js1sdGz8KonGuLsF61CiKB5xt6u1KEXhRyDdXYLjf63JarL4Ozg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-spec": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec/-/rpc-spec-3.0.3.tgz", + "integrity": "sha512-MZn5/8BebB6MQ4Gstw6zyfWsFAZYAyLzMK+AUf/rSfT8tPmWiJ/mcxnxqOXvFup/l6D67U8pyGpIoFqwCeZqqA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/rpc-spec-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-spec-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-spec-types/-/rpc-spec-types-3.0.3.tgz", + "integrity": "sha512-A6Jt8SRRetnN3CeGAvGJxigA9zYRslGgWcSjueAZGvPX+MesFxEUjSWZCfl+FogVFvwkqfkgQZQbPAGZQFJQ6Q==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-subscriptions": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions/-/rpc-subscriptions-3.0.3.tgz", + "integrity": "sha512-LRvz6NaqvtsYFd32KwZ+rwYQ9XCs+DWjV8BvBLsJpt9/NWSuHf/7Sy/vvP6qtKxut692H/TMvHnC4iulg0WmiQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/fast-stable-stringify": "3.0.3", + "@solana/functional": "3.0.3", + "@solana/promises": "3.0.3", + "@solana/rpc-spec-types": "3.0.3", + "@solana/rpc-subscriptions-api": "3.0.3", + "@solana/rpc-subscriptions-channel-websocket": "3.0.3", + "@solana/rpc-subscriptions-spec": "3.0.3", + "@solana/rpc-transformers": "3.0.3", + "@solana/rpc-types": "3.0.3", + "@solana/subscribable": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-subscriptions-api": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-api/-/rpc-subscriptions-api-3.0.3.tgz", + "integrity": "sha512-MGgVK3PUS15qsjuhimpzGZrKD/CTTvS0mAlQ0Jw84zsr1RJVdQJK/F0igu07BVd172eTZL8d90NoAQ3dahW5pA==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/keys": "3.0.3", + "@solana/rpc-subscriptions-spec": "3.0.3", + "@solana/rpc-transformers": "3.0.3", + "@solana/rpc-types": "3.0.3", + "@solana/transaction-messages": "3.0.3", + "@solana/transactions": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-subscriptions-channel-websocket": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-channel-websocket/-/rpc-subscriptions-channel-websocket-3.0.3.tgz", + "integrity": "sha512-zUzUlb8Cwnw+SHlsLrSqyBRtOJKGc+FvSNJo/vWAkLShoV0wUDMPv7VvhTngJx3B/3ANfrOZ4i08i9QfYPAvpQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/functional": "3.0.3", + "@solana/rpc-subscriptions-spec": "3.0.3", + "@solana/subscribable": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3", + "ws": "^8.18.0" + } + }, + "node_modules/@solana/rpc-subscriptions-spec": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-subscriptions-spec/-/rpc-subscriptions-spec-3.0.3.tgz", + "integrity": "sha512-9KpQ32OBJWS85mn6q3gkM0AjQe1LKYlMU7gpJRrla/lvXxNLhI95tz5K6StctpUreVmRWTVkNamHE69uUQyY8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/promises": "3.0.3", + "@solana/rpc-spec-types": "3.0.3", + "@solana/subscribable": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-transformers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-transformers/-/rpc-transformers-3.0.3.tgz", + "integrity": "sha512-lzdaZM/dG3s19Tsk4mkJA5JBoS1eX9DnD7z62gkDwrwJDkDBzkAJT9aLcsYFfTmwTfIp6uU2UPgGYc97i1wezw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/functional": "3.0.3", + "@solana/nominal-types": "3.0.3", + "@solana/rpc-spec-types": "3.0.3", + "@solana/rpc-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-transport-http": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-transport-http/-/rpc-transport-http-3.0.3.tgz", + "integrity": "sha512-bIXFwr2LR5A97Z46dI661MJPbHnPfcShBjFzOS/8Rnr8P4ho3j/9EUtjDrsqoxGJT3SLWj5OlyXAlaDAvVTOUQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3", + "@solana/rpc-spec": "3.0.3", + "@solana/rpc-spec-types": "3.0.3", + "undici-types": "^7.15.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/rpc-types": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/rpc-types/-/rpc-types-3.0.3.tgz", + "integrity": "sha512-petWQ5xSny9UfmC3Qp2owyhNU0w9SyBww4+v7tSVyXMcCC9v6j/XsqTeimH1S0qQUllnv0/FY83ohFaxofmZ6Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/nominal-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/signers": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/signers/-/signers-3.0.3.tgz", + "integrity": "sha512-UwCd/uPYTZiwd283JKVyOWLLN5sIgMBqGDyUmNU3vo9hcmXKv5ZGm/9TvwMY2z35sXWuIOcj7etxJ8OoWc/ObQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/instructions": "3.0.3", + "@solana/keys": "3.0.3", + "@solana/nominal-types": "3.0.3", + "@solana/transaction-messages": "3.0.3", + "@solana/transactions": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/subscribable": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/subscribable/-/subscribable-3.0.3.tgz", + "integrity": "sha512-FJ27LKGHLQ5GGttPvTOLQDLrrOZEgvaJhB7yYaHAhPk25+p+erBaQpjePhfkMyUbL1FQbxn1SUJmS6jUuaPjlQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/sysvars": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/sysvars/-/sysvars-3.0.3.tgz", + "integrity": "sha512-GnHew+QeKCs2f9ow+20swEJMH4mDfJA/QhtPgOPTYQx/z69J4IieYJ7fZenSHnA//lJ45fVdNdmy1trypvPLBQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/accounts": "3.0.3", + "@solana/codecs": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/rpc-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/transaction-confirmation": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/transaction-confirmation/-/transaction-confirmation-3.0.3.tgz", + "integrity": "sha512-dXx0OLtR95LMuARgi2dDQlL1QYmk56DOou5q9wKymmeV3JTvfDExeWXnOgjRBBq/dEfj4ugN1aZuTaS18UirFw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/keys": "3.0.3", + "@solana/promises": "3.0.3", + "@solana/rpc": "3.0.3", + "@solana/rpc-subscriptions": "3.0.3", + "@solana/rpc-types": "3.0.3", + "@solana/transaction-messages": "3.0.3", + "@solana/transactions": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/transaction-messages": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/transaction-messages/-/transaction-messages-3.0.3.tgz", + "integrity": "sha512-s+6NWRnBhnnjFWV4x2tzBzoWa6e5LiIxIvJlWwVQBFkc8fMGY04w7jkFh0PM08t/QFKeXBEWkyBDa/TFYdkWug==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-data-structures": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/functional": "3.0.3", + "@solana/instructions": "3.0.3", + "@solana/nominal-types": "3.0.3", + "@solana/rpc-types": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/transactions": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@solana/transactions/-/transactions-3.0.3.tgz", + "integrity": "sha512-iMX+n9j4ON7H1nKlWEbMqMOpKYC6yVGxKKmWHT1KdLRG7v+03I4DnDeFoI+Zmw56FA+7Bbne8jwwX60Q1vk/MQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/addresses": "3.0.3", + "@solana/codecs-core": "3.0.3", + "@solana/codecs-data-structures": "3.0.3", + "@solana/codecs-numbers": "3.0.3", + "@solana/codecs-strings": "3.0.3", + "@solana/errors": "3.0.3", + "@solana/functional": "3.0.3", + "@solana/instructions": "3.0.3", + "@solana/keys": "3.0.3", + "@solana/nominal-types": "3.0.3", + "@solana/rpc-types": "3.0.3", + "@solana/transaction-messages": "3.0.3" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@solana/web3.js/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/helpers/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD", + "optional": true + }, + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "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, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "optional": true, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz", + "integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", + "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "devOptional": true, + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT", + "optional": true + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", + "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/type-utils": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.48.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", + "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", + "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.48.0", + "@typescript-eslint/types": "^8.48.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", + "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", + "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", + "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz", + "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", + "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.48.0", + "@typescript-eslint/tsconfig-utils": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/visitor-keys": "8.48.0", + "debug": "^4.3.4", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz", + "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.48.0", + "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", + "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.48.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz", + "integrity": "sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.5", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.47", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@wallet-standard/base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/base/-/base-1.1.0.tgz", + "integrity": "sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/wallet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/wallet/-/wallet-1.1.0.tgz", + "integrity": "sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@walletconnect/core": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/core/-/core-2.23.0.tgz", + "integrity": "sha512-W++xuXf+AsMPrBWn1It8GheIbCTp1ynTQP+aoFB86eUwyCtSiK7UQsn/+vJZdwElrn+Ptp2A0RqQx2onTMVHjQ==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/jsonrpc-ws-connection": "1.0.16", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.0", + "@walletconnect/utils": "2.23.0", + "@walletconnect/window-getters": "1.0.1", + "es-toolkit": "1.39.3", + "events": "3.3.0", + "uint8arrays": "3.1.1" + }, + "engines": { + "node": ">=18.20.8" + } + }, + "node_modules/@walletconnect/core/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/core/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/core/node_modules/unstorage": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.3.tgz", + "integrity": "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.4", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/environment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/environment/-/environment-1.0.1.tgz", + "integrity": "sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/events/-/events-1.0.1.tgz", + "integrity": "sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==", + "license": "MIT", + "dependencies": { + "keyvaluestorage-interface": "^1.0.0", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/heartbeat": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@walletconnect/heartbeat/-/heartbeat-1.2.2.tgz", + "integrity": "sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==", + "license": "MIT", + "dependencies": { + "@walletconnect/events": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/jsonrpc-http-connection": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-http-connection/-/jsonrpc-http-connection-1.0.8.tgz", + "integrity": "sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.1", + "cross-fetch": "^3.1.4", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/jsonrpc-provider": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-provider/-/jsonrpc-provider-1.0.14.tgz", + "integrity": "sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.8", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0" + } + }, + "node_modules/@walletconnect/jsonrpc-types": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-types/-/jsonrpc-types-1.0.4.tgz", + "integrity": "sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==", + "license": "MIT", + "dependencies": { + "events": "^3.3.0", + "keyvaluestorage-interface": "^1.0.0" + } + }, + "node_modules/@walletconnect/jsonrpc-utils": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-utils/-/jsonrpc-utils-1.0.8.tgz", + "integrity": "sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==", + "license": "MIT", + "dependencies": { + "@walletconnect/environment": "^1.0.1", + "@walletconnect/jsonrpc-types": "^1.0.3", + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/jsonrpc-ws-connection": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@walletconnect/jsonrpc-ws-connection/-/jsonrpc-ws-connection-1.0.16.tgz", + "integrity": "sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-utils": "^1.0.6", + "@walletconnect/safe-json": "^1.0.2", + "events": "^3.3.0", + "ws": "^7.5.1" + } + }, + "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@walletconnect/logger": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@walletconnect/logger/-/logger-3.0.0.tgz", + "integrity": "sha512-DDktPBFdmt5d7U3sbp4e3fQHNS1b6amsR8FmtOnt6L2SnV7VfcZr8VmAGL12zetAR+4fndegbREmX0P8Mw6eDg==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.2", + "pino": "10.0.0" + } + }, + "node_modules/@walletconnect/relay-api": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-api/-/relay-api-1.0.11.tgz", + "integrity": "sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==", + "license": "MIT", + "dependencies": { + "@walletconnect/jsonrpc-types": "^1.0.2" + } + }, + "node_modules/@walletconnect/relay-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@walletconnect/relay-auth/-/relay-auth-1.1.0.tgz", + "integrity": "sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.8.0", + "@noble/hashes": "1.7.0", + "@walletconnect/safe-json": "^1.0.1", + "@walletconnect/time": "^1.0.2", + "uint8arrays": "^3.0.0" + } + }, + "node_modules/@walletconnect/relay-auth/node_modules/@noble/curves": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.0.tgz", + "integrity": "sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/relay-auth/node_modules/@noble/hashes": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.0.tgz", + "integrity": "sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/safe-json": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/safe-json/-/safe-json-1.0.2.tgz", + "integrity": "sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/sign-client": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/sign-client/-/sign-client-2.23.0.tgz", + "integrity": "sha512-Nzf5x/LnQgC0Yjk0NmkT8kdrIMcScpALiFm9gP0n3CulL+dkf3HumqWzdoTmQSqGPxwHu/TNhGOaRKZLGQXSqw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/core": "2.23.0", + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/logger": "3.0.0", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.0", + "@walletconnect/utils": "2.23.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/time": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@walletconnect/time/-/time-1.0.2.tgz", + "integrity": "sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/types": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/types/-/types-2.23.0.tgz", + "integrity": "sha512-9ZEOJyx/kNVCRncDHh3Qr9eH7Ih1dXBFB4k1J8iEudkv3t4GhYpXhqIt2kNdQWluPb1BBB4wEuckAT96yKuA8g==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/heartbeat": "1.2.2", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/types/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/types/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/types/node_modules/unstorage": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.3.tgz", + "integrity": "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.4", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/universal-provider": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/universal-provider/-/universal-provider-2.23.0.tgz", + "integrity": "sha512-3ZEqAsbtCbk+CV0ZLpy7Qzc04KXEnrW4zCboZ+gkkC0ey4H62x9h23kBOIrU9qew6orjA7D5gg0ikRC2Up1lbw==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@walletconnect/events": "1.0.1", + "@walletconnect/jsonrpc-http-connection": "1.0.8", + "@walletconnect/jsonrpc-provider": "1.0.14", + "@walletconnect/jsonrpc-types": "1.0.4", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "@walletconnect/sign-client": "2.23.0", + "@walletconnect/types": "2.23.0", + "@walletconnect/utils": "2.23.0", + "es-toolkit": "1.39.3", + "events": "3.3.0" + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/universal-provider/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/universal-provider/node_modules/unstorage": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.3.tgz", + "integrity": "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.4", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils": { + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/@walletconnect/utils/-/utils-2.23.0.tgz", + "integrity": "sha512-bVyv4Hl+/wVGueZ6rEO0eYgDy5deSBA4JjpJHAMOdaNoYs05NTE1HymV2lfPQQHuqc7suYexo9jwuW7i3JLuAA==", + "license": "SEE LICENSE IN LICENSE.md", + "dependencies": { + "@msgpack/msgpack": "3.1.2", + "@noble/ciphers": "1.3.0", + "@noble/curves": "1.9.7", + "@noble/hashes": "1.8.0", + "@scure/base": "1.2.6", + "@walletconnect/jsonrpc-utils": "1.0.8", + "@walletconnect/keyvaluestorage": "1.1.1", + "@walletconnect/logger": "3.0.0", + "@walletconnect/relay-api": "1.0.11", + "@walletconnect/relay-auth": "1.1.0", + "@walletconnect/safe-json": "1.0.2", + "@walletconnect/time": "1.0.2", + "@walletconnect/types": "2.23.0", + "@walletconnect/window-getters": "1.0.1", + "@walletconnect/window-metadata": "1.0.1", + "blakejs": "1.2.1", + "bs58": "6.0.0", + "detect-browser": "5.3.0", + "ox": "0.9.3", + "uint8arrays": "3.1.1" + } + }, + "node_modules/@walletconnect/utils/node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" + }, + "node_modules/@walletconnect/utils/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/@walletconnect/keyvaluestorage": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@walletconnect/keyvaluestorage/-/keyvaluestorage-1.1.1.tgz", + "integrity": "sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==", + "license": "MIT", + "dependencies": { + "@walletconnect/safe-json": "^1.0.1", + "idb-keyval": "^6.2.1", + "unstorage": "^1.9.0" + }, + "peerDependencies": { + "@react-native-async-storage/async-storage": "1.x" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/abitype": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.0.tgz", + "integrity": "sha512-fD3ROjckUrWsybaSor2AdWxzA0e/DSyV2dA4aYd7bd8orHsoJjl09fOgKfUkTDfk0BsDGBf4NBgu/c7JoS2Npw==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/@walletconnect/utils/node_modules/ox": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.3.tgz", + "integrity": "sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.0.9", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@walletconnect/utils/node_modules/ox/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@walletconnect/utils/node_modules/unstorage": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.3.tgz", + "integrity": "sha512-i+JYyy0DoKmQ3FximTHbGadmIYb8JEpq7lxUjnjeB702bCPum0vzo6oy5Mfu0lpqISw7hCyMW2yj4nWC8bqJ3Q==", + "license": "MIT", + "dependencies": { + "anymatch": "^3.1.3", + "chokidar": "^4.0.3", + "destr": "^2.0.5", + "h3": "^1.15.4", + "lru-cache": "^10.4.3", + "node-fetch-native": "^1.6.7", + "ofetch": "^1.5.1", + "ufo": "^1.6.1" + }, + "peerDependencies": { + "@azure/app-configuration": "^1.8.0", + "@azure/cosmos": "^4.2.0", + "@azure/data-tables": "^13.3.0", + "@azure/identity": "^4.6.0", + "@azure/keyvault-secrets": "^4.9.0", + "@azure/storage-blob": "^12.26.0", + "@capacitor/preferences": "^6.0.3 || ^7.0.0", + "@deno/kv": ">=0.9.0", + "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0", + "@planetscale/database": "^1.19.0", + "@upstash/redis": "^1.34.3", + "@vercel/blob": ">=0.27.1", + "@vercel/functions": "^2.2.12 || ^3.0.0", + "@vercel/kv": "^1.0.1", + "aws4fetch": "^1.0.20", + "db0": ">=0.2.1", + "idb-keyval": "^6.2.1", + "ioredis": "^5.4.2", + "uploadthing": "^7.4.4" + }, + "peerDependenciesMeta": { + "@azure/app-configuration": { + "optional": true + }, + "@azure/cosmos": { + "optional": true + }, + "@azure/data-tables": { + "optional": true + }, + "@azure/identity": { + "optional": true + }, + "@azure/keyvault-secrets": { + "optional": true + }, + "@azure/storage-blob": { + "optional": true + }, + "@capacitor/preferences": { + "optional": true + }, + "@deno/kv": { + "optional": true + }, + "@netlify/blobs": { + "optional": true + }, + "@planetscale/database": { + "optional": true + }, + "@upstash/redis": { + "optional": true + }, + "@vercel/blob": { + "optional": true + }, + "@vercel/functions": { + "optional": true + }, + "@vercel/kv": { + "optional": true + }, + "aws4fetch": { + "optional": true + }, + "db0": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "ioredis": { + "optional": true + }, + "uploadthing": { + "optional": true + } + } + }, + "node_modules/@walletconnect/window-getters": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-getters/-/window-getters-1.0.1.tgz", + "integrity": "sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==", + "license": "MIT", + "dependencies": { + "tslib": "1.14.1" + } + }, + "node_modules/@walletconnect/window-metadata": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@walletconnect/window-metadata/-/window-metadata-1.0.1.tgz", + "integrity": "sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==", + "license": "MIT", + "dependencies": { + "@walletconnect/window-getters": "^1.0.1", + "tslib": "1.14.1" + } + }, + "node_modules/abitype": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.0.6.tgz", + "integrity": "sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3 >=3.22.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", + "license": "MIT" + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT", + "optional": true + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/axios-retry": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/axios-retry/-/axios-retry-4.5.0.tgz", + "integrity": "sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "is-retry-allowed": "^2.2.0" + }, + "peerDependencies": { + "axios": "0.x || 1.x" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.32", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.32.tgz", + "integrity": "sha512-OPz5aBThlyLFgxyhdwf/s2+8ab3OvT7AdTNvKHBwpXomIYeXqpUUuT8LrdtxZSsWJ4R4CU1un4XGh5Ez3nlTpw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, + "node_modules/big.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-6.2.2.tgz", + "integrity": "sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/bigjs" + } + }, + "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==", + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT", + "optional": true + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/borsh/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/borsh/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "optional": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.28.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.0.tgz", + "integrity": "sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==", + "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" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "baseline-browser-mapping": "^2.8.25", + "caniuse-lite": "^1.0.30001754", + "electron-to-chromium": "^1.5.249", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.1.4" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001757", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001757.tgz", + "integrity": "sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==", + "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" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/charenc": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", + "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/clsx": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", + "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/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, + "license": "MIT" + }, + "node_modules/cookie-es": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", + "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossws": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz", + "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==", + "license": "MIT", + "dependencies": { + "uncrypto": "^0.1.3" + } + }, + "node_modules/crypt": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", + "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": "*" + } + }, + "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==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/defu": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", + "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "license": "MIT" + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-browser": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz", + "integrity": "sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==", + "license": "MIT" + }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "optional": true, + "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.262", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.262.tgz", + "integrity": "sha512-NlAsMteRHek05jRUxUR0a5jpjYq9ykk6+kO0yRaMi5moe7u0fVIOeQ3Y30A8dIiWFBNUoQGi1ljb1i5VtS9WQQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==", + "license": "MIT" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "optional": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "optional": true, + "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/es-toolkit": { + "version": "1.39.3", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.39.3.tgz", + "integrity": "sha512-Qb/TCFCldgOy8lZ5uC7nLGdqJwSabkQiYQShmw4jyiPk1pZzaYWTwaYKYP7EgLccWYgZocMrtItrwh683voaww==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT", + "optional": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.39.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", + "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.1", + "@eslint/config-helpers": "^0.4.2", + "@eslint/core": "^0.17.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.39.1", + "@eslint/plugin-kit": "^0.4.1", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", + "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "hermes-parser": "^0.25.1", + "zod": "^3.25.0 || ^4.0.0", + "zod-validation-error": "^3.5.0 || ^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz", + "integrity": "sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ethers": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", + "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "22.7.5", + "aes-js": "4.0.0-beta.5", + "tslib": "2.7.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/curves": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", + "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", + "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "22.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", + "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/ethers/node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "license": "0BSD" + }, + "node_modules/ethers/node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "license": "MIT" + }, + "node_modules/ethers/node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "optional": true, + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT", + "optional": true + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "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" + } + ], + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "optional": true, + "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/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "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==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "optional": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.5.0.tgz", + "integrity": "sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/h3": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz", + "integrity": "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==", + "license": "MIT", + "dependencies": { + "cookie-es": "^1.2.2", + "crossws": "^0.3.5", + "defu": "^6.1.4", + "destr": "^2.0.5", + "iron-webcrypto": "^1.2.1", + "node-mock-http": "^1.0.2", + "radix3": "^1.1.2", + "ufo": "^1.6.1", + "uncrypto": "^0.1.3" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "optional": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hermes-estree": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", + "dev": true, + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", + "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.25.1" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/idb-keyval": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.1.tgz", + "integrity": "sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==", + "license": "Apache-2.0" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/iron-webcrypto": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz", + "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/brc-dd" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "license": "MIT", + "optional": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "optional": true, + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/isows": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz", + "integrity": "sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT", + "optional": true + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT", + "optional": true + }, + "node_modules/jayson/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "optional": true, + "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/jose": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/jose/-/jose-6.1.2.tgz", + "integrity": "sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC", + "optional": true + }, + "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, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/keyvaluestorage-interface": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/keyvaluestorage-interface/-/keyvaluestorage-interface-1.0.0.tgz", + "integrity": "sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==", + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lit": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lit/-/lit-3.3.0.tgz", + "integrity": "sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit/reactive-element": "^2.1.0", + "lit-element": "^4.2.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-element": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lit-element/-/lit-element-4.2.1.tgz", + "integrity": "sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==", + "license": "BSD-3-Clause", + "dependencies": { + "@lit-labs/ssr-dom-shim": "^1.4.0", + "@lit/reactive-element": "^2.1.0", + "lit-html": "^3.3.0" + } + }, + "node_modules/lit-html": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.3.1.tgz", + "integrity": "sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==", + "license": "BSD-3-Clause", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "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, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", + "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "charenc": "0.0.2", + "crypt": "0.0.2", + "is-buffer": "~1.1.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "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==", + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/multiformats": { + "version": "9.9.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz", + "integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==", + "license": "(Apache-2.0 AND MIT)" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch-native": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", + "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==", + "license": "MIT" + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-mock-http": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.3.tgz", + "integrity": "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==", + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.27", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", + "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ofetch": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", + "integrity": "sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==", + "license": "MIT", + "dependencies": { + "destr": "^2.0.5", + "node-fetch-native": "^1.6.7", + "ufo": "^1.6.1" + } + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ox": { + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.6.9.tgz", + "integrity": "sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@adraffy/ens-normalize": "^1.10.1", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0", + "@scure/bip32": "^1.5.0", + "@scure/bip39": "^1.4.0", + "abitype": "^1.0.6", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/ox/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "optional": true, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-10.0.0.tgz", + "integrity": "sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^2.0.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^5.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "slow-redact": "^0.3.0", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-2.0.0.tgz", + "integrity": "sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==", + "license": "MIT", + "dependencies": { + "split2": "^4.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "license": "MIT" + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "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" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.24.2", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz", + "integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==", + "license": "MIT", + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/process-warning": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-5.0.0.tgz", + "integrity": "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/proxy-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.1.tgz", + "integrity": "sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==", + "license": "MIT" + }, + "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==", + "license": "MIT", + "optional": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.3.tgz", + "integrity": "sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "license": "MIT" + }, + "node_modules/radix3": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz", + "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==", + "license": "MIT" + }, + "node_modules/react": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", + "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", + "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.0" + } + }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "license": "MIT", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/rollup": { + "version": "4.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", + "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", + "dev": true, + "license": "MIT", + "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.53.3", + "@rollup/rollup-android-arm64": "4.53.3", + "@rollup/rollup-darwin-arm64": "4.53.3", + "@rollup/rollup-darwin-x64": "4.53.3", + "@rollup/rollup-freebsd-arm64": "4.53.3", + "@rollup/rollup-freebsd-x64": "4.53.3", + "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", + "@rollup/rollup-linux-arm-musleabihf": "4.53.3", + "@rollup/rollup-linux-arm64-gnu": "4.53.3", + "@rollup/rollup-linux-arm64-musl": "4.53.3", + "@rollup/rollup-linux-loong64-gnu": "4.53.3", + "@rollup/rollup-linux-ppc64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-gnu": "4.53.3", + "@rollup/rollup-linux-riscv64-musl": "4.53.3", + "@rollup/rollup-linux-s390x-gnu": "4.53.3", + "@rollup/rollup-linux-x64-gnu": "4.53.3", + "@rollup/rollup-linux-x64-musl": "4.53.3", + "@rollup/rollup-openharmony-arm64": "4.53.3", + "@rollup/rollup-win32-arm64-msvc": "4.53.3", + "@rollup/rollup-win32-ia32-msvc": "4.53.3", + "@rollup/rollup-win32-x64-gnu": "4.53.3", + "@rollup/rollup-win32-x64-msvc": "4.53.3", + "fsevents": "~2.3.2" + } + }, + "node_modules/rpc-websockets": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.1.tgz", + "integrity": "sha512-bY6a+i/lEtBJ/mUxwsCTgevoV1P0foXTVA7UoThzaIWbM+3NDqorf8NBWs5DmqKTFeA1IoNzgvkWjFCPgnzUiQ==", + "license": "LGPL-3.0-only", + "optional": true, + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slow-redact": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/slow-redact/-/slow-redact-0.3.2.tgz", + "integrity": "sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==", + "license": "MIT" + }, + "node_modules/sonic-boom": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.2.0.tgz", + "integrity": "sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==", + "license": "MIT", + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "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==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==", + "optional": true + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "license": "MIT", + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.48.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz", + "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.48.0", + "@typescript-eslint/parser": "8.48.0", + "@typescript-eslint/typescript-estree": "8.48.0", + "@typescript-eslint/utils": "8.48.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "license": "MIT" + }, + "node_modules/uint8arrays": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.1.1.tgz", + "integrity": "sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==", + "license": "MIT", + "dependencies": { + "multiformats": "^9.4.2" + } + }, + "node_modules/uncrypto": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz", + "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "license": "MIT", + "optional": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz", + "integrity": "sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==", + "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" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "optional": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/valtio": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/valtio/-/valtio-2.1.7.tgz", + "integrity": "sha512-DwJhCDpujuQuKdJ2H84VbTjEJJteaSmqsuUltsfbfdbotVfNeTE4K/qc/Wi57I9x8/2ed4JNdjEna7O6PfavRg==", + "license": "MIT", + "dependencies": { + "proxy-compare": "^3.0.1" + }, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "react": ">=18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/viem": { + "version": "2.40.3", + "resolved": "https://registry.npmjs.org/viem/-/viem-2.40.3.tgz", + "integrity": "sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@noble/curves": "1.9.1", + "@noble/hashes": "1.8.0", + "@scure/bip32": "1.7.0", + "@scure/bip39": "1.6.0", + "abitype": "1.1.0", + "isows": "1.0.7", + "ox": "0.9.6", + "ws": "8.18.3" + }, + "peerDependencies": { + "typescript": ">=5.0.4" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/@adraffy/ens-normalize": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz", + "integrity": "sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==", + "license": "MIT" + }, + "node_modules/viem/node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/viem/node_modules/abitype": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.1.0.tgz", + "integrity": "sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/wevm" + }, + "peerDependencies": { + "typescript": ">=5.0.4", + "zod": "^3.22.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/viem/node_modules/ox": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/ox/-/ox-0.9.6.tgz", + "integrity": "sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/wevm" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "^1.11.0", + "@noble/ciphers": "^1.3.0", + "@noble/curves": "1.9.1", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "abitype": "^1.0.9", + "eventemitter3": "5.0.1" + }, + "peerDependencies": { + "typescript": ">=5.4.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", + "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "devOptional": true, + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-validation-error": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", + "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + } + }, + "node_modules/zustand": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.3.tgz", + "integrity": "sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json new file mode 100644 index 0000000..dea2210 --- /dev/null +++ b/frontend/package.json @@ -0,0 +1,32 @@ +{ + "name": "golden-bridge-frontend", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@reown/appkit": "1.8.14", + "@reown/appkit-adapter-ethers": "1.8.14", + "ethers": "6.15.0", + "react": "19.2.0", + "react-dom": "19.2.0" + }, + "devDependencies": { + "@eslint/js": "9.39.1", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "@vitejs/plugin-react": "5.1.1", + "eslint": "9.39.1", + "eslint-plugin-react-hooks": "7.0.1", + "eslint-plugin-react-refresh": "0.4.24", + "globals": "16.5.0", + "typescript": "5.9.3", + "typescript-eslint": "8.48.0", + "vite": "7.2.4" + } +} diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 0000000..6b6939e --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,39 @@ +import { Dashboard } from "./components/Dashboard/Dashboard"; +import { WalletConnect } from "./components/WalletConnect"; +import "./styles/globals.css"; + +function App() { + return ( +
+
+
+

+ Golden Bridge +

+
+ +
+ +
+ +
+
+ ); +} + +export default App; diff --git a/frontend/src/components/Admin/AdminPanel.module.css b/frontend/src/components/Admin/AdminPanel.module.css new file mode 100644 index 0000000..03b7eb0 --- /dev/null +++ b/frontend/src/components/Admin/AdminPanel.module.css @@ -0,0 +1,360 @@ +.adminPanel { + background: linear-gradient(135deg, rgba(245, 158, 11, 0.05) 0%, rgba(245, 158, 11, 0.02) 100%); + border: 2px solid var(--color-warning); + border-radius: var(--radius-xl); + padding: 1.5rem; + margin-bottom: 1.5rem; + position: relative; +} + +.adminPanel::before { + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: linear-gradient(90deg, var(--color-warning), var(--color-primary)); + border-radius: var(--radius-xl) var(--radius-xl) 0 0; +} + +.header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1rem; + padding-bottom: 1rem; + border-bottom: 1px solid rgba(245, 158, 11, 0.2); +} + +.headerLeft { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.warningIcon { + font-size: 1.5rem; + animation: pulse 2s ease-in-out infinite; +} + +@keyframes pulse { + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.6; + } +} + +.title { + font-size: 1.25rem; + font-weight: 700; + color: var(--color-warning); + margin: 0; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.badge { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.75rem; + background: var(--color-warning-light); + color: var(--color-warning); + border: 1px solid var(--color-warning); + border-radius: var(--radius-md); + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.collapseButton { + background: transparent; + border: 1px solid var(--color-warning); + color: var(--color-warning); + padding: 0.5rem 1rem; + border-radius: var(--radius-md); + font-size: 0.875rem; + cursor: pointer; + transition: all var(--transition-fast); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.collapseButton:hover { + background: var(--color-warning-light); +} + +.content { + display: grid; + gap: 1.5rem; +} + +.contentCollapsed { + display: none; +} + +/* Contract Section */ +.contractSection { + background: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + padding: 1.25rem; +} + +.contractHeader { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1rem; +} + +.contractTitle { + font-size: 1rem; + font-weight: 600; + color: var(--color-text); + display: flex; + align-items: center; + gap: 0.5rem; + margin: 0; +} + +.contractIcon { + font-size: 1.25rem; +} + +.statusBadge { + display: inline-flex; + align-items: center; + gap: 0.25rem; + padding: 0.25rem 0.5rem; + border-radius: var(--radius-sm); + font-size: 0.75rem; + font-weight: 500; +} + +.statusActive { + background: var(--color-success-light); + color: var(--color-success); +} + +.statusPaused { + background: var(--color-error-light); + color: var(--color-error); +} + +.statusUnknown { + background: rgba(156, 163, 175, 0.1); + color: var(--color-text-muted); +} + +/* Admin Actions */ +.adminActions { + display: flex; + flex-wrap: wrap; + gap: 0.75rem; +} + +.adminButton { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.625rem 1rem; + background: transparent; + border: 1px solid var(--color-border); + color: var(--color-text); + border-radius: var(--radius-md); + font-size: 0.875rem; + font-weight: 500; + cursor: pointer; + transition: all var(--transition-fast); +} + +.adminButton:hover:not(:disabled) { + background: var(--color-surface); + border-color: var(--color-warning); + color: var(--color-warning); +} + +.adminButton:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.adminButtonDanger { + border-color: var(--color-error); + color: var(--color-error); +} + +.adminButtonDanger:hover:not(:disabled) { + background: var(--color-error-light); + border-color: var(--color-error); + color: var(--color-error); +} + +.adminButtonSuccess { + border-color: var(--color-success); + color: var(--color-success); +} + +.adminButtonSuccess:hover:not(:disabled) { + background: var(--color-success-light); + border-color: var(--color-success); + color: var(--color-success); +} + +.adminButtonPrimary { + border-color: var(--color-primary); + color: var(--color-primary); +} + +.adminButtonPrimary:hover:not(:disabled) { + background: var(--color-primary-light); + border-color: var(--color-primary); + color: var(--color-primary); +} + +/* Form Section */ +.formSection { + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid var(--color-border); +} + +.formTitle { + font-size: 0.875rem; + font-weight: 600; + color: var(--color-text-muted); + margin-bottom: 0.75rem; +} + +.formRow { + display: flex; + gap: 0.75rem; + align-items: flex-end; +} + +.formInput { + flex: 1; +} + +/* Warning Box */ +.warningBox { + display: flex; + align-items: flex-start; + gap: 0.75rem; + padding: 1rem; + background: var(--color-warning-light); + border: 1px solid var(--color-warning); + border-radius: var(--radius-md); + margin-bottom: 1rem; +} + +.warningBoxIcon { + font-size: 1.25rem; + flex-shrink: 0; +} + +.warningBoxContent { + flex: 1; +} + +.warningBoxTitle { + font-weight: 600; + color: var(--color-warning); + margin-bottom: 0.25rem; +} + +.warningBoxText { + font-size: 0.875rem; + color: var(--color-text-muted); + line-height: 1.5; +} + +/* Locked State */ +.lockedPanel { + background: rgba(156, 163, 175, 0.05); + border: 2px dashed var(--color-border); + border-radius: var(--radius-xl); + padding: 2rem; + text-align: center; +} + +.lockedIcon { + font-size: 3rem; + margin-bottom: 1rem; + opacity: 0.5; +} + +.lockedTitle { + font-size: 1.125rem; + font-weight: 600; + color: var(--color-text-muted); + margin-bottom: 0.5rem; +} + +.lockedText { + font-size: 0.875rem; + color: var(--color-text-muted); + max-width: 400px; + margin: 0 auto; +} + +/* Loading State */ +.loadingState { + display: flex; + align-items: center; + justify-content: center; + gap: 0.75rem; + padding: 2rem; + color: var(--color-text-muted); +} + +.spinner { + width: 1.5rem; + height: 1.5rem; + border: 2px solid var(--color-border); + border-top-color: var(--color-warning); + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +/* Responsive */ +@media (max-width: 768px) { + .adminPanel { + padding: 1rem; + } + + .header { + flex-direction: column; + align-items: flex-start; + gap: 1rem; + } + + .adminActions { + flex-direction: column; + } + + .adminButton { + width: 100%; + justify-content: center; + } + + .formRow { + flex-direction: column; + } +} \ No newline at end of file diff --git a/frontend/src/components/Admin/AdminPanel.tsx b/frontend/src/components/Admin/AdminPanel.tsx new file mode 100644 index 0000000..a00f527 --- /dev/null +++ b/frontend/src/components/Admin/AdminPanel.tsx @@ -0,0 +1,565 @@ +import React, { useCallback, useEffect, useState } from "react"; +import { useAdmin } from "../../hooks/useAdmin"; +import { useGoldToken } from "../../hooks/useGoldToken"; +import { useLotterie } from "../../hooks/useLotterie"; +import { useTokenBridge } from "../../hooks/useTokenBridge"; +import { Alert } from "../ui/Alert"; +import { Button } from "../ui/Button"; +import { Input } from "../ui/Input"; +import { InfoIcon, Tooltip } from "../ui/Tooltip"; +import styles from "./AdminPanel.module.css"; + +interface ContractStatus { + isPaused: boolean; + isLoading: boolean; +} + +export const AdminPanel: React.FC = () => { + const { + loading: adminLoading, + isGoldTokenOwner, + isLotterieOwner, + isTokenBridgeOwner, + isAnyOwner, + } = useAdmin(); + + const { + loading: goldTokenLoading, + pause: pauseGoldToken, + unpause: unpauseGoldToken, + setFeesAddress, + setLotterieAddress, + } = useGoldToken(); + + const { loading: lotterieLoading, randomDraw } = useLotterie(); + + const { + loading: bridgeLoading, + pause: pauseBridge, + unpause: unpauseBridge, + paused: getBridgePaused, + setWhitelistedChain, + setWhitelistedSender, + } = useTokenBridge(); + + const [isCollapsed, setIsCollapsed] = useState(false); + const [successMsg, setSuccessMsg] = useState(null); + const [errorMsg, setErrorMsg] = useState(null); + + // Contract statuses + const [bridgeStatus, setBridgeStatus] = useState({ + isPaused: false, + isLoading: true, + }); + + // Form states + const [feesAddressInput, setFeesAddressInput] = useState(""); + const [lotterieAddressInput, setLotterieAddressInput] = useState(""); + const [whitelistChainSelector, setWhitelistChainSelector] = useState(""); + const [whitelistChainEnabled, setWhitelistChainEnabled] = useState(true); + const [whitelistSenderAddress, setWhitelistSenderAddress] = useState(""); + const [whitelistSenderEnabled, setWhitelistSenderEnabled] = useState(true); + + // Fetch bridge status + useEffect(() => { + if (!isTokenBridgeOwner) return; + + let isMounted = true; + + const fetchStatus = async () => { + try { + const isPaused = await getBridgePaused(); + if (isMounted) { + setBridgeStatus({ isPaused, isLoading: false }); + } + } catch (err) { + console.error("Failed to fetch bridge status:", err); + if (isMounted) { + setBridgeStatus((prev) => ({ ...prev, isLoading: false })); + } + } + }; + + fetchStatus(); + + return () => { + isMounted = false; + }; + }, [isTokenBridgeOwner, getBridgePaused]); + + const refreshBridgeStatus = useCallback(async () => { + try { + const isPaused = await getBridgePaused(); + setBridgeStatus({ isPaused, isLoading: false }); + } catch (err) { + console.error("Failed to fetch bridge status:", err); + } + }, [getBridgePaused]); + + // Handlers + const handlePauseGoldToken = async () => { + try { + setErrorMsg(null); + await pauseGoldToken(); + setSuccessMsg("GoldToken contract paused successfully!"); + } catch (err: any) { + setErrorMsg(err.message || "Failed to pause GoldToken"); + } + }; + + const handleUnpauseGoldToken = async () => { + try { + setErrorMsg(null); + await unpauseGoldToken(); + setSuccessMsg("GoldToken contract unpaused successfully!"); + } catch (err: any) { + setErrorMsg(err.message || "Failed to unpause GoldToken"); + } + }; + + const handleSetFeesAddress = async () => { + if (!feesAddressInput) return; + try { + setErrorMsg(null); + await setFeesAddress(feesAddressInput); + setSuccessMsg("Fees address updated successfully!"); + setFeesAddressInput(""); + } catch (err: any) { + setErrorMsg(err.message || "Failed to set fees address"); + } + }; + + const handleSetLotterieAddress = async () => { + if (!lotterieAddressInput) return; + try { + setErrorMsg(null); + await setLotterieAddress(lotterieAddressInput); + setSuccessMsg("Lotterie address updated successfully!"); + setLotterieAddressInput(""); + } catch (err: any) { + setErrorMsg(err.message || "Failed to set lotterie address"); + } + }; + + const handleRandomDraw = async () => { + try { + setErrorMsg(null); + await randomDraw(); + setSuccessMsg("Random draw initiated! Waiting for VRF callback..."); + } catch (err: any) { + setErrorMsg(err.message || "Failed to initiate random draw"); + } + }; + + const handlePauseBridge = async () => { + try { + setErrorMsg(null); + await pauseBridge(); + setSuccessMsg("TokenBridge paused successfully!"); + refreshBridgeStatus(); + } catch (err: any) { + setErrorMsg(err.message || "Failed to pause bridge"); + } + }; + + const handleUnpauseBridge = async () => { + try { + setErrorMsg(null); + await unpauseBridge(); + setSuccessMsg("TokenBridge unpaused successfully!"); + refreshBridgeStatus(); + } catch (err: any) { + setErrorMsg(err.message || "Failed to unpause bridge"); + } + }; + + const handleSetWhitelistedChain = async () => { + if (!whitelistChainSelector) return; + try { + setErrorMsg(null); + // Default CCIP extra args (empty for basic config) + const ccipExtraArgs = "0x"; + await setWhitelistedChain( + BigInt(whitelistChainSelector), + whitelistChainEnabled, + ccipExtraArgs + ); + setSuccessMsg( + `Chain ${whitelistChainSelector} ${ + whitelistChainEnabled ? "whitelisted" : "removed from whitelist" + }!` + ); + setWhitelistChainSelector(""); + } catch (err: any) { + setErrorMsg(err.message || "Failed to set whitelisted chain"); + } + }; + + const handleSetWhitelistedSender = async () => { + if (!whitelistSenderAddress) return; + try { + setErrorMsg(null); + await setWhitelistedSender( + whitelistSenderAddress, + whitelistSenderEnabled + ); + setSuccessMsg( + `Sender ${whitelistSenderAddress.substring(0, 10)}... ${ + whitelistSenderEnabled ? "whitelisted" : "removed from whitelist" + }!` + ); + setWhitelistSenderAddress(""); + } catch (err: any) { + setErrorMsg(err.message || "Failed to set whitelisted sender"); + } + }; + + // Loading state + if (adminLoading) { + return ( +
+
+
+ Checking admin permissions... +
+
+ ); + } + + // Not an owner - show locked state + if (!isAnyOwner) { + return ( +
+
🔒
+

Admin Access Required

+

+ This section is only accessible to contract owners. Connect with an + owner wallet to access admin functions. +

+
+ ); + } + + return ( +
+ {/* Header */} +
+
+ ⚠️ +

+ Admin Panel + +

+ + 🔑 Owner Access + +
+ +
+ + {/* Alerts */} + {successMsg && ( + setSuccessMsg(null)} + > + {successMsg} + + )} + {errorMsg && ( + setErrorMsg(null)}> + {errorMsg} + + )} + + {/* Content */} +
+ {/* Warning Box */} +
+ ⚠️ +
+
Caution Required
+
+ Admin actions are irreversible and affect all users. Pausing + contracts will prevent all user interactions. Ensure you + understand the implications before proceeding. +
+
+
+ + {/* GoldToken Admin Section */} + {isGoldTokenOwner && ( +
+
+

+ 🪙 + GoldToken Administration +

+ + + ✓ Owner + + +
+ +
+ + + + + + +
+ + {/* Set Fees Address */} +
+
Update Fees Address
+
+
+ setFeesAddressInput(e.target.value)} + /> +
+ +
+
+ + {/* Set Lotterie Address */} +
+
Update Lotterie Address
+
+
+ setLotterieAddressInput(e.target.value)} + /> +
+ +
+
+
+ )} + + {/* Lotterie Admin Section */} + {isLotterieOwner && ( +
+
+

+ 🎰 + Lotterie Administration +

+ + + ✓ Owner + + +
+ +
+ + + +
+
+ )} + + {/* TokenBridge Admin Section */} + {isTokenBridgeOwner && ( +
+
+

+ 🌉 + TokenBridge Administration +

+
+ + + ✓ Owner + + + {bridgeStatus.isLoading ? ( + + Loading... + + ) : ( + + {bridgeStatus.isPaused ? "⏸️ Paused" : "✅ Active"} + + )} +
+
+ +
+ + + + + + +
+ + {/* Whitelist Chain */} +
+
+ Whitelist Chain + +
+
+
+ setWhitelistChainSelector(e.target.value)} + /> +
+ + +
+
+ + {/* Whitelist Sender */} +
+
+ Whitelist Sender + +
+
+
+ setWhitelistSenderAddress(e.target.value)} + /> +
+ + +
+
+
+ )} +
+
+ ); +}; diff --git a/frontend/src/components/Admin/index.ts b/frontend/src/components/Admin/index.ts new file mode 100644 index 0000000..a69970e --- /dev/null +++ b/frontend/src/components/Admin/index.ts @@ -0,0 +1 @@ +export * from "./AdminPanel"; diff --git a/frontend/src/components/Dashboard/Dashboard.module.css b/frontend/src/components/Dashboard/Dashboard.module.css new file mode 100644 index 0000000..320d566 --- /dev/null +++ b/frontend/src/components/Dashboard/Dashboard.module.css @@ -0,0 +1,269 @@ +.container { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; +} + +.header { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 1.5rem; + flex-wrap: wrap; + gap: 1rem; +} + +.headerLeft { + flex: 1; +} + +.headerRight { + display: flex; + align-items: center; + gap: 1rem; +} + +.title { + font-size: 2rem; + font-weight: 700; + color: var(--color-primary); + margin-bottom: 0.5rem; + display: flex; + align-items: center; + gap: 0.5rem; +} + +.subtitle { + color: var(--color-text-muted); + font-size: 1.125rem; +} + +/* Progress Section */ +.progressSection { + margin-bottom: 1.5rem; +} + +/* Onboarding Section */ +.onboardingSection { + margin-bottom: 1.5rem; +} + +/* Admin Section */ +.adminSection { + margin-bottom: 1.5rem; +} + +.dismissOnboarding { + display: inline-block; + margin-top: 1rem; + padding: 0.25rem 0.5rem; + background: transparent; + border: none; + color: var(--color-text-muted); + font-size: 0.75rem; + cursor: pointer; + text-decoration: underline; +} + +.dismissOnboarding:hover { + color: var(--color-primary); +} + +.grid { + display: grid; + grid-template-columns: 1fr; + gap: 1.5rem; +} + +@media (min-width: 1024px) { + .grid { + grid-template-columns: 1.5fr 1fr; + } +} + +.mainColumn { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.sideColumn { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +.sideItem { + flex: 1; +} + +/* Welcome Screen */ +.welcome { + text-align: center; + padding: 3rem 2rem; + background-color: var(--color-surface); + border-radius: var(--radius-lg); + border: 1px solid var(--color-border); + margin-top: 2rem; +} + +.welcomeHeader { + margin-bottom: 2rem; +} + +.valueProps { + max-width: 500px; + margin: 0 auto 2rem auto; +} + +.features { + display: grid; + grid-template-columns: 1fr; + gap: 1.5rem; + margin-top: 2rem; + margin-bottom: 2rem; + text-align: left; +} + +@media (min-width: 768px) { + .features { + grid-template-columns: repeat(3, 1fr); + } +} + +.feature { + padding: 1.5rem; + background-color: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); + transition: border-color 0.2s ease, transform 0.2s ease; +} + +.feature:hover { + border-color: var(--color-primary); + transform: translateY(-2px); +} + +.featureIcon { + font-size: 2rem; + display: block; + margin-bottom: 0.75rem; +} + +.feature h3 { + color: var(--color-primary); + margin-bottom: 0.5rem; + font-size: 1.125rem; +} + +.feature p { + color: var(--color-text-muted); + font-size: 0.875rem; + margin-bottom: 0.75rem; + line-height: 1.5; +} + +/* Technology Stack */ +.techStack { + margin-top: 2rem; + padding: 1.5rem; + background-color: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); + border: 1px solid var(--color-border); +} + +.techTitle { + font-size: 1rem; + font-weight: 600; + color: var(--color-text); + margin-bottom: 1rem; + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.techItems { + display: flex; + justify-content: center; + gap: 2rem; + flex-wrap: wrap; +} + +.techItem { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1rem; + background-color: rgba(255, 215, 0, 0.05); + border: 1px solid rgba(255, 215, 0, 0.2); + border-radius: var(--radius-md); + cursor: help; + transition: all 0.2s ease; +} + +.techItem:hover { + background-color: rgba(255, 215, 0, 0.1); + border-color: var(--color-primary); +} + +.techItem span:first-child { + font-size: 1.5rem; +} + +.techItem span:last-child { + font-size: 0.75rem; + color: var(--color-text-muted); + text-transform: uppercase; + letter-spacing: 0.05em; +} + +/* Connect CTA */ +.connectCta { + margin-top: 2rem; + padding-top: 2rem; + border-top: 1px solid var(--color-border); +} + +.ctaText { + color: var(--color-text-muted); + margin-bottom: 1rem; + font-size: 0.875rem; +} + +/* Footer */ +.footer { + margin-top: 3rem; + padding-top: 1.5rem; + border-top: 1px solid var(--color-border); +} + +.footerContent { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 1rem; +} + +.footerText { + color: var(--color-text-muted); + font-size: 0.875rem; +} + +.footerLinks { + display: flex; + gap: 1rem; +} + +.footerLink { + color: var(--color-text-muted); + font-size: 0.875rem; + text-decoration: none; + transition: color 0.2s ease; +} + +.footerLink:hover { + color: var(--color-primary); + text-decoration: none; +} \ No newline at end of file diff --git a/frontend/src/components/Dashboard/Dashboard.tsx b/frontend/src/components/Dashboard/Dashboard.tsx new file mode 100644 index 0000000..84a73b7 --- /dev/null +++ b/frontend/src/components/Dashboard/Dashboard.tsx @@ -0,0 +1,354 @@ +import { useAppKitAccount } from "@reown/appkit/react"; +import { formatEther } from "ethers"; +import React, { useEffect, useMemo, useState } from "react"; +import { useAdmin } from "../../hooks/useAdmin"; +import { useGoldToken } from "../../hooks/useGoldToken"; +import { useNetwork } from "../../hooks/useNetwork"; +import { AdminPanel } from "../Admin/AdminPanel"; +import { GoldTokenCard } from "../GoldToken/GoldTokenCard"; +import { LotterieCard } from "../Lotterie/LotterieCard"; +import { NetworkSwitcher } from "../NetworkSwitcher"; +import { TokenBridgeCard } from "../TokenBridge/TokenBridgeCard"; +import { Alert } from "../ui/Alert"; +import { Badge } from "../ui/Badge"; +import { FeatureItem, HighlightBox, InfoCard } from "../ui/InfoCard"; +import { CompactStepIndicator, Step } from "../ui/StepIndicator"; +import { InfoIcon, Tooltip } from "../ui/Tooltip"; +import styles from "./Dashboard.module.css"; + +// Define the user journey steps +const JOURNEY_STEPS: Step[] = [ + { + id: "connect", + label: "Connect Wallet", + icon: "🔗", + description: "Connect your Web3 wallet to get started", + }, + { + id: "mint", + label: "Mint GLD", + icon: "🪙", + description: "Convert ETH to gold-backed GLD tokens", + }, + { + id: "lottery", + label: "Lottery", + icon: "🎰", + description: "Participate in daily draws with your GLD", + }, + { + id: "bridge", + label: "Bridge", + icon: "🌉", + description: "Transfer GLD across chains (optional)", + }, +]; + +export const Dashboard: React.FC = () => { + const { isConnected, address } = useAppKitAccount(); + const { isSupportedNetwork } = useNetwork(); + const { balanceOf } = useGoldToken(); + const { isAnyOwner } = useAdmin(); + + const [balance, setBalance] = useState("0"); + const [showOnboarding, setShowOnboarding] = useState(true); + + // Fetch user balance to determine step progress + useEffect(() => { + const fetchBalance = async () => { + if (isConnected && address) { + try { + const bal = await balanceOf(address); + setBalance(formatEther(bal)); + } catch (err) { + console.error("Error fetching balance:", err); + } + } + }; + fetchBalance(); + }, [isConnected, address, balanceOf]); + + // Compute step progress based on user state (using useMemo to avoid cascading renders) + const { currentStep, completedSteps } = useMemo(() => { + const completed: string[] = []; + let current = "connect"; + + if (isConnected) { + completed.push("connect"); + current = "mint"; + + if (parseFloat(balance) > 0) { + completed.push("mint"); + current = "lottery"; + + if (parseFloat(balance) >= 1) { + completed.push("lottery"); + current = "bridge"; + } + } + } + + return { currentStep: current, completedSteps: completed }; + }, [isConnected, balance]); + + // Welcome screen for non-connected users + if (!isConnected) { + return ( +
+
+
+

🏆 Welcome to Golden Bridge

+

+ Your gateway to gold-backed tokens on the blockchain +

+
+ + {/* Value Proposition */} +
+ + 1 GLD = 1 gram of gold +
+ Hold tokenized gold backed by real-time Chainlink price feeds +
+
+ + {/* Feature Cards */} +
+
+ 🪙 +

Gold Token

+

+ Mint GLD tokens backed by real-time gold prices using Chainlink + Price Feeds. +

+ Chainlink Powered +
+
+ 🎰 +

Daily Lottery

+

+ Win rewards from transaction fees in provably fair daily draws. +

+ VRF Secured +
+
+ 🌉 +

Cross-Chain Bridge

+

Seamlessly transfer GLD between Ethereum and BSC networks.

+ CCIP Enabled +
+
+ + {/* How It Works */} + + + + + + + + {/* Technology Stack */} +
+

+ Powered by Chainlink + +

+
+ +
+ 📊 + Price Feeds +
+
+ +
+ 🎲 + VRF +
+
+ +
+ 🔗 + CCIP +
+
+
+
+ + {/* Connect CTA */} +
+

+ Connect your wallet to start your golden journey +

+ +
+
+
+ ); + } + + return ( +
+ {/* Header with Step Indicator */} +
+
+

🏆 Dashboard

+

Manage your Golden Bridge assets

+
+
+ +
+
+ + {/* Progress Indicator */} +
+ +
+ + {/* Network Warning */} + {!isSupportedNetwork() && ( + + Please switch to Sepolia Testnet or BSC Testnet to use the + application. + + )} + + {/* Onboarding Tips */} + {showOnboarding && completedSteps.length < 3 && ( +
+ + {currentStep === "mint" && ( + <> +

+ Next Step: Mint your first GLD tokens! +

+ + Enter an ETH amount in the Gold Token card below and click + "Mint GLD" to convert your ETH to gold-backed tokens. + + + )} + {currentStep === "lottery" && ( + <> +

+ Great progress! You now own GLD tokens. +

+ + {parseFloat(balance) >= 1 ? ( + <> + ✅ You're eligible for the lottery! Check the Lottery card + to see your pending rewards. + + ) : ( + <> + Hold at least 1 GLD to become eligible for daily lottery + draws. You currently have {parseFloat(balance).toFixed(4)}{" "} + GLD. + + )} + + + )} + {currentStep === "bridge" && ( + <> +

+ You're all set! You can now bridge your GLD + to other chains. +

+ + Use the Bridge card to transfer GLD between Ethereum and BSC. + This is optional but useful for accessing different DeFi + ecosystems. + + + )} + +
+
+ )} + + {/* Admin Panel - Only visible to owners */} + {isAnyOwner && ( +
+ +
+ )} + + {/* Main Content Grid */} +
+
+ +
+
+
+ +
+
+ +
+
+
+ + {/* Footer Info */} +
+
+ + Golden Bridge - A Chainlink-powered DeFi showcase + + +
+
+
+ ); +}; diff --git a/frontend/src/components/GoldToken/GoldTokenCard.module.css b/frontend/src/components/GoldToken/GoldTokenCard.module.css new file mode 100644 index 0000000..5139218 --- /dev/null +++ b/frontend/src/components/GoldToken/GoldTokenCard.module.css @@ -0,0 +1,165 @@ +.card { + height: 100%; +} + +.headerTitle { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.statsGrid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; + margin-bottom: 1.5rem; + padding: 1rem; + background-color: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); +} + +.statItem { + display: flex; + flex-direction: column; + align-items: center; + text-align: center; +} + +.statLabel { + font-size: 0.875rem; + color: var(--color-text-muted); + margin-bottom: 0.25rem; + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.statValue { + font-size: 1.25rem; + font-weight: 700; + color: var(--color-primary); +} + +.tabs { + display: flex; + border-bottom: 1px solid var(--color-border); + margin-bottom: 1.5rem; +} + +.tab { + flex: 1; + padding: 0.75rem; + background: transparent; + border: none; + border-bottom: 2px solid transparent; + color: var(--color-text-muted); + font-weight: 500; + transition: all 0.2s; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; +} + +.tab:hover { + color: var(--color-text); + background-color: rgba(255, 255, 255, 0.02); +} + +.activeTab { + color: var(--color-primary); + border-bottom-color: var(--color-primary); +} + +.tabIcon { + font-size: 0.875rem; +} + +.tabContent { + animation: fadeIn 0.3s ease; +} + +.inputLabel { + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.calculationBox { + background-color: rgba(255, 215, 0, 0.05); + border: 1px solid rgba(255, 215, 0, 0.2); + border-radius: var(--radius-md); + padding: 0.75rem 1rem; + margin-bottom: 0.5rem; +} + +.calcRow { + display: flex; + justify-content: space-between; + align-items: center; + font-size: 0.875rem; + padding: 0.25rem 0; +} + +.calcRow span:first-child { + color: var(--color-text-muted); + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.calcValue { + font-weight: 600; + color: var(--color-primary); +} + +.calcFee { + color: var(--color-warning); + font-size: 0.8125rem; +} + +.estimation { + display: flex; + justify-content: space-between; + font-size: 0.875rem; + padding: 0.5rem; + background-color: rgba(255, 215, 0, 0.05); + border-radius: var(--radius-sm); + margin-bottom: 0.5rem; +} + +.feeInfo { + font-size: 0.75rem; + color: var(--color-text-muted); + text-align: center; + margin-bottom: 1rem; +} + +.toggleEducation { + display: block; + width: 100%; + margin-top: 1.5rem; + padding: 0.5rem; + background: transparent; + border: 1px dashed var(--color-border); + border-radius: var(--radius-md); + color: var(--color-text-muted); + font-size: 0.8125rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.toggleEducation:hover { + border-color: var(--color-primary); + color: var(--color-primary); +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/GoldToken/GoldTokenCard.tsx b/frontend/src/components/GoldToken/GoldTokenCard.tsx new file mode 100644 index 0000000..b1cb75b --- /dev/null +++ b/frontend/src/components/GoldToken/GoldTokenCard.tsx @@ -0,0 +1,505 @@ +import { formatEther, formatUnits, parseEther } from "ethers"; +import React, { useEffect, useState } from "react"; +import { useGoldToken } from "../../hooks/useGoldToken"; +import { Alert } from "../ui/Alert"; +import { Badge } from "../ui/Badge"; +import { Button } from "../ui/Button"; +import { Card } from "../ui/Card"; +import { FeatureItem, HighlightBox, InfoCard } from "../ui/InfoCard"; +import { Input } from "../ui/Input"; +import { InfoIcon, Tooltip } from "../ui/Tooltip"; +import styles from "./GoldTokenCard.module.css"; + +export const GoldTokenCard: React.FC = () => { + const { + loading, + error, + isConnected, + address, + mint, + burn, + transfer, + balanceOf, + getGoldPriceInEth, + getFees, + } = useGoldToken(); + + const [balance, setBalance] = useState("0"); + const [goldPrice, setGoldPrice] = useState("0"); + const [fees, setFees] = useState("0"); + const [mintAmount, setMintAmount] = useState(""); + const [burnAmount, setBurnAmount] = useState(""); + const [transferTo, setTransferTo] = useState(""); + const [transferAmount, setTransferAmount] = useState(""); + const [activeTab, setActiveTab] = useState<"mint" | "burn" | "transfer">( + "mint" + ); + const [successMsg, setSuccessMsg] = useState(null); + const [showEducation, setShowEducation] = useState(true); + + const fetchData = async () => { + try { + if (address) { + const bal = await balanceOf(address); + setBalance(formatEther(bal)); + } + const price = await getGoldPriceInEth(); + setGoldPrice(formatUnits(price, 8)); + + const fee = await getFees(); + setFees(fee.toString()); + } catch (err) { + console.error("Error fetching data:", err); + } + }; + + useEffect(() => { + if (isConnected && address) { + fetchData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isConnected, address]); + + const handleMint = async () => { + try { + setSuccessMsg(null); + if (!mintAmount) return; + await mint(parseEther(mintAmount)); + setSuccessMsg(`Successfully minted GLD with ${mintAmount} ETH!`); + setMintAmount(""); + fetchData(); + } catch (err) { + console.error(err); + } + }; + + const handleBurn = async () => { + try { + setSuccessMsg(null); + if (!burnAmount) return; + await burn(parseEther(burnAmount)); + setSuccessMsg(`Successfully burned ${burnAmount} GLD!`); + setBurnAmount(""); + fetchData(); + } catch (err) { + console.error(err); + } + }; + + const handleTransfer = async () => { + try { + setSuccessMsg(null); + if (!transferTo || !transferAmount) return; + await transfer(transferTo, parseEther(transferAmount)); + setSuccessMsg( + `Successfully transferred ${transferAmount} GLD to ${transferTo.substring( + 0, + 6 + )}...${transferTo.substring(38)}!` + ); + setTransferTo(""); + setTransferAmount(""); + fetchData(); + } catch (err) { + console.error(err); + } + }; + + const estimatedGld = + mintAmount && goldPrice && parseFloat(goldPrice) > 0 + ? (parseFloat(mintAmount) / parseFloat(goldPrice)).toFixed(4) + : "0"; + + const feeAmount = + mintAmount && parseFloat(mintAmount) > 0 + ? ((parseFloat(mintAmount) * parseFloat(fees)) / 100).toFixed(6) + : "0"; + + const isEligible = parseFloat(balance) >= 1; + + return ( + + + 🪙 Gold Token (GLD) + + 1 GLD = 1 gram of gold +
+ GLD is an ERC-20 token backed by real-time gold prices from + Chainlink Price Feeds. + + } + size="md" + /> + + } + subtitle="Mint, burn, and transfer gold-backed tokens" + action={ + + + {isEligible ? "✓ Lottery Eligible" : "Not Eligible"} + + + } + /> + + {/* Stats Section */} +
+
+ + Your Balance + + + + {parseFloat(balance).toFixed(4)} GLD + +
+
+ + Gold Price + + Current price of 1 gram of gold in ETH. +
+ Powered by Chainlink Price Feeds +
+ } + size="sm" + /> + + + {parseFloat(goldPrice).toFixed(6)} ETH + +
+
+ + {error && ( + {}}> + {error} + + )} + + {successMsg && ( + setSuccessMsg(null)} + > + {successMsg} + + )} + + {/* Tabs */} +
+ + + +
+ +
+ {/* MINT TAB */} + {activeTab === "mint" && ( +
+ {showEducation && ( + +

+ Minting converts your ETH into GLD tokens + at the current gold price. Each GLD represents 1 gram of + gold. +

+ + How it works: +
+ 1. Enter the amount of ETH you want to spend +
+ 2. The contract calculates how much GLD you'll receive based + on real-time gold prices +
+ 3. A 5% fee is applied (split between lottery pool and + treasury) +
+ +
+ )} + + + Amount (ETH) + + + } + placeholder="0.0" + value={mintAmount} + onChange={(e) => setMintAmount(e.target.value)} + type="number" + min="0" + step="0.0001" + rightElement="ETH" + /> + +
+
+ You'll receive (estimated): + {estimatedGld} GLD +
+
+ + Fee ({fees}%): + + Fee breakdown: +
• 2.5% → Lottery Pool 🎰 +
• 2.5% → Treasury 🏦 +
+ } + size="sm" + /> + + {feeAmount} ETH +
+
+ + +
+ )} + + {/* BURN TAB */} + {activeTab === "burn" && ( +
+ {showEducation && ( + +

+ Burning destroys your GLD tokens, removing + them from circulation. This is how you exit your gold + position. +

+ + ⚠️ Important: Burning is irreversible. Once + burned, tokens cannot be recovered. A 5% fee applies to burn + operations. + + +
+ )} + + + Amount (GLD) + + + } + placeholder="0.0" + value={burnAmount} + onChange={(e) => setBurnAmount(e.target.value)} + type="number" + min="0" + step="0.0001" + rightElement="GLD" + /> + +
+
+ Your balance: + + {parseFloat(balance).toFixed(4)} GLD + +
+
+ Fee ({fees}%): + + {burnAmount + ? ( + (parseFloat(burnAmount) * parseFloat(fees)) / + 100 + ).toFixed(4) + : "0"}{" "} + GLD + +
+
+ + +
+ )} + + {/* TRANSFER TAB */} + {activeTab === "transfer" && ( +
+ {showEducation && ( + +

+ Send GLD tokens to another wallet address. Transfers are + instant and recorded on the blockchain. +

+ + 💡 Tip: Double-check the recipient address + before sending. Blockchain transactions cannot be reversed! + + +
+ )} + + + Recipient Address + + + } + placeholder="0x..." + value={transferTo} + onChange={(e) => setTransferTo(e.target.value)} + /> + setTransferAmount(e.target.value)} + type="number" + min="0" + step="0.0001" + rightElement="GLD" + /> + +
+
+ Your balance: + + {parseFloat(balance).toFixed(4)} GLD + +
+
+ Remaining after transfer: + + {transferAmount + ? Math.max( + 0, + parseFloat(balance) - parseFloat(transferAmount) + ).toFixed(4) + : parseFloat(balance).toFixed(4)}{" "} + GLD + +
+
+ + +
+ )} +
+ + {/* Toggle Education */} + +
+
+ ); +}; diff --git a/frontend/src/components/Lotterie/LotterieCard.module.css b/frontend/src/components/Lotterie/LotterieCard.module.css new file mode 100644 index 0000000..055660d --- /dev/null +++ b/frontend/src/components/Lotterie/LotterieCard.module.css @@ -0,0 +1,108 @@ +.card { + height: 100%; +} + +.headerTitle { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.jackpotSection { + display: flex; + flex-direction: column; + align-items: center; + padding: 2rem; + background: linear-gradient(135deg, rgba(255, 215, 0, 0.1) 0%, rgba(255, 215, 0, 0.05) 100%); + border-radius: var(--radius-md); + border: 1px solid rgba(255, 215, 0, 0.2); + margin-bottom: 1.5rem; + text-align: center; +} + +.jackpotTitle { + font-size: 1rem; + color: var(--color-text-muted); + margin-bottom: 0.5rem; + text-transform: uppercase; + letter-spacing: 0.05em; + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.jackpotValue { + font-size: 2.5rem; + font-weight: 800; + color: var(--color-primary); + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); +} + +.infoSection, +.vrfSection, +.adminSection { + margin-bottom: 1.5rem; + padding: 1rem; + background-color: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); +} + +.sectionTitle { + font-size: 0.875rem; + font-weight: 600; + color: var(--color-text-muted); + margin-bottom: 0.75rem; + border-bottom: 1px solid var(--color-border); + padding-bottom: 0.5rem; + display: inline-flex; + align-items: center; + gap: 0.5rem; + width: 100%; +} + +.infoRow { + display: flex; + justify-content: space-between; + margin-bottom: 0.5rem; + font-size: 0.875rem; +} + +.infoRow:last-child { + margin-bottom: 0; +} + +.label { + color: var(--color-text-muted); + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.value { + font-family: monospace; + color: var(--color-text); +} + +.adminSection { + border: 1px dashed var(--color-border); + background-color: transparent; +} + +.toggleEducation { + display: block; + width: 100%; + margin-top: 1.5rem; + padding: 0.5rem; + background: transparent; + border: 1px dashed var(--color-border); + border-radius: var(--radius-md); + color: var(--color-text-muted); + font-size: 0.8125rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.toggleEducation:hover { + border-color: var(--color-primary); + color: var(--color-primary); +} \ No newline at end of file diff --git a/frontend/src/components/Lotterie/LotterieCard.tsx b/frontend/src/components/Lotterie/LotterieCard.tsx new file mode 100644 index 0000000..7d23f0a --- /dev/null +++ b/frontend/src/components/Lotterie/LotterieCard.tsx @@ -0,0 +1,275 @@ +import { formatEther } from "ethers"; +import React, { useEffect, useState } from "react"; +import { useLotterie } from "../../hooks/useLotterie"; +import { Alert } from "../ui/Alert"; +import { Badge } from "../ui/Badge"; +import { Button } from "../ui/Button"; +import { Card } from "../ui/Card"; +import { FeatureItem, HighlightBox, InfoCard } from "../ui/InfoCard"; +import { InfoIcon, Tooltip } from "../ui/Tooltip"; +import styles from "./LotterieCard.module.css"; + +export const LotterieCard: React.FC = () => { + const { + loading, + error, + isConnected, + address, + claim, + getGains, + getLastRequestId, + getResults, + getVrfSubscriptionId, + getVrfCoordinator, + getKeyHash, + } = useLotterie(); + + const [gains, setGains] = useState("0"); + const [lastRequestId, setLastRequestId] = useState("0"); + const [lastWinner, setLastWinner] = useState("None"); + const [vrfInfo, setVrfInfo] = useState({ + subId: "0", + coordinator: "", + keyHash: "", + }); + const [successMsg, setSuccessMsg] = useState(null); + const [showEducation, setShowEducation] = useState(true); + + const fetchData = async () => { + try { + if (address) { + const userGains = await getGains(address); + setGains(formatEther(userGains)); + } + + const reqId = await getLastRequestId(); + setLastRequestId(reqId.toString()); + + if (reqId > 0n) { + const winner = await getResults(reqId); + setLastWinner( + winner === "0x0000000000000000000000000000000000000000" + ? "Pending..." + : winner + ); + } + + const subId = await getVrfSubscriptionId(); + const coord = await getVrfCoordinator(); + const hash = await getKeyHash(); + + setVrfInfo({ + subId: subId.toString(), + coordinator: coord, + keyHash: hash, + }); + } catch (err) { + console.error("Error fetching lottery data:", err); + } + }; + + useEffect(() => { + if (isConnected && address) { + fetchData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isConnected, address]); + + const handleClaim = async () => { + try { + setSuccessMsg(null); + await claim(); + setSuccessMsg(`Successfully claimed ${gains} GLD!`); + fetchData(); + } catch (err) { + console.error(err); + } + }; + + return ( + + + 🎰 Golden Lottery + + Daily lottery powered by Chainlink VRF +
+ Winners are selected using verifiable random numbers, ensuring + complete fairness and transparency. + + } + size="md" + /> + + } + subtitle="Win rewards from transaction fees" + action={ + + Chainlink VRF (Verifiable Random Function) +
+ Provides cryptographically secure randomness that can be + verified on-chain. + + } + > + 🔗 VRF Secured +
+ } + /> + + {/* Educational Section */} + {showEducation && ( + +

+ The Golden Lottery is funded by 2.5% of all mint and burn fees. + Every day, one lucky GLD holder wins the accumulated prize pool! +

+ + 📋 Eligibility Requirements: +
• Hold at least 1 GLD in your wallet +
+ • Your address is automatically entered when eligible +
• No additional action needed to participate! +
+ + +
+ )} + + {/* Jackpot Section */} +
+

+ Your Pending Rewards + +

+
+ {parseFloat(gains).toFixed(4)} GLD +
+ +
+ + {error && ( + {}}> + {error} + + )} + + {successMsg && ( + setSuccessMsg(null)} + > + {successMsg} + + )} + + {/* Last Draw Info */} +
+
+ 📊 Last Draw Info + +
+
+ Request ID: + + {lastRequestId} + +
+
+ Winner: + + {lastWinner !== "None" && lastWinner !== "Pending..." + ? `${lastWinner.substring(0, 6)}...${lastWinner.substring(38)}` + : lastWinner} + +
+
+ + {/* VRF Configuration */} +
+
+ 🔐 VRF Configuration + + Chainlink VRF ensures fair and verifiable + randomness. +
+
+ These parameters configure how random numbers are requested + and verified on-chain. + + } + size="sm" + /> +
+
+ + Subscription ID: + + + {vrfInfo.subId} +
+
+ + Coordinator: + + + + + {vrfInfo.coordinator.substring(0, 10)}... + + +
+
+ + {/* Toggle Education */} + +
+
+ ); +}; diff --git a/frontend/src/components/NetworkSwitcher.module.css b/frontend/src/components/NetworkSwitcher.module.css new file mode 100644 index 0000000..cf57824 --- /dev/null +++ b/frontend/src/components/NetworkSwitcher.module.css @@ -0,0 +1,84 @@ +.container { + position: relative; + display: inline-block; +} + +.button { + display: flex; + align-items: center; + gap: 8px; + background-color: rgba(255, 255, 255, 0.05); + border: 1px solid rgba(255, 215, 0, 0.2); + border-radius: 20px; + padding: 8px 16px; + color: #e5e7eb; + font-size: 14px; + font-weight: 500; + cursor: pointer; + transition: all 0.2s ease; +} + +.button:hover { + background-color: rgba(255, 215, 0, 0.1); + border-color: rgba(255, 215, 0, 0.4); +} + +.button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.networkIcon { + width: 8px; + height: 8px; + border-radius: 50%; +} + +.dropdown { + position: absolute; + top: 100%; + right: 0; + margin-top: 8px; + background-color: #1f2937; + border: 1px solid rgba(255, 215, 0, 0.2); + border-radius: 12px; + padding: 4px; + min-width: 180px; + z-index: 50; + box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +} + +.menuItem { + display: flex; + align-items: center; + gap: 8px; + width: 100%; + padding: 8px 12px; + border: none; + background: none; + color: #e5e7eb; + font-size: 14px; + text-align: left; + cursor: pointer; + border-radius: 8px; + transition: background-color 0.2s; +} + +.menuItem:hover { + background-color: rgba(255, 215, 0, 0.1); +} + +.menuItem.active { + background-color: rgba(255, 215, 0, 0.15); + color: #ffd700; +} + +.unsupported { + border-color: #ef4444; + color: #ef4444; +} + +.unsupported:hover { + background-color: rgba(239, 68, 68, 0.1); + border-color: #ef4444; +} \ No newline at end of file diff --git a/frontend/src/components/NetworkSwitcher.tsx b/frontend/src/components/NetworkSwitcher.tsx new file mode 100644 index 0000000..a5a52ea --- /dev/null +++ b/frontend/src/components/NetworkSwitcher.tsx @@ -0,0 +1,116 @@ +import React, { useEffect, useRef, useState } from "react"; +import { NETWORKS, SUPPORTED_CHAIN_IDS } from "../config/networks"; +import { useNetwork } from "../hooks/useNetwork"; +import styles from "./NetworkSwitcher.module.css"; + +export const NetworkSwitcher: React.FC = () => { + const { chainId, switchNetwork, isSupportedNetwork } = useNetwork(); + const [isOpen, setIsOpen] = useState(false); + const [isSwitching, setIsSwitching] = useState(false); + const dropdownRef = useRef(null); + + const currentNetwork = chainId ? NETWORKS[chainId as number] : undefined; + const isSupported = isSupportedNetwork(); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if ( + dropdownRef.current && + !dropdownRef.current.contains(event.target as Node) + ) { + setIsOpen(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + const handleSwitch = async (targetChainId: number) => { + if (targetChainId === chainId) { + setIsOpen(false); + return; + } + + setIsSwitching(true); + try { + // Find the network object from supported networks + // We need to pass the network object expected by AppKit, but here we are using the ID + // The hook's switchNetwork expects a network object. + // Let's import the network objects from AppKit networks to be safe + const { sepolia, bscTestnet } = await import("@reown/appkit/networks"); + const targetNetwork = targetChainId === sepolia.id ? sepolia : bscTestnet; + + await switchNetwork(targetNetwork); + setIsOpen(false); + } catch (error) { + console.error("Failed to switch network:", error); + } finally { + setIsSwitching(false); + } + }; + + return ( +
+ + + {isOpen && ( +
+ {SUPPORTED_CHAIN_IDS.map((id) => { + const network = NETWORKS[id]; + return ( + + ); + })} +
+ )} +
+ ); +}; diff --git a/frontend/src/components/TokenBridge/TokenBridgeCard.module.css b/frontend/src/components/TokenBridge/TokenBridgeCard.module.css new file mode 100644 index 0000000..08bea60 --- /dev/null +++ b/frontend/src/components/TokenBridge/TokenBridgeCard.module.css @@ -0,0 +1,175 @@ +.card { + height: 100%; +} + +.headerTitle { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.networkFlow { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 1.5rem; + padding: 1.25rem; + background: linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(139, 92, 246, 0.1) 100%); + border: 1px solid rgba(59, 130, 246, 0.2); + border-radius: var(--radius-md); +} + +.networkNode { + display: flex; + flex-direction: column; + align-items: center; + min-width: 120px; +} + +.networkLabel { + font-size: 0.75rem; + color: var(--color-text-muted); + margin-bottom: 0.25rem; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.networkValue { + font-weight: 600; + color: var(--color-text); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.arrow { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.25rem; + color: var(--color-primary); +} + +.arrowIcon { + font-size: 1.5rem; + animation: pulse 2s infinite; +} + +.arrowLabel { + font-size: 0.625rem; + text-transform: uppercase; + letter-spacing: 0.1em; + color: var(--color-text-muted); +} + +@keyframes pulse { + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.5; + } +} + +.liquidityInfo { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1.5rem; + padding: 0.75rem 1rem; + background-color: rgba(59, 130, 246, 0.1); + border: 1px solid rgba(59, 130, 246, 0.2); + border-radius: var(--radius-md); +} + +.liquidityLabel { + font-size: 0.875rem; + color: #93C5FD; + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.liquidityValue { + font-weight: 700; + color: #93C5FD; +} + +.inputLabel { + display: inline-flex; + align-items: center; + gap: 0.25rem; +} + +.feeSelection { + margin-bottom: 1rem; + padding: 1rem; + background-color: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-md); +} + +.feeLabel { + display: flex; + align-items: center; + gap: 0.25rem; + font-size: 0.875rem; + font-weight: 500; + color: var(--color-text); + margin-bottom: 0.75rem; +} + +.radioGroup { + display: flex; + gap: 1.5rem; +} + +.radioLabel { + display: flex; + align-items: center; + gap: 0.5rem; + cursor: pointer; + font-size: 0.875rem; + padding: 0.5rem 0.75rem; + border-radius: var(--radius-md); + transition: background-color 0.2s ease; +} + +.radioLabel:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.radioLabel input[type="radio"] { + accent-color: var(--color-primary); +} + +.radioText { + display: flex; + align-items: center; + gap: 0.25rem; +} + +.infoNote { + margin-top: 1.5rem; +} + +.toggleEducation { + display: block; + width: 100%; + margin-top: 1.5rem; + padding: 0.5rem; + background: transparent; + border: 1px dashed var(--color-border); + border-radius: var(--radius-md); + color: var(--color-text-muted); + font-size: 0.8125rem; + cursor: pointer; + transition: all 0.2s ease; +} + +.toggleEducation:hover { + border-color: var(--color-primary); + color: var(--color-primary); +} \ No newline at end of file diff --git a/frontend/src/components/TokenBridge/TokenBridgeCard.tsx b/frontend/src/components/TokenBridge/TokenBridgeCard.tsx new file mode 100644 index 0000000..e2c24e9 --- /dev/null +++ b/frontend/src/components/TokenBridge/TokenBridgeCard.tsx @@ -0,0 +1,350 @@ +import { formatEther, parseEther } from "ethers"; +import React, { useEffect, useState } from "react"; +import { NETWORKS } from "../../config/networks"; +import { useNetwork } from "../../hooks/useNetwork"; +import { useTokenBridge } from "../../hooks/useTokenBridge"; +import { PayFeesIn } from "../../types/tokenBridge"; +import { Alert } from "../ui/Alert"; +import { Badge } from "../ui/Badge"; +import { Button } from "../ui/Button"; +import { Card } from "../ui/Card"; +import { FeatureItem, HighlightBox, InfoCard } from "../ui/InfoCard"; +import { Input } from "../ui/Input"; +import { InfoIcon, Tooltip } from "../ui/Tooltip"; +import styles from "./TokenBridgeCard.module.css"; + +export const TokenBridgeCard: React.FC = () => { + const { + loading, + error, + isConnected, + address, + bridgeTokens, + getDestinationChainSelector, + getGoldTokenBalance, + paused, + } = useTokenBridge(); + + const { chainId } = useNetwork(); + + const [bridgeBalance, setBridgeBalance] = useState("0"); + const [destChainSelector, setDestChainSelector] = useState("0"); + const [isPaused, setIsPaused] = useState(false); + const [receiver, setReceiver] = useState(""); + const [amount, setAmount] = useState(""); + const [payFeesIn, setPayFeesIn] = useState(PayFeesIn.Native); + const [successMsg, setSuccessMsg] = useState(null); + const [showEducation, setShowEducation] = useState(true); + + const fetchData = async () => { + try { + const [bal, selector, pausedState] = await Promise.allSettled([ + getGoldTokenBalance(), + getDestinationChainSelector(), + paused(), + ]); + + if (bal.status === "fulfilled") { + setBridgeBalance(formatEther(bal.value)); + } + + if (selector.status === "fulfilled") { + setDestChainSelector(selector.value.toString()); + } + + if (pausedState.status === "fulfilled") { + setIsPaused(pausedState.value); + } + + const rejected = [bal, selector, pausedState].filter( + (r) => r.status === "rejected" + ); + if (rejected.length > 0) { + console.warn( + "Some bridge data fetches failed:", + rejected.map((r) => (r as PromiseRejectedResult).reason) + ); + } + } catch (err) { + console.error("Error fetching bridge data:", err); + } + }; + + useEffect(() => { + if (isConnected && address) { + setReceiver(address); + fetchData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isConnected, address]); + + const handleBridge = async () => { + try { + setSuccessMsg(null); + if (!receiver || !amount) return; + + await bridgeTokens(receiver, parseEther(amount), payFeesIn); + + setSuccessMsg(`Successfully initiated bridge transfer of ${amount} GLD!`); + setAmount(""); + fetchData(); + } catch (err) { + console.error(err); + } + }; + + const getDestNetworkName = (selector: string) => { + if (selector === "16015286601757825753") return "Sepolia Testnet"; + if (selector === "13264668187771770619") return "BSC Testnet"; + return "Unknown Chain"; + }; + + const getDestNetworkIcon = (selector: string) => { + if (selector === "16015286601757825753") return "🔷"; // Ethereum + if (selector === "13264668187771770619") return "🟡"; // BSC + return "❓"; + }; + + const currentNetwork = chainId ? NETWORKS[chainId as number] : undefined; + const currentNetworkIcon = + chainId === 11155111 ? "🔷" : chainId === 97 ? "🟡" : "❓"; + + return ( + + + 🌉 Cross-Chain Bridge + + Chainlink CCIP Bridge +
+ Transfer GLD tokens securely between Ethereum and BSC using + Chainlink's Cross-Chain Interoperability Protocol. + + } + size="md" + /> + + } + subtitle="Transfer GLD between networks" + action={ + + + {isPaused ? "⏸️ Paused" : "✅ Active"} + + + } + /> + + {/* Educational Section */} + {showEducation && ( + +

+ Cross-chain bridging allows you to transfer your GLD tokens + between different blockchain networks. This enables you to use + your tokens on whichever network offers the best opportunities. +

+ + 🔗 Powered by Chainlink CCIP +
+ CCIP (Cross-Chain Interoperability Protocol) is Chainlink's secure + messaging protocol that enables safe token transfers across + blockchains. +
+ + + +
+ )} + + {/* Network Flow Visualization */} +
+
+ From + + {currentNetworkIcon} {currentNetwork?.name || "Unknown Network"} + +
+ +
+ + CCIP +
+
+
+ To + + {getDestNetworkIcon(destChainSelector)}{" "} + {getDestNetworkName(destChainSelector)} + +
+
+ + {/* Liquidity Info */} +
+ + Bridge Liquidity: + + + + {parseFloat(bridgeBalance).toFixed(4)} GLD + +
+ + {error && ( + {}}> + {error} + + )} + + {successMsg && ( + setSuccessMsg(null)} + > + {successMsg} + + )} + + {/* Bridge Form */} +
+ + Receiver Address + + + } + placeholder="0x..." + value={receiver} + onChange={(e) => setReceiver(e.target.value)} + /> + + + Amount (GLD) + + + } + placeholder="0.0" + value={amount} + onChange={(e) => setAmount(e.target.value)} + type="number" + min="0" + step="0.0001" + rightElement="GLD" + /> + +
+ +
+ + +
+
+ + +
+ + {/* Info Note */} +
+ + ⏱️ Transfer Time: Bridge transfers typically take + 15-30 minutes to complete via Chainlink CCIP. You can track your + transfer on the destination chain's block explorer. + +
+ + {/* Toggle Education */} + +
+
+ ); +}; diff --git a/frontend/src/components/WalletConnect.tsx b/frontend/src/components/WalletConnect.tsx new file mode 100644 index 0000000..0edfc90 --- /dev/null +++ b/frontend/src/components/WalletConnect.tsx @@ -0,0 +1,22 @@ +import { useAppKitAccount } from "@reown/appkit/react"; + +export function WalletConnect() { + const { isConnected } = useAppKitAccount(); + + return ( +
+
+ {isConnected} + {/* Reown's built-in button handles connection, network switching, and account view */} + +
+
+ ); +} diff --git a/frontend/src/components/Web3Provider.tsx b/frontend/src/components/Web3Provider.tsx new file mode 100644 index 0000000..9ddcef7 --- /dev/null +++ b/frontend/src/components/Web3Provider.tsx @@ -0,0 +1,11 @@ +import { ReactNode } from "react"; +// Importing the config initializes the AppKit +import "../config/reown"; + +interface Props { + children: ReactNode; +} + +export function Web3Provider({ children }: Props) { + return <>{children}; +} diff --git a/frontend/src/components/ui/Alert.module.css b/frontend/src/components/ui/Alert.module.css new file mode 100644 index 0000000..b05d706 --- /dev/null +++ b/frontend/src/components/ui/Alert.module.css @@ -0,0 +1,64 @@ +.alert { + padding: 1rem; + border-radius: var(--radius-md); + border: 1px solid transparent; + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 1rem; +} + +.content { + flex: 1; +} + +.title { + font-weight: 600; + margin-bottom: 0.25rem; + font-size: 1rem; +} + +.message { + font-size: 0.875rem; + line-height: 1.5; +} + +.closeButton { + background: transparent; + border: none; + font-size: 1.5rem; + line-height: 1; + cursor: pointer; + padding: 0; + margin-left: 1rem; + opacity: 0.7; +} + +.closeButton:hover { + opacity: 1; +} + +/* Variants */ +.info { + background-color: rgba(59, 130, 246, 0.1); + border-color: rgba(59, 130, 246, 0.2); + color: #93C5FD; +} + +.success { + background-color: rgba(16, 185, 129, 0.1); + border-color: rgba(16, 185, 129, 0.2); + color: #6EE7B7; +} + +.warning { + background-color: rgba(245, 158, 11, 0.1); + border-color: rgba(245, 158, 11, 0.2); + color: #FCD34D; +} + +.error { + background-color: rgba(239, 68, 68, 0.1); + border-color: rgba(239, 68, 68, 0.2); + color: #FCA5A5; +} \ No newline at end of file diff --git a/frontend/src/components/ui/Alert.tsx b/frontend/src/components/ui/Alert.tsx new file mode 100644 index 0000000..05d0231 --- /dev/null +++ b/frontend/src/components/ui/Alert.tsx @@ -0,0 +1,39 @@ +import React from "react"; +import styles from "./Alert.module.css"; + +interface AlertProps { + type?: "success" | "error" | "warning" | "info"; + title?: string; + children: React.ReactNode; + className?: string; + onClose?: () => void; +} + +export const Alert: React.FC = ({ + type = "info", + title, + children, + className = "", + onClose, +}) => { + return ( +
+
+ {title &&

{title}

} +
{children}
+
+ {onClose && ( + + )} +
+ ); +}; diff --git a/frontend/src/components/ui/Badge.module.css b/frontend/src/components/ui/Badge.module.css new file mode 100644 index 0000000..3f71f0e --- /dev/null +++ b/frontend/src/components/ui/Badge.module.css @@ -0,0 +1,47 @@ +.badge { + display: inline-flex; + align-items: center; + padding: 0.125rem 0.5rem; + border-radius: 9999px; + font-size: 0.75rem; + font-weight: 600; + line-height: 1.25; + white-space: nowrap; +} + +/* Variants */ +.primary { + background-color: rgba(255, 215, 0, 0.1); + color: var(--color-primary); + border: 1px solid rgba(255, 215, 0, 0.2); +} + +.secondary { + background-color: var(--color-surface); + color: var(--color-text-muted); + border: 1px solid var(--color-border); +} + +.success { + background-color: rgba(16, 185, 129, 0.1); + color: #6EE7B7; + border: 1px solid rgba(16, 185, 129, 0.2); +} + +.error { + background-color: rgba(239, 68, 68, 0.1); + color: #FCA5A5; + border: 1px solid rgba(239, 68, 68, 0.2); +} + +.warning { + background-color: rgba(245, 158, 11, 0.1); + color: #FCD34D; + border: 1px solid rgba(245, 158, 11, 0.2); +} + +.info { + background-color: rgba(59, 130, 246, 0.1); + color: #93C5FD; + border: 1px solid rgba(59, 130, 246, 0.2); +} \ No newline at end of file diff --git a/frontend/src/components/ui/Badge.tsx b/frontend/src/components/ui/Badge.tsx new file mode 100644 index 0000000..7e72045 --- /dev/null +++ b/frontend/src/components/ui/Badge.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import styles from "./Badge.module.css"; + +interface BadgeProps { + children: React.ReactNode; + variant?: "primary" | "secondary" | "success" | "error" | "warning" | "info"; + className?: string; +} + +export const Badge: React.FC = ({ + children, + variant = "primary", + className = "", +}) => { + return ( + + {children} + + ); +}; diff --git a/frontend/src/components/ui/Button.module.css b/frontend/src/components/ui/Button.module.css new file mode 100644 index 0000000..24b87fc --- /dev/null +++ b/frontend/src/components/ui/Button.module.css @@ -0,0 +1,89 @@ +.button { + display: inline-flex; + align-items: center; + justify-content: center; + border-radius: var(--radius-md); + font-weight: 500; + transition: all 0.2s ease; + position: relative; + border: 1px solid transparent; +} + +.button:disabled { + opacity: 0.6; + cursor: not-allowed; +} + +/* Variants */ +.primary { + background-color: var(--color-primary); + color: var(--color-background); +} + +.primary:hover:not(:disabled) { + background-color: var(--color-primary-hover); +} + +.secondary { + background-color: var(--color-surface); + color: var(--color-text); + border-color: var(--color-border); +} + +.secondary:hover:not(:disabled) { + background-color: var(--color-border); +} + +.danger { + background-color: var(--color-error); + color: white; +} + +.danger:hover:not(:disabled) { + filter: brightness(0.9); +} + +.outline { + background-color: transparent; + border-color: var(--color-primary); + color: var(--color-primary); +} + +.outline:hover:not(:disabled) { + background-color: rgba(255, 215, 0, 0.1); +} + +/* Sizes */ +.sm { + padding: 0.25rem 0.75rem; + font-size: 0.875rem; + height: 2rem; +} + +.md { + padding: 0.5rem 1rem; + font-size: 1rem; + height: 2.5rem; +} + +.lg { + padding: 0.75rem 1.5rem; + font-size: 1.125rem; + height: 3rem; +} + +.fullWidth { + width: 100%; +} + +.spinnerWrapper { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + display: flex; +} + +.invisible { + visibility: hidden; +} \ No newline at end of file diff --git a/frontend/src/components/ui/Button.tsx b/frontend/src/components/ui/Button.tsx new file mode 100644 index 0000000..6b6adb0 --- /dev/null +++ b/frontend/src/components/ui/Button.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import styles from "./Button.module.css"; +import { Spinner } from "./Spinner"; + +interface ButtonProps extends React.ButtonHTMLAttributes { + variant?: "primary" | "secondary" | "danger" | "outline"; + size?: "sm" | "md" | "lg"; + isLoading?: boolean; + fullWidth?: boolean; +} + +export const Button: React.FC = ({ + children, + variant = "primary", + size = "md", + isLoading = false, + fullWidth = false, + className = "", + disabled, + ...props +}) => { + return ( + + ); +}; diff --git a/frontend/src/components/ui/Card.module.css b/frontend/src/components/ui/Card.module.css new file mode 100644 index 0000000..11b2d2d --- /dev/null +++ b/frontend/src/components/ui/Card.module.css @@ -0,0 +1,50 @@ +.card { + background-color: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-md); + overflow: hidden; + display: flex; + flex-direction: column; + height: 100%; +} + +.header { + padding: 1.5rem; + border-bottom: 1px solid var(--color-border); + display: flex; + justify-content: space-between; + align-items: flex-start; +} + +.titleContainer { + flex: 1; +} + +.title { + font-size: 1.25rem; + font-weight: 600; + color: var(--color-primary); + margin: 0; +} + +.subtitle { + font-size: 0.875rem; + color: var(--color-text-muted); + margin-top: 0.25rem; +} + +.action { + margin-left: 1rem; +} + +.body { + padding: 1.5rem; + flex: 1; +} + +.footer { + padding: 1rem 1.5rem; + background-color: rgba(0, 0, 0, 0.2); + border-top: 1px solid var(--color-border); +} \ No newline at end of file diff --git a/frontend/src/components/ui/Card.tsx b/frontend/src/components/ui/Card.tsx new file mode 100644 index 0000000..6056c0e --- /dev/null +++ b/frontend/src/components/ui/Card.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import styles from "./Card.module.css"; + +interface CardProps { + children: React.ReactNode; + className?: string; +} + +interface CardHeaderProps { + title: React.ReactNode; + subtitle?: string; + action?: React.ReactNode; +} + +export const Card: React.FC & { + Header: React.FC; + Body: React.FC<{ children: React.ReactNode }>; + Footer: React.FC<{ children: React.ReactNode }>; +} = ({ children, className = "" }) => { + return
{children}
; +}; + +const CardHeader: React.FC = ({ title, subtitle, action }) => { + return ( +
+
+

{title}

+ {subtitle &&

{subtitle}

} +
+ {action &&
{action}
} +
+ ); +}; + +const CardBody: React.FC<{ children: React.ReactNode }> = ({ children }) => { + return
{children}
; +}; + +const CardFooter: React.FC<{ children: React.ReactNode }> = ({ children }) => { + return
{children}
; +}; + +Card.Header = CardHeader; +Card.Body = CardBody; +Card.Footer = CardFooter; diff --git a/frontend/src/components/ui/InfoCard.module.css b/frontend/src/components/ui/InfoCard.module.css new file mode 100644 index 0000000..455eca6 --- /dev/null +++ b/frontend/src/components/ui/InfoCard.module.css @@ -0,0 +1,163 @@ +.infoCard { + background-color: rgba(0, 0, 0, 0.2); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + overflow: hidden; + margin-bottom: 1rem; +} + +.infoCard.highlight { + border-color: var(--color-primary); + background-color: rgba(255, 215, 0, 0.05); +} + +.infoCard.warning { + border-color: var(--color-warning); + background-color: rgba(245, 158, 11, 0.05); +} + +.infoCard.success { + border-color: var(--color-success); + background-color: rgba(16, 185, 129, 0.05); +} + +.header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 1rem; + background-color: rgba(0, 0, 0, 0.2); + border-bottom: 1px solid var(--color-border); +} + +.header.clickable { + cursor: pointer; + transition: background-color 0.2s ease; +} + +.header.clickable:hover { + background-color: rgba(0, 0, 0, 0.3); +} + +.titleRow { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.icon { + font-size: 1.125rem; +} + +.title { + font-size: 0.875rem; + font-weight: 600; + color: var(--color-text); + margin: 0; +} + +.chevron { + font-size: 0.625rem; + color: var(--color-text-muted); + transition: transform 0.2s ease; +} + +.chevron.expanded { + transform: rotate(180deg); +} + +.content { + padding: 1rem; + font-size: 0.875rem; + color: var(--color-text-muted); + line-height: 1.6; +} + +.content p { + margin: 0 0 0.75rem 0; +} + +.content p:last-child { + margin-bottom: 0; +} + +/* Feature Item */ +.featureItem { + display: flex; + align-items: flex-start; + gap: 0.75rem; + padding: 0.5rem 0; +} + +.featureItem:first-child { + padding-top: 0; +} + +.featureItem:last-child { + padding-bottom: 0; +} + +.featureIcon { + color: var(--color-primary); + font-size: 1rem; + flex-shrink: 0; + margin-top: 0.125rem; +} + +.featureContent { + display: flex; + flex-direction: column; + gap: 0.125rem; +} + +.featureTitle { + font-weight: 600; + color: var(--color-text); + font-size: 0.875rem; +} + +.featureDescription { + color: var(--color-text-muted); + font-size: 0.8125rem; +} + +/* Highlight Box */ +.highlightBox { + padding: 0.75rem 1rem; + border-radius: var(--radius-md); + font-size: 0.875rem; + line-height: 1.5; + margin: 0.75rem 0; +} + +.highlightBox:first-child { + margin-top: 0; +} + +.highlightBox:last-child { + margin-bottom: 0; +} + +.highlight-info { + background-color: rgba(59, 130, 246, 0.1); + border: 1px solid rgba(59, 130, 246, 0.3); + color: #93c5fd; +} + +.highlight-warning { + background-color: rgba(245, 158, 11, 0.1); + border: 1px solid rgba(245, 158, 11, 0.3); + color: #fcd34d; +} + +.highlight-success { + background-color: rgba(16, 185, 129, 0.1); + border: 1px solid rgba(16, 185, 129, 0.3); + color: #6ee7b7; +} + +.highlight-gold { + background-color: rgba(255, 215, 0, 0.1); + border: 1px solid rgba(255, 215, 0, 0.3); + color: var(--color-primary); +} \ No newline at end of file diff --git a/frontend/src/components/ui/InfoCard.tsx b/frontend/src/components/ui/InfoCard.tsx new file mode 100644 index 0000000..7fc0444 --- /dev/null +++ b/frontend/src/components/ui/InfoCard.tsx @@ -0,0 +1,94 @@ +import React, { useState } from "react"; +import styles from "./InfoCard.module.css"; + +interface InfoCardProps { + title: string; + icon?: string; + children: React.ReactNode; + variant?: "default" | "highlight" | "warning" | "success"; + collapsible?: boolean; + defaultExpanded?: boolean; + className?: string; +} + +export const InfoCard: React.FC = ({ + title, + icon, + children, + variant = "default", + collapsible = false, + defaultExpanded = true, + className = "", +}) => { + const [isExpanded, setIsExpanded] = useState(defaultExpanded); + + return ( +
+
setIsExpanded(!isExpanded) : undefined} + > +
+ {icon && {icon}} +

{title}

+
+ {collapsible && ( + + ▼ + + )} +
+ {(!collapsible || isExpanded) && ( +
{children}
+ )} +
+ ); +}; + +// Feature list item for use within InfoCard +interface FeatureItemProps { + icon?: string; + title: string; + description: string; +} + +export const FeatureItem: React.FC = ({ + icon = "•", + title, + description, +}) => { + return ( +
+ {icon} +
+ {title} + {description} +
+
+ ); +}; + +// Highlight box for important information +interface HighlightBoxProps { + children: React.ReactNode; + variant?: "info" | "warning" | "success" | "gold"; + className?: string; +} + +export const HighlightBox: React.FC = ({ + children, + variant = "info", + className = "", +}) => { + return ( +
+ {children} +
+ ); +}; diff --git a/frontend/src/components/ui/Input.module.css b/frontend/src/components/ui/Input.module.css new file mode 100644 index 0000000..df2f708 --- /dev/null +++ b/frontend/src/components/ui/Input.module.css @@ -0,0 +1,75 @@ +.container { + display: flex; + flex-direction: column; + gap: 0.25rem; + width: 100%; +} + +.label { + font-size: 0.875rem; + font-weight: 500; + color: var(--color-text); +} + +.inputWrapper { + position: relative; + display: flex; + align-items: center; +} + +.input { + width: 100%; + padding: 0.5rem 0.75rem; + font-size: 1rem; + line-height: 1.5; + color: var(--color-text); + background-color: var(--color-background); + border: 1px solid var(--color-border); + border-radius: var(--radius-md); + transition: border-color 0.2s ease, box-shadow 0.2s ease; +} + +.input:focus { + outline: none; + border-color: var(--color-primary); + box-shadow: 0 0 0 2px rgba(255, 215, 0, 0.2); +} + +.input:disabled { + background-color: var(--color-surface); + cursor: not-allowed; + opacity: 0.7; +} + +.hasError { + border-color: var(--color-error); +} + +.hasError:focus { + border-color: var(--color-error); + box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2); +} + +.hasRightElement { + padding-right: 2.5rem; +} + +.rightElement { + position: absolute; + right: 0.75rem; + display: flex; + align-items: center; + color: var(--color-text-muted); +} + +.error { + font-size: 0.75rem; + color: var(--color-error); + margin-top: 0.25rem; +} + +.helperText { + font-size: 0.75rem; + color: var(--color-text-muted); + margin-top: 0.25rem; +} \ No newline at end of file diff --git a/frontend/src/components/ui/Input.tsx b/frontend/src/components/ui/Input.tsx new file mode 100644 index 0000000..31a049b --- /dev/null +++ b/frontend/src/components/ui/Input.tsx @@ -0,0 +1,50 @@ +import React from "react"; +import styles from "./Input.module.css"; + +interface InputProps extends React.InputHTMLAttributes { + label?: React.ReactNode; + error?: string; + helperText?: string; + rightElement?: React.ReactNode; +} + +export const Input: React.FC = ({ + label, + error, + helperText, + rightElement, + className = "", + id, + ...props +}) => { + const inputId = React.useMemo( + () => id || props.name || crypto.randomUUID(), + [id, props.name] + ); + + return ( +
+ {label && ( + + )} +
+ + {rightElement && ( +
{rightElement}
+ )} +
+ {error &&

{error}

} + {helperText && !error && ( +

{helperText}

+ )} +
+ ); +}; diff --git a/frontend/src/components/ui/Modal.module.css b/frontend/src/components/ui/Modal.module.css new file mode 100644 index 0000000..1b1d1bc --- /dev/null +++ b/frontend/src/components/ui/Modal.module.css @@ -0,0 +1,84 @@ +.overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.7); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + backdrop-filter: blur(4px); +} + +.modal { + background-color: var(--color-surface); + border: 1px solid var(--color-border); + border-radius: var(--radius-lg); + box-shadow: var(--shadow-lg); + width: 100%; + max-width: 500px; + max-height: 90vh; + display: flex; + flex-direction: column; + margin: 1rem; + animation: slideIn 0.2s ease-out; +} + +.header { + padding: 1.5rem; + border-bottom: 1px solid var(--color-border); + display: flex; + justify-content: space-between; + align-items: center; +} + +.title { + font-size: 1.25rem; + font-weight: 600; + color: var(--color-text); + margin: 0; +} + +.closeButton { + background: transparent; + border: none; + font-size: 1.5rem; + line-height: 1; + color: var(--color-text-muted); + cursor: pointer; + padding: 0.25rem; + border-radius: var(--radius-sm); + transition: color 0.2s; +} + +.closeButton:hover { + color: var(--color-text); +} + +.body { + padding: 1.5rem; + overflow-y: auto; +} + +.footer { + padding: 1rem 1.5rem; + border-top: 1px solid var(--color-border); + background-color: rgba(0, 0, 0, 0.2); + display: flex; + justify-content: flex-end; + gap: 0.75rem; +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(10px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} \ No newline at end of file diff --git a/frontend/src/components/ui/Modal.tsx b/frontend/src/components/ui/Modal.tsx new file mode 100644 index 0000000..fcd0eac --- /dev/null +++ b/frontend/src/components/ui/Modal.tsx @@ -0,0 +1,48 @@ +import React, { useEffect } from "react"; +import { createPortal } from "react-dom"; +import styles from "./Modal.module.css"; + +interface ModalProps { + isOpen: boolean; + onClose: () => void; + title: string; + children: React.ReactNode; + footer?: React.ReactNode; +} + +export const Modal: React.FC = ({ + isOpen, + onClose, + title, + children, + footer, +}) => { + useEffect(() => { + if (isOpen) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = "unset"; + } + return () => { + document.body.style.overflow = "unset"; + }; + }, [isOpen]); + + if (!isOpen) return null; + + return createPortal( +
+
e.stopPropagation()}> +
+

{title}

+ +
+
{children}
+ {footer &&
{footer}
} +
+
, + document.body + ); +}; diff --git a/frontend/src/components/ui/Spinner.module.css b/frontend/src/components/ui/Spinner.module.css new file mode 100644 index 0000000..724a6c2 --- /dev/null +++ b/frontend/src/components/ui/Spinner.module.css @@ -0,0 +1,53 @@ +.spinner { + display: inline-block; + border-radius: 50%; + border-style: solid; + border-color: transparent; + animation: spin 0.75s linear infinite; +} + +.sm { + width: 1rem; + height: 1rem; + border-width: 2px; +} + +.md { + width: 1.5rem; + height: 1.5rem; + border-width: 3px; +} + +.lg { + width: 2.5rem; + height: 2.5rem; + border-width: 4px; +} + +.primary { + border-top-color: var(--color-primary); + border-right-color: var(--color-primary); +} + +.white { + border-top-color: #ffffff; + border-right-color: #ffffff; +} + +.srOnly { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/frontend/src/components/ui/Spinner.tsx b/frontend/src/components/ui/Spinner.tsx new file mode 100644 index 0000000..aa0426a --- /dev/null +++ b/frontend/src/components/ui/Spinner.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import styles from "./Spinner.module.css"; + +interface SpinnerProps { + size?: "sm" | "md" | "lg"; + color?: "primary" | "white"; + className?: string; +} + +export const Spinner: React.FC = ({ + size = "md", + color = "primary", + className = "", +}) => { + return ( +
+ Loading... +
+ ); +}; diff --git a/frontend/src/components/ui/StepIndicator.module.css b/frontend/src/components/ui/StepIndicator.module.css new file mode 100644 index 0000000..326c399 --- /dev/null +++ b/frontend/src/components/ui/StepIndicator.module.css @@ -0,0 +1,190 @@ +/* Full Step Indicator */ +.stepIndicator { + display: flex; + flex-direction: column; + gap: 0; +} + +.step { + display: flex; + align-items: flex-start; + gap: 1rem; + padding: 1rem; + border-radius: var(--radius-md); + transition: background-color 0.2s ease; +} + +.step.clickable { + cursor: pointer; +} + +.step.clickable:hover { + background-color: rgba(255, 255, 255, 0.05); +} + +.stepIcon { + width: 2.5rem; + height: 2.5rem; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.125rem; + flex-shrink: 0; + transition: all 0.2s ease; +} + +.step.completed .stepIcon { + background-color: var(--color-success); + color: white; +} + +.step.current .stepIcon { + background-color: var(--color-primary); + color: var(--color-background); + box-shadow: 0 0 0 4px rgba(255, 215, 0, 0.2); +} + +.step.upcoming .stepIcon { + background-color: var(--color-border); + color: var(--color-text-muted); +} + +.checkmark { + font-weight: bold; +} + +.stepContent { + display: flex; + flex-direction: column; + gap: 0.25rem; + padding-top: 0.5rem; +} + +.stepLabel { + font-weight: 600; + font-size: 1rem; + color: var(--color-text); +} + +.step.upcoming .stepLabel { + color: var(--color-text-muted); +} + +.stepDescription { + font-size: 0.875rem; + color: var(--color-text-muted); +} + +.connector { + width: 2px; + height: 1.5rem; + background-color: var(--color-border); + margin-left: calc(1rem + 1.25rem - 1px); + transition: background-color 0.2s ease; +} + +.connectorCompleted { + background-color: var(--color-success); +} + +/* Compact Horizontal Indicator */ +.compactIndicator { + display: flex; + align-items: center; + gap: 0; + padding: 0.75rem 1rem; + background-color: rgba(0, 0, 0, 0.2); + border-radius: var(--radius-lg); + border: 1px solid var(--color-border); + overflow-x: auto; +} + +.compactStep { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0.75rem; + border-radius: var(--radius-md); + white-space: nowrap; + transition: all 0.2s ease; +} + +.compactIcon { + width: 1.5rem; + height: 1.5rem; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 0.75rem; + flex-shrink: 0; +} + +.compactLabel { + font-size: 0.8125rem; + font-weight: 500; +} + +/* Compact Status Styles */ +.compact-completed .compactIcon { + background-color: var(--color-success); + color: white; +} + +.compact-completed .compactLabel { + color: var(--color-success); +} + +.compact-current { + background-color: rgba(255, 215, 0, 0.1); +} + +.compact-current .compactIcon { + background-color: var(--color-primary); + color: var(--color-background); +} + +.compact-current .compactLabel { + color: var(--color-primary); + font-weight: 600; +} + +.compact-upcoming .compactIcon { + background-color: var(--color-border); + color: var(--color-text-muted); +} + +.compact-upcoming .compactLabel { + color: var(--color-text-muted); +} + +.compactConnector { + width: 1.5rem; + height: 2px; + background-color: var(--color-border); + flex-shrink: 0; +} + +.compactConnectorCompleted { + background-color: var(--color-success); +} + +/* Responsive */ +@media (max-width: 768px) { + .compactIndicator { + padding: 0.5rem; + } + + .compactStep { + padding: 0.375rem 0.5rem; + } + + .compactLabel { + display: none; + } + + .compactConnector { + width: 1rem; + } +} \ No newline at end of file diff --git a/frontend/src/components/ui/StepIndicator.tsx b/frontend/src/components/ui/StepIndicator.tsx new file mode 100644 index 0000000..a46dd07 --- /dev/null +++ b/frontend/src/components/ui/StepIndicator.tsx @@ -0,0 +1,132 @@ +import React from "react"; +import styles from "./StepIndicator.module.css"; + +export interface Step { + id: string; + label: string; + icon: string; + description?: string; +} + +interface StepIndicatorProps { + steps: Step[]; + currentStep: string; + completedSteps: string[]; + onStepClick?: (stepId: string) => void; + className?: string; +} + +export const StepIndicator: React.FC = ({ + steps, + currentStep, + completedSteps, + onStepClick, + className = "", +}) => { + const getStepStatus = ( + stepId: string + ): "completed" | "current" | "upcoming" => { + if (completedSteps.includes(stepId)) return "completed"; + if (stepId === currentStep) return "current"; + return "upcoming"; + }; + + return ( +
+ {steps.map((step, index) => { + const status = getStepStatus(step.id); + const isClickable = + onStepClick && (status === "completed" || status === "current"); + + return ( + +
onStepClick(step.id) : undefined} + > +
+ {status === "completed" ? ( + + ) : ( + {step.icon} + )} +
+
+ {step.label} + {step.description && ( + + {step.description} + + )} +
+
+ {index < steps.length - 1 && ( +
+ )} + + ); + })} +
+ ); +}; + +// Compact horizontal version for header +interface CompactStepIndicatorProps { + steps: Step[]; + currentStep: string; + completedSteps: string[]; + className?: string; +} + +export const CompactStepIndicator: React.FC = ({ + steps, + currentStep, + completedSteps, + className = "", +}) => { + const getStepStatus = ( + stepId: string + ): "completed" | "current" | "upcoming" => { + if (completedSteps.includes(stepId)) return "completed"; + if (stepId === currentStep) return "current"; + return "upcoming"; + }; + + return ( +
+ {steps.map((step, index) => { + const status = getStepStatus(step.id); + + return ( + +
+ + {status === "completed" ? "✓" : step.icon} + + {step.label} +
+ {index < steps.length - 1 && ( +
+ )} + + ); + })} +
+ ); +}; diff --git a/frontend/src/components/ui/Tooltip.module.css b/frontend/src/components/ui/Tooltip.module.css new file mode 100644 index 0000000..bdae4c4 --- /dev/null +++ b/frontend/src/components/ui/Tooltip.module.css @@ -0,0 +1,136 @@ +.tooltipWrapper { + position: relative; + display: inline-flex; + align-items: center; +} + +.tooltip { + position: absolute; + z-index: 1000; + pointer-events: none; + animation: fadeIn 0.15s ease-in-out; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(4px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +.tooltipContent { + background-color: var(--color-secondary); + color: var(--color-text); + padding: 0.5rem 0.75rem; + border-radius: var(--radius-md); + font-size: 0.8125rem; + line-height: 1.4; + max-width: 280px; + box-shadow: var(--shadow-lg); + border: 1px solid var(--color-border); + white-space: normal; +} + +.arrow { + position: absolute; + width: 8px; + height: 8px; + background-color: var(--color-secondary); + border: 1px solid var(--color-border); + transform: rotate(45deg); +} + +/* Position: Top */ +.top { + bottom: 100%; + left: 50%; + transform: translateX(-50%); + margin-bottom: 8px; +} + +.top .arrow { + bottom: -5px; + left: 50%; + transform: translateX(-50%) rotate(45deg); + border-top: none; + border-left: none; +} + +/* Position: Bottom */ +.bottom { + top: 100%; + left: 50%; + transform: translateX(-50%); + margin-top: 8px; +} + +.bottom .arrow { + top: -5px; + left: 50%; + transform: translateX(-50%) rotate(45deg); + border-bottom: none; + border-right: none; +} + +/* Position: Left */ +.left { + right: 100%; + top: 50%; + transform: translateY(-50%); + margin-right: 8px; +} + +.left .arrow { + right: -5px; + top: 50%; + transform: translateY(-50%) rotate(45deg); + border-left: none; + border-bottom: none; +} + +/* Position: Right */ +.right { + left: 100%; + top: 50%; + transform: translateY(-50%); + margin-left: 8px; +} + +.right .arrow { + left: -5px; + top: 50%; + transform: translateY(-50%) rotate(45deg); + border-right: none; + border-top: none; +} + +/* Info Icon */ +.infoIcon { + cursor: help; + display: inline-flex; + align-items: center; + justify-content: center; + opacity: 0.7; + transition: opacity 0.2s ease; +} + +.infoIcon:hover { + opacity: 1; +} + +.icon-sm { + font-size: 0.75rem; +} + +.icon-md { + font-size: 0.875rem; +} + +.icon-lg { + font-size: 1rem; +} \ No newline at end of file diff --git a/frontend/src/components/ui/Tooltip.tsx b/frontend/src/components/ui/Tooltip.tsx new file mode 100644 index 0000000..dce6b5b --- /dev/null +++ b/frontend/src/components/ui/Tooltip.tsx @@ -0,0 +1,59 @@ +import React, { useRef, useState } from "react"; +import styles from "./Tooltip.module.css"; + +interface TooltipProps { + content: React.ReactNode; + children: React.ReactNode; + position?: "top" | "bottom" | "left" | "right"; + className?: string; +} + +export const Tooltip: React.FC = ({ + content, + children, + position = "top", + className = "", +}) => { + const [isVisible, setIsVisible] = useState(false); + const tooltipRef = useRef(null); + + return ( +
setIsVisible(true)} + onMouseLeave={() => setIsVisible(false)} + ref={tooltipRef} + > + {children} + {isVisible && ( +
+
{content}
+
+
+ )} +
+ ); +}; + +// Info icon component for use with tooltips +interface InfoIconProps { + tooltip: React.ReactNode; + size?: "sm" | "md" | "lg"; + className?: string; +} + +export const InfoIcon: React.FC = ({ + tooltip, + size = "md", + className = "", +}) => { + return ( + + + ℹ️ + + + ); +}; diff --git a/frontend/src/components/ui/index.ts b/frontend/src/components/ui/index.ts new file mode 100644 index 0000000..8088d76 --- /dev/null +++ b/frontend/src/components/ui/index.ts @@ -0,0 +1,13 @@ +// Core UI Components +export { Alert } from "./Alert"; +export { Badge } from "./Badge"; +export { Button } from "./Button"; +export { Card } from "./Card"; +export { Input } from "./Input"; +export { Spinner } from "./Spinner"; + +// Educational/Guided Experience Components +export { FeatureItem, HighlightBox, InfoCard } from "./InfoCard"; +export { CompactStepIndicator, StepIndicator } from "./StepIndicator"; +export type { Step } from "./StepIndicator"; +export { InfoIcon, Tooltip } from "./Tooltip"; diff --git a/frontend/src/config/contracts.ts b/frontend/src/config/contracts.ts new file mode 100644 index 0000000..87b55b7 --- /dev/null +++ b/frontend/src/config/contracts.ts @@ -0,0 +1,25 @@ +import { bscTestnet, sepolia } from "@reown/appkit/networks"; +import { ENV } from "./env"; + +export const CONTRACT_ADDRESSES = { + [sepolia.id]: { + goldToken: ENV.CONTRACTS.SEPOLIA.GOLD_TOKEN, + lotterie: ENV.CONTRACTS.SEPOLIA.LOTTERIE, + tokenBridge: ENV.CONTRACTS.SEPOLIA.TOKEN_BRIDGE, + }, + [bscTestnet.id]: { + goldToken: ENV.CONTRACTS.BSC_TESTNET.GOLD_TOKEN, + lotterie: ENV.CONTRACTS.BSC_TESTNET.LOTTERIE, + tokenBridge: ENV.CONTRACTS.BSC_TESTNET.TOKEN_BRIDGE, + }, +} as const; + +export type ChainId = keyof typeof CONTRACT_ADDRESSES; + +export const getContractAddress = ( + chainId: number | undefined, + contract: "goldToken" | "lotterie" | "tokenBridge" +): string | undefined => { + if (!chainId) return undefined; + return CONTRACT_ADDRESSES[chainId as ChainId]?.[contract]; +}; diff --git a/frontend/src/config/env.ts b/frontend/src/config/env.ts new file mode 100644 index 0000000..a329a5c --- /dev/null +++ b/frontend/src/config/env.ts @@ -0,0 +1,40 @@ +const getRequiredEnvVar = (key: string): string => { + const value = import.meta.env[key]; + if (!value) { + throw new Error(`Missing required environment variable: ${key}`); + } + return value; +}; + +const getOptionalEnvVar = (key: string, defaultValue: string): string => { + return import.meta.env[key] || defaultValue; +}; + +export const ENV = { + REOWN_PROJECT_ID: getRequiredEnvVar("VITE_REOWN_PROJECT_ID"), + + CONTRACTS: { + SEPOLIA: { + GOLD_TOKEN: getRequiredEnvVar("VITE_CONTRACT_ADDRESS_SEPOLIA_GOLD_TOKEN"), + LOTTERIE: getRequiredEnvVar("VITE_CONTRACT_ADDRESS_SEPOLIA_LOTTERIE"), + TOKEN_BRIDGE: getRequiredEnvVar("VITE_CONTRACT_ADDRESS_SEPOLIA_TOKEN_BRIDGE"), + }, + BSC_TESTNET: { + GOLD_TOKEN: getRequiredEnvVar("VITE_CONTRACT_ADDRESS_BSC_TESTNET_GOLD_TOKEN"), + LOTTERIE: getRequiredEnvVar("VITE_CONTRACT_ADDRESS_BSC_TESTNET_LOTTERIE"), + TOKEN_BRIDGE: getRequiredEnvVar("VITE_CONTRACT_ADDRESS_BSC_TESTNET_TOKEN_BRIDGE"), + }, + }, + + RPC: { + SEPOLIA: getRequiredEnvVar("VITE_RPC_URL_SEPOLIA"), + BSC_TESTNET: getRequiredEnvVar("VITE_RPC_URL_BSC_TESTNET"), + }, + + SITE: { + NAME: getOptionalEnvVar("VITE_SITE_NAME", "Golden Bridge"), + DESCRIPTION: getOptionalEnvVar("VITE_SITE_DESCRIPTION", "Gold-backed tokenization with lottery rewards"), + URL: getOptionalEnvVar("VITE_SITE_URL", "http://localhost:5173"), + ICON: getOptionalEnvVar("VITE_SITE_ICON", "https://assets.reown.com/reown-profile-pic.png"), + } +} as const; \ No newline at end of file diff --git a/frontend/src/config/index.ts b/frontend/src/config/index.ts new file mode 100644 index 0000000..6d5209b --- /dev/null +++ b/frontend/src/config/index.ts @@ -0,0 +1,4 @@ +export * from "./contracts"; +export * from "./networks"; +export * from "./reown"; +export * from "./env"; diff --git a/frontend/src/config/networks.ts b/frontend/src/config/networks.ts new file mode 100644 index 0000000..0552f20 --- /dev/null +++ b/frontend/src/config/networks.ts @@ -0,0 +1,52 @@ +import { bscTestnet, sepolia } from "@reown/appkit/networks"; +import { ENV } from "./env"; + +export interface NetworkConfig { + chainId: number; + name: string; + currency: string; + explorerUrl: string; + rpcUrl: string; + icon?: string; +} + +export const NETWORKS: Record = { + [sepolia.id]: { + chainId: sepolia.id, + name: "Sepolia Testnet", + currency: "ETH", + explorerUrl: "https://sepolia.etherscan.io", + rpcUrl: ENV.RPC.SEPOLIA, + }, + [bscTestnet.id]: { + chainId: bscTestnet.id, + name: "BSC Testnet", + currency: "tBNB", + explorerUrl: "https://testnet.bscscan.com", + rpcUrl: ENV.RPC.BSC_TESTNET, + }, +}; + +export const SUPPORTED_CHAIN_IDS = [sepolia.id, bscTestnet.id]; + +export const getNetworkConfig = ( + chainId: number | undefined +): NetworkConfig | undefined => { + if (!chainId) return undefined; + return NETWORKS[chainId]; +}; + +export const isSupportedNetwork = (chainId: number | undefined): boolean => { + if (!chainId) return false; + return SUPPORTED_CHAIN_IDS.includes(chainId as any); +}; + +export const getExplorerLink = ( + chainId: number | undefined, + hash: string, + type: "tx" | "address" = "tx" +): string => { + const config = getNetworkConfig(chainId); + if (!config) return "#"; + return `${config.explorerUrl}/${type}/${hash}`; +}; diff --git a/frontend/src/config/reown.ts b/frontend/src/config/reown.ts new file mode 100644 index 0000000..cd60ed8 --- /dev/null +++ b/frontend/src/config/reown.ts @@ -0,0 +1,49 @@ +import { EthersAdapter } from "@reown/appkit-adapter-ethers"; +import { bscTestnet, sepolia } from "@reown/appkit/networks"; +import { createAppKit } from "@reown/appkit/react"; +import { ENV } from "./env"; + +// 1. Get projectId +const projectId = ENV.REOWN_PROJECT_ID; + +// 2. Set the networks +const customSepolia = { + ...sepolia, + rpcUrls: { + ...sepolia.rpcUrls, + default: { + http: [ENV.RPC.SEPOLIA], + }, + }, +}; + +const customBscTestnet = { + ...bscTestnet, + rpcUrls: { + ...bscTestnet.rpcUrls, + default: { + http: [ENV.RPC.BSC_TESTNET], + }, + }, +}; + +export const networks = [customSepolia, customBscTestnet]; + +// 3. Create a metadata object +const metadata = { + name: ENV.SITE.NAME, + description: ENV.SITE.DESCRIPTION, + url: ENV.SITE.URL, + icons: [ENV.SITE.ICON], +}; + +// 4. Create the AppKit instance +export const appKit = createAppKit({ + adapters: [new EthersAdapter()], + networks: [customSepolia, customBscTestnet], + metadata, + projectId, + features: { + analytics: true, + }, +}); diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts new file mode 100644 index 0000000..15a0a82 --- /dev/null +++ b/frontend/src/hooks/index.ts @@ -0,0 +1,5 @@ +export * from "./useAdmin"; +export * from "./useGoldToken"; +export * from "./useLotterie"; +export * from "./useNetwork"; +export * from "./useTokenBridge"; diff --git a/frontend/src/hooks/useAdmin.ts b/frontend/src/hooks/useAdmin.ts new file mode 100644 index 0000000..92a997a --- /dev/null +++ b/frontend/src/hooks/useAdmin.ts @@ -0,0 +1,175 @@ +import { + useAppKitAccount, + useAppKitNetwork, + useAppKitProvider, +} from "@reown/appkit/react"; +import { BrowserProvider, Contract, Eip1193Provider } from "ethers"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import iGoldTokenAbi from "../../abi/goldToken/iGoldTokenAbi.json"; +import iLotterieAbi from "../../abi/lotterie/iLotterieAbi.json"; +import tokenBridgeAbi from "../../abi/tokenBridge/tokenBridgeAbi.json"; +import { getContractAddress } from "../config/contracts"; + +export interface AdminStatus { + isGoldTokenOwner: boolean; + isLotterieOwner: boolean; + isTokenBridgeOwner: boolean; + isAnyOwner: boolean; + isAllOwner: boolean; +} + +export const useAdmin = () => { + const { address, isConnected } = useAppKitAccount(); + const { chainId } = useAppKitNetwork(); + const { walletProvider } = useAppKitProvider("eip155"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + const [adminStatus, setAdminStatus] = useState({ + isGoldTokenOwner: false, + isLotterieOwner: false, + isTokenBridgeOwner: false, + isAnyOwner: false, + isAllOwner: false, + }); + + const goldTokenAddress = useMemo( + () => getContractAddress(chainId as number, "goldToken"), + [chainId] + ); + + const lotterieAddress = useMemo( + () => getContractAddress(chainId as number, "lotterie"), + [chainId] + ); + + const tokenBridgeAddress = useMemo( + () => getContractAddress(chainId as number, "tokenBridge"), + [chainId] + ); + + const getProvider = useCallback(async () => { + if (!walletProvider) throw new Error("Wallet not connected"); + return new BrowserProvider(walletProvider as Eip1193Provider); + }, [walletProvider]); + + const checkOwnerRole = useCallback(async () => { + if (!address || !isConnected) { + setAdminStatus({ + isGoldTokenOwner: false, + isLotterieOwner: false, + isTokenBridgeOwner: false, + isAnyOwner: false, + isAllOwner: false, + }); + return; + } + + setLoading(true); + setError(null); + + try { + const provider = await getProvider(); + const results = { + isGoldTokenOwner: false, + isLotterieOwner: false, + isTokenBridgeOwner: false, + }; + + // Check GoldToken owner role + if (goldTokenAddress) { + try { + const goldTokenContract = new Contract( + goldTokenAddress, + iGoldTokenAbi.abi, + provider + ); + results.isGoldTokenOwner = await goldTokenContract.hasOwnerRole( + address + ); + } catch (err) { + console.warn("Failed to check GoldToken owner role:", err); + } + } + + // Check Lotterie owner role + if (lotterieAddress) { + try { + const lotterieContract = new Contract( + lotterieAddress, + iLotterieAbi.abi, + provider + ); + results.isLotterieOwner = await lotterieContract.hasOwnerRole( + address + ); + } catch (err) { + console.warn("Failed to check Lotterie owner role:", err); + } + } + + // Check TokenBridge owner role + if (tokenBridgeAddress) { + try { + const tokenBridgeContract = new Contract( + tokenBridgeAddress, + tokenBridgeAbi.abi, + provider + ); + // TokenBridge uses hasRole with OWNER_ROLE constant + const OWNER_ROLE = + "0xb19546dff01e856fb3f010c267a7b1c60363cf8a4664e21cc89c26224620214e"; + results.isTokenBridgeOwner = await tokenBridgeContract.hasRole( + OWNER_ROLE, + address + ); + } catch (err) { + console.warn("Failed to check TokenBridge owner role:", err); + } + } + + const isAnyOwner = + results.isGoldTokenOwner || + results.isLotterieOwner || + results.isTokenBridgeOwner; + + const isAllOwner = + results.isGoldTokenOwner && + results.isLotterieOwner && + results.isTokenBridgeOwner; + + setAdminStatus({ + ...results, + isAnyOwner, + isAllOwner, + }); + } catch (err: any) { + setError(err.message || "Failed to check admin status"); + console.error("Error checking admin status:", err); + } finally { + setLoading(false); + } + }, [ + address, + isConnected, + getProvider, + goldTokenAddress, + lotterieAddress, + tokenBridgeAddress, + ]); + + // Check owner role when wallet connects or chain changes + useEffect(() => { + if (isConnected && address) { + checkOwnerRole(); + } + }, [isConnected, address, chainId, checkOwnerRole]); + + return { + loading, + error, + ...adminStatus, + checkOwnerRole, + address, + isConnected, + }; +}; diff --git a/frontend/src/hooks/useGoldToken.ts b/frontend/src/hooks/useGoldToken.ts new file mode 100644 index 0000000..b801cd6 --- /dev/null +++ b/frontend/src/hooks/useGoldToken.ts @@ -0,0 +1,319 @@ +import { + useAppKitAccount, + useAppKitNetwork, + useAppKitProvider, +} from "@reown/appkit/react"; +import { BrowserProvider, Contract, Eip1193Provider } from "ethers"; +import { useCallback, useMemo, useState } from "react"; +import iGoldTokenAbi from "../../abi/goldToken/iGoldTokenAbi.json"; +import { getContractAddress } from "../config/contracts"; + +export const useGoldToken = () => { + const { address, isConnected } = useAppKitAccount(); + const { chainId } = useAppKitNetwork(); + const { walletProvider } = useAppKitProvider("eip155"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const contractAddress = useMemo( + () => getContractAddress(chainId as number, "goldToken"), + [chainId] + ); + + const getContract = useCallback( + async (withSigner = false) => { + if (!contractAddress) + throw new Error("Contract not deployed on this network"); + if (!walletProvider) throw new Error("Wallet not connected"); + + const ethersProvider = new BrowserProvider( + walletProvider as Eip1193Provider + ); + + if (withSigner) { + const signer = await ethersProvider.getSigner(); + return new Contract(contractAddress, iGoldTokenAbi.abi, signer); + } + + return new Contract(contractAddress, iGoldTokenAbi.abi, ethersProvider); + }, + [contractAddress, walletProvider] + ); + + // User-Facing Functions + const mint = useCallback( + async (value: bigint) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.mint({ value }); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to mint tokens"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const burn = useCallback( + async (amount: bigint) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.burn(amount); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to burn tokens"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const transfer = useCallback( + async (to: string, amount: bigint) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.transfer(to, amount); + await tx.wait(); + return true; + } catch (err: any) { + setError(err.message || "Failed to transfer tokens"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const balanceOf = useCallback( + async (account: string) => { + try { + const contract = await getContract(false); + return await contract.balanceOf(account); + } catch (err: any) { + setError(err.message || "Failed to get balance"); + throw err; + } + }, + [getContract] + ); + + const claimEth = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.claimEth(); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to claim ETH"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + // View Functions + const getGoldPriceInEth = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getGoldPriceInEth(); + } catch (err: any) { + setError(err.message || "Failed to get gold price"); + throw err; + } + }, [getContract]); + + const getFees = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getFees(); + } catch (err: any) { + setError(err.message || "Failed to get fees"); + throw err; + } + }, [getContract]); + + const getFeesAddress = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getFeesAddress(); + } catch (err: any) { + setError(err.message || "Failed to get fees address"); + throw err; + } + }, [getContract]); + + const getUsers = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getUsers(); + } catch (err: any) { + setError(err.message || "Failed to get users"); + throw err; + } + }, [getContract]); + + const getTimestamps = useCallback(async () => { + try { + const contract = await getContract(false); + const [users, timestamps] = await contract.getTimestamps(); + return { users, timestamps }; + } catch (err: any) { + setError(err.message || "Failed to get timestamps"); + throw err; + } + }, [getContract]); + + const hasOwnerRole = useCallback( + async (account: string) => { + try { + const contract = await getContract(false); + return await contract.hasOwnerRole(account); + } catch (err: any) { + setError(err.message || "Failed to check owner role"); + throw err; + } + }, + [getContract] + ); + + // Admin Functions + const setFeesAddress = useCallback( + async (feesAddress: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setFeesAddress(feesAddress); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set fees address"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setLotterieAddress = useCallback( + async (lotterieAddress: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setLotterieAddress(lotterieAddress); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set lottery address"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const addOwner = useCallback( + async (account: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.addOwner(account); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to add owner"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const removeOwner = useCallback( + async (account: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.removeOwner(account); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to remove owner"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const pause = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.pause(); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to pause contract"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + const unpause = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.unpause(); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to unpause contract"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + return { + loading, + error, + contractAddress, + isConnected, + address, + mint, + burn, + transfer, + balanceOf, + claimEth, + getGoldPriceInEth, + getFees, + getFeesAddress, + getUsers, + getTimestamps, + hasOwnerRole, + setFeesAddress, + setLotterieAddress, + addOwner, + removeOwner, + pause, + unpause, + }; +}; diff --git a/frontend/src/hooks/useLotterie.ts b/frontend/src/hooks/useLotterie.ts new file mode 100644 index 0000000..b52b6bd --- /dev/null +++ b/frontend/src/hooks/useLotterie.ts @@ -0,0 +1,388 @@ +import { + useAppKitAccount, + useAppKitNetwork, + useAppKitProvider, +} from "@reown/appkit/react"; +import { BrowserProvider, Contract, Eip1193Provider } from "ethers"; +import { useCallback, useMemo, useState } from "react"; +import iLotterieAbi from "../../abi/lotterie/iLotterieAbi.json"; +import { getContractAddress } from "../config/contracts"; + +export const useLotterie = () => { + const { address, isConnected } = useAppKitAccount(); + const { chainId } = useAppKitNetwork(); + const { walletProvider } = useAppKitProvider("eip155"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const contractAddress = useMemo( + () => getContractAddress(chainId as number, "lotterie"), + [chainId] + ); + + const getContract = useCallback( + async (withSigner = false) => { + if (!contractAddress) + throw new Error("Contract not deployed on this network"); + if (!walletProvider) throw new Error("Wallet not connected"); + + const ethersProvider = new BrowserProvider( + walletProvider as Eip1193Provider + ); + + if (withSigner) { + const signer = await ethersProvider.getSigner(); + return new Contract(contractAddress, iLotterieAbi.abi, signer); + } + + return new Contract(contractAddress, iLotterieAbi.abi, ethersProvider); + }, + [contractAddress, walletProvider] + ); + + // User-Facing Functions + const claim = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.claim(); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to claim winnings"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + const getGains = useCallback( + async (account: string) => { + try { + const contract = await getContract(false); + return await contract.getGains(account); + } catch (err: any) { + setError(err.message || "Failed to get gains"); + throw err; + } + }, + [getContract] + ); + + // Lottery State Functions (view) + const getLastRequestId = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getLastRequestId(); + } catch (err: any) { + setError(err.message || "Failed to get last request ID"); + throw err; + } + }, [getContract]); + + const getResults = useCallback( + async (requestId: bigint) => { + try { + const contract = await getContract(false); + return await contract.getResults(requestId); + } catch (err: any) { + setError(err.message || "Failed to get results"); + throw err; + } + }, + [getContract] + ); + + const getGoldToken = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getGoldToken(); + } catch (err: any) { + setError(err.message || "Failed to get gold token address"); + throw err; + } + }, [getContract]); + + // VRF Configuration (view) + const getVrfSubscriptionId = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getVrfSubscriptionId(); + } catch (err: any) { + setError(err.message || "Failed to get VRF subscription ID"); + throw err; + } + }, [getContract]); + + const getVrfCoordinator = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getVrfCoordinator(); + } catch (err: any) { + setError(err.message || "Failed to get VRF coordinator"); + throw err; + } + }, [getContract]); + + const getKeyHash = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getKeyHash(); + } catch (err: any) { + setError(err.message || "Failed to get key hash"); + throw err; + } + }, [getContract]); + + const getCallbackGasLimit = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getCallbackGasLimit(); + } catch (err: any) { + setError(err.message || "Failed to get callback gas limit"); + throw err; + } + }, [getContract]); + + const getRequestConfirmations = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getRequestConfirmations(); + } catch (err: any) { + setError(err.message || "Failed to get request confirmations"); + throw err; + } + }, [getContract]); + + const getNumWords = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getNumWords(); + } catch (err: any) { + setError(err.message || "Failed to get num words"); + throw err; + } + }, [getContract]); + + // Admin Functions (OWNER_ROLE) + const randomDraw = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.randomDraw(); + await tx.wait(); + // We might want to return the requestId from the event here, but for now just void + } catch (err: any) { + setError(err.message || "Failed to initiate random draw"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + const setGoldToken = useCallback( + async (goldToken: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setGoldToken(goldToken); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set gold token"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setVrfSubscriptionId = useCallback( + async (vrfSubscriptionId: bigint) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setVrfSubscriptionId(vrfSubscriptionId); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set VRF subscription ID"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setVrfCoordinator = useCallback( + async (vrfCoordinator: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setVrfCoordinator(vrfCoordinator); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set VRF coordinator"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setKeyHash = useCallback( + async (keyHash: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setKeyHash(keyHash); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set key hash"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setCallbackGasLimit = useCallback( + async (callbackGasLimit: number) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setCallbackGasLimit(callbackGasLimit); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set callback gas limit"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setRequestConfirmations = useCallback( + async (requestConfirmations: number) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setRequestConfirmations(requestConfirmations); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set request confirmations"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setNumWords = useCallback( + async (numWords: number) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setNumWords(numWords); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set num words"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const addOwner = useCallback( + async (account: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.addOwner(account); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to add owner"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const removeOwner = useCallback( + async (account: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.removeOwner(account); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to remove owner"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const hasOwnerRole = useCallback( + async (account: string) => { + try { + const contract = await getContract(false); + return await contract.hasOwnerRole(account); + } catch (err: any) { + setError(err.message || "Failed to check owner role"); + throw err; + } + }, + [getContract] + ); + + return { + loading, + error, + contractAddress, + isConnected, + address, + claim, + getGains, + getLastRequestId, + getResults, + getGoldToken, + getVrfSubscriptionId, + getVrfCoordinator, + getKeyHash, + getCallbackGasLimit, + getRequestConfirmations, + getNumWords, + randomDraw, + setGoldToken, + setVrfSubscriptionId, + setVrfCoordinator, + setKeyHash, + setCallbackGasLimit, + setRequestConfirmations, + setNumWords, + addOwner, + removeOwner, + hasOwnerRole, + }; +}; diff --git a/frontend/src/hooks/useNetwork.ts b/frontend/src/hooks/useNetwork.ts new file mode 100644 index 0000000..80488d6 --- /dev/null +++ b/frontend/src/hooks/useNetwork.ts @@ -0,0 +1,39 @@ +import { bscTestnet, sepolia } from "@reown/appkit/networks"; +import { useAppKitNetwork } from "@reown/appkit/react"; +import { isSupportedNetwork as checkSupported } from "../config/networks"; + +export const useNetwork = () => { + const { chainId, switchNetwork } = useAppKitNetwork(); + + const isSepoliaNetwork = () => chainId === sepolia.id; + const isBscTestnet = () => chainId === bscTestnet.id; + const isSupportedNetwork = () => checkSupported(chainId as number); + + const switchToSepolia = async () => { + try { + await switchNetwork(sepolia); + } catch (error) { + console.error("Failed to switch to Sepolia:", error); + throw error; + } + }; + + const switchToBscTestnet = async () => { + try { + await switchNetwork(bscTestnet); + } catch (error) { + console.error("Failed to switch to BSC Testnet:", error); + throw error; + } + }; + + return { + chainId, + isSepoliaNetwork, + isBscTestnet, + isSupportedNetwork, + switchToSepolia, + switchToBscTestnet, + switchNetwork, + }; +}; diff --git a/frontend/src/hooks/useTokenBridge.ts b/frontend/src/hooks/useTokenBridge.ts new file mode 100644 index 0000000..5577517 --- /dev/null +++ b/frontend/src/hooks/useTokenBridge.ts @@ -0,0 +1,296 @@ +import { + useAppKitAccount, + useAppKitNetwork, + useAppKitProvider, +} from "@reown/appkit/react"; +import { BrowserProvider, Contract, Eip1193Provider } from "ethers"; +import { useCallback, useMemo, useState } from "react"; +import tokenBridgeAbi from "../../abi/tokenBridge/tokenBridgeAbi.json"; +import { getContractAddress } from "../config/contracts"; +import { PayFeesIn } from "../types/tokenBridge"; + +export const useTokenBridge = () => { + const { address, isConnected } = useAppKitAccount(); + const { chainId } = useAppKitNetwork(); + const { walletProvider } = useAppKitProvider("eip155"); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const contractAddress = useMemo( + () => getContractAddress(chainId as number, "tokenBridge"), + [chainId] + ); + + const getContract = useCallback( + async (withSigner = false) => { + if (!contractAddress) + throw new Error("Contract not deployed on this network"); + if (!walletProvider) throw new Error("Wallet not connected"); + + const ethersProvider = new BrowserProvider( + walletProvider as Eip1193Provider + ); + + if (withSigner) { + const signer = await ethersProvider.getSigner(); + return new Contract(contractAddress, tokenBridgeAbi.abi, signer); + } + + return new Contract(contractAddress, tokenBridgeAbi.abi, ethersProvider); + }, + [contractAddress, walletProvider] + ); + + // User-Facing Functions + const bridgeTokens = useCallback( + async (receiver: string, amount: bigint, payFeesIn: PayFeesIn) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.bridgeTokens(receiver, amount, payFeesIn); + const receipt = await tx.wait(); + // Find the TokensBridged event to get the messageId + // This is a simplification, in a real app we might want to parse logs + return receipt; + } catch (err: any) { + setError(err.message || "Failed to bridge tokens"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + // State Query Functions (view) + const getDestinationChainSelector = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.destinationChainSelector(); + } catch (err: any) { + setError(err.message || "Failed to get destination chain selector"); + throw err; + } + }, [getContract]); + + const getGoldToken = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.goldToken(); + } catch (err: any) { + setError(err.message || "Failed to get gold token address"); + throw err; + } + }, [getContract]); + + const getLink = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.link(); + } catch (err: any) { + setError(err.message || "Failed to get LINK token address"); + throw err; + } + }, [getContract]); + + const getGoldTokenBalance = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getGoldTokenBalance(); + } catch (err: any) { + setError(err.message || "Failed to get gold token balance"); + throw err; + } + }, [getContract]); + + const getLinkBalance = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.getLinkBalance(); + } catch (err: any) { + setError(err.message || "Failed to get LINK balance"); + throw err; + } + }, [getContract]); + + const getProcessedMessages = useCallback( + async (messageId: string) => { + try { + const contract = await getContract(false); + return await contract.processedMessages(messageId); + } catch (err: any) { + setError(err.message || "Failed to check processed message"); + throw err; + } + }, + [getContract] + ); + + const getWhitelistedChains = useCallback( + async (chainSelector: bigint) => { + try { + const contract = await getContract(false); + return await contract.whitelistedChains(chainSelector); + } catch (err: any) { + setError(err.message || "Failed to check whitelisted chain"); + throw err; + } + }, + [getContract] + ); + + const getWhitelistedSenders = useCallback( + async (sender: string) => { + try { + const contract = await getContract(false); + return await contract.whitelistedSenders(sender); + } catch (err: any) { + setError(err.message || "Failed to check whitelisted sender"); + throw err; + } + }, + [getContract] + ); + + const paused = useCallback(async () => { + try { + const contract = await getContract(false); + return await contract.paused(); + } catch (err: any) { + setError(err.message || "Failed to check pause status"); + throw err; + } + }, [getContract]); + + // Admin Functions (OWNER_ROLE) + const setWhitelistedChain = useCallback( + async (chainSelector: bigint, enabled: boolean, ccipExtraArgs: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setWhitelistedChain( + chainSelector, + enabled, + ccipExtraArgs + ); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set whitelisted chain"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const setWhitelistedSender = useCallback( + async (sender: string, enabled: boolean) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.setWhitelistedSender(sender, enabled); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to set whitelisted sender"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const withdraw = useCallback( + async (beneficiary: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.withdraw(beneficiary); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to withdraw ETH"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const withdrawToken = useCallback( + async (beneficiary: string, token: string) => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.withdrawToken(beneficiary, token); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to withdraw token"); + throw err; + } finally { + setLoading(false); + } + }, + [getContract] + ); + + const pause = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.pause(); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to pause bridge"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + const unpause = useCallback(async () => { + setLoading(true); + setError(null); + try { + const contract = await getContract(true); + const tx = await contract.unpause(); + await tx.wait(); + } catch (err: any) { + setError(err.message || "Failed to unpause bridge"); + throw err; + } finally { + setLoading(false); + } + }, [getContract]); + + return { + loading, + error, + contractAddress, + isConnected, + address, + bridgeTokens, + getDestinationChainSelector, + getGoldToken, + getLink, + getGoldTokenBalance, + getLinkBalance, + getProcessedMessages, + getWhitelistedChains, + getWhitelistedSenders, + paused, + setWhitelistedChain, + setWhitelistedSender, + withdraw, + withdrawToken, + pause, + unpause, + }; +}; diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 0000000..dd64387 --- /dev/null +++ b/frontend/src/main.tsx @@ -0,0 +1,12 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import { Web3Provider } from "./components/Web3Provider"; + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + +); diff --git a/frontend/src/styles/globals.css b/frontend/src/styles/globals.css new file mode 100644 index 0000000..20b3969 --- /dev/null +++ b/frontend/src/styles/globals.css @@ -0,0 +1,262 @@ +:root { + --color-primary: #FFD700; + --color-primary-hover: #E6C200; + --color-primary-light: rgba(255, 215, 0, 0.1); + --color-secondary: #1F2937; + --color-background: #111827; + --color-surface: #1F2937; + --color-text: #F9FAFB; + --color-text-muted: #9CA3AF; + --color-border: #374151; + --color-success: #10B981; + --color-success-light: rgba(16, 185, 129, 0.1); + --color-error: #EF4444; + --color-error-light: rgba(239, 68, 68, 0.1); + --color-warning: #F59E0B; + --color-warning-light: rgba(245, 158, 11, 0.1); + --color-info: #3B82F6; + --color-info-light: rgba(59, 130, 246, 0.1); + + --radius-sm: 0.25rem; + --radius-md: 0.375rem; + --radius-lg: 0.5rem; + --radius-xl: 0.75rem; + + --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); + --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); + --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); + + --transition-fast: 0.15s ease; + --transition-normal: 0.2s ease; + --transition-slow: 0.3s ease; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + color: var(--color-text); + background-color: var(--color-background); + min-height: 100vh; +} + +a { + color: var(--color-primary); + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +button { + cursor: pointer; + font-family: inherit; +} + +input, +select, +textarea { + font-family: inherit; +} + +/* Utility classes */ +.container { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.text-left { + text-align: left; +} + +.flex { + display: flex; +} + +.flex-col { + flex-direction: column; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.justify-between { + justify-content: space-between; +} + +.gap-2 { + gap: 0.5rem; +} + +.gap-4 { + gap: 1rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mt-4 { + margin-top: 1rem; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mb-4 { + margin-bottom: 1rem; +} + +.w-full { + width: 100%; +} + +.font-bold { + font-weight: 700; +} + +.text-sm { + font-size: 0.875rem; +} + +.text-lg { + font-size: 1.125rem; +} + +.text-xl { + font-size: 1.25rem; +} + +.text-2xl { + font-size: 1.5rem; +} + +.text-primary { + color: var(--color-primary); +} + +.text-muted { + color: var(--color-text-muted); +} + +.text-error { + color: var(--color-error); +} + +.text-success { + color: var(--color-success); +} + +/* Scrollbar */ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + background: var(--color-background); +} + +::-webkit-scrollbar-thumb { + background: var(--color-border); + border-radius: 4px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--color-text-muted); +} + +/* Animation utilities */ +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes slideUp { + from { + opacity: 0; + transform: translateY(10px); + } + + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes pulse { + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.5; + } +} + +.animate-fadeIn { + animation: fadeIn var(--transition-normal); +} + +.animate-slideUp { + animation: slideUp var(--transition-slow); +} + +/* Focus styles for accessibility */ +:focus-visible { + outline: 2px solid var(--color-primary); + outline-offset: 2px; +} + +/* Selection styles */ +::selection { + background-color: var(--color-primary); + color: var(--color-background); +} + +/* Emoji styling for consistent display */ +.emoji { + font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif; +} + +/* Screen reader only */ +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} \ No newline at end of file diff --git a/frontend/src/types/goldToken.ts b/frontend/src/types/goldToken.ts new file mode 100644 index 0000000..5071da0 --- /dev/null +++ b/frontend/src/types/goldToken.ts @@ -0,0 +1,51 @@ +export interface GoldTokenEvents { + FeesAddressUpdated: { + previousFeesAddress: string; + newFeesAddress: string; + }; + GoldTokenInitialized: { + owner: string; + dataFeedGold: string; + dataFeedEth: string; + }; + LotterieAddressUpdated: { + previousLotterieAddress: string; + newLotterieAddress: string; + }; + Mint: { + to: string; + amount: bigint; + }; + UserAdded: { + user: string; + timestamp: bigint; + }; + UserRemoved: { + user: string; + }; +} + +export interface GoldTokenFunctions { + // User-Facing + mint: (value: bigint) => Promise; + burn: (amount: bigint) => Promise; + transfer: (to: string, amount: bigint) => Promise; + balanceOf: (account: string) => Promise; + claimEth: () => Promise; + + // View Functions + getGoldPriceInEth: () => Promise; + getFees: () => Promise; + getFeesAddress: () => Promise; + getUsers: () => Promise; + getTimestamps: () => Promise<{ users: string[]; timestamps: bigint[] }>; + hasOwnerRole: (account: string) => Promise; + + // Admin Functions + setFeesAddress: (feesAddress: string) => Promise; + setLotterieAddress: (lotterieAddress: string) => Promise; + addOwner: (account: string) => Promise; + removeOwner: (account: string) => Promise; + pause: () => Promise; + unpause: () => Promise; +} diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts new file mode 100644 index 0000000..9aa3244 --- /dev/null +++ b/frontend/src/types/index.ts @@ -0,0 +1,11 @@ +// Export your types here +export interface User { + address: string; + balance: string; +} + +export * from "./goldToken"; + +export * from "./lotterie"; + +export * from "./tokenBridge"; diff --git a/frontend/src/types/lotterie.ts b/frontend/src/types/lotterie.ts new file mode 100644 index 0000000..57c3203 --- /dev/null +++ b/frontend/src/types/lotterie.ts @@ -0,0 +1,61 @@ +export interface LotterieEvents { + CallbackGasLimitUpdated: { + previousGasLimit: number; + newGasLimit: number; + }; + GainClaimed: { + account: string; + amount: bigint; + }; + GoldTokenUpdated: { + previousGoldToken: string; + newGoldToken: string; + }; + KeyHashUpdated: { + previousKeyHash: string; + newKeyHash: string; + }; + LotterieInitialized: { + owner: string; + vrfCoordinator: string; + goldToken: string; + vrfSubscriptionId: bigint; + keyHash: string; + callbackGasLimit: number; + requestConfirmations: number; + numWords: number; + }; + NumWordsUpdated: { + previousNumWords: number; + newNumWords: number; + }; + RandomDrawed: { + requestId: bigint; + }; + RequestConfirmationsUpdated: { + previousConfirmations: number; + newConfirmations: number; + }; + VrfCoordinatorUpdated: { + previousCoordinator: string; + newCoordinator: string; + }; + VrfSubscriptionUpdated: { + previousSubscriptionId: bigint; + newSubscriptionId: bigint; + }; + Winner: { + winner: string; + }; +} + +export interface LotterieState { + lastRequestId: bigint; + goldToken: string; + vrfSubscriptionId: bigint; + vrfCoordinator: string; + keyHash: string; + callbackGasLimit: number; + requestConfirmations: number; + numWords: number; +} diff --git a/frontend/src/types/tokenBridge.ts b/frontend/src/types/tokenBridge.ts new file mode 100644 index 0000000..b8bb96f --- /dev/null +++ b/frontend/src/types/tokenBridge.ts @@ -0,0 +1,85 @@ +export enum PayFeesIn { + Native = 0, + LINK = 1, +} + +export interface TokenBridgeState { + destinationChainSelector: bigint; + goldToken: string; + link: string; + goldTokenBalance: bigint; + linkBalance: bigint; + isPaused: boolean; +} + +export interface BridgeTokensParams { + receiver: string; + amount: bigint; + payFeesIn: PayFeesIn; +} + +export interface SetWhitelistedChainParams { + chainSelector: bigint; + enabled: boolean; + ccipExtraArgs: string; +} + +export interface SetWhitelistedSenderParams { + sender: string; + enabled: boolean; +} + +export interface WithdrawParams { + beneficiary: string; +} + +export interface WithdrawTokenParams { + beneficiary: string; + token: string; +} + +// Events +export interface TokensBridgedEvent { + messageId: string; + sender: string; + receiver: string; + amount: bigint; + destinationChainSelector: bigint; + feeToken: string; + fees: bigint; +} + +export interface TokensReceivedEvent { + messageId: string; + receiver: string; + amount: bigint; + sourceChainSelector: bigint; +} + +export interface ChainWhitelistedEvent { + chainSelector: bigint; +} + +export interface ChainRemovedEvent { + chainSelector: bigint; +} + +export interface SenderWhitelistedEvent { + sender: string; +} + +export interface SenderRemovedEvent { + sender: string; +} + +export interface TokenBridgeInitializedEvent { + owner: string; + link: string; + goldToken: string; + destinationChainSelector: bigint; +} + +export interface MessageProcessedWithoutTokenEvent { + messageId: string; + sourceChainSelector: bigint; +} diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 0000000..d8dff50 --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1,21 @@ +/// + +interface ImportMetaEnv { + readonly VITE_REOWN_PROJECT_ID: string; + readonly VITE_CONTRACT_ADDRESS_SEPOLIA_GOLD_TOKEN: string; + readonly VITE_CONTRACT_ADDRESS_SEPOLIA_LOTTERIE: string; + readonly VITE_CONTRACT_ADDRESS_SEPOLIA_TOKEN_BRIDGE: string; + readonly VITE_CONTRACT_ADDRESS_BSC_TESTNET_GOLD_TOKEN: string; + readonly VITE_CONTRACT_ADDRESS_BSC_TESTNET_LOTTERIE: string; + readonly VITE_CONTRACT_ADDRESS_BSC_TESTNET_TOKEN_BRIDGE: string; + readonly VITE_RPC_URL_SEPOLIA: string; + readonly VITE_RPC_URL_BSC_TESTNET: string; + readonly VITE_SITE_NAME: string; + readonly VITE_SITE_DESCRIPTION: string; + readonly VITE_SITE_URL: string; + readonly VITE_SITE_ICON: string; +} + +interface ImportMeta { + readonly env: ImportMetaEnv; +} diff --git a/frontend/tsconfig.app.json b/frontend/tsconfig.app.json new file mode 100644 index 0000000..d739292 --- /dev/null +++ b/frontend/tsconfig.app.json @@ -0,0 +1,27 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"] +} diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json new file mode 100644 index 0000000..c452f43 --- /dev/null +++ b/frontend/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} \ No newline at end of file diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 0000000..3afdd6e --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "composite": true, + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true, + "strict": true, + "noEmit": true + }, + "include": ["vite.config.ts"] +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..1ff0da0 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,7 @@ +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}); From 013ecd4259490f3c04121260c3bb04fdbe015ef8 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Tue, 2 Dec 2025 14:36:41 -0300 Subject: [PATCH 2/9] fix: no precise info printed if callback fails on random draw trigger --- .../components/Admin/AdminPanel.module.css | 11 +++ frontend/src/components/Admin/AdminPanel.tsx | 85 ++++++++++++++++--- .../components/Dashboard/Dashboard.module.css | 31 +++++-- .../GoldToken/GoldTokenCard.module.css | 59 +++++++++++++ .../Lotterie/LotterieCard.module.css | 58 +++++++++++++ .../src/components/NetworkSwitcher.module.css | 19 +++++ .../TokenBridge/TokenBridgeCard.module.css | 81 ++++++++++++++++++ frontend/src/components/ui/Button.module.css | 15 ++++ frontend/src/components/ui/Card.module.css | 35 ++++++++ frontend/src/components/ui/Input.module.css | 13 +++ frontend/src/components/ui/Tooltip.module.css | 16 ++-- frontend/src/hooks/useLotterie.ts | 83 +++++++++++++++++- frontend/src/styles/globals.css | 14 ++- script/deployCoreContracts.s.sol | 4 +- src/Lotterie.sol | 6 +- 15 files changed, 499 insertions(+), 31 deletions(-) diff --git a/frontend/src/components/Admin/AdminPanel.module.css b/frontend/src/components/Admin/AdminPanel.module.css index 03b7eb0..ec29488 100644 --- a/frontend/src/components/Admin/AdminPanel.module.css +++ b/frontend/src/components/Admin/AdminPanel.module.css @@ -222,6 +222,17 @@ color: var(--color-primary); } +.adminButtonSecondary { + border-color: var(--color-text-muted); + color: var(--color-text-muted); +} + +.adminButtonSecondary:hover:not(:disabled) { + background: var(--color-surface); + border-color: var(--color-text); + color: var(--color-text); +} + /* Form Section */ .formSection { margin-top: 1rem; diff --git a/frontend/src/components/Admin/AdminPanel.tsx b/frontend/src/components/Admin/AdminPanel.tsx index a00f527..57998c1 100644 --- a/frontend/src/components/Admin/AdminPanel.tsx +++ b/frontend/src/components/Admin/AdminPanel.tsx @@ -31,7 +31,12 @@ export const AdminPanel: React.FC = () => { setLotterieAddress, } = useGoldToken(); - const { loading: lotterieLoading, randomDraw } = useLotterie(); + const { + loading: lotterieLoading, + randomDraw, + clearError, + checkVrfConfiguration, + } = useLotterie(); const { loading: bridgeLoading, @@ -144,13 +149,41 @@ export const AdminPanel: React.FC = () => { const handleRandomDraw = async () => { try { setErrorMsg(null); - await randomDraw(); - setSuccessMsg("Random draw initiated! Waiting for VRF callback..."); + const requestId = await randomDraw(); + if (requestId) { + setSuccessMsg( + `Random draw initiated! Request ID: ${requestId.toString()}. Waiting for VRF callback...` + ); + } else { + setSuccessMsg("Random draw initiated! Waiting for VRF callback..."); + } } catch (err: any) { + console.error("Random draw failed:", err); setErrorMsg(err.message || "Failed to initiate random draw"); } }; + const handleRetryRandomDraw = () => { + setErrorMsg(null); + setSuccessMsg(null); + clearError(); + }; + + const handleCheckVrfConfig = async () => { + try { + setErrorMsg(null); + setSuccessMsg(null); + const config = await checkVrfConfiguration(); + console.log("VRF Configuration:", config); + setSuccessMsg("VRF configuration checked. See console for details."); + } catch (err: any) { + console.error("VRF config check error:", err); + setErrorMsg( + "Failed to check VRF configuration. See console for details." + ); + } + }; + const handlePauseBridge = async () => { try { setErrorMsg(null); @@ -402,15 +435,43 @@ export const AdminPanel: React.FC = () => {
- - - +
+ + + + + {/* Retry Button - shown when there's an error */} + {errorMsg && ( + + + + )} + + {/* Debug Button - always visible for troubleshooting */} + + + +
)} diff --git a/frontend/src/components/Dashboard/Dashboard.module.css b/frontend/src/components/Dashboard/Dashboard.module.css index 320d566..df865a5 100644 --- a/frontend/src/components/Dashboard/Dashboard.module.css +++ b/frontend/src/components/Dashboard/Dashboard.module.css @@ -1,7 +1,19 @@ .container { max-width: 1280px; margin: 0 auto; - padding: 2rem; + padding: 1rem; +} + +@media (min-width: 768px) { + .container { + padding: 1.5rem; + } +} + +@media (min-width: 1024px) { + .container { + padding: 2rem; + } } .header { @@ -13,16 +25,25 @@ gap: 1rem; } -.headerLeft { - flex: 1; -} - .headerRight { display: flex; align-items: center; gap: 1rem; } +/* Mobile-specific adjustments */ +@media (max-width: 640px) { + .header { + flex-direction: column; + align-items: stretch; + gap: 0.75rem; + } + + .headerRight { + justify-content: center; + } +} + .title { font-size: 2rem; font-weight: 700; diff --git a/frontend/src/components/GoldToken/GoldTokenCard.module.css b/frontend/src/components/GoldToken/GoldTokenCard.module.css index 5139218..1a763e6 100644 --- a/frontend/src/components/GoldToken/GoldTokenCard.module.css +++ b/frontend/src/components/GoldToken/GoldTokenCard.module.css @@ -18,6 +18,19 @@ border-radius: var(--radius-md); } +/* Mobile adjustments for stats grid */ +@media (max-width: 640px) { + .statsGrid { + grid-template-columns: 1fr; + gap: 0.75rem; + padding: 0.75rem; + } + + .statItem { + padding: 0.5rem 0; + } +} + .statItem { display: flex; flex-direction: column; @@ -59,6 +72,21 @@ align-items: center; justify-content: center; gap: 0.5rem; + min-height: 44px; + /* Touch target */ +} + +/* Mobile adjustments for tabs */ +@media (max-width: 640px) { + .tab { + padding: 0.625rem 0.5rem; + font-size: 0.875rem; + gap: 0.25rem; + } + + .tabIcon { + font-size: 0.75rem; + } } .tab:hover { @@ -93,6 +121,24 @@ margin-bottom: 0.5rem; } +/* Mobile adjustments for calculation box */ +@media (max-width: 640px) { + .calculationBox { + padding: 0.625rem 0.75rem; + } + + .calcRow { + font-size: 0.8125rem; + flex-direction: column; + align-items: flex-start; + gap: 0.25rem; + } + + .calcRow span:first-child { + font-size: 0.8125rem; + } +} + .calcRow { display: flex; justify-content: space-between; @@ -147,6 +193,19 @@ font-size: 0.8125rem; cursor: pointer; transition: all 0.2s ease; + min-height: 44px; + /* Touch target */ +} + +/* Mobile adjustments for toggle education */ +@media (max-width: 640px) { + .toggleEducation { + margin-top: 1rem; + padding: 0.75rem; + min-height: 48px; + /* Larger touch target */ + font-size: 0.875rem; + } } .toggleEducation:hover { diff --git a/frontend/src/components/Lotterie/LotterieCard.module.css b/frontend/src/components/Lotterie/LotterieCard.module.css index 055660d..bf04427 100644 --- a/frontend/src/components/Lotterie/LotterieCard.module.css +++ b/frontend/src/components/Lotterie/LotterieCard.module.css @@ -38,6 +38,25 @@ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } +/* Mobile adjustments for jackpot section */ +@media (max-width: 640px) { + .jackpotSection { + padding: 1rem; + margin-bottom: 1rem; + } + + .jackpotTitle { + font-size: 0.875rem; + margin-bottom: 0.375rem; + } + + .jackpotValue { + font-size: 1.75rem; + /* Much smaller on mobile */ + line-height: 1.2; + } +} + .infoSection, .vrfSection, .adminSection { @@ -47,6 +66,17 @@ border-radius: var(--radius-md); } +/* Mobile adjustments for info sections */ +@media (max-width: 640px) { + + .infoSection, + .vrfSection, + .adminSection { + margin-bottom: 1rem; + padding: 0.75rem; + } +} + .sectionTitle { font-size: 0.875rem; font-weight: 600; @@ -67,6 +97,21 @@ font-size: 0.875rem; } +/* Mobile adjustments for info rows */ +@media (max-width: 640px) { + .infoRow { + flex-direction: column; + gap: 0.25rem; + align-items: flex-start; + } + + .infoRow .value { + font-size: 0.8125rem; + word-break: break-all; + max-width: 100%; + } +} + .infoRow:last-child { margin-bottom: 0; } @@ -100,6 +145,19 @@ font-size: 0.8125rem; cursor: pointer; transition: all 0.2s ease; + min-height: 44px; + /* Touch target */ +} + +/* Mobile adjustments for toggle education */ +@media (max-width: 640px) { + .toggleEducation { + margin-top: 1rem; + padding: 0.75rem; + min-height: 48px; + /* Larger touch target */ + font-size: 0.875rem; + } } .toggleEducation:hover { diff --git a/frontend/src/components/NetworkSwitcher.module.css b/frontend/src/components/NetworkSwitcher.module.css index cf57824..2d83aed 100644 --- a/frontend/src/components/NetworkSwitcher.module.css +++ b/frontend/src/components/NetworkSwitcher.module.css @@ -16,6 +16,25 @@ font-weight: 500; cursor: pointer; transition: all 0.2s ease; + min-height: 44px; + /* Touch target size */ +} + +/* Mobile adjustments for NetworkSwitcher */ +@media (max-width: 640px) { + .button { + padding: 10px 16px; + /* Slightly larger touch target */ + font-size: 14px; + } + + .dropdown { + right: auto; + left: 0; + /* Align dropdown to left on mobile */ + min-width: 200px; + /* Slightly wider on mobile */ + } } .button:hover { diff --git a/frontend/src/components/TokenBridge/TokenBridgeCard.module.css b/frontend/src/components/TokenBridge/TokenBridgeCard.module.css index 08bea60..e5e53db 100644 --- a/frontend/src/components/TokenBridge/TokenBridgeCard.module.css +++ b/frontend/src/components/TokenBridge/TokenBridgeCard.module.css @@ -19,6 +19,24 @@ border-radius: var(--radius-md); } +/* Mobile adjustments for network flow */ +@media (max-width: 640px) { + .networkFlow { + flex-direction: column; + gap: 1rem; + text-align: center; + } + + .networkNode { + min-width: auto; + width: 100%; + } + + .arrow { + transform: rotate(90deg); + } +} + .networkNode { display: flex; flex-direction: column; @@ -85,6 +103,25 @@ border-radius: var(--radius-md); } +/* Mobile adjustments for liquidity info */ +@media (max-width: 640px) { + .liquidityInfo { + flex-direction: column; + gap: 0.5rem; + text-align: center; + padding: 0.625rem 0.75rem; + margin-bottom: 1rem; + } + + .liquidityLabel { + font-size: 0.8125rem; + } + + .liquidityValue { + font-size: 0.9rem; + } +} + .liquidityLabel { font-size: 0.875rem; color: #93C5FD; @@ -111,6 +148,19 @@ border-radius: var(--radius-md); } +/* Mobile adjustments for fee selection */ +@media (max-width: 640px) { + .feeSelection { + margin-bottom: 0.75rem; + padding: 0.75rem; + } + + .feeLabel { + font-size: 0.8125rem; + margin-bottom: 0.625rem; + } +} + .feeLabel { display: flex; align-items: center; @@ -126,6 +176,14 @@ gap: 1.5rem; } +/* Mobile adjustments for radio group */ +@media (max-width: 640px) { + .radioGroup { + flex-direction: column; + gap: 0.75rem; + } +} + .radioLabel { display: flex; align-items: center; @@ -135,6 +193,16 @@ padding: 0.5rem 0.75rem; border-radius: var(--radius-md); transition: background-color 0.2s ease; + min-height: 44px; + /* Touch target size */ +} + +/* Mobile adjustments for radio labels */ +@media (max-width: 640px) { + .radioLabel { + padding: 0.75rem; + font-size: 0.9rem; + } } .radioLabel:hover { @@ -167,6 +235,19 @@ font-size: 0.8125rem; cursor: pointer; transition: all 0.2s ease; + min-height: 44px; + /* Touch target */ +} + +/* Mobile adjustments for toggle education */ +@media (max-width: 640px) { + .toggleEducation { + margin-top: 1rem; + padding: 0.75rem; + min-height: 48px; + /* Larger touch target */ + font-size: 0.875rem; + } } .toggleEducation:hover { diff --git a/frontend/src/components/ui/Button.module.css b/frontend/src/components/ui/Button.module.css index 24b87fc..310c05a 100644 --- a/frontend/src/components/ui/Button.module.css +++ b/frontend/src/components/ui/Button.module.css @@ -72,6 +72,21 @@ height: 3rem; } +/* Mobile touch target adjustments */ +@media (max-width: 640px) { + .md { + height: 2.75rem; + /* Larger touch target */ + padding: 0.625rem 1.25rem; + } + + .lg { + height: 3.25rem; + /* Larger touch target */ + padding: 0.875rem 1.75rem; + } +} + .fullWidth { width: 100%; } diff --git a/frontend/src/components/ui/Card.module.css b/frontend/src/components/ui/Card.module.css index 11b2d2d..e220e9b 100644 --- a/frontend/src/components/ui/Card.module.css +++ b/frontend/src/components/ui/Card.module.css @@ -17,6 +17,20 @@ align-items: flex-start; } +/* Mobile adjustments for card header */ +@media (max-width: 640px) { + .header { + padding: 1rem; + flex-direction: column; + gap: 0.75rem; + } + + .action { + margin-left: 0; + align-self: stretch; + } +} + .titleContainer { flex: 1; } @@ -28,6 +42,13 @@ margin: 0; } +/* Mobile adjustments for title */ +@media (max-width: 640px) { + .title { + font-size: 1.125rem; + } +} + .subtitle { font-size: 0.875rem; color: var(--color-text-muted); @@ -43,8 +64,22 @@ flex: 1; } +/* Mobile adjustments for card body */ +@media (max-width: 640px) { + .body { + padding: 1rem; + } +} + .footer { padding: 1rem 1.5rem; background-color: rgba(0, 0, 0, 0.2); border-top: 1px solid var(--color-border); +} + +/* Mobile adjustments for card footer */ +@media (max-width: 640px) { + .footer { + padding: 0.75rem 1rem; + } } \ No newline at end of file diff --git a/frontend/src/components/ui/Input.module.css b/frontend/src/components/ui/Input.module.css index df2f708..0944638 100644 --- a/frontend/src/components/ui/Input.module.css +++ b/frontend/src/components/ui/Input.module.css @@ -27,6 +27,19 @@ border: 1px solid var(--color-border); border-radius: var(--radius-md); transition: border-color 0.2s ease, box-shadow 0.2s ease; + min-height: 44px; + /* Touch target size */ +} + +/* Mobile adjustments for input */ +@media (max-width: 640px) { + .input { + padding: 0.75rem; + font-size: 16px; + /* Prevent zoom on iOS */ + min-height: 48px; + /* Larger touch target */ + } } .input:focus { diff --git a/frontend/src/components/ui/Tooltip.module.css b/frontend/src/components/ui/Tooltip.module.css index bdae4c4..5ec2123 100644 --- a/frontend/src/components/ui/Tooltip.module.css +++ b/frontend/src/components/ui/Tooltip.module.css @@ -14,28 +14,34 @@ @keyframes fadeIn { from { opacity: 0; - transform: translateY(4px); } to { opacity: 1; - transform: translateY(0); } } .tooltipContent { background-color: var(--color-secondary); color: var(--color-text); - padding: 0.5rem 0.75rem; + padding: 0.5rem 1rem; border-radius: var(--radius-md); font-size: 0.8125rem; - line-height: 1.4; - max-width: 280px; + line-height: 1.3; + width: 280px; + /* Mobile-first: narrower width for vertical content display */ box-shadow: var(--shadow-lg); border: 1px solid var(--color-border); white-space: normal; } +/* Tablet and larger screens: wider layout for horizontal content display */ +@media (min-width: 768px) { + .tooltipContent { + width: 400px; + } +} + .arrow { position: absolute; width: 8px; diff --git a/frontend/src/hooks/useLotterie.ts b/frontend/src/hooks/useLotterie.ts index b52b6bd..058f40a 100644 --- a/frontend/src/hooks/useLotterie.ts +++ b/frontend/src/hooks/useLotterie.ts @@ -171,10 +171,31 @@ export const useLotterie = () => { try { const contract = await getContract(true); const tx = await contract.randomDraw(); - await tx.wait(); - // We might want to return the requestId from the event here, but for now just void + const receipt = await tx.wait(); + + // Extract requestId from transaction receipt if available + const requestId = receipt?.logs?.[0]?.args?.[0]; + console.log("VRF Request initiated with ID:", requestId?.toString()); + + return requestId; } catch (err: any) { - setError(err.message || "Failed to initiate random draw"); + console.error("VRF Random Draw Error:", err); + + // Provide specific error messages for common VRF issues + let errorMessage = "Failed to initiate random draw"; + if (err.message?.includes("gas")) { + errorMessage = "Gas estimation failed. Please try again."; + } else if (err.message?.includes("OneRandomDrawPerDay")) { + errorMessage = + "Random draw can only be performed once per day. Please try again tomorrow."; + } else if (err.message?.includes("execution reverted")) { + errorMessage = + "Transaction reverted. Please check your permissions and try again."; + } else if (err.message) { + errorMessage = err.message; + } + + setError(errorMessage); throw err; } finally { setLoading(false); @@ -356,12 +377,67 @@ export const useLotterie = () => { [getContract] ); + // Diagnostic function to check VRF configuration + const checkVrfConfiguration = useCallback(async () => { + try { + const [ + subscriptionId, + coordinator, + keyHash, + callbackGasLimit, + requestConfirmations, + numWords, + ] = await Promise.all([ + getVrfSubscriptionId(), + getVrfCoordinator(), + getKeyHash(), + getCallbackGasLimit(), + getRequestConfirmations(), + getNumWords(), + ]); + + console.log("VRF Configuration Check:"); + console.log("- Subscription ID:", subscriptionId.toString()); + console.log("- Coordinator:", coordinator); + console.log("- Key Hash:", keyHash); + console.log("- Callback Gas Limit:", callbackGasLimit.toString()); + console.log("- Request Confirmations:", requestConfirmations.toString()); + console.log("- Num Words:", numWords.toString()); + + return { + subscriptionId, + coordinator, + keyHash, + callbackGasLimit, + requestConfirmations, + numWords, + }; + } catch (err: any) { + console.error("VRF Configuration Check Failed:", err); + setError(err.message || "Failed to check VRF configuration"); + throw err; + } + }, [ + getVrfSubscriptionId, + getVrfCoordinator, + getKeyHash, + getCallbackGasLimit, + getRequestConfirmations, + getNumWords, + ]); + + // Function to manually clear error state + const clearError = useCallback(() => { + setError(null); + }, []); + return { loading, error, contractAddress, isConnected, address, + clearError, claim, getGains, getLastRequestId, @@ -384,5 +460,6 @@ export const useLotterie = () => { addOwner, removeOwner, hasOwnerRole, + checkVrfConfiguration, }; }; diff --git a/frontend/src/styles/globals.css b/frontend/src/styles/globals.css index 20b3969..3b55bc7 100644 --- a/frontend/src/styles/globals.css +++ b/frontend/src/styles/globals.css @@ -70,7 +70,19 @@ textarea { .container { max-width: 1280px; margin: 0 auto; - padding: 2rem; + padding: 1rem; +} + +@media (min-width: 768px) { + .container { + padding: 1.5rem; + } +} + +@media (min-width: 1024px) { + .container { + padding: 2rem; + } } .text-center { diff --git a/script/deployCoreContracts.s.sol b/script/deployCoreContracts.s.sol index 078408a..d54b7a6 100644 --- a/script/deployCoreContracts.s.sol +++ b/script/deployCoreContracts.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {Script, console2} from "forge-std/Script.sol"; +import {Script, console2} from "forge-std/src/Script.sol"; import {GoldToken} from "../src/GoldToken.sol"; import {Lotterie} from "../src/Lotterie.sol"; import {TokenBridge} from "../src/TokenBridge.sol"; @@ -69,7 +69,7 @@ contract DeployCoreContracts is Script { }); // Chainlink VRF parameters (same for both networks) - uint32 constant CALLBACK_GAS_LIMIT = 40000; + uint32 constant CALLBACK_GAS_LIMIT = 100000; uint16 constant REQUEST_CONFIRMATIONS = 3; uint32 constant NUM_WORDS = 1; diff --git a/src/Lotterie.sol b/src/Lotterie.sol index c3556d2..492642c 100644 --- a/src/Lotterie.sol +++ b/src/Lotterie.sol @@ -93,9 +93,9 @@ contract Lotterie is _vrfSubscriptionId = vrfSubscriptionId; s_vrfCoordinator = IVRFCoordinatorV2Plus(vrfCoordinator); _vrfKeyHash = keyHash; - _callbackGasLimit = callbackGasLimit; // 40000 - _requestConfirmations = requestConfirmations; // 3 - _numWords = numWords; // 1 + _callbackGasLimit = callbackGasLimit; + _requestConfirmations = requestConfirmations; + _numWords = numWords; _lastRandomDraw = block.timestamp - 1 days; _goldToken = IGoldToken(goldToken); From edcaf9890de252fe30ae157a1577891f83842e44 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Wed, 3 Dec 2025 10:09:47 -0300 Subject: [PATCH 3/9] feat: adding _randomDrawCooldown and making _vrfNativePayment state variables --- script/deployCoreContracts.s.sol | 1 + src/Lotterie.sol | 28 +++++++++++++++------- src/interfaces/ILotterie.sol | 41 +++++++++++++++++++++++++++++--- test/Lotterie.fuzz.t.sol | 4 +++- test/Lotterie.t.sol | 14 ++++++++--- 5 files changed, 72 insertions(+), 16 deletions(-) diff --git a/script/deployCoreContracts.s.sol b/script/deployCoreContracts.s.sol index d54b7a6..d3a50c2 100644 --- a/script/deployCoreContracts.s.sol +++ b/script/deployCoreContracts.s.sol @@ -72,6 +72,7 @@ contract DeployCoreContracts is Script { uint32 constant CALLBACK_GAS_LIMIT = 100000; uint16 constant REQUEST_CONFIRMATIONS = 3; uint32 constant NUM_WORDS = 1; + bool constant VRF_NATIVE_PAYMENT = false; function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); diff --git a/src/Lotterie.sol b/src/Lotterie.sol index 492642c..1b859e8 100644 --- a/src/Lotterie.sol +++ b/src/Lotterie.sol @@ -38,6 +38,9 @@ contract Lotterie is /// @notice Key hash identifying the VRF proving key used for draws bytes32 internal _vrfKeyHash; + /// @notice Whether the payment in native tokens is enabled for the VRF subscription + bool internal _vrfNativePayment; + /// @notice Gas limit allocated to `fulfillRandomWords` uint32 internal _callbackGasLimit; @@ -47,12 +50,15 @@ contract Lotterie is /// @notice Amount of random words requested per draw uint32 internal _numWords; - /// @notice GoldToken proxy feeding participant balances and payouts - IGoldToken internal _goldToken; + /// @notice randomDrawCooldown amount of time required between draws + uint256 internal _randomDrawCooldown; - /// @notice Timestamp of the most recent draw, used to enforce the daily cadence + /// @notice Timestamp of the most recent draw, used to enforce the cooldown period uint256 internal _lastRandomDraw; + /// @notice GoldToken proxy feeding participant balances and payouts + IGoldToken internal _goldToken; + /// @notice Historical record of VRF request identifiers uint256[] internal _requestIds; @@ -78,10 +84,12 @@ contract Lotterie is address owner, uint256 vrfSubscriptionId, address vrfCoordinator, + bool vrfNativePayment, bytes32 keyHash, uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, + uint256 randomDrawCooldown, address goldToken ) external override initializer { __AccessControl_init(); @@ -93,10 +101,11 @@ contract Lotterie is _vrfSubscriptionId = vrfSubscriptionId; s_vrfCoordinator = IVRFCoordinatorV2Plus(vrfCoordinator); _vrfKeyHash = keyHash; + _vrfNativePayment = vrfNativePayment; _callbackGasLimit = callbackGasLimit; _requestConfirmations = requestConfirmations; _numWords = numWords; - + _randomDrawCooldown = randomDrawCooldown; _lastRandomDraw = block.timestamp - 1 days; _goldToken = IGoldToken(goldToken); @@ -105,10 +114,12 @@ contract Lotterie is vrfCoordinator, goldToken, vrfSubscriptionId, + vrfNativePayment, keyHash, callbackGasLimit, requestConfirmations, - numWords + numWords, + randomDrawCooldown ); } @@ -187,8 +198,8 @@ contract Lotterie is /// @inheritdoc ILotterie function randomDraw() external override onlyRole(OWNER_ROLE) returns (uint256) { - if (_lastRandomDraw + 1 days > block.timestamp) { - revert OneRandomDrawPerDay(); + if (_lastRandomDraw + _randomDrawCooldown > block.timestamp) { + revert DrawCooldownNotExpired(_lastRandomDraw, _randomDrawCooldown, block.timestamp); } uint256 requestId = s_vrfCoordinator.requestRandomWords( @@ -198,8 +209,7 @@ contract Lotterie is requestConfirmations: _requestConfirmations, callbackGasLimit: _callbackGasLimit, numWords: _numWords, - // Set nativePayment to true to pay for VRF requests with Sepolia ETH instead of LINK - extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: false})) + extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: _vrfNativePayment})) }) ); diff --git a/src/interfaces/ILotterie.sol b/src/interfaces/ILotterie.sol index 58c567d..539578f 100644 --- a/src/interfaces/ILotterie.sol +++ b/src/interfaces/ILotterie.sol @@ -15,6 +15,7 @@ interface ILotterie { * @param requestId Unique identifier for the Chainlink VRF request */ event RandomDrawed(uint256 indexed requestId); + /** * @notice Emitted when a winner is determined for the active lottery * @param winner Address receiving the lottery gains @@ -27,20 +28,24 @@ interface ILotterie { * @param vrfCoordinator Chainlink VRF coordinator contract address * @param goldToken GoldToken proxy associated with the lottery * @param vrfSubscriptionId VRF subscription identifier configured for draws + * @param vrfNativePayment Whether the VRF subscription is configured for native payment * @param keyHash Chainlink VRF key hash used to request randomness * @param callbackGasLimit Gas limit allocated to fulfillRandomWords * @param requestConfirmations Number of confirmations required per VRF request * @param numWords Number of random words requested per draw + * @param randomDrawCooldown Minimum time required between lottery draws */ event LotterieInitialized( address indexed owner, address indexed vrfCoordinator, address indexed goldToken, uint256 vrfSubscriptionId, + bool vrfNativePayment, bytes32 keyHash, uint32 callbackGasLimit, uint16 requestConfirmations, - uint32 numWords + uint32 numWords, + uint256 randomDrawCooldown ); /** @@ -102,10 +107,17 @@ interface ILotterie { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ - /// @notice Reverts when attempting to draw more than once within a rolling 24-hour window - error OneRandomDrawPerDay(); + /** + * @notice Reverts when attempting to draw more than once within the cooldown period + * @param lastDraw Timestamp of the last draw + * @param cooldown Minimum time between draws + * @param currentTime Current block timestamp + */ + error DrawCooldownNotExpired(uint256 lastDraw, uint256 cooldown, uint256 currentTime); + /// @notice Reverts when a user tries to claim gains but has none error NoGainToClaim(); + /// @notice Reverts when the GoldToken transfer fails during a claim error TransferFailed(); @@ -115,39 +127,47 @@ interface ILotterie { /// @notice Grants OWNER_ROLE to a new account /// @param account Address receiving OWNER_ROLE function addOwner(address account) external; + /// @notice Revokes OWNER_ROLE from an account /// @param account Address losing OWNER_ROLE function removeOwner(address account) external; + /** * @notice Updates the Chainlink VRF subscription identifier * @param vrfSubscriptionId New subscription id */ function setVrfSubscriptionId(uint256 vrfSubscriptionId) external; + /** * @notice Updates the VRF coordinator contract reference * @param vrfCoordinator Address of the VRF coordinator contract */ function setVrfCoordinator(address vrfCoordinator) external; + /** * @notice Updates the VRF key hash used for randomness requests * @param keyHash New VRF key hash */ function setKeyHash(bytes32 keyHash) external; + /** * @notice Adjusts the gas limit used for the VRF callback * @param callbackGasLimit New callback gas limit */ function setCallbackGasLimit(uint32 callbackGasLimit) external; + /** * @notice Adjusts the number of confirmations required for VRF requests * @param requestConfirmations New confirmation count */ function setRequestConfirmations(uint16 requestConfirmations) external; + /** * @notice Adjusts the number of random words requested from VRF * @param numWords New number of random words per request */ function setNumWords(uint32 numWords) external; + /** * @notice Updates the GoldToken implementation used to read balances and manage gains * @param goldToken Address of the GoldToken proxy @@ -162,20 +182,24 @@ interface ILotterie { * @param owner Address granted OWNER_ROLE * @param vrfSubscriptionId Subscription id funding VRF requests * @param vrfCoordinator Address of the VRF coordinator + * @param vrfNativePayment True when the VRF subscription uses native payment * @param keyHash Chainlink VRF key hash used for randomness * @param callbackGasLimit Gas limit allocated for fulfillRandomWords * @param requestConfirmations Number of confirmations required for VRF responses * @param numWords Number of random words requested per draw + * @param randomDrawCooldown Minimum time between draws * @param goldToken Address of the GoldToken proxy */ function initialize( address owner, uint256 vrfSubscriptionId, address vrfCoordinator, + bool vrfNativePayment, bytes32 keyHash, uint32 callbackGasLimit, uint16 requestConfirmations, uint32 numWords, + uint256 randomDrawCooldown, address goldToken ) external; @@ -184,6 +208,7 @@ interface ILotterie { * @return requestId Identifier of the VRF request */ function randomDraw() external returns (uint256 requestId); + /// @notice Claims accrued lottery gains for the caller function claim() external; @@ -194,8 +219,10 @@ interface ILotterie { /// @param account Address to inspect /// @return True when the account has OWNER_ROLE function hasOwnerRole(address account) external view returns (bool); + /// @notice Returns the most recent VRF request identifier /// @return requestId Last stored VRF request id (zero when no draws) + function getLastRequestId() external view returns (uint256); /** * @notice Returns the pending gains assigned to an account @@ -203,42 +230,50 @@ interface ILotterie { * @return Amount of GLD available to claim */ function getGains(address account) external view returns (uint256); + /** * @notice Returns the winner associated with a specific VRF request id * @param requestId VRF request identifier * @return Winner address linked to the request */ function getResults(uint256 requestId) external view returns (address); + /** * @notice Returns the VRF coordinator in use * @return Address of the VRF coordinator contract */ function getVrfCoordinator() external view returns (address); + /** * @notice Returns the VRF key hash currently configured * @return VRF key hash value */ function getKeyHash() external view returns (bytes32); + /** * @notice Returns the gas limit used for VRF callbacks * @return Callback gas limit */ function getCallbackGasLimit() external view returns (uint32); + /** * @notice Returns the number of confirmations before VRF fulfills requests * @return Confirmation count */ function getRequestConfirmations() external view returns (uint16); + /** * @notice Returns the number of random words requested per draw * @return Number of random words */ function getNumWords() external view returns (uint32); + /** * @notice Returns the GoldToken proxy address used by the lottery * @return GoldToken address */ function getGoldToken() external view returns (address); + /** * @notice Returns the VRF subscription identifier currently configured * @return Subscription id diff --git a/test/Lotterie.fuzz.t.sol b/test/Lotterie.fuzz.t.sol index f3a154e..f17201e 100644 --- a/test/Lotterie.fuzz.t.sol +++ b/test/Lotterie.fuzz.t.sol @@ -43,10 +43,12 @@ contract LotterieFuzzTest is Test { address(this), vrfSubscriptionId, address(vrfCoordinator), + false, bytes32(0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae), 100000, 3, 1, + 86400, address(goldToken) ) ); @@ -157,7 +159,7 @@ contract LotterieFuzzTest is Test { vm.warp(block.timestamp + timeElapsed); if (timeElapsed < 1 days) { - vm.expectRevert(ILotterie.OneRandomDrawPerDay.selector); + vm.expectRevert(ILotterie.DrawCooldownNotExpired.selector); lotterie.randomDraw(); } else { uint256 requestId = lotterie.randomDraw(); diff --git a/test/Lotterie.t.sol b/test/Lotterie.t.sol index 8aea0f9..8964551 100644 --- a/test/Lotterie.t.sol +++ b/test/Lotterie.t.sol @@ -25,10 +25,12 @@ contract LotterieTest is Test { address indexed vrfCoordinator, address indexed goldToken, uint256 vrfSubscriptionId, + bool vrfNativePayment, bytes32 keyHash, uint32 callbackGasLimit, uint16 requestConfirmations, - uint32 numWords + uint32 numWords, + uint256 randomDrawCooldown ); event VrfSubscriptionUpdated(uint256 indexed previousSubscriptionId, uint256 indexed newSubscriptionId); event VrfCoordinatorUpdated(address indexed previousCoordinator, address indexed newCoordinator); @@ -68,10 +70,12 @@ contract LotterieTest is Test { address(this), subscription, address(vrfCoordinator), + false, bytes32(0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae), 100000, 3, 1, + 86400, address(goldToken) ) ); @@ -101,7 +105,7 @@ contract LotterieTest is Test { function test_randomDrawBefore1DayWaiting() public { vm.warp(block.timestamp - 1 hours); - vm.expectRevert(ILotterie.OneRandomDrawPerDay.selector); + vm.expectRevert(ILotterie.DrawCooldownNotExpired.selector); lotterie.randomDraw(); } @@ -249,10 +253,12 @@ contract LotterieTest is Test { address(vrfCoordinator), address(goldToken), subscription, + true, bytes32(uint256(0x1111)), 50_000, 2, - 1 + 1, + 86400 ); new ERC1967Proxy( address(implementation), @@ -261,10 +267,12 @@ contract LotterieTest is Test { address(this), subscription, address(vrfCoordinator), + true, bytes32(uint256(0x1111)), 50_000, 2, 1, + 86400, address(goldToken) ) ); From 42546ccfbcb2c2cdd037352f46bfe86da79e95e0 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Wed, 3 Dec 2025 10:55:00 -0300 Subject: [PATCH 4/9] fix: failing tests caused by the adding of _randomDrawCooldown and _vrfNativePayment as state variables --- test/Lotterie.fuzz.t.sol | 9 ++++++++- test/Lotterie.t.sol | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/test/Lotterie.fuzz.t.sol b/test/Lotterie.fuzz.t.sol index f17201e..78d2b25 100644 --- a/test/Lotterie.fuzz.t.sol +++ b/test/Lotterie.fuzz.t.sol @@ -159,7 +159,14 @@ contract LotterieFuzzTest is Test { vm.warp(block.timestamp + timeElapsed); if (timeElapsed < 1 days) { - vm.expectRevert(ILotterie.DrawCooldownNotExpired.selector); + vm.expectRevert( + abi.encodeWithSelector( + ILotterie.DrawCooldownNotExpired.selector, + block.timestamp - timeElapsed, + 1 days, + block.timestamp + ) + ); lotterie.randomDraw(); } else { uint256 requestId = lotterie.randomDraw(); diff --git a/test/Lotterie.t.sol b/test/Lotterie.t.sol index 8964551..82aaa21 100644 --- a/test/Lotterie.t.sol +++ b/test/Lotterie.t.sol @@ -104,8 +104,15 @@ contract LotterieTest is Test { } function test_randomDrawBefore1DayWaiting() public { + uint256 lastDraw = block.timestamp - 1 days; + uint256 cooldown = 1 days; + vm.warp(block.timestamp - 1 hours); - vm.expectRevert(ILotterie.DrawCooldownNotExpired.selector); + uint256 currentTime = block.timestamp; + + vm.expectRevert( + abi.encodeWithSelector(ILotterie.DrawCooldownNotExpired.selector, lastDraw, cooldown, currentTime) + ); lotterie.randomDraw(); } From 41feb161080ba12aee49f631633be3243f4177f0 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Wed, 3 Dec 2025 15:41:21 -0300 Subject: [PATCH 5/9] feat: adding setter, getter and event for randomDrawCooldown and vrfNativePayment --- script/deployCoreContracts.s.sol | 5 +++- script/deployCoreContractsDefender.s.sol | 23 ++++++++------ src/Lotterie.sol | 24 +++++++++++++++ src/interfaces/ILotterie.sol | 38 ++++++++++++++++++++++++ test/Lotterie.fuzz.t.sol | 25 ++++++++++------ test/Lotterie.t.sol | 16 ++++++++++ 6 files changed, 112 insertions(+), 19 deletions(-) diff --git a/script/deployCoreContracts.s.sol b/script/deployCoreContracts.s.sol index d3a50c2..2bd6f98 100644 --- a/script/deployCoreContracts.s.sol +++ b/script/deployCoreContracts.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.28; -import {Script, console2} from "forge-std/src/Script.sol"; +import {Script, console2} from "forge-std/Script.sol"; import {GoldToken} from "../src/GoldToken.sol"; import {Lotterie} from "../src/Lotterie.sol"; import {TokenBridge} from "../src/TokenBridge.sol"; @@ -73,6 +73,7 @@ contract DeployCoreContracts is Script { uint16 constant REQUEST_CONFIRMATIONS = 3; uint32 constant NUM_WORDS = 1; bool constant VRF_NATIVE_PAYMENT = false; + uint32 constant RANDOM_DRAW_COOLDOWN = 5 minutes; // low cooldown set for testing purposes function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); @@ -112,10 +113,12 @@ contract DeployCoreContracts is Script { deployer, config.vrfSubscriptionId, config.vrfCoordinator, + VRF_NATIVE_PAYMENT, config.keyHash, CALLBACK_GAS_LIMIT, REQUEST_CONFIRMATIONS, NUM_WORDS, + RANDOM_DRAW_COOLDOWN, address(goldToken) ); ERC1967Proxy lotterieProxy = new ERC1967Proxy(address(lotterieImpl), lotterieData); diff --git a/script/deployCoreContractsDefender.s.sol b/script/deployCoreContractsDefender.s.sol index 4b8e25f..e5df6fb 100644 --- a/script/deployCoreContractsDefender.s.sol +++ b/script/deployCoreContractsDefender.s.sol @@ -15,16 +15,17 @@ import {Options, Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; * openzeppelin-foundry-upgrades so relayers/Safe approvals can manage ownership. */ contract DeployCoreContractsWithDefender is Script { + // Network specific configurations struct NetworkConfig { - address router; - address link; - uint256 vrfSubscriptionId; - uint64 chainSelector; - uint64 destSelector; - address goldUsdFeed; - address ethUsdFeed; - address vrfCoordinator; - bytes32 keyHash; + address router; // CCIP Router + address link; // LINK Token + uint256 vrfSubscriptionId; // VRF Subscription ID + uint64 chainSelector; // This chain's selector + uint64 destSelector; // Destination chain's selector + address goldUsdFeed; // Gold/USD price feed + address ethUsdFeed; // ETH/USD or BNB/USD price feed + address vrfCoordinator; // VRF Coordinator + bytes32 keyHash; // VRF key hash } error UnsupportedNetwork(uint256 chainId); @@ -59,6 +60,8 @@ contract DeployCoreContractsWithDefender is Script { uint32 constant CALLBACK_GAS_LIMIT = 40000; uint16 constant REQUEST_CONFIRMATIONS = 3; uint32 constant NUM_WORDS = 1; + bool constant VRF_NATIVE_PAYMENT = false; + uint32 constant RANDOM_DRAW_COOLDOWN = 1 days; function run() external { NetworkConfig memory config = _currentNetwork(); @@ -83,10 +86,12 @@ contract DeployCoreContractsWithDefender is Script { owner, config.vrfSubscriptionId, config.vrfCoordinator, + VRF_NATIVE_PAYMENT, config.keyHash, CALLBACK_GAS_LIMIT, REQUEST_CONFIRMATIONS, NUM_WORDS, + RANDOM_DRAW_COOLDOWN, goldTokenProxy ) ), diff --git a/src/Lotterie.sol b/src/Lotterie.sol index 1b859e8..0821a5f 100644 --- a/src/Lotterie.sol +++ b/src/Lotterie.sol @@ -192,6 +192,20 @@ contract Lotterie is emit GoldTokenUpdated(previous, goldToken); } + /// @inheritdoc ILotterie + function setRandomDrawCooldown(uint256 randomDrawCooldown) external override onlyRole(OWNER_ROLE) { + uint256 previous = _randomDrawCooldown; + _randomDrawCooldown = randomDrawCooldown; + emit RandomDrawCooldownUpdated(previous, randomDrawCooldown); + } + + /// @inheritdoc ILotterie + function setVrfNativePayment(bool vrfNativePayment) external override onlyRole(OWNER_ROLE) { + bool previous = _vrfNativePayment; + _vrfNativePayment = vrfNativePayment; + emit VrfNativePaymentUpdated(previous, vrfNativePayment); + } + /*////////////////////////////////////////////////////////////// CORE FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -301,4 +315,14 @@ contract Lotterie is function getVrfSubscriptionId() external view override returns (uint256) { return _vrfSubscriptionId; } + + /// @inheritdoc ILotterie + function getRandomDrawCooldown() external view override returns (uint256) { + return _randomDrawCooldown; + } + + /// @inheritdoc ILotterie + function getVrfNativePayment() external view override returns (bool) { + return _vrfNativePayment; + } } diff --git a/src/interfaces/ILotterie.sol b/src/interfaces/ILotterie.sol index 539578f..ecfe18f 100644 --- a/src/interfaces/ILotterie.sol +++ b/src/interfaces/ILotterie.sol @@ -97,6 +97,20 @@ interface ILotterie { */ event GoldTokenUpdated(address indexed previousGoldToken, address indexed newGoldToken); + /** + * @notice Emitted when the random draw cooldown changes + * @param previousCooldown Cooldown before the update + * @param newCooldown Cooldown after the update + */ + event RandomDrawCooldownUpdated(uint256 indexed previousCooldown, uint256 indexed newCooldown); + + /** + * @notice Emitted when the VRF native payment setting changes + * @param previousNativePayment Setting before the update + * @param newNativePayment Setting after the update + */ + event VrfNativePaymentUpdated(bool indexed previousNativePayment, bool indexed newNativePayment); + /** * @notice Emitted when a participant successfully claims lottery gains * @param account Winner address claiming their gains @@ -174,6 +188,18 @@ interface ILotterie { */ function setGoldToken(address goldToken) external; + /** + * @notice Updates the minimum time required between lottery draws + * @param randomDrawCooldown New cooldown period + */ + function setRandomDrawCooldown(uint256 randomDrawCooldown) external; + + /** + * @notice Updates the VRF native payment setting + * @param vrfNativePayment New native payment setting + */ + function setVrfNativePayment(bool vrfNativePayment) external; + /*////////////////////////////////////////////////////////////// CORE FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -279,4 +305,16 @@ interface ILotterie { * @return Subscription id */ function getVrfSubscriptionId() external view returns (uint256); + + /** + * @notice Returns the minimum time required between lottery draws + * @return Cooldown period + */ + function getRandomDrawCooldown() external view returns (uint256); + + /** + * @notice Returns whether the VRF subscription uses native payment + * @return True if native payment is enabled + */ + function getVrfNativePayment() external view returns (bool); } diff --git a/test/Lotterie.fuzz.t.sol b/test/Lotterie.fuzz.t.sol index 78d2b25..56a94da 100644 --- a/test/Lotterie.fuzz.t.sol +++ b/test/Lotterie.fuzz.t.sol @@ -147,33 +147,40 @@ contract LotterieFuzzTest is Test { } /// @notice Fuzz test time constraints between draws - function testFuzz_randomDraw_timeConstraints(uint32 timeElapsed) public { - vm.assume(timeElapsed < 2 days); + function testFuzz_randomDraw_timeConstraints(uint32 timeElapsed, uint32 cooldown) public { + vm.assume(cooldown > 1 hours); + vm.assume(cooldown < 365 days); + vm.assume(timeElapsed < cooldown * 2); + + lotterie.setRandomDrawCooldown(cooldown); vm.deal(address(this), 1 ether); goldToken.mint{value: 1 ether}(); - vm.warp(block.timestamp + 1 days); + vm.warp(block.timestamp + cooldown); lotterie.randomDraw(); vm.warp(block.timestamp + timeElapsed); - if (timeElapsed < 1 days) { + if (timeElapsed < cooldown) { vm.expectRevert( abi.encodeWithSelector( - ILotterie.DrawCooldownNotExpired.selector, - block.timestamp - timeElapsed, - 1 days, - block.timestamp + ILotterie.DrawCooldownNotExpired.selector, block.timestamp - timeElapsed, cooldown, block.timestamp ) ); lotterie.randomDraw(); } else { uint256 requestId = lotterie.randomDraw(); - assertGt(requestId, 0, "Should succeed after 1 day"); + assertGt(requestId, 0, "Should succeed after cooldown"); } } + /// @notice Fuzz test VRF native payment setting + function testFuzz_setVrfNativePayment(bool useNative) public { + lotterie.setVrfNativePayment(useNative); + assertEq(lotterie.getVrfNativePayment(), useNative, "Native payment setting should update"); + } + /// @notice Fuzz test VRF subscription ID changes function testFuzz_setVrfSubscriptionId(uint256 newSubscriptionId) public { vm.assume(newSubscriptionId > 0); diff --git a/test/Lotterie.t.sol b/test/Lotterie.t.sol index 82aaa21..b987d7f 100644 --- a/test/Lotterie.t.sol +++ b/test/Lotterie.t.sol @@ -39,6 +39,8 @@ contract LotterieTest is Test { event RequestConfirmationsUpdated(uint16 indexed previousConfirmations, uint16 indexed newConfirmations); event NumWordsUpdated(uint32 indexed previousNumWords, uint32 indexed newNumWords); event GoldTokenUpdated(address indexed previousGoldToken, address indexed newGoldToken); + event RandomDrawCooldownUpdated(uint256 indexed previousCooldown, uint256 indexed newCooldown); + event VrfNativePaymentUpdated(bool indexed previousNativePayment, bool indexed newNativePayment); event GainClaimed(address indexed account, uint256 amount); function setUp() public { @@ -251,6 +253,20 @@ contract LotterieTest is Test { assertEq(goldTokenAddress, address(0x1), "goldToken should be 0x1"); } + function test_setRandomDrawCooldown() public { + vm.expectEmit(true, true, false, false, address(lotterie)); + emit RandomDrawCooldownUpdated(lotterie.getRandomDrawCooldown(), 1 days + 1); + lotterie.setRandomDrawCooldown(1 days + 1); + assertEq(lotterie.getRandomDrawCooldown(), 1 days + 1, "cooldown should be updated"); + } + + function test_setVrfNativePayment() public { + vm.expectEmit(true, true, false, false, address(lotterie)); + emit VrfNativePaymentUpdated(lotterie.getVrfNativePayment(), true); + lotterie.setVrfNativePayment(true); + assertTrue(lotterie.getVrfNativePayment(), "native payment should be true"); + } + function test_initialize_emits_event() public { Lotterie implementation = new Lotterie(address(vrfCoordinator)); uint256 subscription = vrfCoordinator.createSubscription(); From 39b3a0d67d968f8e31664ece8a97529cd245c1fb Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Thu, 4 Dec 2025 09:12:42 -0300 Subject: [PATCH 6/9] fix: Critical vulnerability in React Server Components CVE-2025-55182 --- frontend/package-lock.json | 180 ++++++++++++++++++------------------- frontend/package.json | 10 +-- 2 files changed, 95 insertions(+), 95 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bf9b015..db585ae 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,24 +8,24 @@ "name": "golden-bridge-frontend", "version": "0.0.0", "dependencies": { - "@reown/appkit": "^1.8.14", - "@reown/appkit-adapter-ethers": "^1.8.14", - "ethers": "^6.15.0", - "react": "^19.2.0", - "react-dom": "^19.2.0" + "@reown/appkit": "1.8.14", + "@reown/appkit-adapter-ethers": "1.8.14", + "ethers": "6.16.0", + "react": "19.2.1", + "react-dom": "19.2.1" }, "devDependencies": { - "@eslint/js": "^9.39.1", - "@types/react": "^19.2.7", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^5.1.1", - "eslint": "^9.39.1", - "eslint-plugin-react-hooks": "^7.0.1", - "eslint-plugin-react-refresh": "^0.4.24", - "globals": "^16.5.0", - "typescript": "^5.9.3", - "typescript-eslint": "^8.48.0", - "vite": "^7.2.4" + "@eslint/js": "9.39.1", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "@vitejs/plugin-react": "5.1.1", + "eslint": "9.39.1", + "eslint-plugin-react-hooks": "7.0.1", + "eslint-plugin-react-refresh": "0.4.24", + "globals": "16.5.0", + "typescript": "5.9.3", + "typescript-eslint": "8.48.1", + "vite": "7.2.6" } }, "node_modules/@adraffy/ens-normalize": { @@ -2771,17 +2771,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.0.tgz", - "integrity": "sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.48.1.tgz", + "integrity": "sha512-X63hI1bxl5ohelzr0LY5coufyl0LJNthld+abwxpCoo6Gq+hSqhKwci7MUWkXo67mzgUK6YFByhmaHmUcuBJmA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/type-utils": "8.48.0", - "@typescript-eslint/utils": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/type-utils": "8.48.1", + "@typescript-eslint/utils": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", "graphemer": "^1.4.0", "ignore": "^7.0.0", "natural-compare": "^1.4.0", @@ -2795,7 +2795,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.48.0", + "@typescript-eslint/parser": "^8.48.1", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } @@ -2811,17 +2811,17 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.0.tgz", - "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.48.1.tgz", + "integrity": "sha512-PC0PDZfJg8sP7cmKe6L3QIL8GZwU5aRvUFedqSIpw3B+QjRSUZeeITC2M5XKeMXEzL6wccN196iy3JLwKNvDVA==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4" }, "engines": { @@ -2837,14 +2837,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.0.tgz", - "integrity": "sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.48.1.tgz", + "integrity": "sha512-HQWSicah4s9z2/HifRPQ6b6R7G+SBx64JlFQpgSSHWPKdvCZX57XCbszg/bapbRsOEv42q5tayTYcEFpACcX1w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.48.0", - "@typescript-eslint/types": "^8.48.0", + "@typescript-eslint/tsconfig-utils": "^8.48.1", + "@typescript-eslint/types": "^8.48.1", "debug": "^4.3.4" }, "engines": { @@ -2859,14 +2859,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.0.tgz", - "integrity": "sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.48.1.tgz", + "integrity": "sha512-rj4vWQsytQbLxC5Bf4XwZ0/CKd362DkWMUkviT7DCS057SK64D5lH74sSGzhI6PDD2HCEq02xAP9cX68dYyg1w==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0" + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2877,9 +2877,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.0.tgz", - "integrity": "sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.48.1.tgz", + "integrity": "sha512-k0Jhs4CpEffIBm6wPaCXBAD7jxBtrHjrSgtfCjUvPp9AZ78lXKdTR8fxyZO5y4vWNlOvYXRtngSZNSn+H53Jkw==", "dev": true, "license": "MIT", "engines": { @@ -2894,15 +2894,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.0.tgz", - "integrity": "sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.48.1.tgz", + "integrity": "sha512-1jEop81a3LrJQLTf/1VfPQdhIY4PlGDBc/i67EVWObrtvcziysbLN3oReexHOM6N3jyXgCrkBsZpqwH0hiDOQg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/utils": "8.48.0", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/utils": "8.48.1", "debug": "^4.3.4", "ts-api-utils": "^2.1.0" }, @@ -2919,9 +2919,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.0.tgz", - "integrity": "sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.48.1.tgz", + "integrity": "sha512-+fZ3LZNeiELGmimrujsDCT4CRIbq5oXdHe7chLiW8qzqyPMnn1puNstCrMNVAqwcl2FdIxkuJ4tOs/RFDBVc/Q==", "dev": true, "license": "MIT", "engines": { @@ -2933,16 +2933,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.0.tgz", - "integrity": "sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.48.1.tgz", + "integrity": "sha512-/9wQ4PqaefTK6POVTjJaYS0bynCgzh6ClJHGSBj06XEHjkfylzB+A3qvyaXnErEZSaxhIo4YdyBgq6j4RysxDg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.48.0", - "@typescript-eslint/tsconfig-utils": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/visitor-keys": "8.48.0", + "@typescript-eslint/project-service": "8.48.1", + "@typescript-eslint/tsconfig-utils": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/visitor-keys": "8.48.1", "debug": "^4.3.4", "minimatch": "^9.0.4", "semver": "^7.6.0", @@ -2987,16 +2987,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.0.tgz", - "integrity": "sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.48.1.tgz", + "integrity": "sha512-fAnhLrDjiVfey5wwFRwrweyRlCmdz5ZxXz2G/4cLn0YDLjTapmN4gcCsTBR1N2rWnZSDeWpYtgLDsJt+FpmcwA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", - "@typescript-eslint/scope-manager": "8.48.0", - "@typescript-eslint/types": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0" + "@typescript-eslint/scope-manager": "8.48.1", + "@typescript-eslint/types": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3011,13 +3011,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.0.tgz", - "integrity": "sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.48.1.tgz", + "integrity": "sha512-BmxxndzEWhE4TIEEMBs8lP3MBWN3jFPs/p6gPm/wkv02o41hI6cq9AuSmGAaTTHPtA1FTi2jBre4A9rm5ZmX+Q==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.48.0", + "@typescript-eslint/types": "8.48.1", "eslint-visitor-keys": "^4.2.1" }, "engines": { @@ -4984,9 +4984,9 @@ } }, "node_modules/ethers": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", - "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", + "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", "funding": [ { "type": "individual", @@ -6379,9 +6379,9 @@ "license": "MIT" }, "node_modules/react": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz", - "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.1.tgz", + "integrity": "sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==", "license": "MIT", "peer": true, "engines": { @@ -6389,15 +6389,15 @@ } }, "node_modules/react-dom": { - "version": "19.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz", - "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==", + "version": "19.2.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz", + "integrity": "sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==", "license": "MIT", "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.0" + "react": "^19.2.1" } }, "node_modules/react-refresh": { @@ -6809,16 +6809,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.0.tgz", - "integrity": "sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==", + "version": "8.48.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.48.1.tgz", + "integrity": "sha512-FbOKN1fqNoXp1hIl5KYpObVrp0mCn+CLgn479nmu2IsRMrx2vyv74MmsBLVlhg8qVwNFGbXSp8fh1zp8pEoC2A==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.48.0", - "@typescript-eslint/parser": "8.48.0", - "@typescript-eslint/typescript-estree": "8.48.0", - "@typescript-eslint/utils": "8.48.0" + "@typescript-eslint/eslint-plugin": "8.48.1", + "@typescript-eslint/parser": "8.48.1", + "@typescript-eslint/typescript-estree": "8.48.1", + "@typescript-eslint/utils": "8.48.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -7050,9 +7050,9 @@ } }, "node_modules/vite": { - "version": "7.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.4.tgz", - "integrity": "sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==", + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.6.tgz", + "integrity": "sha512-tI2l/nFHC5rLh7+5+o7QjKjSR04ivXDF4jcgV0f/bTQ+OJiITy5S6gaynVsEM+7RqzufMnVbIon6Sr5x1SDYaQ==", "dev": true, "license": "MIT", "peer": true, diff --git a/frontend/package.json b/frontend/package.json index dea2210..963ab37 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -12,9 +12,9 @@ "dependencies": { "@reown/appkit": "1.8.14", "@reown/appkit-adapter-ethers": "1.8.14", - "ethers": "6.15.0", - "react": "19.2.0", - "react-dom": "19.2.0" + "ethers": "6.16.0", + "react": "19.2.1", + "react-dom": "19.2.1" }, "devDependencies": { "@eslint/js": "9.39.1", @@ -26,7 +26,7 @@ "eslint-plugin-react-refresh": "0.4.24", "globals": "16.5.0", "typescript": "5.9.3", - "typescript-eslint": "8.48.0", - "vite": "7.2.4" + "typescript-eslint": "8.48.1", + "vite": "7.2.6" } } From d1ac313dbfb25a35f39d75a7472cedf06530446f Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Thu, 4 Dec 2025 10:31:07 -0300 Subject: [PATCH 7/9] feat: added a LotterieConfig struct used for lotterie initialization and deployment --- lcov.info | 500 ++++++++++++----------- script/deployCoreContracts.s.sol | 23 +- script/deployCoreContractsDefender.s.sol | 25 +- src/Lotterie.sol | 53 +-- src/interfaces/ILotterie.sol | 61 +-- 5 files changed, 344 insertions(+), 318 deletions(-) diff --git a/lcov.info b/lcov.info index 451c17b..66b22a6 100644 --- a/lcov.info +++ b/lcov.info @@ -1,23 +1,23 @@ TN: SF:src/GoldToken.sol -DA:65,375 +DA:65,378 FN:65,GoldToken.constructor -FNDA:375,GoldToken.constructor -DA:66,375 -DA:70,373 +FNDA:378,GoldToken.constructor +DA:66,378 +DA:70,376 FN:70,GoldToken.initialize -FNDA:373,GoldToken.initialize -DA:75,373 -DA:76,373 -DA:77,373 -DA:79,373 -DA:81,373 -DA:83,373 -DA:86,373 -DA:90,373 -DA:91,373 -DA:92,373 -DA:94,373 +FNDA:376,GoldToken.initialize +DA:75,376 +DA:76,376 +DA:77,376 +DA:79,376 +DA:81,376 +DA:83,376 +DA:86,376 +DA:90,376 +DA:91,376 +DA:92,376 +DA:94,376 DA:98,2 FN:98,GoldToken._authorizeUpgrade FNDA:2,GoldToken._authorizeUpgrade @@ -43,12 +43,12 @@ FNDA:70,GoldToken.setFeesAddress DA:129,70 DA:130,70 DA:131,70 -DA:135,380 +DA:135,383 FN:135,GoldToken.setLotterieAddress -FNDA:380,GoldToken.setLotterieAddress -DA:136,380 -DA:137,380 -DA:138,380 +FNDA:383,GoldToken.setLotterieAddress +DA:136,383 +DA:137,383 +DA:138,383 DA:142,257 FN:142,GoldToken.pause FNDA:257,GoldToken.pause @@ -57,29 +57,29 @@ DA:147,257 FN:147,GoldToken.unpause FNDA:257,GoldToken.unpause DA:148,257 -DA:159,12756 +DA:159,12735 FN:159,GoldToken.mint -FNDA:12756,GoldToken.mint -DA:160,12499 +FNDA:12735,GoldToken.mint +DA:160,12478 BRDA:160,1,0,1 DA:161,1 -DA:164,12498 -DA:165,12498 +DA:164,12477 +DA:165,12477 BRDA:165,2,0,6 DA:166,6 -DA:171,12492 -DA:172,12492 -DA:173,12492 +DA:171,12471 +DA:172,12471 +DA:173,12471 BRDA:173,3,0,10 DA:174,10 -DA:177,12482 -DA:179,12482 -DA:180,12482 -DA:182,12482 -DA:184,12482 -DA:185,12482 -DA:186,12482 -DA:188,12482 +DA:177,12461 +DA:179,12461 +DA:180,12461 +DA:182,12461 +DA:184,12461 +DA:185,12461 +DA:186,12461 +DA:188,12461 DA:192,515 FN:192,GoldToken.burn FNDA:515,GoldToken.burn @@ -94,38 +94,38 @@ DA:201,2104 BRDA:201,5,0,1 DA:202,1 DA:204,2103 -BRDA:204,6,0,318 -DA:205,318 +BRDA:204,6,0,322 +DA:205,322 DA:207,2103 DA:208,2103 DA:209,2103 -DA:213,800 +DA:213,804 FN:213,GoldToken._removeUser -FNDA:800,GoldToken._removeUser -DA:214,800 -DA:215,800 -DA:216,800 -DA:217,802 -BRDA:217,7,0,780 -DA:218,780 -DA:219,780 -DA:220,780 -DA:221,780 -DA:227,14585 +FNDA:804,GoldToken._removeUser +DA:214,804 +DA:215,804 +DA:216,804 +DA:217,806 +BRDA:217,7,0,782 +DA:218,782 +DA:219,782 +DA:220,782 +DA:221,782 +DA:227,14564 FN:227,GoldToken._addUser -FNDA:14585,GoldToken._addUser -DA:228,14585 -BRDA:228,8,0,14107 -DA:229,14107 -DA:230,14107 -DA:231,14107 -DA:240,1027 +FNDA:14564,GoldToken._addUser +DA:228,14564 +BRDA:228,8,0,14087 +DA:229,14087 +DA:230,14087 +DA:231,14087 +DA:240,1026 FN:240,GoldToken.getGoldPriceInEth -FNDA:1027,GoldToken.getGoldPriceInEth -DA:241,13525 -DA:242,13525 -DA:244,13525 -DA:245,13525 +FNDA:1026,GoldToken.getGoldPriceInEth +DA:241,13503 +DA:242,13503 +DA:244,13503 +DA:245,13503 DA:249,1 FN:249,GoldToken.getFees FNDA:1,GoldToken.getFees @@ -134,10 +134,10 @@ DA:254,27 FN:254,GoldToken.getFeesAddress FNDA:27,GoldToken.getFeesAddress DA:255,27 -DA:259,2935 +DA:259,2921 FN:259,GoldToken.getUsers -FNDA:2935,GoldToken.getUsers -DA:260,2935 +FNDA:2921,GoldToken.getUsers +DA:260,2921 DA:264,257 FN:264,GoldToken.getTimestamps FNDA:257,GoldToken.getTimestamps @@ -150,10 +150,10 @@ DA:274,2 FN:274,GoldToken.hasOwnerRole FNDA:2,GoldToken.hasOwnerRole DA:275,2 -DA:279,16925 +DA:279,16872 FN:279,GoldToken.balanceOf -FNDA:16925,GoldToken.balanceOf -DA:280,18508 +FNDA:16872,GoldToken.balanceOf +DA:280,18457 FNF:22 FNH:22 LF:101 @@ -163,25 +163,27 @@ BRH:9 end_of_record TN: SF:src/Lotterie.sol -DA:72,33 -FN:72,Lotterie.constructor -FNDA:33,Lotterie.constructor -DA:73,33 -DA:77,31 -FN:77,Lotterie.initialize -FNDA:31,Lotterie.initialize -DA:87,31 -DA:89,31 -DA:91,31 -DA:93,31 -DA:94,31 -DA:95,31 -DA:96,31 -DA:97,31 -DA:98,31 -DA:100,31 -DA:101,31 -DA:103,31 +DA:78,36 +FN:78,Lotterie.constructor +FNDA:36,Lotterie.constructor +DA:79,36 +DA:83,34 +FN:83,Lotterie.initialize +FNDA:34,Lotterie.initialize +DA:84,34 +DA:86,34 +DA:88,34 +DA:90,34 +DA:91,34 +DA:92,34 +DA:93,34 +DA:94,34 +DA:95,34 +DA:96,34 +DA:97,34 +DA:98,34 +DA:99,34 +DA:101,34 DA:115,2 FN:115,Lotterie._authorizeUpgrade FNDA:2,Lotterie._authorizeUpgrade @@ -235,98 +237,118 @@ FNDA:257,Lotterie.setGoldToken DA:179,257 DA:180,257 DA:181,257 -DA:189,2680 -FN:189,Lotterie.randomDraw -FNDA:2680,Lotterie.randomDraw -DA:190,2680 -BRDA:190,0,0,251 -DA:191,251 -DA:194,2429 -DA:206,2429 -DA:207,2429 -DA:208,2429 -DA:209,2429 -DA:212,2166 -FN:212,Lotterie.fulfillRandomWords -FNDA:2166,Lotterie.fulfillRandomWords -DA:214,2166 -DA:215,2166 -DA:217,2165 -DA:218,2165 -DA:220,2165 -DA:224,259 -FN:224,Lotterie.claim +DA:185,257 +FN:185,Lotterie.setRandomDrawCooldown +FNDA:257,Lotterie.setRandomDrawCooldown +DA:186,257 +DA:187,257 +DA:188,257 +DA:192,257 +FN:192,Lotterie.setVrfNativePayment +FNDA:257,Lotterie.setVrfNativePayment +DA:193,257 +DA:194,257 +DA:195,257 +DA:203,2666 +FN:203,Lotterie.randomDraw +FNDA:2666,Lotterie.randomDraw +DA:204,2666 +BRDA:204,0,0,227 +DA:205,227 +DA:208,2439 +DA:219,2439 +DA:220,2439 +DA:221,2439 +DA:222,2439 +DA:225,2152 +FN:225,Lotterie.fulfillRandomWords +FNDA:2152,Lotterie.fulfillRandomWords +DA:227,2152 +DA:228,2152 +DA:230,2151 +DA:231,2151 +DA:233,2151 +DA:237,259 +FN:237,Lotterie.claim FNDA:259,Lotterie.claim -DA:225,259 -DA:226,259 -BRDA:226,1,0,1 -DA:227,1 -DA:229,258 -DA:230,258 -DA:231,258 -BRDA:231,2,0,1 -DA:232,1 -DA:234,257 -DA:238,2 -FN:238,Lotterie.hasOwnerRole +DA:238,259 +DA:239,259 +BRDA:239,1,0,1 +DA:240,1 +DA:242,258 +DA:243,258 +DA:244,258 +BRDA:244,2,0,1 +DA:245,1 +DA:247,257 +DA:251,2 +FN:251,Lotterie.hasOwnerRole FNDA:2,Lotterie.hasOwnerRole -DA:239,2 -DA:243,2 -FN:243,Lotterie.getLastRequestId +DA:252,2 +DA:256,2 +FN:256,Lotterie.getLastRequestId FNDA:2,Lotterie.getLastRequestId -DA:244,2 -BRDA:244,3,0,1 -DA:245,1 -DA:247,1 -DA:251,1028 -FN:251,Lotterie.getGains +DA:257,2 +BRDA:257,3,0,1 +DA:258,1 +DA:260,1 +DA:264,1028 +FN:264,Lotterie.getGains FNDA:1028,Lotterie.getGains -DA:252,1028 -DA:256,2167 -FN:256,Lotterie.getResults -FNDA:2167,Lotterie.getResults -DA:257,2167 -DA:261,2 -FN:261,Lotterie.getVrfCoordinator +DA:265,1028 +DA:269,2153 +FN:269,Lotterie.getResults +FNDA:2153,Lotterie.getResults +DA:270,2153 +DA:274,2 +FN:274,Lotterie.getVrfCoordinator FNDA:2,Lotterie.getVrfCoordinator -DA:262,2 -DA:266,2 -FN:266,Lotterie.getKeyHash +DA:275,2 +DA:279,2 +FN:279,Lotterie.getKeyHash FNDA:2,Lotterie.getKeyHash -DA:267,2 -DA:271,258 -FN:271,Lotterie.getCallbackGasLimit +DA:280,2 +DA:284,258 +FN:284,Lotterie.getCallbackGasLimit FNDA:258,Lotterie.getCallbackGasLimit -DA:272,258 -DA:276,258 -FN:276,Lotterie.getRequestConfirmations +DA:285,258 +DA:289,258 +FN:289,Lotterie.getRequestConfirmations FNDA:258,Lotterie.getRequestConfirmations -DA:277,258 -DA:281,258 -FN:281,Lotterie.getNumWords +DA:290,258 +DA:294,258 +FN:294,Lotterie.getNumWords FNDA:258,Lotterie.getNumWords -DA:282,258 -DA:286,257 -FN:286,Lotterie.getGoldToken +DA:295,258 +DA:299,257 +FN:299,Lotterie.getGoldToken FNDA:257,Lotterie.getGoldToken -DA:287,257 -DA:291,258 -FN:291,Lotterie.getVrfSubscriptionId +DA:300,257 +DA:304,258 +FN:304,Lotterie.getVrfSubscriptionId FNDA:258,Lotterie.getVrfSubscriptionId -DA:292,258 -FNF:26 -FNH:26 -LF:95 -LH:95 +DA:305,258 +DA:309,2 +FN:309,Lotterie.getRandomDrawCooldown +FNDA:2,Lotterie.getRandomDrawCooldown +DA:310,2 +DA:314,258 +FN:314,Lotterie.getVrfNativePayment +FNDA:258,Lotterie.getVrfNativePayment +DA:315,258 +FNF:30 +FNH:30 +LF:109 +LH:109 BRF:4 BRH:4 end_of_record TN: SF:src/TokenBridge.sol -DA:87,522 +DA:87,520 FN:87,TokenBridge.onlyEnabledChain -FNDA:522,TokenBridge.onlyEnabledChain -DA:88,522 +FNDA:520,TokenBridge.onlyEnabledChain +DA:88,520 DA:97,54 FN:97,TokenBridge.constructor FNDA:54,TokenBridge.constructor @@ -362,30 +384,30 @@ DA:168,1 FN:168,TokenBridge.removeOwner FNDA:1,TokenBridge.removeOwner DA:169,1 -DA:177,523 +DA:177,521 FN:177,TokenBridge.bridgeTokens -FNDA:523,TokenBridge.bridgeTokens -DA:184,522 -DA:185,522 -DA:195,522 +FNDA:521,TokenBridge.bridgeTokens +DA:184,520 +DA:185,520 +DA:195,520 FN:195,TokenBridge._bridgeTokens -FNDA:522,TokenBridge._bridgeTokens -DA:200,521 +FNDA:520,TokenBridge._bridgeTokens +DA:200,519 BRDA:200,1,0,1 -DA:201,520 +DA:201,518 BRDA:201,2,0,1 -DA:203,519 -DA:204,519 -DA:206,519 -DA:207,519 -DA:209,519 -DA:211,519 -DA:219,519 -DA:220,519 -DA:222,519 -BRDA:222,3,0,421 +DA:203,517 +DA:204,517 +DA:206,517 +DA:207,517 +DA:209,517 +DA:211,517 +DA:219,517 +DA:220,517 +DA:222,517 +BRDA:222,3,0,419 BRDA:222,3,1,1 -DA:223,421 +DA:223,419 BRDA:223,4,0,1 DA:225,98 BRDA:225,5,0,2 @@ -394,71 +416,71 @@ DA:227,2 BRDA:227,6,0,1 DA:228,1 DA:230,1 -DA:234,517 -DA:236,517 -DA:238,517 -DA:246,1293 +DA:234,515 +DA:236,515 +DA:238,515 +DA:246,1289 FN:246,TokenBridge._ccipReceive -FNDA:1293,TokenBridge._ccipReceive -DA:247,258 -BRDA:247,7,0,258 -DA:248,258 -DA:251,1034 +FNDA:1289,TokenBridge._ccipReceive +DA:247,257 +BRDA:247,7,0,257 +DA:248,257 +DA:251,1031 BRDA:251,8,0,1 DA:252,1 -DA:255,1033 -DA:256,1033 +DA:255,1030 +DA:256,1030 BRDA:256,9,0,277 -DA:258,756 -DA:259,756 +DA:258,753 +DA:259,753 BRDA:259,10,0,1 -DA:261,755 -DA:262,755 -DA:264,755 -DA:265,755 -BRDA:265,11,0,516 -DA:266,516 -DA:267,516 -BRDA:267,12,0,516 -DA:268,516 -DA:269,516 -DA:271,516 +DA:261,752 +DA:262,752 +DA:264,752 +DA:265,752 +BRDA:265,11,0,515 +DA:266,515 +DA:267,515 +BRDA:267,12,0,515 +DA:268,515 +DA:269,515 +DA:271,515 BRDA:271,13,0,1 -DA:273,515 -DA:275,515 -DA:277,515 -DA:282,754 -BRDA:282,14,0,239 -DA:283,239 -DA:284,239 -DA:293,522 +DA:273,514 +DA:275,514 +DA:277,514 +DA:282,751 +BRDA:282,14,0,237 +DA:283,237 +DA:284,237 +DA:293,520 FN:293,TokenBridge._onlyEnabledChain -FNDA:522,TokenBridge._onlyEnabledChain -DA:294,522 +FNDA:520,TokenBridge._onlyEnabledChain +DA:294,520 BRDA:294,15,0,1 DA:295,1 -DA:304,1079 +DA:304,1077 FN:304,TokenBridge.setWhitelistedChain -FNDA:1079,TokenBridge.setWhitelistedChain -DA:309,1079 +FNDA:1077,TokenBridge.setWhitelistedChain +DA:309,1077 BRDA:309,16,0,1 -DA:311,1078 -DA:313,1076 -BRDA:313,17,0,1076 +DA:311,1076 +DA:313,1074 +BRDA:313,17,0,1074 BRDA:313,17,1,2 -DA:314,1076 +DA:314,1074 DA:316,2 -DA:321,824 +DA:321,821 FN:321,TokenBridge.setWhitelistedSender -FNDA:824,TokenBridge.setWhitelistedSender -DA:322,824 +FNDA:821,TokenBridge.setWhitelistedSender +DA:322,821 BRDA:322,18,0,1 -DA:323,823 -DA:324,545 -BRDA:324,19,0,545 -BRDA:324,19,1,278 -DA:325,545 -DA:327,278 +DA:323,820 +DA:324,543 +BRDA:324,19,0,543 +BRDA:324,19,1,277 +DA:325,543 +DA:327,277 DA:335,857 FN:335,TokenBridge.pause FNDA:857,TokenBridge.pause @@ -478,17 +500,17 @@ BRDA:358,21,0,1 DA:360,259 DA:361,259 BRDA:361,22,0,1 -DA:365,262 +DA:365,261 FN:365,TokenBridge.withdrawToken -FNDA:262,TokenBridge.withdrawToken -DA:366,262 +FNDA:261,TokenBridge.withdrawToken +DA:366,261 BRDA:366,23,0,1 -DA:367,261 +DA:367,260 BRDA:367,24,0,1 -DA:369,260 -DA:370,260 +DA:369,259 +DA:370,259 BRDA:370,25,0,1 -DA:372,259 +DA:372,258 DA:380,259 FN:380,TokenBridge.whitelistedChains FNDA:259,TokenBridge.whitelistedChains diff --git a/script/deployCoreContracts.s.sol b/script/deployCoreContracts.s.sol index 2bd6f98..b031032 100644 --- a/script/deployCoreContracts.s.sol +++ b/script/deployCoreContracts.s.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.28; import {Script, console2} from "forge-std/Script.sol"; import {GoldToken} from "../src/GoldToken.sol"; import {Lotterie} from "../src/Lotterie.sol"; +import {ILotterie} from "../src/interfaces/ILotterie.sol"; import {TokenBridge} from "../src/TokenBridge.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; @@ -110,16 +111,18 @@ contract DeployCoreContracts is Script { bytes memory lotterieData = abi.encodeWithSelector( Lotterie.initialize.selector, - deployer, - config.vrfSubscriptionId, - config.vrfCoordinator, - VRF_NATIVE_PAYMENT, - config.keyHash, - CALLBACK_GAS_LIMIT, - REQUEST_CONFIRMATIONS, - NUM_WORDS, - RANDOM_DRAW_COOLDOWN, - address(goldToken) + ILotterie.LotterieConfig({ + owner: deployer, + vrfSubscriptionId: config.vrfSubscriptionId, + vrfCoordinator: config.vrfCoordinator, + vrfNativePayment: VRF_NATIVE_PAYMENT, + keyHash: config.keyHash, + callbackGasLimit: CALLBACK_GAS_LIMIT, + requestConfirmations: REQUEST_CONFIRMATIONS, + numWords: NUM_WORDS, + randomDrawCooldown: RANDOM_DRAW_COOLDOWN, + goldToken: address(goldToken) + }) ); ERC1967Proxy lotterieProxy = new ERC1967Proxy(address(lotterieImpl), lotterieData); Lotterie lotterie = Lotterie(address(lotterieProxy)); diff --git a/script/deployCoreContractsDefender.s.sol b/script/deployCoreContractsDefender.s.sol index e5df6fb..d64dddf 100644 --- a/script/deployCoreContractsDefender.s.sol +++ b/script/deployCoreContractsDefender.s.sol @@ -4,6 +4,7 @@ pragma solidity 0.8.28; import {Script, console2} from "forge-std/Script.sol"; import {GoldToken} from "../src/GoldToken.sol"; import {Lotterie} from "../src/Lotterie.sol"; +import {ILotterie} from "../src/interfaces/ILotterie.sol"; import {TokenBridge} from "../src/TokenBridge.sol"; import {ApprovalProcessResponse, Defender} from "openzeppelin-foundry-upgrades/Defender.sol"; import {Options, Upgrades} from "openzeppelin-foundry-upgrades/Upgrades.sol"; @@ -82,18 +83,18 @@ contract DeployCoreContractsWithDefender is Script { "src/Lotterie.sol", abi.encodeCall( Lotterie.initialize, - ( - owner, - config.vrfSubscriptionId, - config.vrfCoordinator, - VRF_NATIVE_PAYMENT, - config.keyHash, - CALLBACK_GAS_LIMIT, - REQUEST_CONFIRMATIONS, - NUM_WORDS, - RANDOM_DRAW_COOLDOWN, - goldTokenProxy - ) + (ILotterie.LotterieConfig({ + owner: owner, + vrfSubscriptionId: config.vrfSubscriptionId, + vrfCoordinator: config.vrfCoordinator, + vrfNativePayment: VRF_NATIVE_PAYMENT, + keyHash: config.keyHash, + callbackGasLimit: CALLBACK_GAS_LIMIT, + requestConfirmations: REQUEST_CONFIRMATIONS, + numWords: NUM_WORDS, + randomDrawCooldown: RANDOM_DRAW_COOLDOWN, + goldToken: goldTokenProxy + })) ), lotterieOpts ); diff --git a/src/Lotterie.sol b/src/Lotterie.sol index 0821a5f..8aaaf66 100644 --- a/src/Lotterie.sol +++ b/src/Lotterie.sol @@ -80,46 +80,35 @@ contract Lotterie is } /// @inheritdoc ILotterie - function initialize( - address owner, - uint256 vrfSubscriptionId, - address vrfCoordinator, - bool vrfNativePayment, - bytes32 keyHash, - uint32 callbackGasLimit, - uint16 requestConfirmations, - uint32 numWords, - uint256 randomDrawCooldown, - address goldToken - ) external override initializer { + function initialize(LotterieConfig calldata config) external override initializer { __AccessControl_init(); - _grantRole(OWNER_ROLE, owner); + _grantRole(OWNER_ROLE, config.owner); _setRoleAdmin(OWNER_ROLE, OWNER_ROLE); - _vrfSubscriptionId = vrfSubscriptionId; - s_vrfCoordinator = IVRFCoordinatorV2Plus(vrfCoordinator); - _vrfKeyHash = keyHash; - _vrfNativePayment = vrfNativePayment; - _callbackGasLimit = callbackGasLimit; - _requestConfirmations = requestConfirmations; - _numWords = numWords; - _randomDrawCooldown = randomDrawCooldown; + _vrfSubscriptionId = config.vrfSubscriptionId; + s_vrfCoordinator = IVRFCoordinatorV2Plus(config.vrfCoordinator); + _vrfKeyHash = config.keyHash; + _vrfNativePayment = config.vrfNativePayment; + _callbackGasLimit = config.callbackGasLimit; + _requestConfirmations = config.requestConfirmations; + _numWords = config.numWords; + _randomDrawCooldown = config.randomDrawCooldown; _lastRandomDraw = block.timestamp - 1 days; - _goldToken = IGoldToken(goldToken); + _goldToken = IGoldToken(config.goldToken); emit LotterieInitialized( - owner, - vrfCoordinator, - goldToken, - vrfSubscriptionId, - vrfNativePayment, - keyHash, - callbackGasLimit, - requestConfirmations, - numWords, - randomDrawCooldown + config.owner, + config.vrfCoordinator, + config.goldToken, + config.vrfSubscriptionId, + config.vrfNativePayment, + config.keyHash, + config.callbackGasLimit, + config.requestConfirmations, + config.numWords, + config.randomDrawCooldown ); } diff --git a/src/interfaces/ILotterie.sol b/src/interfaces/ILotterie.sol index ecfe18f..8f8f586 100644 --- a/src/interfaces/ILotterie.sol +++ b/src/interfaces/ILotterie.sol @@ -7,9 +7,40 @@ pragma solidity 0.8.28; * @dev Consumed by GoldToken, deployment scripts, and monitoring infrastructure */ interface ILotterie { + /*////////////////////////////////////////////////////////////// + STRUCTS + //////////////////////////////////////////////////////////////*/ + + /** + * @notice Configuration struct used during Lotterie initialization + * @param owner Address granted OWNER_ROLE + * @param vrfSubscriptionId Subscription id funding VRF requests + * @param vrfCoordinator Address of the VRF coordinator + * @param vrfNativePayment True when the VRF subscription uses native payment + * @param keyHash Chainlink VRF key hash used for randomness + * @param callbackGasLimit Gas limit allocated for fulfillRandomWords + * @param requestConfirmations Number of confirmations required for VRF responses + * @param numWords Number of random words requested per draw + * @param randomDrawCooldown Minimum time between draws + * @param goldToken Address of the GoldToken proxy + */ + struct LotterieConfig { + address owner; + uint256 vrfSubscriptionId; + address vrfCoordinator; + bool vrfNativePayment; + bytes32 keyHash; + uint32 callbackGasLimit; + uint16 requestConfirmations; + uint32 numWords; + uint256 randomDrawCooldown; + address goldToken; + } + /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ + /** * @notice Emitted whenever a VRF request for randomness is sent * @param requestId Unique identifier for the Chainlink VRF request @@ -121,6 +152,7 @@ interface ILotterie { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ + /** * @notice Reverts when attempting to draw more than once within the cooldown period * @param lastDraw Timestamp of the last draw @@ -138,6 +170,7 @@ interface ILotterie { /*////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ + /// @notice Grants OWNER_ROLE to a new account /// @param account Address receiving OWNER_ROLE function addOwner(address account) external; @@ -203,31 +236,9 @@ interface ILotterie { /*////////////////////////////////////////////////////////////// CORE FUNCTIONS //////////////////////////////////////////////////////////////*/ - /** - * @notice Initializes the proxy with VRF configuration and GoldToken reference - * @param owner Address granted OWNER_ROLE - * @param vrfSubscriptionId Subscription id funding VRF requests - * @param vrfCoordinator Address of the VRF coordinator - * @param vrfNativePayment True when the VRF subscription uses native payment - * @param keyHash Chainlink VRF key hash used for randomness - * @param callbackGasLimit Gas limit allocated for fulfillRandomWords - * @param requestConfirmations Number of confirmations required for VRF responses - * @param numWords Number of random words requested per draw - * @param randomDrawCooldown Minimum time between draws - * @param goldToken Address of the GoldToken proxy - */ - function initialize( - address owner, - uint256 vrfSubscriptionId, - address vrfCoordinator, - bool vrfNativePayment, - bytes32 keyHash, - uint32 callbackGasLimit, - uint16 requestConfirmations, - uint32 numWords, - uint256 randomDrawCooldown, - address goldToken - ) external; + + /// @notice Initializes the proxy with VRF configuration and GoldToken reference + function initialize(LotterieConfig calldata config) external; /** * @notice Requests randomness from Chainlink to pick a lottery winner From 9c40b5e3db11ab24831b85fd1487cf03340f3ea0 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Thu, 4 Dec 2025 10:53:05 -0300 Subject: [PATCH 8/9] feat: using Event declared in the interface of each contract instead of using unsafe duplication --- test/GoldToken.t.sol | 19 ++++++------------ test/Lotterie.t.sol | 45 +++++++++++------------------------------- test/TokenBridge.t.sol | 33 ++++++------------------------- 3 files changed, 23 insertions(+), 74 deletions(-) diff --git a/test/GoldToken.t.sol b/test/GoldToken.t.sol index 7811fb2..e9ee09f 100644 --- a/test/GoldToken.t.sol +++ b/test/GoldToken.t.sol @@ -32,13 +32,6 @@ contract GoldTokenTest is Test { bytes32 public constant OWNER_ROLE = keccak256("OWNER_ROLE"); - event GoldTokenInitialized(address indexed owner, address indexed dataFeedGold, address indexed dataFeedEth); - event FeesAddressUpdated(address indexed previousFeesAddress, address indexed newFeesAddress); - event LotterieAddressUpdated(address indexed previousLotterieAddress, address indexed newLotterieAddress); - event UserAdded(address indexed user, uint256 timestamp); - event UserRemoved(address indexed user); - event Mint(address indexed to, uint256 amount); - function setUp() public { uint256 id; assembly { @@ -118,7 +111,7 @@ contract GoldTokenTest is Test { assertEq(feesAddress, address(this)); vm.expectEmit(true, true, false, false, address(goldToken)); - emit FeesAddressUpdated(address(this), address(signers[0])); + emit IGoldToken.FeesAddressUpdated(address(this), address(signers[0])); goldToken.setFeesAddress(address(signers[0])); feesAddress = goldToken.getFeesAddress(); @@ -128,7 +121,7 @@ contract GoldTokenTest is Test { function test_initialize_emits_event() public { GoldToken implementation = new GoldToken(); vm.expectEmit(true, false, false, true); - emit GoldTokenInitialized(address(this), address(goldAggregator), address(ethAggregator)); + emit IGoldToken.GoldTokenInitialized(address(this), address(goldAggregator), address(ethAggregator)); new ERC1967Proxy( address(implementation), abi.encodeWithSelector( @@ -140,7 +133,7 @@ contract GoldTokenTest is Test { function test_mint_emits_user_added_event() public { vm.deal(address(this), 1 ether); vm.expectEmit(true, false, false, true, address(goldToken)); - emit UserAdded(address(this), block.timestamp); + emit IGoldToken.UserAdded(address(this), block.timestamp); goldToken.mint{value: 0.1 ether}(); } @@ -151,7 +144,7 @@ contract GoldTokenTest is Test { (uint256 expectedUserMint,,) = GoldReference.calcMintBreakdown(1 ether, goldPrice, ethPrice); vm.expectEmit(true, false, false, true, address(goldToken)); - emit Mint(address(this), expectedUserMint); + emit IGoldToken.Mint(address(this), expectedUserMint); goldToken.mint{value: 1 ether}(); } @@ -161,14 +154,14 @@ contract GoldTokenTest is Test { uint256 balance = goldToken.balanceOf(address(this)); vm.expectEmit(true, false, false, false, address(goldToken)); - emit UserRemoved(address(this)); + emit IGoldToken.UserRemoved(address(this)); goldToken.burn(balance); } /// @notice Table-driven test for various mint scenarios. Check https://getfoundry.sh/forge/advanced-testing/table-testing/ for more details. function tableMintScenario(MintScenario memory mintScenario) public { vm.expectEmit(true, true, false, false, address(goldToken)); - emit LotterieAddressUpdated(DEFAULT_LOTTERIE, TABLE_LOTTERIE); + emit IGoldToken.LotterieAddressUpdated(DEFAULT_LOTTERIE, TABLE_LOTTERIE); goldToken.setLotterieAddress(TABLE_LOTTERIE); goldToken.setFeesAddress(TABLE_FEES); diff --git a/test/Lotterie.t.sol b/test/Lotterie.t.sol index b987d7f..f93f740 100644 --- a/test/Lotterie.t.sol +++ b/test/Lotterie.t.sol @@ -20,29 +20,6 @@ contract LotterieTest is Test { Lotterie public lotterie; VRFCoordinatorV2_5Mock public vrfCoordinator; - event LotterieInitialized( - address indexed owner, - address indexed vrfCoordinator, - address indexed goldToken, - uint256 vrfSubscriptionId, - bool vrfNativePayment, - bytes32 keyHash, - uint32 callbackGasLimit, - uint16 requestConfirmations, - uint32 numWords, - uint256 randomDrawCooldown - ); - event VrfSubscriptionUpdated(uint256 indexed previousSubscriptionId, uint256 indexed newSubscriptionId); - event VrfCoordinatorUpdated(address indexed previousCoordinator, address indexed newCoordinator); - event KeyHashUpdated(bytes32 indexed previousKeyHash, bytes32 indexed newKeyHash); - event CallbackGasLimitUpdated(uint32 indexed previousGasLimit, uint32 indexed newGasLimit); - event RequestConfirmationsUpdated(uint16 indexed previousConfirmations, uint16 indexed newConfirmations); - event NumWordsUpdated(uint32 indexed previousNumWords, uint32 indexed newNumWords); - event GoldTokenUpdated(address indexed previousGoldToken, address indexed newGoldToken); - event RandomDrawCooldownUpdated(uint256 indexed previousCooldown, uint256 indexed newCooldown); - event VrfNativePaymentUpdated(bool indexed previousNativePayment, bool indexed newNativePayment); - event GainClaimed(address indexed account, uint256 amount); - function setUp() public { vm.deal(address(this), 100 ether); // Advance time by 2 days to avoid underflow issues with last random draw time (set during initialization to block.timestamp - 1 days) @@ -158,7 +135,7 @@ contract LotterieTest is Test { uint256 winnerBalanceBefore = goldToken.balanceOf(winner); vm.expectEmit(true, false, false, true, address(lotterie)); - emit GainClaimed(winner, gains); + emit ILotterie.GainClaimed(winner, gains); vm.prank(winner); lotterie.claim(); @@ -197,7 +174,7 @@ contract LotterieTest is Test { function test_setVrfSubscriptionId() public { uint256 previous = lotterie.getVrfSubscriptionId(); vm.expectEmit(true, true, false, false, address(lotterie)); - emit VrfSubscriptionUpdated(previous, 10); + emit ILotterie.VrfSubscriptionUpdated(previous, 10); lotterie.setVrfSubscriptionId(10); uint256 vrfSubscriptionId = lotterie.getVrfSubscriptionId(); assertEq(vrfSubscriptionId, 10, "vrfSubscriptionId should be 10"); @@ -206,7 +183,7 @@ contract LotterieTest is Test { function test_setVrfCoordinator() public { address previous = lotterie.getVrfCoordinator(); vm.expectEmit(true, true, false, false, address(lotterie)); - emit VrfCoordinatorUpdated(previous, address(0x1)); + emit ILotterie.VrfCoordinatorUpdated(previous, address(0x1)); lotterie.setVrfCoordinator(address(0x1)); address vrf = lotterie.getVrfCoordinator(); assertEq(vrf, address(0x1), "vrfCoordinator should be 0x1"); @@ -215,7 +192,7 @@ contract LotterieTest is Test { function test_setKeyHash() public { bytes32 expectedKeyHash = keccak256(abi.encodePacked("test-key-hash")); vm.expectEmit(true, true, false, false, address(lotterie)); - emit KeyHashUpdated(lotterie.getKeyHash(), expectedKeyHash); + emit ILotterie.KeyHashUpdated(lotterie.getKeyHash(), expectedKeyHash); lotterie.setKeyHash(expectedKeyHash); bytes32 keyHash = lotterie.getKeyHash(); assertEq(keyHash, expectedKeyHash, "keyHash should match expected value"); @@ -223,7 +200,7 @@ contract LotterieTest is Test { function test_setCallbackGasLimit() public { vm.expectEmit(true, true, false, false, address(lotterie)); - emit CallbackGasLimitUpdated(lotterie.getCallbackGasLimit(), 10); + emit ILotterie.CallbackGasLimitUpdated(lotterie.getCallbackGasLimit(), 10); lotterie.setCallbackGasLimit(10); uint32 gasLimit = lotterie.getCallbackGasLimit(); assertEq(gasLimit, 10, "gasLimit should be 10"); @@ -231,7 +208,7 @@ contract LotterieTest is Test { function test_setRequestConfirmations() public { vm.expectEmit(true, true, false, false, address(lotterie)); - emit RequestConfirmationsUpdated(lotterie.getRequestConfirmations(), 10); + emit ILotterie.RequestConfirmationsUpdated(lotterie.getRequestConfirmations(), 10); lotterie.setRequestConfirmations(10); uint16 confirmations = lotterie.getRequestConfirmations(); assertEq(confirmations, 10, "confirmations should be 10"); @@ -239,7 +216,7 @@ contract LotterieTest is Test { function test_setNumWords() public { vm.expectEmit(true, true, false, false, address(lotterie)); - emit NumWordsUpdated(lotterie.getNumWords(), 10); + emit ILotterie.NumWordsUpdated(lotterie.getNumWords(), 10); lotterie.setNumWords(10); uint32 numWords = lotterie.getNumWords(); assertEq(numWords, 10, "numWords should be 10"); @@ -247,7 +224,7 @@ contract LotterieTest is Test { function test_setGoldToken() public { vm.expectEmit(true, true, false, false, address(lotterie)); - emit GoldTokenUpdated(address(goldToken), address(0x1)); + emit ILotterie.GoldTokenUpdated(address(goldToken), address(0x1)); lotterie.setGoldToken(address(0x1)); address goldTokenAddress = lotterie.getGoldToken(); assertEq(goldTokenAddress, address(0x1), "goldToken should be 0x1"); @@ -255,14 +232,14 @@ contract LotterieTest is Test { function test_setRandomDrawCooldown() public { vm.expectEmit(true, true, false, false, address(lotterie)); - emit RandomDrawCooldownUpdated(lotterie.getRandomDrawCooldown(), 1 days + 1); + emit ILotterie.RandomDrawCooldownUpdated(lotterie.getRandomDrawCooldown(), 1 days + 1); lotterie.setRandomDrawCooldown(1 days + 1); assertEq(lotterie.getRandomDrawCooldown(), 1 days + 1, "cooldown should be updated"); } function test_setVrfNativePayment() public { vm.expectEmit(true, true, false, false, address(lotterie)); - emit VrfNativePaymentUpdated(lotterie.getVrfNativePayment(), true); + emit ILotterie.VrfNativePaymentUpdated(lotterie.getVrfNativePayment(), true); lotterie.setVrfNativePayment(true); assertTrue(lotterie.getVrfNativePayment(), "native payment should be true"); } @@ -271,7 +248,7 @@ contract LotterieTest is Test { Lotterie implementation = new Lotterie(address(vrfCoordinator)); uint256 subscription = vrfCoordinator.createSubscription(); vm.expectEmit(true, true, true, true); - emit LotterieInitialized( + emit ILotterie.LotterieInitialized( address(this), address(vrfCoordinator), address(goldToken), diff --git a/test/TokenBridge.t.sol b/test/TokenBridge.t.sol index 6b45761..7c18cc0 100644 --- a/test/TokenBridge.t.sol +++ b/test/TokenBridge.t.sol @@ -37,27 +37,6 @@ contract TokenBridgeTest is Test { MockV3Aggregator public goldAggregator; MockV3Aggregator public ethAggregator; - event TokenBridgeInitialized( - address indexed owner, address indexed link, address indexed goldToken, uint64 destinationChainSelector - ); - event MessageProcessedWithoutToken(bytes32 indexed messageId, uint64 indexed sourceChainSelector); - event TokensBridged( - bytes32 indexed messageId, - address indexed sender, - address indexed receiver, - uint256 amount, - uint64 destinationChainSelector, - address feeToken, - uint256 fees - ); - event TokensReceived( - bytes32 indexed messageId, address indexed receiver, uint256 amount, uint64 indexed sourceChainSelector - ); - event ChainWhitelisted(uint64 indexed chainSelector); - event ChainRemoved(uint64 indexed chainSelector); - event SenderWhitelisted(address indexed sender); - event SenderRemoved(address indexed sender); - function setUp() public { // Setup accounts owner = address(this); @@ -152,7 +131,7 @@ contract TokenBridgeTest is Test { function test_initialize_emits_event() public { TokenBridge implementation = new TokenBridge(address(router)); vm.expectEmit(true, true, true, true); - emit TokenBridgeInitialized(owner, address(linkToken), address(goldToken), BSC_CHAIN_SELECTOR); + emit ITokenBridge.TokenBridgeInitialized(owner, address(linkToken), address(goldToken), BSC_CHAIN_SELECTOR); new ERC1967Proxy( address(implementation), abi.encodeWithSelector( @@ -452,7 +431,7 @@ contract TokenBridgeTest is Test { }); vm.expectEmit(true, true, false, false, address(tokenBridge)); - emit MessageProcessedWithoutToken(message.messageId, BSC_CHAIN_SELECTOR); + emit ITokenBridge.MessageProcessedWithoutToken(message.messageId, BSC_CHAIN_SELECTOR); vm.prank(address(router)); tokenBridge.ccipReceive(message); @@ -585,12 +564,12 @@ contract TokenBridgeTest is Test { Client._argsToBytes(Client.EVMExtraArgsV2({gasLimit: 300_000, allowOutOfOrderExecution: true})); vm.expectEmit(false, false, false, true, address(tokenBridge)); - emit ChainWhitelisted(newChain); + emit ITokenBridge.ChainWhitelisted(newChain); tokenBridge.setWhitelistedChain(newChain, true, args); assertTrue(tokenBridge.whitelistedChains(newChain)); vm.expectEmit(false, false, false, true, address(tokenBridge)); - emit ChainRemoved(newChain); + emit ITokenBridge.ChainRemoved(newChain); tokenBridge.setWhitelistedChain(newChain, false, ""); assertFalse(tokenBridge.whitelistedChains(newChain)); } @@ -599,12 +578,12 @@ contract TokenBridgeTest is Test { address newSender = signers[0]; vm.expectEmit(false, false, false, true, address(tokenBridge)); - emit SenderWhitelisted(newSender); + emit ITokenBridge.SenderWhitelisted(newSender); tokenBridge.setWhitelistedSender(newSender, true); assertTrue(tokenBridge.whitelistedSenders(newSender)); vm.expectEmit(false, false, false, true, address(tokenBridge)); - emit SenderRemoved(newSender); + emit ITokenBridge.SenderRemoved(newSender); tokenBridge.setWhitelistedSender(newSender, false); assertFalse(tokenBridge.whitelistedSenders(newSender)); } From e7c3bac6d16741f3d6885ef70807a93ae9cdd559 Mon Sep 17 00:00:00 2001 From: Vincent Rainaud Date: Fri, 5 Dec 2025 11:04:54 -0300 Subject: [PATCH 9/9] feat: changing _vrfNativePayment from state variable to an active param of randomDraw & huge gas improvement for fulfillRandomWords by using getUserByIndex instead of getUsers --- script/deployCoreContracts.s.sol | 4 +- script/deployCoreContractsDefender.s.sol | 4 +- src/GoldToken.sol | 10 ++++ src/Lotterie.sol | 40 ++++++--------- src/interfaces/IGoldToken.sol | 65 ++++++++++++++++++++---- src/interfaces/ILotterie.sol | 26 +--------- test/Lotterie.fuzz.t.sol | 31 +++++------ test/Lotterie.t.sol | 22 +++----- 8 files changed, 102 insertions(+), 100 deletions(-) diff --git a/script/deployCoreContracts.s.sol b/script/deployCoreContracts.s.sol index b031032..52a862f 100644 --- a/script/deployCoreContracts.s.sol +++ b/script/deployCoreContracts.s.sol @@ -70,10 +70,9 @@ contract DeployCoreContracts is Script { }); // Chainlink VRF parameters (same for both networks) - uint32 constant CALLBACK_GAS_LIMIT = 100000; + uint32 constant CALLBACK_GAS_LIMIT = 40_000; uint16 constant REQUEST_CONFIRMATIONS = 3; uint32 constant NUM_WORDS = 1; - bool constant VRF_NATIVE_PAYMENT = false; uint32 constant RANDOM_DRAW_COOLDOWN = 5 minutes; // low cooldown set for testing purposes function run() external { @@ -115,7 +114,6 @@ contract DeployCoreContracts is Script { owner: deployer, vrfSubscriptionId: config.vrfSubscriptionId, vrfCoordinator: config.vrfCoordinator, - vrfNativePayment: VRF_NATIVE_PAYMENT, keyHash: config.keyHash, callbackGasLimit: CALLBACK_GAS_LIMIT, requestConfirmations: REQUEST_CONFIRMATIONS, diff --git a/script/deployCoreContractsDefender.s.sol b/script/deployCoreContractsDefender.s.sol index d64dddf..0372868 100644 --- a/script/deployCoreContractsDefender.s.sol +++ b/script/deployCoreContractsDefender.s.sol @@ -58,10 +58,9 @@ contract DeployCoreContractsWithDefender is Script { keyHash: 0x8596b430971ac45bdf6088665b9ad8e8630c9d5049ab54b14dff711bee7c0e26 }); - uint32 constant CALLBACK_GAS_LIMIT = 40000; + uint32 constant CALLBACK_GAS_LIMIT = 40_000; uint16 constant REQUEST_CONFIRMATIONS = 3; uint32 constant NUM_WORDS = 1; - bool constant VRF_NATIVE_PAYMENT = false; uint32 constant RANDOM_DRAW_COOLDOWN = 1 days; function run() external { @@ -87,7 +86,6 @@ contract DeployCoreContractsWithDefender is Script { owner: owner, vrfSubscriptionId: config.vrfSubscriptionId, vrfCoordinator: config.vrfCoordinator, - vrfNativePayment: VRF_NATIVE_PAYMENT, keyHash: config.keyHash, callbackGasLimit: CALLBACK_GAS_LIMIT, requestConfirmations: REQUEST_CONFIRMATIONS, diff --git a/src/GoldToken.sol b/src/GoldToken.sol index f8c6387..17b0cef 100644 --- a/src/GoldToken.sol +++ b/src/GoldToken.sol @@ -260,6 +260,16 @@ contract GoldToken is return _users; } + /// @inheritdoc IGoldToken + function getUserByIndex(uint256 index) external view override returns (address) { + return _users[index]; + } + + /// @inheritdoc IGoldToken + function getUserCount() external view override returns (uint256) { + return _users.length; + } + /// @inheritdoc IGoldToken function getTimestamps() external view override returns (address[] memory, uint256[] memory) { uint256 length = _users.length; diff --git a/src/Lotterie.sol b/src/Lotterie.sol index 8aaaf66..372b53b 100644 --- a/src/Lotterie.sol +++ b/src/Lotterie.sol @@ -38,9 +38,6 @@ contract Lotterie is /// @notice Key hash identifying the VRF proving key used for draws bytes32 internal _vrfKeyHash; - /// @notice Whether the payment in native tokens is enabled for the VRF subscription - bool internal _vrfNativePayment; - /// @notice Gas limit allocated to `fulfillRandomWords` uint32 internal _callbackGasLimit; @@ -90,7 +87,6 @@ contract Lotterie is _vrfSubscriptionId = config.vrfSubscriptionId; s_vrfCoordinator = IVRFCoordinatorV2Plus(config.vrfCoordinator); _vrfKeyHash = config.keyHash; - _vrfNativePayment = config.vrfNativePayment; _callbackGasLimit = config.callbackGasLimit; _requestConfirmations = config.requestConfirmations; _numWords = config.numWords; @@ -103,7 +99,6 @@ contract Lotterie is config.vrfCoordinator, config.goldToken, config.vrfSubscriptionId, - config.vrfNativePayment, config.keyHash, config.callbackGasLimit, config.requestConfirmations, @@ -188,19 +183,12 @@ contract Lotterie is emit RandomDrawCooldownUpdated(previous, randomDrawCooldown); } - /// @inheritdoc ILotterie - function setVrfNativePayment(bool vrfNativePayment) external override onlyRole(OWNER_ROLE) { - bool previous = _vrfNativePayment; - _vrfNativePayment = vrfNativePayment; - emit VrfNativePaymentUpdated(previous, vrfNativePayment); - } - /*////////////////////////////////////////////////////////////// CORE FUNCTIONS //////////////////////////////////////////////////////////////*/ /// @inheritdoc ILotterie - function randomDraw() external override onlyRole(OWNER_ROLE) returns (uint256) { + function randomDraw(bool enableNativePayment) external override onlyRole(OWNER_ROLE) returns (uint256) { if (_lastRandomDraw + _randomDrawCooldown > block.timestamp) { revert DrawCooldownNotExpired(_lastRandomDraw, _randomDrawCooldown, block.timestamp); } @@ -212,7 +200,9 @@ contract Lotterie is requestConfirmations: _requestConfirmations, callbackGasLimit: _callbackGasLimit, numWords: _numWords, - extraArgs: VRFV2PlusClient._argsToBytes(VRFV2PlusClient.ExtraArgsV1({nativePayment: _vrfNativePayment})) + extraArgs: VRFV2PlusClient._argsToBytes( + VRFV2PlusClient.ExtraArgsV1({nativePayment: enableNativePayment}) + ) }) ); @@ -223,14 +213,19 @@ contract Lotterie is } function fulfillRandomWords(uint256 requestId, uint256[] calldata randomWords) internal override { - // transform the result to a number between 0 and number of participants - address[] memory users = _goldToken.getUsers(); - uint256 index = (randomWords[0] % users.length); + uint256 userCount = _goldToken.getUserCount(); + if (userCount == 0) { + emit Winner(address(0)); + return; + } - _results[requestId] = users[index]; - _gains[users[index]] = _goldToken.balanceOf(address(this)); + uint256 index = (randomWords[0] % userCount); + address winner = _goldToken.getUserByIndex(index); - emit Winner(users[index]); + _results[requestId] = winner; + _gains[winner] = _goldToken.balanceOf(address(this)); + + emit Winner(winner); } /// @inheritdoc ILotterie @@ -309,9 +304,4 @@ contract Lotterie is function getRandomDrawCooldown() external view override returns (uint256) { return _randomDrawCooldown; } - - /// @inheritdoc ILotterie - function getVrfNativePayment() external view override returns (bool) { - return _vrfNativePayment; - } } diff --git a/src/interfaces/IGoldToken.sol b/src/interfaces/IGoldToken.sol index 29fd64a..4df1829 100644 --- a/src/interfaces/IGoldToken.sol +++ b/src/interfaces/IGoldToken.sol @@ -10,6 +10,7 @@ interface IGoldToken { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ + /** * @notice Emitted once during proxy initialization to capture deployment context * @param owner Address granted OWNER_ROLE and set as initial fee recipient @@ -55,44 +56,60 @@ interface IGoldToken { /*////////////////////////////////////////////////////////////// ERRORS //////////////////////////////////////////////////////////////*/ + /// @notice Thrown when a function expecting a positive ETH value receives zero error ValueMustBeGreaterThanZero(); + /// @notice Thrown when a mint, burn, or transfer amount is zero error AmountMustBeGreaterThanZero(); + /// @notice Thrown when Chainlink feeds yield a non-positive gold price in ETH error InvalidGoldPrice(); + /// @notice Thrown when withdrawing ETH to an owner fails error EthTransferFailed(); /*////////////////////////////////////////////////////////////// ADMIN FUNCTIONS //////////////////////////////////////////////////////////////*/ - /// @notice Grants OWNER_ROLE to a new account - /// @param account Address receiving OWNER_ROLE + + /** + * @notice Grants OWNER_ROLE to a new account + * @param account Address receiving OWNER_ROLE + */ function addOwner(address account) external; - /// @notice Revokes OWNER_ROLE from an account - /// @param account Address losing OWNER_ROLE + + /** + * @notice Revokes OWNER_ROLE from an account + * @param account Address losing OWNER_ROLE + */ function removeOwner(address account) external; + /// @notice Pauses minting and burning operations function pause() external; + /// @notice Resumes minting and burning operations function unpause() external; + /** * @notice Updates the recipient of protocol fees * @param feesAddress Address receiving fees minted during token operations */ function setFeesAddress(address feesAddress) external; + /** * @notice Sets the Lotterie contract address used for fee distribution and user tracking * @param lotterieAddress Address of the Lotterie contract */ function setLotterieAddress(address lotterieAddress) external; + /// @notice Withdraws the entire ETH balance accumulated in the token contract function claimEth() external; /*////////////////////////////////////////////////////////////// CORE FUNCTIONS //////////////////////////////////////////////////////////////*/ + /** * @notice Initializes the proxy with owner credentials and Chainlink price feeds * @param owner Address granted OWNER_ROLE and initial fee recipient @@ -103,11 +120,13 @@ interface IGoldToken { /// @notice Converts supplied ETH into GLD using Chainlink prices and mints tokens function mint() external payable; + /** * @notice Burns GLD from the caller and updates lottery eligibility bookkeeping * @param amount Amount of GLD to burn */ function burn(uint256 amount) external; + /** * @notice Transfers GLD while keeping user eligibility data in sync * @param to Recipient address @@ -119,32 +138,58 @@ interface IGoldToken { /*////////////////////////////////////////////////////////////// VIEW FUNCTIONS //////////////////////////////////////////////////////////////*/ - /// @notice Returns the protocol fee percentage expressed in whole percents - /// @return Protocol fee percentage applied to mint/burn amounts + + /** + * @notice Returns the protocol fee percentage expressed in whole percents + * @return Protocol fee percentage applied to mint/burn amounts + */ function getFees() external view returns (uint256); - /// @notice Returns the address receiving protocol fees - /// @return Fee recipient address + + /** + * @notice Returns the address receiving protocol fees + * @return Fee recipient address + */ function getFeesAddress() external view returns (address); - /// @notice Returns the list of lottery-eligible users tracked by GoldToken - /// @return Array of user addresses + + /** + * @notice Returns the list of lottery-eligible users tracked by GoldToken + * @return Array of user addresses + */ function getUsers() external view returns (address[] memory); + + /** + * @notice Returns the user at a specific index in the tracked users array + * @param index Index of the user to retrieve + * @return User address at the specified index + */ + function getUserByIndex(uint256 index) external view returns (address); + + /** + * @notice Returns the total number of tracked users + * @return Total count of users + */ + function getUserCount() external view returns (uint256); + /** * @notice Returns users alongside their latest eligibility timestamps * @return users Array of tracked addresses * @return timestamps Array of UNIX timestamps matching the users array */ function getTimestamps() external view returns (address[] memory, uint256[] memory); + /** * @notice Checks whether an account owns OWNER_ROLE * @param account Address to inspect * @return True if OWNER_ROLE is assigned to the account */ function hasOwnerRole(address account) external view returns (bool); + /** * @notice Returns the Chainlink-derived gold price expressed in ETH with 18 decimals * @return Gold price in ETH scaled by 1e18 */ function getGoldPriceInEth() external view returns (int256); + /** * @notice Returns the GLD balance of an account * @param account Address to query diff --git a/src/interfaces/ILotterie.sol b/src/interfaces/ILotterie.sol index 8f8f586..635bf2d 100644 --- a/src/interfaces/ILotterie.sol +++ b/src/interfaces/ILotterie.sol @@ -16,7 +16,6 @@ interface ILotterie { * @param owner Address granted OWNER_ROLE * @param vrfSubscriptionId Subscription id funding VRF requests * @param vrfCoordinator Address of the VRF coordinator - * @param vrfNativePayment True when the VRF subscription uses native payment * @param keyHash Chainlink VRF key hash used for randomness * @param callbackGasLimit Gas limit allocated for fulfillRandomWords * @param requestConfirmations Number of confirmations required for VRF responses @@ -28,7 +27,6 @@ interface ILotterie { address owner; uint256 vrfSubscriptionId; address vrfCoordinator; - bool vrfNativePayment; bytes32 keyHash; uint32 callbackGasLimit; uint16 requestConfirmations; @@ -59,7 +57,6 @@ interface ILotterie { * @param vrfCoordinator Chainlink VRF coordinator contract address * @param goldToken GoldToken proxy associated with the lottery * @param vrfSubscriptionId VRF subscription identifier configured for draws - * @param vrfNativePayment Whether the VRF subscription is configured for native payment * @param keyHash Chainlink VRF key hash used to request randomness * @param callbackGasLimit Gas limit allocated to fulfillRandomWords * @param requestConfirmations Number of confirmations required per VRF request @@ -71,7 +68,6 @@ interface ILotterie { address indexed vrfCoordinator, address indexed goldToken, uint256 vrfSubscriptionId, - bool vrfNativePayment, bytes32 keyHash, uint32 callbackGasLimit, uint16 requestConfirmations, @@ -135,13 +131,6 @@ interface ILotterie { */ event RandomDrawCooldownUpdated(uint256 indexed previousCooldown, uint256 indexed newCooldown); - /** - * @notice Emitted when the VRF native payment setting changes - * @param previousNativePayment Setting before the update - * @param newNativePayment Setting after the update - */ - event VrfNativePaymentUpdated(bool indexed previousNativePayment, bool indexed newNativePayment); - /** * @notice Emitted when a participant successfully claims lottery gains * @param account Winner address claiming their gains @@ -227,12 +216,6 @@ interface ILotterie { */ function setRandomDrawCooldown(uint256 randomDrawCooldown) external; - /** - * @notice Updates the VRF native payment setting - * @param vrfNativePayment New native payment setting - */ - function setVrfNativePayment(bool vrfNativePayment) external; - /*////////////////////////////////////////////////////////////// CORE FUNCTIONS //////////////////////////////////////////////////////////////*/ @@ -242,9 +225,10 @@ interface ILotterie { /** * @notice Requests randomness from Chainlink to pick a lottery winner + * @param enableNativePayment When true, the VRF request will be paid in native tokens otherwise LINK will be used * @return requestId Identifier of the VRF request */ - function randomDraw() external returns (uint256 requestId); + function randomDraw(bool enableNativePayment) external returns (uint256 requestId); /// @notice Claims accrued lottery gains for the caller function claim() external; @@ -322,10 +306,4 @@ interface ILotterie { * @return Cooldown period */ function getRandomDrawCooldown() external view returns (uint256); - - /** - * @notice Returns whether the VRF subscription uses native payment - * @return True if native payment is enabled - */ - function getVrfNativePayment() external view returns (bool); } diff --git a/test/Lotterie.fuzz.t.sol b/test/Lotterie.fuzz.t.sol index 56a94da..1de1387 100644 --- a/test/Lotterie.fuzz.t.sol +++ b/test/Lotterie.fuzz.t.sol @@ -43,12 +43,11 @@ contract LotterieFuzzTest is Test { address(this), vrfSubscriptionId, address(vrfCoordinator), - false, bytes32(0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae), - 100000, + 40_000, 3, 1, - 86400, + 86_400, // One day address(goldToken) ) ); @@ -98,7 +97,7 @@ contract LotterieFuzzTest is Test { vm.warp(block.timestamp + 1 days); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); assertGt(requestId, 0, "Request ID should be positive"); // Fulfill the randomness @@ -131,7 +130,7 @@ contract LotterieFuzzTest is Test { vm.warp(block.timestamp + 1 days); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); address winner = lotterie.getResults(requestId); @@ -158,7 +157,7 @@ contract LotterieFuzzTest is Test { goldToken.mint{value: 1 ether}(); vm.warp(block.timestamp + cooldown); - lotterie.randomDraw(); + lotterie.randomDraw(false); vm.warp(block.timestamp + timeElapsed); @@ -168,19 +167,13 @@ contract LotterieFuzzTest is Test { ILotterie.DrawCooldownNotExpired.selector, block.timestamp - timeElapsed, cooldown, block.timestamp ) ); - lotterie.randomDraw(); + lotterie.randomDraw(false); } else { - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); assertGt(requestId, 0, "Should succeed after cooldown"); } } - /// @notice Fuzz test VRF native payment setting - function testFuzz_setVrfNativePayment(bool useNative) public { - lotterie.setVrfNativePayment(useNative); - assertEq(lotterie.getVrfNativePayment(), useNative, "Native payment setting should update"); - } - /// @notice Fuzz test VRF subscription ID changes function testFuzz_setVrfSubscriptionId(uint256 newSubscriptionId) public { vm.assume(newSubscriptionId > 0); @@ -202,7 +195,7 @@ contract LotterieFuzzTest is Test { for (uint256 i = 0; i < drawCount; i++) { currentTime += 1 days + 1; vm.warp(currentTime); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); assertGt(requestId, 0, "Request ID should be positive"); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); @@ -231,7 +224,7 @@ contract LotterieFuzzTest is Test { } vm.warp(block.timestamp + 1 days); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); address winner = lotterie.getResults(requestId); @@ -268,7 +261,7 @@ contract LotterieFuzzTest is Test { uint256 balanceBefore = goldToken.balanceOf(address(lotterie)); vm.assume(balanceBefore > 0); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); address winner = lotterie.getResults(requestId); @@ -303,7 +296,7 @@ contract LotterieFuzzTest is Test { newGoldToken.mint{value: mintAmount2}(); vm.warp(block.timestamp + 1 days); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); address winner = lotterie.getResults(requestId); @@ -314,7 +307,7 @@ contract LotterieFuzzTest is Test { /// @notice Documents that draws without users keep winner unset function test_randomDraw_withoutUsersLeavesWinnerUnset() public { vm.warp(block.timestamp + 1 days); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); diff --git a/test/Lotterie.t.sol b/test/Lotterie.t.sol index f93f740..b2a3eab 100644 --- a/test/Lotterie.t.sol +++ b/test/Lotterie.t.sol @@ -49,12 +49,11 @@ contract LotterieTest is Test { address(this), subscription, address(vrfCoordinator), - false, bytes32(0x787d74caea10b2b357790d5b5247c2f63d1d91572a9846f780606e4d953677ae), - 100000, + 40_000, 3, 1, - 86400, + 86_400, // One day address(goldToken) ) ); @@ -92,13 +91,13 @@ contract LotterieTest is Test { vm.expectRevert( abi.encodeWithSelector(ILotterie.DrawCooldownNotExpired.selector, lastDraw, cooldown, currentTime) ); - lotterie.randomDraw(); + lotterie.randomDraw(false); } function test_randomDraw() public { vm.warp(block.timestamp + 1 days); vm.recordLogs(); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); Vm.Log[] memory logs = vm.getRecordedLogs(); (Vm.Log memory randomDrawLog, bool found) = _findLog(logs, keccak256("RandomDrawed(uint256)")); @@ -111,7 +110,7 @@ contract LotterieTest is Test { function test_randomDrawFulfillmentAndClaimFlow() public { vm.warp(block.timestamp + 1 days); goldToken.mint{value: 1 ether}(); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); assertEq(lotterie.getLastRequestId(), requestId, "last request id should match the recent draw"); @@ -151,7 +150,7 @@ contract LotterieTest is Test { function test_claim_reverts_when_transfer_fails() public { vm.warp(block.timestamp + 1 days); goldToken.mint{value: 1 ether}(); - uint256 requestId = lotterie.randomDraw(); + uint256 requestId = lotterie.randomDraw(false); vrfCoordinator.fulfillRandomWords(requestId, address(lotterie)); address winner = lotterie.getResults(requestId); @@ -237,13 +236,6 @@ contract LotterieTest is Test { assertEq(lotterie.getRandomDrawCooldown(), 1 days + 1, "cooldown should be updated"); } - function test_setVrfNativePayment() public { - vm.expectEmit(true, true, false, false, address(lotterie)); - emit ILotterie.VrfNativePaymentUpdated(lotterie.getVrfNativePayment(), true); - lotterie.setVrfNativePayment(true); - assertTrue(lotterie.getVrfNativePayment(), "native payment should be true"); - } - function test_initialize_emits_event() public { Lotterie implementation = new Lotterie(address(vrfCoordinator)); uint256 subscription = vrfCoordinator.createSubscription(); @@ -253,7 +245,6 @@ contract LotterieTest is Test { address(vrfCoordinator), address(goldToken), subscription, - true, bytes32(uint256(0x1111)), 50_000, 2, @@ -267,7 +258,6 @@ contract LotterieTest is Test { address(this), subscription, address(vrfCoordinator), - true, bytes32(uint256(0x1111)), 50_000, 2,