diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..6e832bf --- /dev/null +++ b/.env.example @@ -0,0 +1,71 @@ +# ─── Wallets ────────────────────────────────────────────────────────────────── +# Deployer wallet — pays gas for contract deployments and delegation txs +PRIVATE_KEY=0xyour_deployer_private_key + +# Secondary wallet (optional — used for testing with a second account) +PRIVATE_KEY2=0xyour_second_private_key + +# Platform owner / whitelisted user — signs UserOps (needs no ETH for gasless ops) +OWNER_PRIVATE_KEY=0xyour_owner_private_key + +# ─── RPC Endpoints ──────────────────────────────────────────────────────────── +# Get free endpoints at https://infura.io or https://alchemy.com +SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/your_infura_project_id +AMOY_RPC_URL=https://polygon-amoy.infura.io/v3/your_infura_project_id + +# ─── Bundler ────────────────────────────────────────────────────────────────── +# Get a free Pimlico API key at https://dashboard.pimlico.io +PIMLICO_API_KEY=pim_your_pimlico_api_key + +# ─── EntryPoint ─────────────────────────────────────────────────────────────── +# Canonical EntryPoint v0.8 — same address on all supported chains +ENTRY_POINT=0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108 + +# ─── Document / Token Config ────────────────────────────────────────────────── +# Used by mintDocumentGasless.ts +TOKEN_ID=0xyour_document_hash_as_uint256 +TOKEN_NAME=MyRegistry +TOKEN_SYMBOL=MYR +REMARK=optional remark text +BENEFICIARY_ADDRESS=0xbeneficiary_wallet_address +HOLDER_ADDRESS=0xholder_wallet_address +NOMINEE_ADDR=0xnominee_wallet_address +NEW_HOLDER_ADDR=0xnew_holder_wallet_address + +# ─── Sepolia Deployments ────────────────────────────────────────────────────── +# Filled in automatically by deploy scripts — run in order: +# 1. npx hardhat run scripts/deployEIP7702.ts --network sepolia +# 2. npx hardhat run scripts/deployImplementation.ts --network sepolia +# 3. npx hardhat run scripts/deployFactory.ts --network sepolia +# 4. npx hardhat run scripts/deployPlatformPaymaster.ts --network sepolia +# 5. npx hardhat run scripts/stakePlatformPaymaster.ts --network sepolia + +EIP7702_IMPL_ADDRESS_SEPOLIA=0x_filled_by_deployEIP7702 +PAYMASTER_IMPLEMENTATION_SEPOLIA=0x_filled_by_deployImplementation +FACTORY_ADDRESS_SEPOLIA=0x_filled_by_deployFactory +PAYMASTER_ADDRESS_SEPOLIA=0x_filled_by_deployPlatformPaymaster + +# TrustVC infrastructure on Sepolia (pre-deployed — do not change) +TDOC_DEPLOYER_ADDRESS_SEPOLIA=0x64bc665056DC8bE4092e569ED13a7F273Be28cD2 +TDOC_IMPLEMENTATION_SEPOLIA=0x45c382574bb1B9C432a2e100Ab2086A4EAcB73Fd + +# Filled in after running deployRegistryGasless.ts / mintDocumentGasless.ts +REGISTRY_ADDRESS_SEPOLIA=0x_filled_after_deployRegistry +TITLE_ESCROW_ADDRESS_SEPOLIA=0x_filled_after_mintDocument + +# ─── Polygon Amoy Deployments ───────────────────────────────────────────────── +# Same deploy order as above but with --network amoy and NETWORK=amoy + +EIP7702_IMPL_ADDRESS_AMOY=0x_filled_by_deployEIP7702 +PAYMASTER_IMPLEMENTATION_AMOY=0x_filled_by_deployImplementation +FACTORY_ADDRESS_AMOY=0x_filled_by_deployFactory +PAYMASTER_ADDRESS_AMOY=0x_filled_by_deployPlatformPaymaster + +# TrustVC infrastructure on Amoy (pre-deployed — do not change) +TDOC_DEPLOYER_ADDRESS_AMOY=0xfcafea839e576967b96ad1FBFB52b5CA26cd1D25 +TDOC_IMPLEMENTATION_AMOY=0x_tdoc_implementation_on_amoy + +# Filled in after running gasless scripts with NETWORK=amoy +REGISTRY_ADDRESS_AMOY=0x_filled_after_deployRegistry +TITLE_ESCROW_ADDRESS_AMOY=0x_filled_after_mintDocument +FACTORY_ADDRESS_AMOY=0x_filled_after_deployFactory diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..ba46a50 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,6 @@ +dist +artifacts +cache +src/abis +node_modules +7702Frontend diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..ad7eecd --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,43 @@ +{ + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json", + "ecmaVersion": 2020, + "sourceType": "module" + }, + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended" + ], + "env": { + "node": true, + "mocha": true + }, + "rules": { + "no-console": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-explicit-any": "warn", + "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + "import/no-extraneous-dependencies": "off" + }, + "overrides": [ + { + "files": ["test/**/*.ts"], + "env": { "mocha": true }, + "rules": { + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-unused-expressions": "off", + "no-unused-expressions": "off" + } + }, + { + "files": ["scripts/**/*.ts"], + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } + } + ], + "ignorePatterns": ["dist", "artifacts", "cache", "src/abis", "7702Frontend", "node_modules"] +} diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 0000000..9c9a7ca --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,28 @@ +on: + workflow_call: + +env: + NODE_ENV: ci + +name: "Linters" + +jobs: + lint: + name: Code Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + - run: npm ci --ignore-scripts + - run: npm run lint + + commit-lint: + name: Commit Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install Commit Lint Dependencies + run: npm install @commitlint/config-conventional + - uses: JulienKode/pull-request-name-linter-action@v0.5.0 diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml new file mode 100644 index 0000000..deb9e9e --- /dev/null +++ b/.github/workflows/pull_requests.yml @@ -0,0 +1,30 @@ +on: + pull_request: + types: [opened, reopened, synchronize] + +env: + NODE_ENV: ci + +name: "Pull Requests" + +jobs: + tests: + name: Tests + uses: ./.github/workflows/tests.yml + + linters: + name: Linters + uses: ./.github/workflows/linters.yml + + eslint-review: + name: ESLint Review + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + steps: + - uses: actions/checkout@v4 + - uses: reviewdog/action-eslint@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + eslint_flags: "src scripts test --ext .ts" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..1f351d1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +name: Release + +on: + push: + branches: + - main + - dev + +env: + NODE_ENV: ci + +jobs: + tests: + name: Tests + uses: ./.github/workflows/tests.yml + + linters: + name: Linters + uses: ./.github/workflows/linters.yml + + release: + name: Publish Release + runs-on: ubuntu-latest + needs: [tests, linters] + permissions: + contents: write + packages: write + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Cache node modules + uses: actions/cache@v4 + with: + path: ~/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + + - uses: actions/setup-node@v4 + with: + node-version: 24 + registry-url: https://registry.npmjs.org/ + + - run: npm ci + - run: npm run build + - run: npm run semantic-release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.npm_token }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..e4eb331 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,31 @@ +on: + workflow_call: + +env: + NODE_ENV: ci + +name: "Tests" + +jobs: + run-tests: + name: Run Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + - run: npm ci --ignore-scripts + - run: npm run build:sol + - run: npm test + + test-build: + name: Test Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 24.x + - run: npm ci --ignore-scripts + - run: npm run build diff --git a/.gitignore b/.gitignore index e8c12ff..5ad699b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ node_modules .env +/dist # Hardhat files /cache /artifacts +/7702Frontend # TypeChain files /typechain diff --git a/7702Frontend/.env.example b/7702Frontend/.env.example deleted file mode 100644 index d90c84e..0000000 --- a/7702Frontend/.env.example +++ /dev/null @@ -1,11 +0,0 @@ -# Copy this to .env and fill in values from the root .env - -VITE_PIMLICO_API_KEY=your_pimlico_api_key -VITE_SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/your_key - -# From root .env -VITE_EIP7702_IMPL_ADDRESS=0xa46EC3920Ac5fc54F4bA33185A91ae250aDF59B8 -VITE_PAYMASTER_ADDRESS=0xB6977A2942A775A3C62a25912867700ECEb7F9Cc -VITE_REGISTRY_ADDRESS=0x22B8eB51f834e48a61874015C872C19FF16A7E44 -VITE_TITLE_ESCROW_ADDRESS=0x3aa575D729FaF5Aad7DB6192b317F2D0cD39789D -VITE_STORAGE_ADDRESS=0xeF71781776Bd5F7E3C301EA16378D880B5E52115 diff --git a/7702Frontend/index.html b/7702Frontend/index.html deleted file mode 100644 index b181f8c..0000000 --- a/7702Frontend/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - TrustVC 7702 Demo - - -
- - - diff --git a/7702Frontend/package-lock.json b/7702Frontend/package-lock.json deleted file mode 100644 index d197986..0000000 --- a/7702Frontend/package-lock.json +++ /dev/null @@ -1,3068 +0,0 @@ -{ - "name": "7702-frontend", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "7702-frontend", - "version": "0.1.0", - "dependencies": { - "ethers": "^6.13.5", - "permissionless": "^0.2.37", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "viem": "^2.21.54" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.15", - "typescript": "^5.6.3", - "vite": "^5.4.11" - } - }, - "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/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", - "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", - "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-compilation-targets": "^7.29.7", - "@babel/helper-module-transforms": "^7.29.7", - "@babel/helpers": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", - "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7", - "@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.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", - "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.29.7", - "@babel/helper-validator-option": "^7.29.7", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", - "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", - "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", - "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7", - "@babel/traverse": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", - "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", - "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", - "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", - "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", - "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.29.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", - "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", - "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", - "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/types": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", - "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.7", - "@babel/generator": "^7.29.7", - "@babel/helper-globals": "^7.29.7", - "@babel/parser": "^7.29.7", - "@babel/template": "^7.29.7", - "@babel/types": "^7.29.7", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", - "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.29.7", - "@babel/helper-validator-identifier": "^7.29.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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/@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.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/@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/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.0.tgz", - "integrity": "sha512-IPIQ55ythEHkfEd9jMEi32OQ7SxURsGA43JI22lj01OLZNt2NUbJX8YUHxkVWyQ6daHPNn0truF5nSj3DQp6YQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.0.tgz", - "integrity": "sha512-M6s9cr10MibETyo8JsOkq+Lo1+lU6hcvb1MApnUql5qte/5hMEgzlN8/ReIKNfRV8rrqX50W1BX9zoUhC192RA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.0.tgz", - "integrity": "sha512-BqCoMoIbn0keKys+dEAdBa70EtOwV1bEsQCUgU9FdiZmmMge/Zk7LlkYGqbrdHR+Frnt0E1FOanly+rlwvvQzw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.0.tgz", - "integrity": "sha512-SIMzST3VFNXDAbeIWDWiFCNM5qncUBDWaEV7NfE7oZbDt2mgfW4MvbKdbYiGOLoM32gbTv608UMd0XktEYSD7w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.0.tgz", - "integrity": "sha512-ezjfSQMP7ArdUsbBwbQIfwAlhE84I2iVnzQNCFSveqV42q+BmKlzVpf7mxv5EchLcoWU4y6/heFzVg1F+hodUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.0.tgz", - "integrity": "sha512-9+qTWGW9AZRhnUgwtTwzNwcPlL87ngkeN0LA+q1bADvmY9aNvWaF2TFW8BZgnQPYxpDI7+rMVLivcd4V737TAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.0.tgz", - "integrity": "sha512-T1dMEQhXA/jkJ/jyMIw9IovK8bSUq7A8kLIlvZTb/6YIVsp2zLavr4F3oyllHWo7eIVJRyE5n3tUjQJEbE1IuQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.0.tgz", - "integrity": "sha512-2as0LgT7qQpyceQq6VUJYnumUMUrgGQCWIiDIN9DE0/tglsk6o66uCB4f3djRawAltvfCNLyZZrsqbPA6inCsA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.0.tgz", - "integrity": "sha512-bVURMg+6eNN9C/yc0aVjooZcwTTtYF4YW3xta5pP0//r3o1V8gXEHXWCndj47w/HhwsFroZrFhR+6uQP5T0n0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.0.tgz", - "integrity": "sha512-Ful8pM/2yYI83PViWdFdpZhdI8HJ5qsXANe5atypbHDf+KIBBDsZsbyy8hbXnULVvW9NsTh5DHwbcBftyLTfiw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.0.tgz", - "integrity": "sha512-9Gp/DgrkzfUBmNPVTyPTvay+4xEP7M/clXpj3efXBcm6uTIVIgDg4rqUpqKXvLEuFRVuEpSAOkhgNeecvaZ4Cg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.0.tgz", - "integrity": "sha512-m9tsJz54LUXkSYM8+8PG81B9IKK5r+2T0clMq4QrS16xFosufU7firBDAZEsDheDs7wTlP7h3++S7lMsU955HA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.0.tgz", - "integrity": "sha512-3UvJ5PNVU16aJf6M3tFI24pWzAl2/ynfbyRN3ICyQajK1lSkrnVYNnLz3v04J32qKa0FczJc22zeToc0lr2A3w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.0.tgz", - "integrity": "sha512-vRWUAbYLGHBZS6Q8Msb2sfnf1fvJf+47t8l/TwOerM2qArzy+IeNMTHrYLHXh95h8MoatPHI5hhSZNs+mGXKPg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.0.tgz", - "integrity": "sha512-c00T5SYENHAt86cfW47URaP3Us5vLC/4QO7GYud1G5VNRffCwwCuBspwqYrriuJB+5m0WFzClCn9wed0FBjKvg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.0.tgz", - "integrity": "sha512-krrCDilhXOwFkSkO3Wm9I/f9H0L92XHHwy2fwxjukxIbh0dem8gZqOW5Y8BsHrpJv5qwlRBV+Wl4ZFyRWhUpwg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.0.tgz", - "integrity": "sha512-7pfYFSTc4/rUC/FtAI0Qp6QthDBCIi6/AuP1xYqFk5vanI6KnL5dWKP60OM/05LOsbwTmIcvr6eXC4CJuJ75IA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.0.tgz", - "integrity": "sha512-7SDIalKeIpG0Ifogbbdn58HmSotYMlf23K3dCJEmiVd9Fg36Vmni82iPQec27N3wY4Bvbxftkxz6vSx9OcouTg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.0.tgz", - "integrity": "sha512-eRZevouTH2i1HeAVLqJuLnt256krQkGY0TN6WsTmsIhuzbh457HuWDMakKwmi0Cjadux983CoSr8Lim2QhUIFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.0.tgz", - "integrity": "sha512-3oVS7FLGa4U1qcvao9ylGxrjXZyUQqR8UwxEcnUEyPX53O/C/mKDZegNXTdHCP+h3e6ta/f1EN38Yif1mmZHYg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.0.tgz", - "integrity": "sha512-yTB9TgfWj5wHe5QgktAgXTLLot1gvEjl1NiPPAUiCs4oPrIWFl5V4nC3GrkNdj9LaAU4s94nVrGbGOCqUpyWsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.0.tgz", - "integrity": "sha512-5LOhoaesY3doG1c+ac/2JtgREpKoJr5bUHH8tKY0V8di7+uSV6BwLs2PlR0/yzefGOkR+wE7ZolZphHCsyG5Rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.0.tgz", - "integrity": "sha512-yYkWHhmbhRTWTnWos5HC4GcPQfjlzzCNbM9e/+GXrLuaBXYA3qSDR9f0Vgufd5S8yX81U8jPKp7ZnAjZFMtRnw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.0.tgz", - "integrity": "sha512-SoTb6lPg25xZlA2ibwQ++ahCCnH+FP0qmEuafMJ4gznZKOlXioKEAeJLgCrqjM98ACziXM9V1amFjICVL4IFoA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.0.tgz", - "integrity": "sha512-5L+T1fMX4RIEBoZzT0+sQ0PhTS36NULFmMXtl1TZo44TMAROIMHbZufSOjVWt/Y622BtxgxtaNOokbTDvfsrZA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@scure/base": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", - "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", - "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/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/@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/@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/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "dev": true, - "license": "MIT" - }, - "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/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.31", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.31.tgz", - "integrity": "sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/abitype": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/abitype/-/abitype-1.2.3.tgz", - "integrity": "sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==", - "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/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/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/autoprefixer": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.5.0.tgz", - "integrity": "sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.2", - "caniuse-lite": "^1.0.30001787", - "fraction.js": "^5.3.4", - "picocolors": "^1.1.1", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.38", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz", - "integrity": "sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.28.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", - "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", - "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": { - "baseline-browser-mapping": "^2.10.12", - "caniuse-lite": "^1.0.30001782", - "electron-to-chromium": "^1.5.328", - "node-releases": "^2.0.36", - "update-browserslist-db": "^1.2.3" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001799", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz", - "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==", - "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/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "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/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "dev": true, - "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/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, - "node_modules/electron-to-chromium": { - "version": "1.5.375", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.375.tgz", - "integrity": "sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==", - "dev": true, - "license": "ISC" - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ethers": { - "version": "6.17.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.17.0.tgz", - "integrity": "sha512-BpyrpIPJ3ydEVow8zGaz1DuPS7YU8DcWxuBnY9a0UA/lvAPwrMr+EPXsfrul628SRaekPNeIM4UFh/91GWZang==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/ethers-io/" - }, - { - "type": "individual", - "url": "https://www.buymeacoffee.com/ricmoo" - } - ], - "license": "MIT", - "dependencies": { - "@adraffy/ens-normalize": "1.11.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.21.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "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/fast-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fraction.js": { - "version": "5.3.4", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.3.4.tgz", - "integrity": "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "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==", - "dev": true, - "license": "MIT", - "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/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/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", - "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/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/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "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==", - "license": "MIT" - }, - "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/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/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "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/node-releases": { - "version": "2.0.48", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.48.tgz", - "integrity": "sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/ox": { - "version": "0.14.29", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.29.tgz", - "integrity": "sha512-M5j87Ec4V99MQdRct/g09eWXW60g6zhHTUs1lr4deUtrPDnezBdCJTgKd7pxqTpSZBFveV0ALi9jMMuT1qKyNg==", - "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.2.3", - "eventemitter3": "5.0.1" - }, - "peerDependencies": { - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "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/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", - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "node_modules/permissionless": { - "version": "0.2.57", - "resolved": "https://registry.npmjs.org/permissionless/-/permissionless-0.2.57.tgz", - "integrity": "sha512-QrzAoQGYPV/NJ2x5Sj18h7qed6f+kCyQAojrncN091UPiGqHjFNjgdsgreiv8pxlQgF4UcpuJUvsHLpOEBd6cQ==", - "license": "MIT", - "peerDependencies": { - "ox": "^0.8.0", - "viem": "^2.28.1" - }, - "peerDependenciesMeta": { - "ox": { - "optional": true - } - } - }, - "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": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "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.12", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.4.tgz", - "integrity": "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "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/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.12", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", - "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.62.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.0.tgz", - "integrity": "sha512-nc72Wgq62I7rtDV4izT5/aaS0zxy3kttkinf9586ApknY3jZO9NYsmtc24fUckA0X7Q2v+ML4a15pdUlV5V/jA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.9" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.62.0", - "@rollup/rollup-android-arm64": "4.62.0", - "@rollup/rollup-darwin-arm64": "4.62.0", - "@rollup/rollup-darwin-x64": "4.62.0", - "@rollup/rollup-freebsd-arm64": "4.62.0", - "@rollup/rollup-freebsd-x64": "4.62.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.62.0", - "@rollup/rollup-linux-arm-musleabihf": "4.62.0", - "@rollup/rollup-linux-arm64-gnu": "4.62.0", - "@rollup/rollup-linux-arm64-musl": "4.62.0", - "@rollup/rollup-linux-loong64-gnu": "4.62.0", - "@rollup/rollup-linux-loong64-musl": "4.62.0", - "@rollup/rollup-linux-ppc64-gnu": "4.62.0", - "@rollup/rollup-linux-ppc64-musl": "4.62.0", - "@rollup/rollup-linux-riscv64-gnu": "4.62.0", - "@rollup/rollup-linux-riscv64-musl": "4.62.0", - "@rollup/rollup-linux-s390x-gnu": "4.62.0", - "@rollup/rollup-linux-x64-gnu": "4.62.0", - "@rollup/rollup-linux-x64-musl": "4.62.0", - "@rollup/rollup-openbsd-x64": "4.62.0", - "@rollup/rollup-openharmony-arm64": "4.62.0", - "@rollup/rollup-win32-arm64-msvc": "4.62.0", - "@rollup/rollup-win32-ia32-msvc": "4.62.0", - "@rollup/rollup-win32-x64-gnu": "4.62.0", - "@rollup/rollup-win32-x64-msvc": "4.62.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "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": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "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/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/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/tinyglobby/node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "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/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", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "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/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "license": "MIT" - }, - "node_modules/viem": { - "version": "2.52.2", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.52.2.tgz", - "integrity": "sha512-HSU12p5aD/kAPZfrlbCUqdiP4P/c6hQ9AhfTS51VbLUQIjkWd1d5EjrCx/SCxZ0zhZVRn4Iv5X5WDqXPG8Ubew==", - "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.2.3", - "isows": "1.0.7", - "ox": "0.14.29", - "ws": "8.20.1" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "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/ws": { - "version": "8.20.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", - "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", - "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/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/ws": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", - "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", - "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/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" - } - } -} diff --git a/7702Frontend/package.json b/7702Frontend/package.json deleted file mode 100644 index 2d7275e..0000000 --- a/7702Frontend/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "7702-frontend", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "dependencies": { - "ethers": "^6.13.5", - "permissionless": "^0.2.37", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "viem": "^2.21.54" - }, - "devDependencies": { - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", - "@vitejs/plugin-react": "^4.3.4", - "autoprefixer": "^10.4.20", - "postcss": "^8.4.47", - "tailwindcss": "^3.4.15", - "typescript": "^5.6.3", - "vite": "^5.4.11" - } -} diff --git a/7702Frontend/postcss.config.js b/7702Frontend/postcss.config.js deleted file mode 100644 index 2aa7205..0000000 --- a/7702Frontend/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; diff --git a/7702Frontend/src/App.tsx b/7702Frontend/src/App.tsx deleted file mode 100644 index 9dc67a5..0000000 --- a/7702Frontend/src/App.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { useState } from "react"; -import { WalletConnect } from "./components/WalletConnect"; -import { PaymasterPanel } from "./components/PaymasterPanel"; -import { PaymasterAdminPanel } from "./components/PaymasterAdminPanel"; -import { RegistryPanel } from "./components/RegistryPanel"; -import { TitleEscrowPanel } from "./components/TitleEscrowPanel"; -import { DelegationPanel } from "./components/DelegationPanel"; -import { TrustVCPanel } from "./components/TrustVCPanel"; -import { PAYMASTER_ADDRESS } from "./lib/constants"; - -export default function App() { - const [address, setAddress] = useState(null); - const [isDelegated, setIsDelegated] = useState(false); - const [paymasterAddress, setPaymasterAddress] = useState<`0x${string}` | null>( - PAYMASTER_ADDRESS && PAYMASTER_ADDRESS !== "0x" ? PAYMASTER_ADDRESS : null - ); - const [registryAddress, setRegistryAddress] = useState<`0x${string}` | null>(null); - const [titleEscrowAddress, setTitleEscrowAddress] = useState<`0x${string}` | null>(null); - - function handleDisconnect() { - setAddress(null); - setIsDelegated(false); - setRegistryAddress(null); - setTitleEscrowAddress(null); - } - - return ( -
-
-

- TrustVC EIP-7702 -

-

- Gasless trade document operations via Account Abstraction · Sepolia -

-
- - - - - - - - - - - - - - - -

- EIP-7702 · ERC-4337 · Pimlico Bundler · Sepolia Testnet -

-
- ); -} diff --git a/7702Frontend/src/components/DelegationPanel.tsx b/7702Frontend/src/components/DelegationPanel.tsx deleted file mode 100644 index 580d06f..0000000 --- a/7702Frontend/src/components/DelegationPanel.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { checkDelegation, PERMISSIONLESS_IMPL } from "../lib/pimlico"; - -interface Props { - address: string | null; - onDelegated: (delegated: boolean) => void; -} - -export function DelegationPanel({ address, onDelegated }: Props) { - const [currentDelegate, setCurrentDelegate] = useState< - string | null | undefined - >(undefined); - const [checking, setChecking] = useState(false); - - const isDelegated = - currentDelegate?.toLowerCase() === PERMISSIONLESS_IMPL.toLowerCase(); - - const refresh = useCallback(async () => { - if (!address) return; - setChecking(true); - try { - const delegate = await checkDelegation(address as `0x${string}`); - setCurrentDelegate(delegate); - onDelegated( - delegate?.toLowerCase() === PERMISSIONLESS_IMPL.toLowerCase(), - ); - } finally { - setChecking(false); - } - }, [address, onDelegated]); - - useEffect(() => { - refresh(); - }, [refresh]); - - if (!address) { - return ( -
-

EIP-7702 Delegation

-

Connect wallet first

-
- ); - } - - return ( -
-
-

EIP-7702 Delegation

- {checking ? ( - - checking... - - ) : currentDelegate === undefined ? null : isDelegated ? ( - - - Active - - ) : ( - - - Pending - - )} -
- -
-
- Target impl: - - {PERMISSIONLESS_IMPL} - -
-
- Current delegate: - - {currentDelegate === undefined ? "—" : (currentDelegate ?? "none")} - -
-
- - {isDelegated ? ( -

- Your EOA is delegated to the implementation contract above. All - transactions are sent as smart account UserOps. -

- ) : ( -
-

Not delegated

-

- Your EOA has not been delegated yet. To delegate, run the following - command in the CLI: -

-
-            npx ts-node scripts/trFunctions/delegate.ts
-          
-
- )} - - -
- ); -} diff --git a/7702Frontend/src/components/PaymasterAdminPanel.tsx b/7702Frontend/src/components/PaymasterAdminPanel.tsx deleted file mode 100644 index 073b8c1..0000000 --- a/7702Frontend/src/components/PaymasterAdminPanel.tsx +++ /dev/null @@ -1,314 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { createWalletClient, createPublicClient, custom, http, parseAbi, parseEther, formatEther, isAddress } from "viem"; -import { sepolia } from "viem/chains"; -import { SEPOLIA_RPC_URL } from "../lib/constants"; - -const ENTRY_POINT = "0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108" as const; - -const paymasterAbi = parseAbi([ - "function setTdocDeployer(address _tdocDeployer) external", - "function setUserWhitelist(address user, uint256 credits) external", - "function addStake(uint32 unstakeDelaySec) external payable", - "function deposit() external payable", -]); - -const entryPointAbi = parseAbi([ - "function getDepositInfo(address account) external view returns (uint256 deposit, bool staked, uint112 stake, uint32 unstakeDelaySec, uint48 withdrawTime)", -]); - -interface DepositInfo { - deposit: bigint; - staked: boolean; - stake: bigint; - unstakeDelaySec: number; -} - -interface Props { - address: string | null; - paymasterAddress: string | null; -} - -export function PaymasterAdminPanel({ address, paymasterAddress }: Props) { - const [depositInfo, setDepositInfo] = useState(null); - - const [deployerInput, setDeployerInput] = useState(""); - const [deployerLoading, setDeployerLoading] = useState(false); - const [deployerError, setDeployerError] = useState(null); - const [deployerSuccess, setDeployerSuccess] = useState(false); - - const [whitelistInput, setWhitelistInput] = useState(""); - const [credits, setCredits] = useState("3"); - const [whitelistLoading, setWhitelistLoading] = useState(false); - const [whitelistError, setWhitelistError] = useState(null); - const [whitelistSuccess, setWhitelistSuccess] = useState(null); - - const [fundAmount, setFundAmount] = useState("0.05"); - const [fundLoading, setFundLoading] = useState(false); - const [fundError, setFundError] = useState(null); - const [fundSuccess, setFundSuccess] = useState(false); - - const [stakeAmount, setStakeAmount] = useState("0.01"); - const [unstakeDelay, setUnstakeDelay] = useState("86400"); - const [stakeLoading, setStakeLoading] = useState(false); - const [stakeError, setStakeError] = useState(null); - const [stakeSuccess, setStakeSuccess] = useState(false); - - const disabled = !address || !paymasterAddress; - - const fetchDepositInfo = useCallback(async () => { - if (!paymasterAddress) return; - try { - const publicClient = createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - const raw = await publicClient.readContract({ - address: ENTRY_POINT, - abi: entryPointAbi, - functionName: "getDepositInfo", - args: [paymasterAddress as `0x${string}`], - }) as [bigint, boolean, bigint, number, number]; - setDepositInfo({ deposit: raw[0], staked: raw[1], stake: raw[2], unstakeDelaySec: raw[3] }); - } catch { /* ignore */ } - }, [paymasterAddress]); - - useEffect(() => { fetchDepositInfo(); }, [fetchDepositInfo]); - - const publicClient = () => createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - - function walletClient() { - return createWalletClient({ - account: address as `0x${string}`, - chain: sepolia, - transport: custom(window.ethereum), - }); - } - - async function sendAndWait(fn: () => Promise<`0x${string}`>) { - const hash = await fn(); - await publicClient().waitForTransactionReceipt({ hash }); - return hash; - } - - async function handleSetDeployer() { - if (!address || !paymasterAddress) return; - setDeployerError(null); setDeployerSuccess(false); - const addr = deployerInput.trim(); - if (!isAddress(addr)) { setDeployerError("Invalid address."); return; } - setDeployerLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "setTdocDeployer", - args: [addr as `0x${string}`], - })); - setDeployerSuccess(true); - setDeployerInput(""); - } catch (e: unknown) { - setDeployerError(e instanceof Error ? e.message : String(e)); - } finally { setDeployerLoading(false); } - } - - async function handleWhitelist() { - if (!address || !paymasterAddress) return; - setWhitelistError(null); setWhitelistSuccess(null); - const addr = whitelistInput.trim(); - if (!isAddress(addr)) { setWhitelistError("Invalid address."); return; } - const c = parseInt(credits); - if (isNaN(c) || c < 0 || c > 3) { setWhitelistError("Credits must be 0–3."); return; } - setWhitelistLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "setUserWhitelist", - args: [addr as `0x${string}`, BigInt(c)], - })); - setWhitelistSuccess(`${addr} whitelisted with ${c} credit${c !== 1 ? "s" : ""}.`); - setWhitelistInput(""); - } catch (e: unknown) { - setWhitelistError(e instanceof Error ? e.message : String(e)); - } finally { setWhitelistLoading(false); } - } - - async function handleFund() { - if (!address || !paymasterAddress) return; - setFundError(null); setFundSuccess(false); - const eth = parseFloat(fundAmount); - if (isNaN(eth) || eth <= 0) { setFundError("Enter a valid ETH amount."); return; } - setFundLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "deposit", - value: parseEther(fundAmount), - })); - setFundSuccess(true); - await fetchDepositInfo(); - } catch (e: unknown) { - setFundError(e instanceof Error ? e.message : String(e)); - } finally { setFundLoading(false); } - } - - async function handleStake() { - if (!address || !paymasterAddress) return; - setStakeError(null); setStakeSuccess(false); - const eth = parseFloat(stakeAmount); - const delay = parseInt(unstakeDelay); - if (isNaN(eth) || eth <= 0) { setStakeError("Enter a valid ETH amount."); return; } - if (isNaN(delay) || delay < 1) { setStakeError("Enter a valid unstake delay (seconds)."); return; } - setStakeLoading(true); - try { - await sendAndWait(() => walletClient().writeContract({ - address: paymasterAddress as `0x${string}`, - abi: paymasterAbi, - functionName: "addStake", - args: [delay], - value: parseEther(stakeAmount), - })); - setStakeSuccess(true); - await fetchDepositInfo(); - } catch (e: unknown) { - setStakeError(e instanceof Error ? e.message : String(e)); - } finally { setStakeLoading(false); } - } - - return ( -
-

Paymaster Admin

- - {!paymasterAddress && ( -

Set up a paymaster first.

- )} - - {/* EntryPoint status */} - {depositInfo && ( -
-

EntryPoint Status

-
- Gas deposit: - 0n ? "text-emerald-400" : "text-yellow-400"}`}> - {formatEther(depositInfo.deposit)} ETH - -
-
- Stake: - - {depositInfo.staked ? `${formatEther(depositInfo.stake)} ETH (locked ${depositInfo.unstakeDelaySec}s)` : "Not staked"} - -
- -
- )} - - {/* Fund gas pool */} -
-

Fund Gas Pool

-

- Deposit ETH into the EntryPoint gas pool. This is what pays for sponsored UserOps. -

-
- { setFundAmount(e.target.value); setFundError(null); setFundSuccess(false); }} - disabled={disabled || fundLoading} - /> - -
- {fundSuccess &&

Gas pool funded ✓

} - {fundError &&

{fundError}

} -
- - {/* Add stake */} -
-

Add Stake

-

- Lock ETH as a bundler-compliance bond. Required for the paymaster to be accepted by bundlers. -

-
- { setStakeAmount(e.target.value); setStakeError(null); setStakeSuccess(false); }} - disabled={disabled || stakeLoading} - /> - setUnstakeDelay(e.target.value)} - disabled={disabled || stakeLoading} - /> - -
-

Unstake delay: 86400 = 1 day (cannot be reduced once set)

- {stakeSuccess &&

Stake added ✓

} - {stakeError &&

{stakeError}

} -
- - {/* Set TDoc Deployer */} -
-

TDoc Deployer

-

- The factory contract that deploys TDoc registries. Required for deployRegistry. -

-
- { setDeployerInput(e.target.value); setDeployerError(null); setDeployerSuccess(false); }} - disabled={disabled || deployerLoading} - /> - -
- {deployerSuccess &&

TDoc deployer updated ✓

} - {deployerError &&

{deployerError}

} -
- - {/* Whitelist User */} -
-

Whitelist User

-

- Grant deployment credits (max 3) for gasless deployRegistry and mintDocument. -

-
- { setWhitelistInput(e.target.value); setWhitelistError(null); setWhitelistSuccess(null); }} - disabled={disabled || whitelistLoading} - /> - - -
-

Credits: 1 = deployRegistry only · 2 = + mintDocument · 3 = max

- {whitelistSuccess &&

{whitelistSuccess} ✓

} - {whitelistError &&

{whitelistError}

} -
-
- ); -} diff --git a/7702Frontend/src/components/PaymasterPanel.tsx b/7702Frontend/src/components/PaymasterPanel.tsx deleted file mode 100644 index 86168a6..0000000 --- a/7702Frontend/src/components/PaymasterPanel.tsx +++ /dev/null @@ -1,270 +0,0 @@ -import { useState, useEffect } from "react"; -import { createWalletClient, createPublicClient, custom, http, parseAbi, parseEventLogs, parseEther, isAddress } from "viem"; -import { sepolia } from "viem/chains"; -import { PAYMASTER_ADDRESS, FACTORY_ADDRESS, SEPOLIA_RPC_URL } from "../lib/constants"; -const PERMANENT_OWNER = "0x433097a1C1b8a3e9188d8C54eCC057B1D69f1638".toLowerCase(); -const LS_KEY = "trustvc_paymaster"; - -const factoryAbi = parseAbi([ - "function deployPlatformPaymaster(address platformAddress, uint256 dailyLimit, bytes32 salt) external returns (address paymaster)", - "event PlatformOnboarded(address indexed platformAddress, address indexed paymaster)", -]); - -interface Props { - address: string | null; - onPaymasterDeployed: (address: `0x${string}`) => void; -} - -type Mode = "deploy" | "load"; - -export function PaymasterPanel({ address, onPaymasterDeployed }: Props) { - const envPaymaster = PAYMASTER_ADDRESS && PAYMASTER_ADDRESS !== "0x" ? PAYMASTER_ADDRESS : null; - - const [mode, setMode] = useState("deploy"); - const [activePaymaster, setActivePaymaster] = useState(null); - const [deploying, setDeploying] = useState(false); - const [dailyLimitEth, setDailyLimitEth] = useState("0"); - const [loadInput, setLoadInput] = useState(""); - const [loadError, setLoadError] = useState(null); - const [deployError, setDeployError] = useState(null); - const [justDeployed, setJustDeployed] = useState(false); - const [justLoaded, setJustLoaded] = useState(false); - - // When address changes, resolve which paymaster to use - useEffect(() => { - if (!address) { - setActivePaymaster(null); - return; - } - - // Permanent owner → always use env paymaster - if (address.toLowerCase() === PERMANENT_OWNER && envPaymaster) { - setActivePaymaster(envPaymaster); - onPaymasterDeployed(envPaymaster); - return; - } - - // Anyone else → check localStorage - const saved = localStorage.getItem(LS_KEY); - if (saved) { - setActivePaymaster(saved); - onPaymasterDeployed(saved as `0x${string}`); - } else { - setActivePaymaster(null); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]); - - const isPermanentOwner = address?.toLowerCase() === PERMANENT_OWNER; - const disabled = !address; - - function handleLoad() { - setLoadError(null); - const trimmed = loadInput.trim(); - if (!isAddress(trimmed)) { - setLoadError("Invalid address."); - return; - } - localStorage.setItem(LS_KEY, trimmed); - setActivePaymaster(trimmed); - setJustLoaded(true); - onPaymasterDeployed(trimmed as `0x${string}`); - } - - async function handleDeploy() { - if (!address) return; - setDeployError(null); - setDeploying(true); - try { - const transport = http(SEPOLIA_RPC_URL); - const publicClient = createPublicClient({ chain: sepolia, transport }); - const walletClient = createWalletClient({ - account: address as `0x${string}`, - chain: sepolia, - transport: custom(window.ethereum), - }); - - const salt = ("0x" + Array.from(crypto.getRandomValues(new Uint8Array(32))) - .map((b) => b.toString(16).padStart(2, "0")) - .join("")) as `0x${string}`; - - const dailyLimit = dailyLimitEth && parseFloat(dailyLimitEth) > 0 - ? parseEther(dailyLimitEth) - : 0n; - - const txHash = await walletClient.writeContract({ - address: FACTORY_ADDRESS, - abi: factoryAbi, - functionName: "deployPlatformPaymaster", - args: [address as `0x${string}`, dailyLimit, salt], - }); - - const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }); - const logs = parseEventLogs({ abi: factoryAbi, logs: receipt.logs, eventName: "PlatformOnboarded" }); - const paymasterAddr = logs[0]?.args?.paymaster; - if (!paymasterAddr) throw new Error("Deploy succeeded but paymaster address not found in logs"); - - localStorage.setItem(LS_KEY, paymasterAddr); - setActivePaymaster(paymasterAddr); - setJustDeployed(true); - onPaymasterDeployed(paymasterAddr); - } catch (e: unknown) { - setDeployError(e instanceof Error ? e.message : String(e)); - } finally { - setDeploying(false); - } - } - - // Active state - if (activePaymaster) { - return ( -
-
-

Platform Paymaster

- - - {justDeployed ? "Deployed" : "Active"} - -
- -
-
- Paymaster: - - {activePaymaster} - -
- {isPermanentOwner && ( -

Loaded from environment (permanent owner).

- )} - {justDeployed && ( -

Deployed and saved to local storage.

- )} - {justLoaded && ( -

Paymaster loaded and saved for this browser.

- )} -
- - {!isPermanentOwner && ( - - )} -
- ); - } - - return ( -
-
-

Platform Paymaster

- - - Not set - -
- - {/* Mode toggle */} -
- - -
- - {mode === "deploy" ? ( -
-

- Deploy a PlatformPaymaster via the factory. Your connected wallet becomes the paymaster owner. -

- -
- - setDailyLimitEth(e.target.value)} - disabled={disabled || deploying} - /> -
- -
-
- Platform owner: - {address ?? "—"} -
-
- Factory: - {FACTORY_ADDRESS} -
-
- - - - {deployError && ( -

{deployError}

- )} -
- ) : ( -
-

- Already have a deployed paymaster? Paste the address below — it will be saved in your browser. -

- - { setLoadInput(e.target.value); setLoadError(null); }} - disabled={disabled} - /> - - - - {loadError && ( -

{loadError}

- )} -
- )} -
- ); -} diff --git a/7702Frontend/src/components/RegistryPanel.tsx b/7702Frontend/src/components/RegistryPanel.tsx deleted file mode 100644 index dab4bef..0000000 --- a/7702Frontend/src/components/RegistryPanel.tsx +++ /dev/null @@ -1,336 +0,0 @@ -import { useState, useEffect } from "react"; -import { - createPublicClient, - http, - parseAbi, - parseEventLogs, - isAddress, - encodeFunctionData, -} from "viem"; -import { sepolia } from "viem/chains"; -import { - REGISTRY_ADDRESS, - SEPOLIA_RPC_URL, - TDOC_IMPLEMENTATION, -} from "../lib/constants"; -import { buildSmartAccountClient } from "../lib/pimlico"; - -const PERMANENT_OWNER = - "0x433097a1C1b8a3e9188d8C54eCC057B1D69f1638".toLowerCase(); -const LS_KEY = "trustvc_registry"; - -const paymasterAbi = parseAbi([ - "function deployRegistry(address implementation, string name, string symbol) external returns (address deployed)", - "event RegistryDeployed(address indexed user, address indexed deployed, uint256 creditsLeft)", -]); - -interface Props { - address: string | null; - paymasterAddress: string | null; - isDelegated: boolean; - onRegistryReady: (address: `0x${string}`) => void; -} - -type Mode = "deploy" | "load"; - -export function RegistryPanel({ - address, - paymasterAddress, - isDelegated, - onRegistryReady, -}: Props) { - const envRegistry = - REGISTRY_ADDRESS && REGISTRY_ADDRESS !== "0x" ? REGISTRY_ADDRESS : null; - - const [mode, setMode] = useState("deploy"); - const [activeRegistry, setActiveRegistry] = useState(null); - const [deploying, setDeploying] = useState(false); - const [implAddress, setImplAddress] = useState( - TDOC_IMPLEMENTATION ?? "", - ); - const [tokenName, setTokenName] = useState(""); - const [tokenSymbol, setTokenSymbol] = useState(""); - const [loadInput, setLoadInput] = useState(""); - const [loadError, setLoadError] = useState(null); - const [deployError, setDeployError] = useState(null); - const [justDeployed, setJustDeployed] = useState(false); - const [justLoaded, setJustLoaded] = useState(false); - - useEffect(() => { - if (!address) { - setActiveRegistry(null); - return; - } - if (address.toLowerCase() === PERMANENT_OWNER && envRegistry) { - setActiveRegistry(envRegistry); - onRegistryReady(envRegistry); - return; - } - const saved = localStorage.getItem(LS_KEY); - if (saved) { - setActiveRegistry(saved); - onRegistryReady(saved as `0x${string}`); - } else setActiveRegistry(null); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]); - - const isPermanentOwner = address?.toLowerCase() === PERMANENT_OWNER; - const disabled = !address || !paymasterAddress; - - function handleLoad() { - setLoadError(null); - const trimmed = loadInput.trim(); - if (!isAddress(trimmed)) { - setLoadError("Invalid address."); - return; - } - localStorage.setItem(LS_KEY, trimmed); - setActiveRegistry(trimmed); - setJustLoaded(true); - onRegistryReady(trimmed as `0x${string}`); - } - - async function handleDeploy() { - if (!address || !paymasterAddress) return; - if (!isAddress(implAddress)) { - setDeployError("Invalid implementation address."); - return; - } - if (!tokenName.trim()) { - setDeployError("Token name is required."); - return; - } - if (!tokenSymbol.trim()) { - setDeployError("Token symbol is required."); - return; - } - setDeployError(null); - setDeploying(true); - try { - const publicClient = createPublicClient({ - chain: sepolia, - transport: http(SEPOLIA_RPC_URL), - }); - const calldata = encodeFunctionData({ - abi: paymasterAbi, - functionName: "deployRegistry", - args: [ - implAddress as `0x${string}`, - tokenName.trim(), - tokenSymbol.trim(), - ], - }); - - let txHash: `0x${string}`; - if (isDelegated) { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}`, - paymasterAddress as `0x${string}`, - ); - txHash = (await smartAccountClient.sendTransaction({ - to: paymasterAddress as `0x${string}`, - value: 0n, - data: calldata, - })) as `0x${string}`; - } else { - throw new Error( - "Delegation required for gasless registry deploy. Run the delegate script first or delegate via DelegationPanel.", - ); - } - - const receipt = await publicClient.waitForTransactionReceipt({ - hash: txHash, - }); - const logs = parseEventLogs({ - abi: paymasterAbi, - logs: receipt.logs, - eventName: "RegistryDeployed", - }); - const registryAddr = logs[0]?.args?.deployed; - if (!registryAddr) - throw new Error( - "Deploy succeeded but registry address not found in logs", - ); - - localStorage.setItem(LS_KEY, registryAddr); - setActiveRegistry(registryAddr); - setJustDeployed(true); - onRegistryReady(registryAddr); - } catch (e: unknown) { - setDeployError(e instanceof Error ? e.message : String(e)); - } finally { - setDeploying(false); - } - } - - if (activeRegistry) { - return ( -
-
-

Token Registry

- - - {justDeployed ? "Deployed" : "Active"} - -
-
-
- Registry: - - {activeRegistry} - -
- {isPermanentOwner && ( -

- Loaded from environment (permanent owner). -

- )} - {justDeployed && ( -

- Deployed and saved to local storage. -

- )} - {justLoaded && ( -

Registry loaded.

- )} -
- {!isPermanentOwner && ( - - )} -
- ); - } - - return ( -
-
-

Token Registry

- - - Not set - -
- - {!paymasterAddress && ( -

- Set up a paymaster first. -

- )} - -
- - -
- - {mode === "deploy" ? ( -
-

- Deploy a new TDoc registry via the paymaster. Requires whitelist - credits on the paymaster. -

- setImplAddress(e.target.value)} - disabled={disabled || deploying} - /> - setTokenName(e.target.value)} - disabled={disabled || deploying} - /> - setTokenSymbol(e.target.value)} - disabled={disabled || deploying} - /> - - {!isDelegated && !disabled && ( -

- Delegation required — run{" "} - - npx ts-node scripts/trFunctions/delegate.ts - {" "} - first. -

- )} - {deployError && ( -

{deployError}

- )} -
- ) : ( -
-

- Already have a registry? Paste the address — it will be saved in - your browser. -

- { - setLoadInput(e.target.value); - setLoadError(null); - }} - disabled={disabled} - /> - - {loadError &&

{loadError}

} -
- )} -
- ); -} diff --git a/7702Frontend/src/components/SignerPanel.tsx b/7702Frontend/src/components/SignerPanel.tsx deleted file mode 100644 index b38edc8..0000000 --- a/7702Frontend/src/components/SignerPanel.tsx +++ /dev/null @@ -1,2 +0,0 @@ -// Unused — MetaMask signs UserOps via signTypedData (EIP-712) with to7702SimpleSmartAccount. -export {}; diff --git a/7702Frontend/src/components/StoragePanel.tsx b/7702Frontend/src/components/StoragePanel.tsx deleted file mode 100644 index 06ec31b..0000000 --- a/7702Frontend/src/components/StoragePanel.tsx +++ /dev/null @@ -1,276 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { encodeFunctionData, parseAbiItem, createPublicClient, http } from "viem"; -import { sepolia } from "viem/chains"; -import { buildSmartAccountClient } from "../lib/pimlico"; -import { STORAGE_ADDRESS, SEPOLIA_RPC_URL } from "../lib/constants"; -import { STORAGE_ABI } from "../lib/abis"; - -interface Item { - id: number; - data: string; - deleted: boolean; -} - -interface Props { - address: string | null; - isDelegated: boolean; -} - -// Typed event definitions — getLogs returns decoded args when using these -const CREATED_EVENT = parseAbiItem( - "event ItemCreated(uint256 indexed id, string data, uint256 timestamp)" -); -const UPDATED_EVENT = parseAbiItem( - "event ItemUpdated(uint256 indexed id, string data, uint256 timestamp)" -); -const DELETED_EVENT = parseAbiItem("event ItemDeleted(uint256 indexed id)"); - -export function StoragePanel({ address, isDelegated }: Props) { - const [items, setItems] = useState([]); - const [newData, setNewData] = useState(""); - const [updateId, setUpdateId] = useState(""); - const [updateData, setUpdateData] = useState(""); - const [removeId, setRemoveId] = useState(""); - const [loading, setLoading] = useState(null); - const [lastTx, setLastTx] = useState(null); - const [error, setError] = useState(null); - - const fetchItems = useCallback(async () => { - try { - const publicClient = createPublicClient({ - chain: sepolia, - transport: http(SEPOLIA_RPC_URL), - }); - - // getLogs with a typed parseAbiItem event returns fully-typed args - const [created, updated, deleted] = await Promise.all([ - publicClient.getLogs({ address: STORAGE_ADDRESS, event: CREATED_EVENT, fromBlock: 0n }), - publicClient.getLogs({ address: STORAGE_ADDRESS, event: UPDATED_EVENT, fromBlock: 0n }), - publicClient.getLogs({ address: STORAGE_ADDRESS, event: DELETED_EVENT, fromBlock: 0n }), - ]); - - const map: Record = {}; - - for (const log of created) { - const id = Number(log.args.id); - map[id] = { id, data: log.args.data ?? "", deleted: false }; - } - for (const log of updated) { - const id = Number(log.args.id); - if (map[id]) map[id].data = log.args.data ?? ""; - } - for (const log of deleted) { - const id = Number(log.args.id); - if (map[id]) map[id].deleted = true; - } - - setItems(Object.values(map).sort((a, b) => a.id - b.id)); - } catch (e) { - console.error("fetchItems error:", e); - } - }, []); - - useEffect(() => { - fetchItems(); - }, [fetchItems]); - - async function sendUserOp(calldata: `0x${string}`, label: string) { - if (!address) return; - setError(null); - setLastTx(null); - setLoading(label); - try { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}` - ); - const txHash = await smartAccountClient.sendTransaction({ - to: STORAGE_ADDRESS, - value: 0n, - data: calldata, - }); - setLastTx(txHash); - await fetchItems(); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setLoading(null); - } - } - - async function handleCreate() { - if (!newData.trim()) return; - const data = encodeFunctionData({ - abi: STORAGE_ABI, - functionName: "create", - args: [newData.trim()], - }); - await sendUserOp(data, "create"); - setNewData(""); - } - - async function handleUpdate() { - if (!updateId || !updateData.trim()) return; - const data = encodeFunctionData({ - abi: STORAGE_ABI, - functionName: "update", - args: [BigInt(updateId), updateData.trim()], - }); - await sendUserOp(data, "update"); - setUpdateId(""); - setUpdateData(""); - } - - async function handleRemove() { - if (!removeId) return; - const data = encodeFunctionData({ - abi: STORAGE_ABI, - functionName: "remove", - args: [BigInt(removeId)], - }); - await sendUserOp(data, "remove"); - setRemoveId(""); - } - - const disabled = !address || !isDelegated; - - return ( -
-
-

Storage CRUD

- gasless via UserOp -
- - {disabled && ( -

- {!address ? "Connect wallet first." : "Delegate your EOA first."} -

- )} - - {/* Item list */} -
-

- Items on-chain -

- {items.length === 0 ? ( -

No items yet.

- ) : ( -
- {items.map((item) => ( -
- #{item.id} - {item.data} -
- ))} -
- )} - -
- - {/* Create */} -
-

- Create -

-
- setNewData(e.target.value)} - disabled={disabled} - /> - -
-
- - {/* Update */} -
-

- Update -

-
- setUpdateId(e.target.value)} - disabled={disabled} - /> - setUpdateData(e.target.value)} - disabled={disabled} - /> - -
-
- - {/* Remove */} -
-

- Remove -

-
- setRemoveId(e.target.value)} - disabled={disabled} - /> - -
-
- - {lastTx && ( -

- Tx: {lastTx} -

- )} - {error && ( -

{error}

- )} -
- ); -} diff --git a/7702Frontend/src/components/TitleEscrowPanel.tsx b/7702Frontend/src/components/TitleEscrowPanel.tsx deleted file mode 100644 index 97d2de0..0000000 --- a/7702Frontend/src/components/TitleEscrowPanel.tsx +++ /dev/null @@ -1,246 +0,0 @@ -import { useState, useEffect } from "react"; -import { createWalletClient, createPublicClient, custom, http, parseAbi, parseEventLogs, isAddress, toHex, encodeFunctionData } from "viem"; -import { sepolia } from "viem/chains"; -import { TITLE_ESCROW_ADDRESS, SEPOLIA_RPC_URL } from "../lib/constants"; -import { buildSmartAccountClient } from "../lib/pimlico"; - -const PERMANENT_OWNER = "0x433097a1C1b8a3e9188d8C54eCC057B1D69f1638".toLowerCase(); -const LS_KEY = "trustvc_title_escrow"; - -const paymasterAbi = parseAbi([ - "function mintDocument(address registry, address beneficiary, address holder, uint256 tokenId, bytes remark) external returns (address titleEscrow)", - "event TitleEscrowLinked(address indexed titleEscrow, address indexed registry)", -]); - -interface Props { - address: string | null; - isDelegated: boolean; - paymasterAddress: string | null; - registryAddress: string | null; - onTitleEscrowReady: (address: `0x${string}`) => void; -} - -type Mode = "mint" | "load"; - -export function TitleEscrowPanel({ address, isDelegated, paymasterAddress, registryAddress, onTitleEscrowReady }: Props) { - const envEscrow = TITLE_ESCROW_ADDRESS && TITLE_ESCROW_ADDRESS !== "0x" ? TITLE_ESCROW_ADDRESS : null; - - const [mode, setMode] = useState("mint"); - const [activeTitleEscrow, setActiveTitleEscrow] = useState(null); - const [minting, setMinting] = useState(false); - const [beneficiary, setBeneficiary] = useState(""); - const [holder, setHolder] = useState(""); - const [tokenId, setTokenId] = useState(""); - const [remark, setRemark] = useState(""); - const [loadInput, setLoadInput] = useState(""); - const [loadError, setLoadError] = useState(null); - const [mintError, setMintError] = useState(null); - const [justMinted, setJustMinted] = useState(false); - const [justLoaded, setJustLoaded] = useState(false); - - useEffect(() => { - if (!address) { setActiveTitleEscrow(null); return; } - if (address.toLowerCase() === PERMANENT_OWNER && envEscrow) { - setActiveTitleEscrow(envEscrow); - onTitleEscrowReady(envEscrow); - return; - } - const saved = localStorage.getItem(LS_KEY); - if (saved) { setActiveTitleEscrow(saved); onTitleEscrowReady(saved as `0x${string}`); } - else setActiveTitleEscrow(null); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [address]); - - const isPermanentOwner = address?.toLowerCase() === PERMANENT_OWNER; - const disabled = !address || !paymasterAddress || !registryAddress; - - function randomTokenId(): string { - const bytes = crypto.getRandomValues(new Uint8Array(32)); - return BigInt("0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("")).toString(); - } - - function handleLoad() { - setLoadError(null); - const trimmed = loadInput.trim(); - if (!isAddress(trimmed)) { setLoadError("Invalid address."); return; } - localStorage.setItem(LS_KEY, trimmed); - setActiveTitleEscrow(trimmed); - setJustLoaded(true); - onTitleEscrowReady(trimmed as `0x${string}`); - } - - async function handleMint() { - if (!address || !paymasterAddress || !registryAddress) return; - if (!isAddress(beneficiary)) { setMintError("Invalid beneficiary address."); return; } - if (!isAddress(holder)) { setMintError("Invalid holder address."); return; } - setMintError(null); - setMinting(true); - try { - const publicClient = createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - const tid = tokenId.trim() ? BigInt(tokenId.trim()) : BigInt("0x" + - Array.from(crypto.getRandomValues(new Uint8Array(32))).map((b) => b.toString(16).padStart(2, "0")).join("")); - const remarkBytes: `0x${string}` = remark.trim() ? toHex(remark.trim()) : "0x"; - - const calldata = encodeFunctionData({ - abi: paymasterAbi, - functionName: "mintDocument", - args: [registryAddress as `0x${string}`, beneficiary as `0x${string}`, holder as `0x${string}`, tid, remarkBytes], - }); - - let txHash: `0x${string}`; - if (isDelegated) { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}`, - paymasterAddress as `0x${string}`, - ); - txHash = await smartAccountClient.sendTransaction({ - to: paymasterAddress as `0x${string}`, - value: 0n, - data: calldata, - }) as `0x${string}`; - } else { - const walletClient = createWalletClient({ - account: address as `0x${string}`, - chain: sepolia, - transport: custom(window.ethereum), - }); - txHash = await walletClient.sendTransaction({ - to: paymasterAddress as `0x${string}`, - value: 0n, - data: calldata, - }); - await publicClient.waitForTransactionReceipt({ hash: txHash }); - } - - const receipt = await publicClient.getTransactionReceipt({ hash: txHash }); - const logs = parseEventLogs({ abi: paymasterAbi, logs: receipt.logs, eventName: "TitleEscrowLinked" }); - const escrowAddr = logs[0]?.args?.titleEscrow; - if (!escrowAddr) throw new Error("Mint succeeded but TitleEscrow address not found in logs"); - - localStorage.setItem(LS_KEY, escrowAddr); - setActiveTitleEscrow(escrowAddr); - setJustMinted(true); - onTitleEscrowReady(escrowAddr); - } catch (e: unknown) { - setMintError(e instanceof Error ? e.message : String(e)); - } finally { - setMinting(false); - } - } - - if (activeTitleEscrow) { - return ( -
-
-

Title Escrow

- - - {justMinted ? "Minted" : "Active"} - -
-
-
- Title Escrow: - - {activeTitleEscrow} - -
- {isPermanentOwner && ( -

Loaded from environment (permanent owner).

- )} - {justMinted && ( -

- Minted and saved to local storage. -

- )} - {justLoaded &&

Title escrow loaded.

} -
- {!isPermanentOwner && ( - - )} -
- ); - } - - return ( -
-
-

Title Escrow

- - - Not set - -
- - {!registryAddress && ( -

Set up a registry first.

- )} - -
- - -
- - {mode === "mint" ? ( -
-

- Mint a new trade document. This deploys a TitleEscrow and assigns the initial beneficiary and holder. -

- setBeneficiary(e.target.value)} disabled={disabled || minting} /> - setHolder(e.target.value)} disabled={disabled || minting} /> -
- setTokenId(e.target.value)} disabled={disabled || minting} /> - -
- setRemark(e.target.value)} disabled={disabled || minting} /> - -
-
- Registry: - {registryAddress ?? "—"} -
-
- - - {mintError &&

{mintError}

} -
- ) : ( -
-

Already have a title escrow? Paste the address — it will be saved in your browser.

- { setLoadInput(e.target.value); setLoadError(null); }} disabled={disabled} /> - - {loadError &&

{loadError}

} -
- )} -
- ); -} diff --git a/7702Frontend/src/components/TrustVCPanel.tsx b/7702Frontend/src/components/TrustVCPanel.tsx deleted file mode 100644 index feeff90..0000000 --- a/7702Frontend/src/components/TrustVCPanel.tsx +++ /dev/null @@ -1,379 +0,0 @@ -import { useState, useEffect, useCallback } from "react"; -import { encodeFunctionData, createPublicClient, createWalletClient, custom, http, keccak256, toBytes } from "viem"; -import { sepolia } from "viem/chains"; -import { buildSmartAccountClient, toRemarkBytes, getPublicClient } from "../lib/pimlico"; -import { SEPOLIA_RPC_URL } from "../lib/constants"; -import { TITLE_ESCROW_ABI, REGISTRY_ABI } from "../lib/abis"; - -const ZERO_ADDR = "0x0000000000000000000000000000000000000000"; -const MINTER_ROLE = keccak256(toBytes("MINTER_ROLE")); - -type Action = - | "nominate" - | "transferBeneficiary" - | "transferHolder" - | "transferOwners" - | "rejectBeneficiary" - | "rejectHolder" - | "rejectOwners" - | "returnToIssuer" - | "shred"; - -interface EscrowState { - beneficiary: string; - holder: string; - nominee: string; - prevBeneficiary: string; - prevHolder: string; - isHoldingToken: boolean; - isAcceptor: boolean; -} - -interface Props { - address: string | null; - isDelegated: boolean; - paymasterAddress: string | null; - titleEscrowAddress: string | null; - registryAddress: string | null; -} - -const ACTION_LABELS: Record = { - nominate: "Nominate", - transferBeneficiary: "Transfer Beneficiary", - transferHolder: "Transfer Holder", - transferOwners: "Transfer Owners", - rejectBeneficiary: "Reject (Beneficiary)", - rejectHolder: "Reject (Holder)", - rejectOwners: "Reject (Owners)", - returnToIssuer: "Return to Issuer", - shred: "Shred Document", -}; - -const ADDRESS_ACTIONS: Action[] = ["nominate", "transferBeneficiary", "transferHolder"]; -const DUAL_ADDRESS_ACTIONS: Action[] = ["transferOwners"]; -const REMARK_ONLY_ACTIONS: Action[] = ["rejectBeneficiary", "rejectHolder", "rejectOwners", "returnToIssuer", "shred"]; - -function computeAvailableActions( - escrow: EscrowState | null, - account: string | null, -): Action[] { - if (!escrow || !account) return []; - - const addr = account.toLowerCase(); - const isReturnedToIssuer = !escrow.isHoldingToken; - const isActiveTitleEscrow = !isReturnedToIssuer; - const isHolder = addr === escrow.holder.toLowerCase(); - const isBeneficiary = addr === escrow.beneficiary.toLowerCase(); - const isHolderAndBeneficiary = isHolder && isBeneficiary; - const hasNominee = !!escrow.nominee && escrow.nominee !== ZERO_ADDR; - const hasPrevBeneficiary = !!escrow.prevBeneficiary && escrow.prevBeneficiary !== ZERO_ADDR; - const hasPrevHolder = !!escrow.prevHolder && escrow.prevHolder !== ZERO_ADDR; - - const available: Action[] = []; - - // nominate: beneficiary-only (not holder+beneficiary) nominates a new beneficiary - if (isActiveTitleEscrow && isBeneficiary && !isHolder) - available.push("nominate"); - - // transferBeneficiary: holder+beneficiary direct transfer, OR holder endorsing a nominee - if (isActiveTitleEscrow && (isHolderAndBeneficiary || (isHolder && hasNominee))) - available.push("transferBeneficiary"); - - // transferHolder - if (isActiveTitleEscrow && isHolder) - available.push("transferHolder"); - - // transferOwners - if (isActiveTitleEscrow && isHolder && isBeneficiary) - available.push("transferOwners"); - - // rejectBeneficiary: beneficiary-only, has a previous beneficiary to revert to - if (!isHolderAndBeneficiary && isActiveTitleEscrow && isBeneficiary && hasPrevBeneficiary && !(isHolder && hasPrevHolder)) - available.push("rejectBeneficiary"); - - // rejectHolder: holder-only, has a previous holder to revert to - if (!isHolderAndBeneficiary && isActiveTitleEscrow && isHolder && hasPrevHolder && !(isBeneficiary && hasPrevBeneficiary)) - available.push("rejectHolder"); - - // rejectOwners: both holder+beneficiary, both have previous values - if (isActiveTitleEscrow && isHolderAndBeneficiary && hasPrevHolder && hasPrevBeneficiary) - available.push("rejectOwners"); - - // returnToIssuer: holder+beneficiary surrenders - if (isActiveTitleEscrow && isHolder && isBeneficiary) - available.push("returnToIssuer"); - - // shred: only acceptor (minter role on registry) after surrender - if (!isActiveTitleEscrow && isReturnedToIssuer && escrow.isAcceptor) - available.push("shred"); - - return available; -} - -export function TrustVCPanel({ address, isDelegated, paymasterAddress, titleEscrowAddress, registryAddress }: Props) { - const TITLE_ESCROW_ADDRESS = (titleEscrowAddress ?? "") as `0x${string}`; - const [escrowState, setEscrowState] = useState(null); - const [activeAction, setActiveAction] = useState(null); - const [targetAddress, setTargetAddress] = useState(""); - const [secondAddress, setSecondAddress] = useState(""); - const [remark, setRemark] = useState(""); - const [loading, setLoading] = useState(false); - const [lastTx, setLastTx] = useState<{ hash: string; gasless: boolean } | null>(null); - const [error, setError] = useState(null); - - const fetchEscrowState = useCallback(async () => { - if (!titleEscrowAddress) return; - try { - const publicClient = createPublicClient({ chain: sepolia, transport: http(SEPOLIA_RPC_URL) }); - const [beneficiary, holder, nominee, isHoldingToken, prevBeneficiary, prevHolder] = await Promise.all([ - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "beneficiary" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "holder" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "nominee" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "isHoldingToken" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "prevBeneficiary" }), - publicClient.readContract({ address: TITLE_ESCROW_ADDRESS, abi: TITLE_ESCROW_ABI, functionName: "prevHolder" }), - ]); - - // Check if connected address has MINTER_ROLE on the registry (for shred/restore) - let isAcceptor = false; - if (address && registryAddress) { - try { - isAcceptor = await publicClient.readContract({ - address: registryAddress as `0x${string}`, - abi: REGISTRY_ABI, - functionName: "hasRole", - args: [MINTER_ROLE, address as `0x${string}`], - }) as boolean; - } catch { /* registry may not support hasRole */ } - } - - setEscrowState({ - beneficiary: beneficiary as string, - holder: holder as string, - nominee: nominee as string, - prevBeneficiary: prevBeneficiary as string, - prevHolder: prevHolder as string, - isHoldingToken: isHoldingToken as boolean, - isAcceptor, - }); - } catch (e) { - console.error("fetchEscrowState error:", e); - } - }, [TITLE_ESCROW_ADDRESS, address, registryAddress, titleEscrowAddress]); - - useEffect(() => { fetchEscrowState(); }, [fetchEscrowState]); - - // Auto-select first available action when conditions change - const availableActions = computeAvailableActions(escrowState, address); - useEffect(() => { - if (!activeAction || !availableActions.includes(activeAction)) { - setActiveAction(availableActions[0] ?? null); - } - }, [availableActions.join(",")]); // eslint-disable-line react-hooks/exhaustive-deps - - function buildCalldata(): `0x${string}` { - const remarkBytes = toRemarkBytes(remark); - switch (activeAction) { - case "nominate": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "nominate", args: [targetAddress as `0x${string}`, remarkBytes] }); - case "transferBeneficiary": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "transferBeneficiary", args: [targetAddress as `0x${string}`, remarkBytes] }); - case "transferHolder": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "transferHolder", args: [targetAddress as `0x${string}`, remarkBytes] }); - case "transferOwners": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "transferOwners", args: [targetAddress as `0x${string}`, secondAddress as `0x${string}`, remarkBytes] }); - case "rejectBeneficiary": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "rejectTransferBeneficiary", args: [remarkBytes] }); - case "rejectHolder": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "rejectTransferHolder", args: [remarkBytes] }); - case "rejectOwners": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "rejectTransferOwners", args: [remarkBytes] }); - case "returnToIssuer": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "returnToIssuer", args: [remarkBytes] }); - case "shred": - return encodeFunctionData({ abi: TITLE_ESCROW_ABI, functionName: "shred", args: [remarkBytes] }); - default: - throw new Error("Unknown action"); - } - } - - async function handleSend() { - if (!address || !activeAction) return; - setError(null); - setLastTx(null); - setLoading(true); - try { - const calldata = buildCalldata(); - let txHash: string; - - if (isDelegated) { - const { smartAccountClient } = await buildSmartAccountClient( - address as `0x${string}`, - paymasterAddress as `0x${string}`, - ); - txHash = await smartAccountClient.sendTransaction({ to: TITLE_ESCROW_ADDRESS, value: 0n, data: calldata }); - } else { - const walletClient = createWalletClient({ account: address as `0x${string}`, chain: sepolia, transport: custom(window.ethereum) }); - txHash = await walletClient.sendTransaction({ to: TITLE_ESCROW_ADDRESS, value: 0n, data: calldata }); - await getPublicClient().waitForTransactionReceipt({ hash: txHash as `0x${string}` }); - } - - setLastTx({ hash: txHash, gasless: isDelegated }); - await fetchEscrowState(); - setTargetAddress(""); - setSecondAddress(""); - setRemark(""); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : String(e)); - } finally { - setLoading(false); - } - } - - const disabled = !address || !!!paymasterAddress || !titleEscrowAddress; - const needsAddress = activeAction ? ADDRESS_ACTIONS.includes(activeAction) : false; - const needsDualAddress = activeAction ? DUAL_ADDRESS_ACTIONS.includes(activeAction) : false; - const isRemarkOnly = activeAction ? REMARK_ONLY_ACTIONS.includes(activeAction) : false; - - const canSend = - !disabled && - !loading && - !!activeAction && - (isRemarkOnly || - (needsAddress && targetAddress.startsWith("0x")) || - (needsDualAddress && targetAddress.startsWith("0x") && secondAddress.startsWith("0x"))); - - return ( -
-
-

TrustVC Operations

- {isDelegated - ? gasless via UserOp - : regular tx · pays gas} -
- - {!address &&

Connect wallet first.

} - {address && !!!paymasterAddress &&

Set up a paymaster first.

} - {address && !!paymasterAddress && !titleEscrowAddress &&

Set up a title escrow first.

} - - {/* TitleEscrow state */} - {escrowState && ( -
-

TitleEscrow State

- - - - {escrowState.prevBeneficiary !== ZERO_ADDR && ( - - )} - {escrowState.prevHolder !== ZERO_ADDR && ( - - )} -
- Status: - - {escrowState.isHoldingToken ? "Active" : "Returned to issuer"} - -
- -
- )} - - {/* Action selector — only available actions */} - {availableActions.length === 0 && !disabled && ( -

No actions available for your address on this document.

- )} - - {availableActions.length > 0 && ( -
-

Action

-
- {availableActions.map((action) => ( - - ))} -
-
- )} - - {/* Inputs */} - {activeAction && availableActions.length > 0 && ( -
- {(needsAddress || needsDualAddress) && ( - setTargetAddress(e.target.value)} - disabled={disabled} - /> - )} - {needsDualAddress && ( - setSecondAddress(e.target.value)} - disabled={disabled} - /> - )} - setRemark(e.target.value)} - disabled={disabled} - /> -
- )} - - {activeAction && availableActions.length > 0 && ( - - )} - - {lastTx && ( -
-

- Transaction confirmed ✓ {lastTx.gasless ? "(gasless)" : "(gas paid)"} -

- - {lastTx.hash} - -
- )} - {error &&

{error}

} -
- ); -} - -function StateRow({ label, value, highlight }: { label: string; value: string; highlight?: boolean }) { - return ( -
- {label}: - {value} -
- ); -} diff --git a/7702Frontend/src/components/WalletConnect.tsx b/7702Frontend/src/components/WalletConnect.tsx deleted file mode 100644 index 83f0317..0000000 --- a/7702Frontend/src/components/WalletConnect.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useState, useEffect } from "react"; -import { ethers } from "ethers"; -import { SEPOLIA_CHAIN_ID } from "../lib/constants"; - -interface Props { - address: string | null; - onConnect: (address: string) => void; - onDisconnect: () => void; -} - -export function WalletConnect({ address, onConnect, onDisconnect }: Props) { - const [balance, setBalance] = useState(null); - const [network, setNetwork] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - if (!address) return; - (async () => { - try { - const provider = new ethers.BrowserProvider(window.ethereum); - const bal = await provider.getBalance(address); - setBalance(ethers.formatEther(bal).slice(0, 7)); - const net = await provider.getNetwork(); - setNetwork(net.chainId.toString()); - } catch { - // ignore - } - })(); - }, [address]); - - async function connect() { - setError(null); - if (!window.ethereum) { - setError("MetaMask not detected. Install the Chrome extension."); - return; - } - try { - const provider = new ethers.BrowserProvider(window.ethereum); - // Switch to Sepolia first - try { - await window.ethereum.request({ - method: "wallet_switchEthereumChain", - params: [{ chainId: `0x${SEPOLIA_CHAIN_ID.toString(16)}` }], - }); - } catch { - // chain not added — ignore, user can add manually - } - const accounts = await provider.send("eth_requestAccounts", []); - onConnect(accounts[0] as string); - } catch (e: unknown) { - setError(e instanceof Error ? e.message : "Connection rejected"); - } - } - - const isWrongNetwork = network && network !== SEPOLIA_CHAIN_ID.toString(); - - return ( -
-
-

Wallet

- {address ? ( -
- {address} - {balance && ( - {balance} ETH - )} - {isWrongNetwork && ( - Wrong network — switch to Sepolia - )} - {!isWrongNetwork && network && ( - Sepolia - )} -
- ) : ( -

Not connected

- )} - {error &&

{error}

} -
- - {address ? ( - - ) : ( - - )} -
- ); -} diff --git a/7702Frontend/src/index.css b/7702Frontend/src/index.css deleted file mode 100644 index 078bad1..0000000 --- a/7702Frontend/src/index.css +++ /dev/null @@ -1,42 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -@layer base { - body { - @apply bg-gray-950 text-gray-100 font-mono; - } -} - -@layer components { - .panel { - @apply bg-gray-900 border border-gray-700 rounded-xl p-5; - } - .panel-title { - @apply text-sm font-semibold text-indigo-400 uppercase tracking-widest mb-4; - } - .btn { - @apply px-4 py-2 rounded-lg text-sm font-semibold transition-all duration-150 disabled:opacity-40 disabled:cursor-not-allowed; - } - .btn-primary { - @apply btn bg-indigo-600 hover:bg-indigo-500 text-white; - } - .btn-danger { - @apply btn bg-red-700 hover:bg-red-600 text-white; - } - .btn-ghost { - @apply btn bg-gray-800 hover:bg-gray-700 text-gray-300; - } - .input { - @apply bg-gray-800 border border-gray-600 rounded-lg px-3 py-2 text-sm text-gray-100 outline-none focus:border-indigo-500 w-full; - } - .badge-green { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold bg-emerald-900/60 text-emerald-300 border border-emerald-700; - } - .badge-yellow { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold bg-yellow-900/60 text-yellow-300 border border-yellow-700; - } - .badge-red { - @apply inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-semibold bg-red-900/60 text-red-300 border border-red-700; - } -} diff --git a/7702Frontend/src/lib/abis.ts b/7702Frontend/src/lib/abis.ts deleted file mode 100644 index 37d7e5c..0000000 --- a/7702Frontend/src/lib/abis.ts +++ /dev/null @@ -1,224 +0,0 @@ -export const ENTRY_POINT_ABI = [ - { - type: "function", - name: "getNonce", - inputs: [ - { name: "sender", type: "address" }, - { name: "key", type: "uint192" }, - ], - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - }, -] as const; - -export const IMPL_ABI = [ - { - type: "function", - name: "execute", - inputs: [ - { name: "to", type: "address" }, - { name: "value", type: "uint256" }, - { name: "data", type: "bytes" }, - ], - outputs: [{ name: "", type: "bytes" }], - stateMutability: "payable", - }, -] as const; - -export const STORAGE_ABI = [ - { - type: "function", - name: "create", - inputs: [{ name: "_data", type: "string" }], - outputs: [{ name: "", type: "uint256" }], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "update", - inputs: [ - { name: "_id", type: "uint256" }, - { name: "_newData", type: "string" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "remove", - inputs: [{ name: "_id", type: "uint256" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "exists", - inputs: [{ name: "_id", type: "uint256" }], - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - }, - { - type: "function", - name: "getItemCount", - inputs: [], - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - }, - { - type: "event", - name: "ItemCreated", - inputs: [ - { name: "id", type: "uint256", indexed: true }, - { name: "data", type: "string", indexed: false }, - { name: "timestamp", type: "uint256", indexed: false }, - ], - }, - { - type: "event", - name: "ItemUpdated", - inputs: [ - { name: "id", type: "uint256", indexed: true }, - { name: "data", type: "string", indexed: false }, - { name: "timestamp", type: "uint256", indexed: false }, - ], - }, - { - type: "event", - name: "ItemDeleted", - inputs: [{ name: "id", type: "uint256", indexed: true }], - }, -] as const; - -export const TITLE_ESCROW_ABI = [ - { - type: "function", - name: "nominate", - inputs: [ - { name: "_nominee", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferBeneficiary", - inputs: [ - { name: "_nominee", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferHolder", - inputs: [ - { name: "newHolder", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "transferOwners", - inputs: [ - { name: "_nominee", type: "address" }, - { name: "newHolder", type: "address" }, - { name: "_remark", type: "bytes" }, - ], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "rejectTransferBeneficiary", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "rejectTransferHolder", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "rejectTransferOwners", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "returnToIssuer", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "shred", - inputs: [{ name: "_remark", type: "bytes" }], - outputs: [], - stateMutability: "nonpayable", - }, - { - type: "function", - name: "beneficiary", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "holder", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "nominee", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "isHoldingToken", - inputs: [], - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - }, - { - type: "function", - name: "prevBeneficiary", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, - { - type: "function", - name: "prevHolder", - inputs: [], - outputs: [{ name: "", type: "address" }], - stateMutability: "view", - }, -] as const; - -export const REGISTRY_ABI = [ - { - type: "function", - name: "hasRole", - inputs: [ - { name: "role", type: "bytes32" }, - { name: "account", type: "address" }, - ], - outputs: [{ name: "", type: "bool" }], - stateMutability: "view", - }, -] as const; diff --git a/7702Frontend/src/lib/constants.ts b/7702Frontend/src/lib/constants.ts deleted file mode 100644 index a0b6d15..0000000 --- a/7702Frontend/src/lib/constants.ts +++ /dev/null @@ -1,23 +0,0 @@ -export const PAYMASTER_ADDRESS = (import.meta.env.VITE_PAYMASTER_ADDRESS ?? - "") as `0x${string}`; - -export const TDOC_IMPLEMENTATION = (import.meta.env.VITE_TDOC_IMPLEMENTATION ?? - "") as `0x${string}`; - -export const REGISTRY_ADDRESS = (import.meta.env.VITE_REGISTRY_ADDRESS ?? - "") as `0x${string}`; - -export const TITLE_ESCROW_ADDRESS = (import.meta.env - .VITE_TITLE_ESCROW_ADDRESS ?? "") as `0x${string}`; - -export const FACTORY_ADDRESS = (import.meta.env.VITE_FACTORY_ADDRESS ?? - "") as `0x${string}`; - -export const PIMLICO_API_KEY = import.meta.env.VITE_PIMLICO_API_KEY ?? ""; - -export const SEPOLIA_RPC_URL = - import.meta.env.VITE_SEPOLIA_RPC_URL ?? "https://rpc.sepolia.org"; - -export const PIMLICO_URL = `https://api.pimlico.io/v2/11155111/rpc?apikey=${PIMLICO_API_KEY}`; - -export const SEPOLIA_CHAIN_ID = 11155111; diff --git a/7702Frontend/src/lib/pimlico.ts b/7702Frontend/src/lib/pimlico.ts deleted file mode 100644 index f519f8b..0000000 --- a/7702Frontend/src/lib/pimlico.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { - createPublicClient, - createWalletClient, - custom, - http, - toHex, -} from "viem"; -import { entryPoint08Address } from "viem/account-abstraction"; -import { sepolia } from "viem/chains"; -import { createPimlicoClient } from "permissionless/clients/pimlico"; -import { createSmartAccountClient } from "permissionless"; -import { to7702SimpleSmartAccount } from "permissionless/accounts"; - -import { PAYMASTER_ADDRESS, PIMLICO_URL, SEPOLIA_RPC_URL } from "./constants"; - -// permissionless's EIP-7702 compatible SimpleAccount for v0.8 -export const PERMISSIONLESS_IMPL = - "0xe6Cae83BdE06E4c305530e199D7217f42808555B" as const; - -export function getPublicClient() { - return createPublicClient({ - chain: sepolia, - transport: http(SEPOLIA_RPC_URL), - }); -} - -export async function checkDelegation(address: `0x${string}`) { - const publicClient = getPublicClient(); - const code = await publicClient.getCode({ address }); - if (!code || code === "0x") return null; - if (code.startsWith("0xef0100")) { - return `0x${code.slice(8, 48)}` as `0x${string}`; - } - return null; -} - -export async function buildSmartAccountClient( - ownerAddress: `0x${string}`, - paymasterOverride?: `0x${string}`, -) { - if (!window.ethereum) throw new Error("MetaMask not found"); - - const PAYMASTER = paymasterOverride ?? PAYMASTER_ADDRESS; - if (!PAYMASTER || PAYMASTER === "0x") - throw new Error("No paymaster address configured"); - - const walletClient = createWalletClient({ - account: ownerAddress, - chain: sepolia, - transport: custom(window.ethereum), - }); - - const publicClient = getPublicClient(); - - const pimlicoClient = createPimlicoClient({ - transport: http(PIMLICO_URL), - entryPoint: { address: entryPoint08Address, version: "0.8" }, - }); - - const account = await to7702SimpleSmartAccount({ - client: publicClient, - owner: walletClient, - }); - - const smartAccountClient = createSmartAccountClient({ - account, - chain: sepolia, - bundlerTransport: http(PIMLICO_URL), - client: publicClient, - // Custom PlatformPaymaster — validates on-chain, no off-chain signature needed - paymaster: { - async getPaymasterStubData() { - return { - paymaster: PAYMASTER as `0x${string}`, - paymasterData: "0x" as `0x${string}`, - paymasterVerificationGasLimit: 300_000n, - paymasterPostOpGasLimit: 150_000n, - isFinal: false, - }; - }, - async getPaymasterData() { - return { - paymaster: PAYMASTER as `0x${string}`, - paymasterData: "0x" as `0x${string}`, - paymasterVerificationGasLimit: 300_000n, - paymasterPostOpGasLimit: 150_000n, - }; - }, - }, - userOperation: { - estimateFeesPerGas: async () => { - const { fast } = await pimlicoClient.getUserOperationGasPrice(); - return { - maxFeePerGas: fast.maxFeePerGas, - maxPriorityFeePerGas: fast.maxPriorityFeePerGas, - }; - }, - }, - }); - - return { smartAccountClient, publicClient }; -} - -export function toRemarkBytes(s: string): `0x${string}` { - return toHex(s); -} diff --git a/7702Frontend/src/main.tsx b/7702Frontend/src/main.tsx deleted file mode 100644 index 12fa35b..0000000 --- a/7702Frontend/src/main.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; -import "./index.css"; -import App from "./App"; - -createRoot(document.getElementById("root")!).render( - - - -); diff --git a/7702Frontend/src/vite-env.d.ts b/7702Frontend/src/vite-env.d.ts deleted file mode 100644 index b50dcfa..0000000 --- a/7702Frontend/src/vite-env.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// - -interface Window { - ethereum: import("ethers").Eip1193Provider & { - request: (args: { method: string; params?: unknown[] }) => Promise; - on: (event: string, handler: (...args: unknown[]) => void) => void; - }; -} diff --git a/7702Frontend/tailwind.config.js b/7702Frontend/tailwind.config.js deleted file mode 100644 index f61974c..0000000 --- a/7702Frontend/tailwind.config.js +++ /dev/null @@ -1,12 +0,0 @@ -/** @type {import('tailwindcss').Config} */ -export default { - content: ["./index.html", "./src/**/*.{ts,tsx}"], - theme: { - extend: { - colors: { - brand: "#6366f1", - }, - }, - }, - plugins: [], -}; diff --git a/7702Frontend/tsconfig.json b/7702Frontend/tsconfig.json deleted file mode 100644 index 6bfa73a..0000000 --- a/7702Frontend/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": false, - "noUnusedParameters": false, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/7702Frontend/vite.config.ts b/7702Frontend/vite.config.ts deleted file mode 100644 index 75e3905..0000000 --- a/7702Frontend/vite.config.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { defineConfig } from "vite"; -import react from "@vitejs/plugin-react"; - -export default defineConfig({ - plugins: [react()], - define: { - global: "globalThis", - }, -}); diff --git a/EIP7702_METAMASK_ARCHITECTURE.md b/EIP7702_METAMASK_ARCHITECTURE.md deleted file mode 100644 index 3769512..0000000 --- a/EIP7702_METAMASK_ARCHITECTURE.md +++ /dev/null @@ -1,120 +0,0 @@ -# EIP-7702 + MetaMask Architecture - -## The Core Problem - -MetaMask does **not** support `wallet_signAuthorization`. -Ethers `signer.authorize()` also fails with MetaMask (`UNSUPPORTED_OPERATION`). -The current `wallet_signAuthorization` wrapper in `pimlico.ts` is dead code that will throw at runtime. - ---- - -## Architecture Options - -### Option A — SimpleAccount (ERC-4337) `scripts/metamaskDelegation/` - -**Status: Scripts written, CLI-testable today.** - -``` -EOA: 0xABC → SimpleAccount: 0xABC_SA (different address) -``` - -| Step | Script | -|------|--------| -| Print SimpleAccount address | `printAddress.ts` | -| Whitelist for platform ops | `whitelistAccount.ts` | -| Deploy registry (gasless) | `deployRegistryGasless.ts` | -| Mint document (gasless) | `mintDocumentGasless.ts` | -| Transfer holder (gasless) | `transferHolder.ts` | -| Nominate (gasless) | `nominate.ts` | - -**Paymaster interaction:** -- Path A (TitleEscrow calls): target = TitleEscrow → `authorizedTitleEscrows[target]` → **any sender accepted, no whitelist** -- Path B (platform ops): target = paymaster → `userWhitelist[0xABC_SA]` must be > 0 - -**Problem:** `holder` in TitleEscrow becomes `0xABC_SA`, not `0xABC`. User rejected this — holder must stay `0xABC` (EOA address). - ---- - -### Option B — Rabby Wallet + EIP-7702 ✓ **Cleanest browser solution** - -``` -Rabby signs EIP-7702 natively → holder = 0xABC (EOA address preserved) -``` - -Rabby supports EIP-7702 delegation in-browser without any special API. No `wallet_signAuthorization` needed. The delegation signature is bundled into the transaction automatically. - -**Problem:** Users must install Rabby. Not a MetaMask solution. - ---- - -### Option C — `wallet_grantPermissions` (ERC-7715) + Session Key **Best UX for MetaMask** - -**Status: Not yet implemented. MetaMask supports ERC-7715.** - -``` -ONE-TIME SETUP (user approves once in MetaMask popup): - wallet_grantPermissions({ - signer: { type: "key", data: { id: 0xDEF } }, // session key from Privy/Dynamic - permissions: [...], - ... - }) - → MetaMask: signs EIP-7702 auth (upgrades 0xABC to smart account) - + signs delegation granting 0xDEF permission - -FIRST UserOp (atomic): - userOp.sender = 0xABC ← EOA address preserved ✓ - userOp.eip7702Auth = signed auth ← upgrades 0xABC in same tx - userOp.signature = 0xDEF sig + delegation proof - callData = execute(TitleEscrow, 0, transferHolder(...)) - -SUBSEQUENT UserOps (silent, no popup): - userOp.sender = 0xABC - userOp.signature = 0xDEF sig + stored delegation proof - callData = execute(TitleEscrow, 0, ...) -``` - -#### Paymaster whitelist in this flow - -| Operation | `userOp.sender` | Path | Whitelist? | -|-----------|-----------------|------|------------| -| TitleEscrow calls | `0xABC` | A (target = TitleEscrow) | **No** | -| deployRegistry / mintDocument | `0xABC` | B (target = paymaster) | **Yes — whitelist `0xABC`** | - -`0xDEF` is only in the signature field — **never appears as `userOp.sender`**, never needs whitelisting. - -#### Critical blocker - -MetaMask's **Hybrid / Delegation Toolkit** uses **EntryPoint v0.7**. -Our `PlatformPaymaster` uses **EntryPoint v0.8**. -These are incompatible — the paymaster will reject v0.7 UserOps with AA33. - -Resolution options: -1. Deploy a second `PlatformPaymaster` targeting v0.7 EntryPoint -2. Wait for MetaMask to upgrade Delegation Toolkit to v0.8 -3. Use a different wallet that supports EIP-7702 + v0.8 (Privy embedded wallet, Dynamic, etc.) - ---- - -## EntryPoint Versions Quick Reference - -| Component | EntryPoint | -|-----------|-----------| -| `PlatformPaymaster` | **v0.8** `0x4337084D9E255Ff0702461CF8895CE9E3b5Ff108` | -| `to7702SimpleSmartAccount` (permissionless) | **v0.8** | -| `toSimpleSmartAccount` (permissionless) | v0.7 default, **pass v0.8 explicitly** | -| MetaMask Delegation Toolkit | **v0.7** ← incompatible | -| v0.8 SimpleAccount factory (Sepolia) | `0x13E9ed32155810FDbd067D4522C492D6f68E5944` | - ---- - -## Files To Fix (pimlico.ts / DelegationPanel.tsx) - -- `7702Frontend/src/lib/pimlico.ts` — `wallet_signAuthorization` wrapper is broken dead code; remove it -- `7702Frontend/src/components/DelegationPanel.tsx` — shows "auto-delegation on first transaction" which is incorrect; update messaging to reflect actual wallet support status - ---- - -## Decision Pending - -- Pursue Option C (`wallet_grantPermissions`) → resolve EntryPoint v0.7/v0.8 mismatch first -- Or go with Rabby wallet for browser flow + CLI scripts for all other users diff --git a/PIMLICO_EIP7702_DOCS.md b/PIMLICO_EIP7702_DOCS.md deleted file mode 100644 index f116223..0000000 --- a/PIMLICO_EIP7702_DOCS.md +++ /dev/null @@ -1,315 +0,0 @@ -# EIP-7702 + Pimlico Integration — Developer Reference - -## Table of Contents - -1. [How Pimlico Works](#1-how-pimlico-works) -2. [API Key Setup](#2-api-key-setup) -3. [How PaymasterV2 Works](#3-how-paymasterv2-works) -4. [Registry Whitelisting](#4-registry-whitelisting) -5. [Function Reference](#5-function-reference) - ---- - -## 1. How Pimlico Works - -### EIP-7702 in one line - -EIP-7702 lets a regular wallet (EOA) temporarily point to a smart contract -implementation. From that point on, calling the EOA executes smart contract -logic — without deploying a new contract address. - -### The delegation (one-time, per EOA) - -Before any sponsored transaction can be sent, the EOA must be delegated to -our implementation contract. This is a standard Ethereum type-4 transaction -paid by the operator wallet (`PRIVATE_KEY`). The end user only signs an -authorization — no ETH required on their side. - -``` -OWNER_PRIVATE_KEY → end user / holder — signs UserOps, zero ETH needed -PRIVATE_KEY → operator — pays for the one-time delegation tx only -``` - -After delegation, the EOA's on-chain code becomes: - -``` -0xef0100 + 0xECD2812e299c6aD5C3B1F11B91D8Cab83003E09D -``` - -### UserOperation flow (every transaction after delegation) - -``` -User signs UserOp (OWNER_PRIVATE_KEY, raw ECDSA — no ETH) - ↓ -Pimlico Bundler receives the UserOp - ↓ -PaymasterV2 validates and agrees to sponsor gas - ↓ -EntryPoint (0x0000000071727De22E5E9d8BAf0edAc6f37da032) executes - ↓ -EOA's delegated implementation calls execute(to, value, data) - ↓ -Target contract function runs (e.g. nominate(), transferHolder()) -``` - -The end user never touches ETH. Gas is deducted from the paymaster's -pre-funded deposit in the EntryPoint. - -### Key contracts on Sepolia - -| Role | Address | -| ------------------ | -------------------------------------------- | -| EntryPoint v0.7 | `0x0000000071727De22E5E9d8BAf0edAc6f37da032` | -| EOA Implementation | `0xECD2812e299c6aD5C3B1F11B91D8Cab83003E09D` | -| PaymasterV2 | `0xbdd57218ac281eE281A92051C699751738E687Be` | - ---- - -## 2. API Key Setup - -### Get a free Pimlico API key - -1. Go to [dashboard.pimlico.io](https://dashboard.pimlico.io) -2. Create a project → copy the API key -3. Add to your `.env`: - -```env -PIMLICO_API_KEY=your_key_here -OWNER_PRIVATE_KEY=0x... # end user's private key -PRIVATE_KEY=0x... # operator wallet (needs Sepolia ETH) -SEPOLIA_RPC_URL=https://... -REGISTRY_ADDRESS=0x145c2dae82b2717267e2da0c8525f4aed796a120 -``` - -### How it is used in code - -```typescript -const PIMLICO_URL = - `https://api.pimlico.io/v2/11155111/rpc?apikey=${process.env.PIMLICO_API_KEY}`; - -// Pimlico client — handles gas pricing and UserOp submission -const pimlicoClient = createPimlicoClient({ - transport: http(PIMLICO_URL), - entryPoint: { address: ENTRY_POINT, version: "0.7" }, -}); - -// Smart account client — converts sendTransaction() into a UserOp -const smartAccountClient = createSmartAccountClient({ - account: smartAccount, - bundlerTransport: http(PIMLICO_URL), // UserOps go to Pimlico - client: publicClient, // eth_* calls go to your own node - paymaster: { ... }, // PaymasterV2 wired here -}); -``` - -Pimlico is only used for two things: - -- `eth_estimateUserOperationGas` — estimate gas for the UserOp -- `eth_sendUserOperation` — submit the UserOp to the mempool - -All other calls (`eth_getCode`, `eth_getTransactionCount`, etc.) go through -your own `SEPOLIA_RPC_URL`, keeping costs low. - ---- - -## 3. How PaymasterV2 Works - -PaymasterV2 is a custom on-chain paymaster that sponsors gas for UserOps -targeting authorized contracts. No off-chain signing service is required — -all validation happens on-chain. - -### Validation logic (`_validatePaymasterUserOp`) - -Every UserOp goes through this check before gas is committed: - -``` -1. callData length ≥ 36 bytes (must contain at least a selector + address) -2. Selector == execute(address,uint256,bytes) (only our implementation's execute) -3. Decoded `to` address ∈ authorizedRegistries (target must be whitelisted) -4. dailySpend[sender] + maxCost ≤ dailyLimit (per-user daily cap, 0 = no cap) -``` - -If any check fails, the UserOp is rejected — no gas is spent. - -### Gas sponsorship flow - -``` -UserOp arrives at EntryPoint - ↓ -EntryPoint calls PaymasterV2.validatePaymasterUserOp() - ↓ (all 4 checks pass) -EntryPoint executes the UserOp - ↓ -EntryPoint calls PaymasterV2.postOp(actualGasCost) - ↓ -PaymasterV2 records dailySpend[sender] += actualGasCost - ↓ -Gas deducted from PaymasterV2's deposit in EntryPoint -``` - -### Deployed configuration - -``` -Address: 0xbdd57218ac281eE281A92051C699751738E687Be -EntryPoint: 0x0000000071727De22E5E9d8BAf0edAc6f37da032 -Authorized registry: 0x145c2dae82b2717267e2da0c8525f4aed796a120 (TR contract) -Daily limit: 0 (no cap) -``` - ---- - -## 4. Registry Whitelisting - -PaymasterV2 uses a mapping to control which target contracts it will sponsor: - -```solidity -mapping(address => bool) public authorizedRegistries; -``` - -Only UserOps whose `execute()` call targets a whitelisted registry are -sponsored. Calls to any other address are rejected with `"unauthorized target"`. - -### Add a registry (owner only) - -```solidity -function addRegistry(address registry) external onlyOwner -``` - -Script call: - -```typescript -await walletClient.writeContract({ - address: "0xbdd57218ac281eE281A92051C699751738E687Be", - abi: parseAbi(["function addRegistry(address) external"]), - functionName: "addRegistry", - args: ["0xYourNewRegistryAddress"], -}); -``` - -### Remove a registry (owner only) - -```solidity -function removeRegistry(address registry) external onlyOwner -``` - -### Check if a registry is authorized - -```typescript -const ok = await publicClient.readContract({ - address: "0xbdd57218ac281eE281A92051C699751738E687Be", - abi: parseAbi(["function authorizedRegistries(address) view returns (bool)"]), - functionName: "authorizedRegistries", - args: ["0x145c2dae82b2717267e2da0c8525f4aed796a120"], -}); -// ok === true -``` - -> **Note:** The paymaster does NOT whitelist users. Any EOA delegated to the -> implementation can call any authorized registry — access control is enforced -> by the TR contract itself (e.g. `require(msg.sender == holder)`). - ---- - -## 5. Function Reference - -All scripts live in `scripts/trFunctions/`. Run any of them with: - -```bash -npx hardhat run scripts/trFunctions/