From a11dab563f384be3f0e0220dafe386f81f030748 Mon Sep 17 00:00:00 2001 From: roger-gan Date: Sat, 29 Aug 2026 07:39:47 +0800 Subject: [PATCH] chore: remove retired legacy archive --- .claude/rules/CLAUDE.md | 2 +- .github/pull_request_template.md | 4 - .gitignore | 2 - CHANGELOG.md | 6 + CLAUDE.md | 35 +- CONTRIBUTING.md | 1 - README.md | 2 - RELEASE_NOTES.md | 6 +- legacy/.env.example | 71 - legacy/e2e/CLAUDE.md | 61 - legacy/e2e/README.md | 56 - legacy/e2e/clients/__init__.py | 6 - legacy/e2e/clients/test_client.py | 276 - legacy/e2e/mock_facilitator/__init__.py | 6 - legacy/e2e/mock_facilitator/__main__.py | 59 - legacy/e2e/mock_facilitator/app.py | 255 - legacy/e2e/scenarios/README.md | 82 - .../exact_gasfree_happy_path/config.json | 54 - .../expected_payment_response.json | 14 - .../scenarios/exact_happy_path/config.json | 48 - .../expected_payment_response.json | 14 - .../exact_permit_happy_path/README.md | 53 - .../exact_permit_happy_path/config.json | 48 - .../expected_payment_response.json | 14 - legacy/e2e/scenarios/run_all.sh | 35 - legacy/e2e/scenarios/run_testnet.sh | 75 - legacy/e2e/scenarios/testnet/README.md | 80 - .../testnet/exact_gasfree_testnet/config.json | 48 - .../testnet/exact_permit_testnet/config.json | 48 - .../testnet/exact_testnet/config.json | 48 - .../unhappy_settle_insufficient/config.json | 48 - .../expected_payment_response.json | 8 - .../unhappy_settle_revert/config.json | 48 - .../expected_payment_response.json | 8 - .../unhappy_verify_expired/config.json | 48 - .../expected_payment_response.json | 8 - .../unhappy_verify_invalid_sig/config.json | 48 - .../expected_payment_response.json | 8 - .../config.json | 48 - .../expected_payment_response.json | 8 - legacy/e2e/servers/__init__.py | 6 - legacy/e2e/servers/resource_server.py | 167 - legacy/examples/CLAUDE.md | 20 - legacy/examples/bsc-testnet-smoke/README.md | 44 - .../bsc-testnet-smoke/bsc_exact_client.py | 67 - .../bsc-testnet-smoke/bsc_exact_client.ts | 89 - .../bsc-testnet-smoke/bsc_exact_server.py | 50 - legacy/examples/facilitator/__init__.py | 0 legacy/examples/facilitator/__main__.py | 5 - legacy/examples/facilitator/server.py | 338 -- legacy/integration/CLAUDE.md | 42 - legacy/integration/README.md | 87 - legacy/integration/commands.py | 345 -- legacy/integration/configs/_smoke_a.json | 5 - legacy/integration/configs/_smoke_b.json | 5 - legacy/integration/configs/smoke.json | 18 - legacy/integration/run.py | 229 - legacy/package.json | 21 - legacy/protected_image.png | Bin 349692 -> 0 bytes legacy/pyproject.toml | 7 - legacy/python/x402/CLAUDE.md | 66 - legacy/python/x402/README.md | 65 - legacy/python/x402/pyproject.toml | 80 - legacy/python/x402/pytest.ini | 7 - legacy/python/x402/scripts/publish_pypi.sh | 55 - .../python/x402/src/bankofai/x402/__init__.py | 76 - legacy/python/x402/src/bankofai/x402/abi.py | 305 - .../src/bankofai/x402/address/__init__.py | 15 - .../src/bankofai/x402/address/converter.py | 83 - .../src/bankofai/x402/clients/__init__.py | 23 - .../src/bankofai/x402/clients/policies.py | 108 - .../bankofai/x402/clients/token_selection.py | 86 - .../src/bankofai/x402/clients/x402_client.py | 302 - .../bankofai/x402/clients/x402_http_client.py | 184 - .../python/x402/src/bankofai/x402/config.py | 132 - .../python/x402/src/bankofai/x402/encoding.py | 57 - .../x402/src/bankofai/x402/exceptions.py | 126 - .../src/bankofai/x402/facilitator/__init__.py | 8 - .../x402/facilitator/facilitator_client.py | 147 - .../x402/facilitator/x402_facilitator.py | 258 - .../src/bankofai/x402/fastapi/__init__.py | 7 - .../src/bankofai/x402/fastapi/middleware.py | 348 -- .../x402/src/bankofai/x402/logging_config.py | 47 - .../src/bankofai/x402/mechanisms/__init__.py | 77 - .../x402/mechanisms/_base/__init__.py | 13 - .../bankofai/x402/mechanisms/_base/client.py | 70 - .../x402/mechanisms/_base/facilitator.py | 81 - .../bankofai/x402/mechanisms/_base/server.py | 86 - .../x402/mechanisms/_exact_base/__init__.py | 35 - .../x402/mechanisms/_exact_base/base.py | 466 -- .../x402/mechanisms/_exact_base/types.py | 151 - .../mechanisms/_exact_permit_base/__init__.py | 15 - .../mechanisms/_exact_permit_base/client.py | 186 - .../_exact_permit_base/facilitator.py | 386 -- .../mechanisms/_exact_permit_base/server.py | 210 - .../bankofai/x402/mechanisms/evm/__init__.py | 23 - .../x402/mechanisms/evm/exact/__init__.py | 15 - .../x402/mechanisms/evm/exact/adapter.py | 26 - .../x402/mechanisms/evm/exact/client.py | 18 - .../x402/mechanisms/evm/exact/facilitator.py | 22 - .../x402/mechanisms/evm/exact/server.py | 13 - .../mechanisms/evm/exact_permit/__init__.py | 13 - .../mechanisms/evm/exact_permit/client.py | 11 - .../evm/exact_permit/facilitator.py | 47 - .../mechanisms/evm/exact_permit/server.py | 22 - .../bankofai/x402/mechanisms/tron/__init__.py | 23 - .../x402/mechanisms/tron/exact/__init__.py | 15 - .../x402/mechanisms/tron/exact/adapter.py | 29 - .../x402/mechanisms/tron/exact/client.py | 18 - .../x402/mechanisms/tron/exact/facilitator.py | 22 - .../x402/mechanisms/tron/exact/server.py | 13 - .../mechanisms/tron/exact_gasfree/__init__.py | 0 .../mechanisms/tron/exact_gasfree/client.py | 266 - .../tron/exact_gasfree/facilitator.py | 375 -- .../mechanisms/tron/exact_gasfree/server.py | 33 - .../mechanisms/tron/exact_permit/__init__.py | 15 - .../mechanisms/tron/exact_permit/client.py | 11 - .../tron/exact_permit/facilitator.py | 103 - .../mechanisms/tron/exact_permit/server.py | 59 - .../x402/src/bankofai/x402/server/__init__.py | 7 - .../src/bankofai/x402/server/x402_server.py | 406 -- .../src/bankofai/x402/signers/__init__.py | 7 - .../bankofai/x402/signers/client/__init__.py | 9 - .../src/bankofai/x402/signers/client/base.py | 116 - .../x402/signers/client/evm_signer.py | 189 - .../x402/signers/client/tron_signer.py | 304 - .../x402/signers/facilitator/__init__.py | 9 - .../bankofai/x402/signers/facilitator/base.py | 109 - .../x402/signers/facilitator/evm_signer.py | 182 - .../x402/signers/facilitator/tron_signer.py | 410 -- .../x402/src/bankofai/x402/signers/utils.py | 43 - .../x402/src/bankofai/x402/tokens/__init__.py | 6 - .../x402/src/bankofai/x402/tokens/registry.py | 223 - legacy/python/x402/src/bankofai/x402/types.py | 260 - .../x402/src/bankofai/x402/utils/__init__.py | 39 - .../x402/src/bankofai/x402/utils/address.py | 172 - .../x402/src/bankofai/x402/utils/eip712.py | 88 - .../x402/src/bankofai/x402/utils/gasfree.py | 246 - .../src/bankofai/x402/utils/payment_id.py | 19 - .../src/bankofai/x402/utils/tron_client.py | 94 - .../bankofai/x402/utils/tron_verification.py | 162 - .../bankofai/x402/utils/tx_verification.py | 221 - legacy/python/x402/tests/__init__.py | 0 legacy/python/x402/tests/client/__init__.py | 0 .../python/x402/tests/client/test_client.py | 143 - .../tests/client/test_evm_payment_permit.py | 126 - .../x402/tests/client/test_payment_permit.py | 86 - .../python/x402/tests/client/test_policies.py | 92 - .../python/x402/tests/client/test_signers.py | 248 - legacy/python/x402/tests/common/__init__.py | 0 .../x402/tests/common/test_payment_id.py | 36 - legacy/python/x402/tests/common/test_types.py | 74 - legacy/python/x402/tests/conftest.py | 47 - legacy/python/x402/tests/exact/__init__.py | 0 legacy/python/x402/tests/exact/test_client.py | 141 - .../x402/tests/exact/test_facilitator.py | 281 - .../x402/tests/exact/test_gasfree_client.py | 402 -- .../tests/exact/test_gasfree_facilitator.py | 175 - legacy/python/x402/tests/exact/test_server.py | 143 - .../x402/tests/exact/test_tron_client.py | 132 - .../x402/tests/exact/test_tron_facilitator.py | 241 - .../x402/tests/exact/test_tron_server.py | 125 - legacy/python/x402/tests/exact/test_types.py | 129 - .../python/x402/tests/facilitator/__init__.py | 0 .../facilitator/test_evm_payment_permit.py | 225 - .../x402/tests/facilitator/test_evm_signer.py | 149 - .../tests/facilitator/test_payment_permit.py | 218 - .../tests/facilitator/test_tron_signer.py | 73 - .../facilitator/test_x402_facilitator.py | 52 - legacy/python/x402/tests/server/__init__.py | 0 .../x402/tests/server/test_evm_exact.py | 128 - .../server/test_signature_verification.py | 245 - legacy/python/x402/tests/test_config.py | 8 - .../tests/utils/test_address_normalization.py | 25 - .../x402/tests/utils/test_address_utils.py | 51 - .../tests/utils/test_evm_address_converter.py | 33 - .../x402/tests/utils/test_gasfree_utils.py | 217 - .../tests/utils/test_tron_client_factory.py | 97 - legacy/python/x402/uv.lock | 2298 -------- legacy/scripts/upload_pkgs.sh | 67 - legacy/specs/001-exact-v2-compat/spec.md | 104 - legacy/specs/CLAUDE.md | 42 - legacy/specs/config.md | 144 - legacy/specs/protocol.md | 202 - legacy/specs/roles.md | 161 - legacy/specs/schemes/exact-gasfree.md | 270 - legacy/specs/schemes/exact-permit.md | 129 - legacy/specs/schemes/exact.md | 91 - legacy/specs/transports/facilitator-http.md | 260 - legacy/typescript/CLAUDE.md | 56 - legacy/typescript/README.md | 51 - legacy/typescript/package-lock.json | 5179 ----------------- legacy/typescript/package.json | 23 - legacy/typescript/packages/x402/CLAUDE.md | 43 - legacy/typescript/packages/x402/README.md | 365 -- legacy/typescript/packages/x402/package.json | 75 - legacy/typescript/packages/x402/src/abi.ts | 207 - .../typescript/packages/x402/src/address.ts | 193 - .../packages/x402/src/client/index.ts | 15 - .../packages/x402/src/client/policies.test.ts | 138 - .../packages/x402/src/client/policies.ts | 99 - .../x402/src/client/tokenSelection.ts | 53 - .../packages/x402/src/client/x402Client.ts | 294 - .../packages/x402/src/config.test.ts | 68 - legacy/typescript/packages/x402/src/config.ts | 207 - legacy/typescript/packages/x402/src/errors.ts | 93 - .../x402/src/facilitator/client.test.ts | 195 - .../packages/x402/src/facilitator/client.ts | 197 - .../packages/x402/src/facilitator/index.ts | 14 - .../src/facilitator/x402Facilitator.test.ts | 277 - .../x402/src/facilitator/x402Facilitator.ts | 276 - .../packages/x402/src/http/client.test.ts | 194 - .../packages/x402/src/http/client.ts | 195 - .../packages/x402/src/http/index.ts | 5 - legacy/typescript/packages/x402/src/index.ts | 49 - .../x402/src/mechanisms/_base/index.ts | 22 - .../src/mechanisms/_exact_base/adapter.ts | 23 - .../src/mechanisms/_exact_base/evmAdapter.ts | 34 - .../src/mechanisms/_exact_base/facilitator.ts | 316 - .../x402/src/mechanisms/_exact_base/index.ts | 22 - .../x402/src/mechanisms/_exact_base/server.ts | 85 - .../src/mechanisms/_exact_base/tronAdapter.ts | 50 - .../x402/src/mechanisms/_exact_base/types.ts | 88 - .../_exact_permit_base/facilitator.ts | 396 -- .../mechanisms/_exact_permit_base/index.ts | 10 - .../mechanisms/_exact_permit_base/server.ts | 72 - .../src/mechanisms/evm/exact/client.test.ts | 38 - .../x402/src/mechanisms/evm/exact/client.ts | 104 - .../src/mechanisms/evm/exact/facilitator.ts | 54 - .../x402/src/mechanisms/evm/exact/index.ts | 3 - .../x402/src/mechanisms/evm/exact/server.ts | 29 - .../evm/exact_permit/client.test.ts | 64 - .../src/mechanisms/evm/exact_permit/client.ts | 134 - .../evm/exact_permit/facilitator.ts | 77 - .../src/mechanisms/evm/exact_permit/index.ts | 3 - .../src/mechanisms/evm/exact_permit/server.ts | 18 - .../packages/x402/src/mechanisms/index.ts | 64 - .../x402/src/mechanisms/registry.test.ts | 208 - .../x402/src/mechanisms/tron/exact/client.ts | 104 - .../src/mechanisms/tron/exact/facilitator.ts | 69 - .../x402/src/mechanisms/tron/exact/index.ts | 3 - .../x402/src/mechanisms/tron/exact/server.ts | 28 - .../tron/exact_gasfree/client.test.ts | 489 -- .../mechanisms/tron/exact_gasfree/client.ts | 289 - .../tron/exact_gasfree/facilitator.test.ts | 203 - .../tron/exact_gasfree/facilitator.ts | 310 - .../mechanisms/tron/exact_gasfree/index.ts | 4 - .../mechanisms/tron/exact_gasfree/server.ts | 59 - .../mechanisms/tron/exact_permit/client.ts | 155 - .../tron/exact_permit/facilitator.ts | 124 - .../src/mechanisms/tron/exact_permit/index.ts | 3 - .../mechanisms/tron/exact_permit/server.ts | 20 - .../packages/x402/src/middleware/core.test.ts | 230 - .../packages/x402/src/middleware/core.ts | 296 - .../x402/src/middleware/express.test.ts | 183 - .../packages/x402/src/middleware/express.ts | 88 - .../packages/x402/src/middleware/hono.test.ts | 177 - .../packages/x402/src/middleware/hono.ts | 78 - .../packages/x402/src/middleware/index.ts | 12 - .../packages/x402/src/server/index.ts | 12 - .../packages/x402/src/server/types.ts | 88 - .../x402/src/server/x402Server.test.ts | 388 -- .../packages/x402/src/server/x402Server.ts | 381 -- .../x402/src/signers/evmSigner.test.ts | 81 - .../packages/x402/src/signers/evmSigner.ts | 249 - .../x402/src/signers/facilitator/base.ts | 95 - .../x402/src/signers/facilitator/evmSigner.ts | 204 - .../src/signers/facilitator/tronSigner.ts | 384 -- .../packages/x402/src/signers/index.ts | 24 - .../packages/x402/src/signers/signer.ts | 297 - .../x402/src/signers/tronSigner.test.ts | 60 - .../packages/x402/src/signers/types.ts | 82 - .../packages/x402/src/tokens.test.ts | 90 - legacy/typescript/packages/x402/src/tokens.ts | 186 - .../packages/x402/src/types/index.ts | 6 - .../packages/x402/src/types/payment.ts | 131 - .../packages/x402/src/types/responses.ts | 81 - .../packages/x402/src/utils/encoding.ts | 132 - .../packages/x402/src/utils/gasfree.test.ts | 285 - .../packages/x402/src/utils/gasfree.ts | 306 - .../packages/x402/src/utils/index.ts | 15 - .../x402/src/utils/tx_verification.test.ts | 129 - .../x402/src/utils/tx_verification.ts | 180 - legacy/typescript/packages/x402/tsconfig.json | 9 - legacy/typescript/pnpm-lock.yaml | 3153 ---------- legacy/typescript/pnpm-workspace.yaml | 3 - legacy/typescript/scripts/publish-npm.sh | 50 - legacy/typescript/tsconfig.base.json | 20 - 288 files changed, 28 insertions(+), 40610 deletions(-) delete mode 100644 legacy/.env.example delete mode 100644 legacy/e2e/CLAUDE.md delete mode 100644 legacy/e2e/README.md delete mode 100644 legacy/e2e/clients/__init__.py delete mode 100644 legacy/e2e/clients/test_client.py delete mode 100644 legacy/e2e/mock_facilitator/__init__.py delete mode 100644 legacy/e2e/mock_facilitator/__main__.py delete mode 100644 legacy/e2e/mock_facilitator/app.py delete mode 100644 legacy/e2e/scenarios/README.md delete mode 100644 legacy/e2e/scenarios/exact_gasfree_happy_path/config.json delete mode 100644 legacy/e2e/scenarios/exact_gasfree_happy_path/expected_payment_response.json delete mode 100644 legacy/e2e/scenarios/exact_happy_path/config.json delete mode 100644 legacy/e2e/scenarios/exact_happy_path/expected_payment_response.json delete mode 100644 legacy/e2e/scenarios/exact_permit_happy_path/README.md delete mode 100644 legacy/e2e/scenarios/exact_permit_happy_path/config.json delete mode 100644 legacy/e2e/scenarios/exact_permit_happy_path/expected_payment_response.json delete mode 100755 legacy/e2e/scenarios/run_all.sh delete mode 100755 legacy/e2e/scenarios/run_testnet.sh delete mode 100644 legacy/e2e/scenarios/testnet/README.md delete mode 100644 legacy/e2e/scenarios/testnet/exact_gasfree_testnet/config.json delete mode 100644 legacy/e2e/scenarios/testnet/exact_permit_testnet/config.json delete mode 100644 legacy/e2e/scenarios/testnet/exact_testnet/config.json delete mode 100644 legacy/e2e/scenarios/unhappy_settle_insufficient/config.json delete mode 100644 legacy/e2e/scenarios/unhappy_settle_insufficient/expected_payment_response.json delete mode 100644 legacy/e2e/scenarios/unhappy_settle_revert/config.json delete mode 100644 legacy/e2e/scenarios/unhappy_settle_revert/expected_payment_response.json delete mode 100644 legacy/e2e/scenarios/unhappy_verify_expired/config.json delete mode 100644 legacy/e2e/scenarios/unhappy_verify_expired/expected_payment_response.json delete mode 100644 legacy/e2e/scenarios/unhappy_verify_invalid_sig/config.json delete mode 100644 legacy/e2e/scenarios/unhappy_verify_invalid_sig/expected_payment_response.json delete mode 100644 legacy/e2e/scenarios/unhappy_verify_network_mismatch/config.json delete mode 100644 legacy/e2e/scenarios/unhappy_verify_network_mismatch/expected_payment_response.json delete mode 100644 legacy/e2e/servers/__init__.py delete mode 100644 legacy/e2e/servers/resource_server.py delete mode 100644 legacy/examples/CLAUDE.md delete mode 100644 legacy/examples/bsc-testnet-smoke/README.md delete mode 100644 legacy/examples/bsc-testnet-smoke/bsc_exact_client.py delete mode 100644 legacy/examples/bsc-testnet-smoke/bsc_exact_client.ts delete mode 100644 legacy/examples/bsc-testnet-smoke/bsc_exact_server.py delete mode 100644 legacy/examples/facilitator/__init__.py delete mode 100644 legacy/examples/facilitator/__main__.py delete mode 100644 legacy/examples/facilitator/server.py delete mode 100644 legacy/integration/CLAUDE.md delete mode 100644 legacy/integration/README.md delete mode 100644 legacy/integration/commands.py delete mode 100644 legacy/integration/configs/_smoke_a.json delete mode 100644 legacy/integration/configs/_smoke_b.json delete mode 100644 legacy/integration/configs/smoke.json delete mode 100644 legacy/integration/run.py delete mode 100644 legacy/package.json delete mode 100644 legacy/protected_image.png delete mode 100644 legacy/pyproject.toml delete mode 100644 legacy/python/x402/CLAUDE.md delete mode 100644 legacy/python/x402/README.md delete mode 100644 legacy/python/x402/pyproject.toml delete mode 100644 legacy/python/x402/pytest.ini delete mode 100755 legacy/python/x402/scripts/publish_pypi.sh delete mode 100644 legacy/python/x402/src/bankofai/x402/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/abi.py delete mode 100644 legacy/python/x402/src/bankofai/x402/address/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/address/converter.py delete mode 100644 legacy/python/x402/src/bankofai/x402/clients/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/clients/policies.py delete mode 100644 legacy/python/x402/src/bankofai/x402/clients/token_selection.py delete mode 100644 legacy/python/x402/src/bankofai/x402/clients/x402_client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/clients/x402_http_client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/config.py delete mode 100644 legacy/python/x402/src/bankofai/x402/encoding.py delete mode 100644 legacy/python/x402/src/bankofai/x402/exceptions.py delete mode 100644 legacy/python/x402/src/bankofai/x402/facilitator/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/facilitator/facilitator_client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/facilitator/x402_facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/fastapi/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/fastapi/middleware.py delete mode 100644 legacy/python/x402/src/bankofai/x402/logging_config.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_base/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_base/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_base/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_base/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_base/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_base/base.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_base/types.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_permit_base/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_permit_base/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_permit_base/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/_exact_permit_base/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact/adapter.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact_permit/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact_permit/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact_permit/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/evm/exact_permit/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact/adapter.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_gasfree/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_gasfree/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_gasfree/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_gasfree/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_permit/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_permit/client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_permit/facilitator.py delete mode 100644 legacy/python/x402/src/bankofai/x402/mechanisms/tron/exact_permit/server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/server/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/server/x402_server.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/client/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/client/base.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/client/evm_signer.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/client/tron_signer.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/facilitator/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/facilitator/base.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/facilitator/evm_signer.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/facilitator/tron_signer.py delete mode 100644 legacy/python/x402/src/bankofai/x402/signers/utils.py delete mode 100644 legacy/python/x402/src/bankofai/x402/tokens/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/tokens/registry.py delete mode 100644 legacy/python/x402/src/bankofai/x402/types.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/__init__.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/address.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/eip712.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/gasfree.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/payment_id.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/tron_client.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/tron_verification.py delete mode 100644 legacy/python/x402/src/bankofai/x402/utils/tx_verification.py delete mode 100644 legacy/python/x402/tests/__init__.py delete mode 100644 legacy/python/x402/tests/client/__init__.py delete mode 100644 legacy/python/x402/tests/client/test_client.py delete mode 100644 legacy/python/x402/tests/client/test_evm_payment_permit.py delete mode 100644 legacy/python/x402/tests/client/test_payment_permit.py delete mode 100644 legacy/python/x402/tests/client/test_policies.py delete mode 100644 legacy/python/x402/tests/client/test_signers.py delete mode 100644 legacy/python/x402/tests/common/__init__.py delete mode 100644 legacy/python/x402/tests/common/test_payment_id.py delete mode 100644 legacy/python/x402/tests/common/test_types.py delete mode 100644 legacy/python/x402/tests/conftest.py delete mode 100644 legacy/python/x402/tests/exact/__init__.py delete mode 100644 legacy/python/x402/tests/exact/test_client.py delete mode 100644 legacy/python/x402/tests/exact/test_facilitator.py delete mode 100644 legacy/python/x402/tests/exact/test_gasfree_client.py delete mode 100644 legacy/python/x402/tests/exact/test_gasfree_facilitator.py delete mode 100644 legacy/python/x402/tests/exact/test_server.py delete mode 100644 legacy/python/x402/tests/exact/test_tron_client.py delete mode 100644 legacy/python/x402/tests/exact/test_tron_facilitator.py delete mode 100644 legacy/python/x402/tests/exact/test_tron_server.py delete mode 100644 legacy/python/x402/tests/exact/test_types.py delete mode 100644 legacy/python/x402/tests/facilitator/__init__.py delete mode 100644 legacy/python/x402/tests/facilitator/test_evm_payment_permit.py delete mode 100644 legacy/python/x402/tests/facilitator/test_evm_signer.py delete mode 100644 legacy/python/x402/tests/facilitator/test_payment_permit.py delete mode 100644 legacy/python/x402/tests/facilitator/test_tron_signer.py delete mode 100644 legacy/python/x402/tests/facilitator/test_x402_facilitator.py delete mode 100644 legacy/python/x402/tests/server/__init__.py delete mode 100644 legacy/python/x402/tests/server/test_evm_exact.py delete mode 100644 legacy/python/x402/tests/server/test_signature_verification.py delete mode 100644 legacy/python/x402/tests/test_config.py delete mode 100644 legacy/python/x402/tests/utils/test_address_normalization.py delete mode 100644 legacy/python/x402/tests/utils/test_address_utils.py delete mode 100644 legacy/python/x402/tests/utils/test_evm_address_converter.py delete mode 100644 legacy/python/x402/tests/utils/test_gasfree_utils.py delete mode 100644 legacy/python/x402/tests/utils/test_tron_client_factory.py delete mode 100644 legacy/python/x402/uv.lock delete mode 100755 legacy/scripts/upload_pkgs.sh delete mode 100644 legacy/specs/001-exact-v2-compat/spec.md delete mode 100644 legacy/specs/CLAUDE.md delete mode 100644 legacy/specs/config.md delete mode 100644 legacy/specs/protocol.md delete mode 100644 legacy/specs/roles.md delete mode 100644 legacy/specs/schemes/exact-gasfree.md delete mode 100644 legacy/specs/schemes/exact-permit.md delete mode 100644 legacy/specs/schemes/exact.md delete mode 100644 legacy/specs/transports/facilitator-http.md delete mode 100644 legacy/typescript/CLAUDE.md delete mode 100644 legacy/typescript/README.md delete mode 100644 legacy/typescript/package-lock.json delete mode 100644 legacy/typescript/package.json delete mode 100644 legacy/typescript/packages/x402/CLAUDE.md delete mode 100644 legacy/typescript/packages/x402/README.md delete mode 100644 legacy/typescript/packages/x402/package.json delete mode 100644 legacy/typescript/packages/x402/src/abi.ts delete mode 100644 legacy/typescript/packages/x402/src/address.ts delete mode 100644 legacy/typescript/packages/x402/src/client/index.ts delete mode 100644 legacy/typescript/packages/x402/src/client/policies.test.ts delete mode 100644 legacy/typescript/packages/x402/src/client/policies.ts delete mode 100644 legacy/typescript/packages/x402/src/client/tokenSelection.ts delete mode 100644 legacy/typescript/packages/x402/src/client/x402Client.ts delete mode 100644 legacy/typescript/packages/x402/src/config.test.ts delete mode 100644 legacy/typescript/packages/x402/src/config.ts delete mode 100644 legacy/typescript/packages/x402/src/errors.ts delete mode 100644 legacy/typescript/packages/x402/src/facilitator/client.test.ts delete mode 100644 legacy/typescript/packages/x402/src/facilitator/client.ts delete mode 100644 legacy/typescript/packages/x402/src/facilitator/index.ts delete mode 100644 legacy/typescript/packages/x402/src/facilitator/x402Facilitator.test.ts delete mode 100644 legacy/typescript/packages/x402/src/facilitator/x402Facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/http/client.test.ts delete mode 100644 legacy/typescript/packages/x402/src/http/client.ts delete mode 100644 legacy/typescript/packages/x402/src/http/index.ts delete mode 100644 legacy/typescript/packages/x402/src/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_base/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/adapter.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/evmAdapter.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/server.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/tronAdapter.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_base/types.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/server.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.test.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact/server.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.test.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/server.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/registry.test.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact/client.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact/server.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.test.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.test.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/server.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/client.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/facilitator.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/index.ts delete mode 100644 legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/server.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/core.test.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/core.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/express.test.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/express.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/hono.test.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/hono.ts delete mode 100644 legacy/typescript/packages/x402/src/middleware/index.ts delete mode 100644 legacy/typescript/packages/x402/src/server/index.ts delete mode 100644 legacy/typescript/packages/x402/src/server/types.ts delete mode 100644 legacy/typescript/packages/x402/src/server/x402Server.test.ts delete mode 100644 legacy/typescript/packages/x402/src/server/x402Server.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/evmSigner.test.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/evmSigner.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/facilitator/base.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/facilitator/evmSigner.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/facilitator/tronSigner.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/index.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/signer.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/tronSigner.test.ts delete mode 100644 legacy/typescript/packages/x402/src/signers/types.ts delete mode 100644 legacy/typescript/packages/x402/src/tokens.test.ts delete mode 100644 legacy/typescript/packages/x402/src/tokens.ts delete mode 100644 legacy/typescript/packages/x402/src/types/index.ts delete mode 100644 legacy/typescript/packages/x402/src/types/payment.ts delete mode 100644 legacy/typescript/packages/x402/src/types/responses.ts delete mode 100644 legacy/typescript/packages/x402/src/utils/encoding.ts delete mode 100644 legacy/typescript/packages/x402/src/utils/gasfree.test.ts delete mode 100644 legacy/typescript/packages/x402/src/utils/gasfree.ts delete mode 100644 legacy/typescript/packages/x402/src/utils/index.ts delete mode 100644 legacy/typescript/packages/x402/src/utils/tx_verification.test.ts delete mode 100644 legacy/typescript/packages/x402/src/utils/tx_verification.ts delete mode 100644 legacy/typescript/packages/x402/tsconfig.json delete mode 100644 legacy/typescript/pnpm-lock.yaml delete mode 100644 legacy/typescript/pnpm-workspace.yaml delete mode 100755 legacy/typescript/scripts/publish-npm.sh delete mode 100644 legacy/typescript/tsconfig.base.json diff --git a/.claude/rules/CLAUDE.md b/.claude/rules/CLAUDE.md index 75b7fd10..39f83513 100644 --- a/.claude/rules/CLAUDE.md +++ b/.claude/rules/CLAUDE.md @@ -2,7 +2,7 @@ This is the rules knowledge base. Every file here is a **self-contained rule sheet** Claude loads on demand when the touched code matches its scope. Rules override defaults; CLAUDE.md at the repo root sets the floor. -The SDK is a **TypeScript-only** pnpm/turbo monorepo under [typescript/](../../typescript/CLAUDE.md). `core` and `mechanisms/evm` are **upstream forks** (keep byte-identical, additions go in overlays); `mechanisms/tron` is in-house. There is no Python in the current SDK. (The previous-generation Python + old TypeScript code lives under `legacy/` and is slated for removal — these rules do **not** cover it.) +The SDK is a **TypeScript-only** pnpm/turbo monorepo under [typescript/](../../typescript/CLAUDE.md). `core` and `mechanisms/evm` are **upstream forks** (keep byte-identical, additions go in overlays); `mechanisms/tron` is in-house. There is no Python in the current SDK. ## When Claude reads what diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8ce71397..30f84ed1 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,6 @@ ## Description @@ -33,7 +30,6 @@ For TypeScript: Run `pnpm test` from the `/typescript` directory - [ ] I have formatted and linted my code - [ ] All new and existing tests pass - [ ] I added a Changeset for publishable package changes, or this PR does not require one -- [ ] My commits are signed (required for merge) -- you may need to rebase if you initially pushed unsigned commits | | - | | | - | 2. 402 Payment Required | | - | Headers: PAYMENT-REQUIRED | | - |<------------------------------| | - | | | - | (client creates signed | | - | payment payload) | | - | | | - | 3. GET /resource | | - | Headers: PAYMENT-SIGNATURE | | - |------------------------------>| | - | | 4. verify + settle | - | |----------------------------->| - | | | - | | 5. SettleResponse | - | |<-----------------------------| - | | | - | 6. 200 OK + resource | | - |<------------------------------| | -``` - -## HTTP Headers - -| Header | Direction | Description | -|--------|-----------|-------------| -| `PAYMENT-REQUIRED` | Server -> Client | Base64-encoded `PaymentRequired` JSON (in 402 response) | -| `PAYMENT-SIGNATURE` | Client -> Server | Base64-encoded `PaymentPayload` JSON (in retry request) | -| `PAYMENT-RESPONSE` | Server -> Client | Settlement result info (in success response) | - -**Encoding convention**: All header values are encoded as `Base64(UTF-8(JSON.stringify(object)))`. - -The 402 response body MAY also contain `PaymentRequired` as raw JSON. Clients should try the header first, then fall back to the body. - -## Constants - -| Name | Value | Description | -|------|-------|-------------| -| `DeliveryKind` | `"PAYMENT_ONLY"` | Only supported delivery mode | -| `KIND_MAP` | `{ "PAYMENT_ONLY": 0 }` | Maps to uint8 for EIP-712 signing | -| Payment ID format | `0x` + 32 hex chars | 16 random bytes, used as `bytes16` in signatures | - -## Wire-Format Data Structures - -All structures use **camelCase** field names on the wire (JSON). Python implementations use snake_case internally with camelCase aliases. - -### PaymentRequired (Server -> Client, 402 response) - -```json -{ - "x402Version": 2, - "error": "(optional) string", - "resource": { - "url": "(optional) string", - "description": "(optional) string", - "mimeType": "(optional) string" - }, - "accepts": [ PaymentRequirements, ... ], - "extensions": { - "paymentPermitContext": { - "meta": { - "kind": "PAYMENT_ONLY", - "paymentId": "0x...", - "nonce": "string", - "validAfter": 1234567890, - "validBefore": 1234567890 - } - } - } -} -``` - -### PaymentRequirements - -```json -{ - "scheme": "exact_permit | exact | exact_gasfree", - "network": "tron:mainnet | eip155:97 | ...", - "amount": "1000000", - "asset": "token contract address", - "payTo": "recipient address", - "maxTimeoutSeconds": "(optional) int", - "extra": { - "name": "(optional) token name, for ERC-3009 domain", - "version": "(optional) token version, for ERC-3009 domain", - "fee": { - "facilitatorId": "(optional) string", - "feeTo": "fee recipient address", - "feeAmount": "fee in smallest unit", - "caller": "(optional) caller address" - } - } -} -``` - -### PaymentPayload (Client -> Server, retry request) - -```json -{ - "x402Version": 2, - "resource": { - "url": "(optional) string", - "description": "(optional) string", - "mimeType": "(optional) string" - }, - "accepted": PaymentRequirements, - "payload": { - "signature": "EIP-712 signature hex string", - "merchantSignature": "(optional) string", - "paymentPermit": PaymentPermit - }, - "extensions": { } -} -``` - -### PaymentPermit - -```json -{ - "meta": { - "kind": "PAYMENT_ONLY", - "paymentId": "0x...", - "nonce": "string", - "validAfter": 1234567890, - "validBefore": 1234567890 - }, - "buyer": "payer address", - "caller": "address authorized to call permitTransferFrom", - "payment": { - "payToken": "token contract address", - "payAmount": "amount in smallest unit", - "payTo": "recipient address" - }, - "fee": { - "feeTo": "fee recipient address", - "feeAmount": "fee in smallest unit" - } -} -``` - -### VerifyResponse - -```json -{ - "isValid": true, - "invalidReason": "(optional) string" -} -``` - -### SettleResponse - -```json -{ - "success": true, - "transaction": "(optional) tx hash string", - "network": "(optional) network identifier", - "errorReason": "(optional) string" -} -``` - -### FeeQuoteResponse - -```json -{ - "fee": { - "feeTo": "address", - "feeAmount": "string" - }, - "pricing": "string", - "scheme": "exact_permit | exact | ...", - "network": "tron:mainnet | ...", - "asset": "token address", - "expiresAt": "(optional) unix timestamp" -} -``` - -### SupportedResponse - -```json -{ - "kinds": [ - { "x402Version": 2, "scheme": "exact_permit", "network": "tron:mainnet" }, - ... - ] -} -``` diff --git a/legacy/specs/roles.md b/legacy/specs/roles.md deleted file mode 100644 index 28d8540f..00000000 --- a/legacy/specs/roles.md +++ /dev/null @@ -1,161 +0,0 @@ -# Client, Server & Facilitator Roles - -## Client - -The client initiates payments and makes requests to protected resources. - -### Mechanism Registration - -Mechanisms are registered against **network patterns**: - -- **Exact match**: `"tron:nile"` matches only `tron:nile` — higher priority -- **Wildcard match**: `"tron:*"` matches any `tron:` — lower priority - -When multiple mechanisms match a network, the most specific pattern wins. Each mechanism is associated with a scheme (e.g., `exact_permit`, `exact_gasfree`). - -### Payment Selection Pipeline - -When the client receives a 402 response with multiple `accepts` (payment requirements), it runs a selection pipeline: - -``` -accepts[] - | - v -[1] Filter by scheme (if filter specified) - | - v -[2] Filter by network (if filter specified) - | - v -[3] Filter by max amount (if filter specified) - | - v -[4] Filter by registered mechanisms - (keep only requirements that have a matching mechanism) - | - v -[5] Apply policies in registration order - (each policy receives the list and returns a filtered/reordered subset) - | - v -[6] Token selection strategy - (pick a single requirement from the remaining list) - | - v - selected PaymentRequirements -``` - -### Policies - -A policy receives a list of payment requirements and returns a subset. Policies are applied sequentially in registration order. - -**SufficientBalancePolicy** (built-in): -- For each requirement, checks if the buyer has enough token balance (amount + fee) -- If balance check fails (network error, no signer, etc.), the requirement is **kept** (fail-open) -- Requirements with insufficient balance are removed - -### Token Selection Strategy - -After filtering, a strategy picks the single best requirement: - -- **CheapestTokenSelectionStrategy** (default): selects the requirement with the lowest cost, normalized by token decimals -- **DefaultTokenSelectionStrategy**: selects the first requirement in the list - -### HTTP Client Behavior - -The HTTP client wraps standard HTTP calls with automatic 402 handling: - -1. Make the original HTTP request -2. If response status is **not** 402, return the response as-is -3. If 402: - a. Try to decode `PAYMENT-REQUIRED` header (Base64 JSON) - b. If header missing or invalid, try to parse the response body as JSON - c. Extract the `accepts` array from the PaymentRequired structure - d. Run the payment selection pipeline - e. Create a PaymentPayload via the selected mechanism - f. Encode the payload as Base64 JSON - g. Retry the original request with `PAYMENT-SIGNATURE` header - h. Return the retry response - -Convenience methods: `get(url)`, `post(url, body)`, `put(url, body)`, `delete(url)`. - ---- - -## Server - -The server protects resources behind payment requirements and delegates settlement to the facilitator. - -### Endpoint Protection - -Endpoints are configured with: -- **Price**: human-readable string (e.g., `"100 USDT"`, `"0.5 USDD"`) -- **Scheme**: which payment scheme(s) to accept -- **Network**: which blockchain network(s) -- **Pay-to address**: recipient of the payment -- **Validity window**: how long the payment permit is valid - -### Building Payment Requirements - -When a client requests a protected resource without payment: - -1. Parse the price string (e.g., `"100 USDT"`) into amount + asset address via the token registry -2. Construct `PaymentRequirements` for each price/scheme/network combination -3. Request a fee quote from the facilitator (for schemes that support fees) -4. Merge fee info into requirements -5. Generate `PaymentPermitContext`: - - `paymentId`: random 16-byte hex with `0x` prefix - - `nonce`: random value (as string) - - `validAfter`: current Unix timestamp - - `validBefore`: current timestamp + validity window -6. Return 402 response with `PaymentRequired` in header and/or body - -### Payment Verification & Settlement - -When a client retries with `PAYMENT-SIGNATURE`: - -1. Decode the `PaymentPayload` from the header -2. **Anti-tampering check**: verify the `accepted` requirements in the payload match what this server originally issued (scheme, network, amount, asset, payTo) -3. Delegate to facilitator for cryptographic verification -4. If valid, delegate to facilitator for on-chain settlement -5. On success, return the protected resource with a 200 status - -### Framework Integrations - -- **FastAPI**: middleware/decorator that wraps endpoint functions — intercepts requests before the handler, returns 402 or passes through -- **Flask**: similar decorator pattern - ---- - -## Facilitator - -The facilitator is the cryptographic and on-chain authority — it verifies signatures and executes settlements. - -### Fee Quoting - -- Receives payment requirements and returns a `FeeQuoteResponse` -- Fee structure depends on the scheme: - - `exact_permit`: configurable flat fee per token - - `exact`: no fees (always returns feeAmount `"0"`) - - `exact_gasfree`: fee determined by service provider - -### Verification - -- Recovers the signer from the EIP-712/TIP-712 signature -- Verifies the recovered address matches the `buyer` in the permit -- Validates permit fields against the original requirements (see validation rules in each scheme spec) - -### Settlement - -- Calls the appropriate on-chain function: - - `exact_permit`: `permitTransferFrom` on the PaymentPermit contract - - `exact`: `transferWithAuthorization` on the token contract - - `exact_gasfree`: submits to the GasFree API relay -- Waits for transaction receipt / confirmation -- Validates on-chain transaction status -- Returns `SettleResponse` with transaction hash or error - -### Error Handling - -All facilitator operations catch exceptions and return structured responses: -- Verification errors → `VerifyResponse { isValid: false, invalidReason: "..." }` -- Settlement errors → `SettleResponse { success: false, errorReason: "..." }` diff --git a/legacy/specs/schemes/exact-gasfree.md b/legacy/specs/schemes/exact-gasfree.md deleted file mode 100644 index 0c929033..00000000 --- a/legacy/specs/schemes/exact-gasfree.md +++ /dev/null @@ -1,270 +0,0 @@ -# exact_gasfree (TRON GasFree) Scheme Specification - -## Overview - -The `exact_gasfree` scheme enables gasless payments on TRON. Users hold tokens in a **GasFree custodial wallet** and sign TIP-712 permits. A **service provider** (relayer) submits the transaction on-chain, paying the gas fees and collecting a maxFee. This scheme is **TRON-only**. - -## Scheme Identifier - -`"exact_gasfree"` - -## TIP-712 Signing Specification - -### Domain - -```json -{ - "name": "GasFreeController", - "version": "V1.0.0", - "chainId": "", - "verifyingContract": "" -} -``` - -Domain type definition: -``` -[ - { name: "name", type: "string" }, - { name: "version", type: "string" }, - { name: "chainId", type: "uint256" }, - { name: "verifyingContract", type: "address" } -] -``` - -### Types - -``` -PermitTransfer: # << Primary Type - token address # Token contract address - serviceProvider address # Relayer / service provider address - user address # Buyer's address - receiver address # Payment recipient - value uint256 # Payment amount - maxFee uint256 # Maximum fee the relayer can deduct - deadline uint256 # Unix seconds expiry - version uint256 # Always 1 - nonce uint256 # From GasFree API (incrementing) -``` - -### Primary Type - -`"PermitTransfer"` - -## GasFree Custodial Model - -Each user has a **gasFreeAddress** — a custodial wallet managed by the GasFree contract. The user's tokens are held in this address. Transfers deduct from the gasFreeAddress balance, not the user's main wallet. - -- The gasFreeAddress is derived deterministically from the user's main address -- The account must be **activated** before use (first transaction triggers activation) -- Balance check: `gasFreeAddress balance >= payment amount + maxFee` - -## GasFree API Contract - -All endpoints are served through the BankOfAI proxy: -- Mainnet: `https://facilitator.bankofai.io/mainnet` -- Shasta: `https://facilitator.bankofai.io/shasta` -- Nile: `https://facilitator.bankofai.io/nile` - -All responses share a common envelope: -```json -{ - "code": 200, - "reason": null, - "message": null, - "data": { ... } -} -``` - -### GET /api/v1/address/{user} - -Returns account info for a user address. - -**Response `data`**: -```json -{ - "accountAddress": "user's main address", - "gasFreeAddress": "custodial wallet address", - "active": true, - "nonce": 5, - "allowSubmit": true, - "assets": [ - { - "tokenAddress": "token contract address", - "tokenSymbol": "USDT", - "activateFee": 5000000, - "transferFee": 3000000, - "decimal": 6, - "frozen": 0, - "balance": "100000000" - } - ] -} -``` - -### GET /api/v1/config/provider/all - -Returns list of supported service providers (relayers). - -**Response `data`**: -```json -{ - "providers": [ - { - "address": "provider address", - "name": "Provider Name", - "icon": "url", - "website": "url", - "config": { - "maxPendingTransfer": 10, - "minDeadlineDuration": 50, - "maxDeadlineDuration": 600, - "defaultDeadlineDuration": 300 - } - } - ] -} -``` - -### POST /api/v1/gasfree/submit - -Submit a signed GasFree transaction. - -**Request body**: -```json -{ - "token": "EVM hex address", - "serviceProvider": "EVM hex address", - "user": "EVM hex address", - "receiver": "EVM hex address", - "value": "string (uint256)", - "maxFee": "string (uint256)", - "deadline": 1234567890, - "version": 1, - "nonce": 5, - "sig": "hex signature WITHOUT 0x prefix", - "requestId": "x402-{unix_timestamp_ms}-{first_8_chars_of_sig}" -} -``` - -**Response `data`**: returns a `GasFreeSubmitResponseData` with an `id` (trace ID) for polling. - -### GET /api/v1/gasfree/{traceId} - -Poll transaction status. - -**Response `data`**: -```json -{ - "id": "trace-id", - "state": "WAITING | INPROGRESS | CONFIRMING | SUCCEED | FAILED", - "txnHash": "on-chain tx hash (when available)", - "txnState": "INIT | NOT_ON_CHAIN | ON_CHAIN | SOLIDITY | ON_CHAIN_FAILED", - "reason": "error message (on failure)", - "accountAddress": "...", - "gasFreeAddress": "...", - "providerAddress": "...", - "targetAddress": "...", - "nonce": 5, - "tokenAddress": "...", - "amount": "...", - "createdAt": "ISO timestamp", - "expiredAt": "ISO timestamp" -} -``` - -### Status State Machine - -``` -WAITING -> INPROGRESS -> CONFIRMING -> SUCCEED - -> FAILED - -txnState: INIT -> NOT_ON_CHAIN -> ON_CHAIN -> SOLIDITY - -> ON_CHAIN_FAILED -``` - -**Terminal success conditions**: -- `state == "SUCCEED"`, OR -- `txnHash` exists AND `txnState` is `"ON_CHAIN"` or `"SOLIDITY"` - -**Terminal failure conditions**: -- `state == "FAILED"`, OR -- `txnState == "ON_CHAIN_FAILED"` - -## Business Rules - -### Deadline Bounds - -The signed `deadline` must be clamped to network-specific bounds: - -| Network | Min (seconds from now) | Max (seconds from now) | -|---------|----------------------|----------------------| -| tron:mainnet | 55 | 595 | -| tron:shasta, tron:nile | 55 | 3595 | - -If the requested validity window exceeds the max, it is clamped. If below the min, it is rejected. - -### Fee Calculation - -`maxFee` in the signed message is calculated as: - -``` -maxFee = max(transferFee, facilitatorFee) -if account is NOT active AND activateFee > 0: - maxFee += activateFee -if maxFee == 0: - maxFee = 1 token unit (10^decimals) -``` - -Where: -- `transferFee`: per-token fee from the GasFree API account info (`assets[].transferFee`) -- `facilitatorFee`: from `PaymentRequirements.extra.fee.feeAmount` -- `activateFee`: one-time fee for account activation (`assets[].activateFee`) - -### Balance Requirement - -``` -gasFreeAddress token balance >= payment amount + maxFee -``` - -If insufficient, reject with an `InsufficientGasFreeBalance` error. - -### Account Eligibility - -The user's GasFree account must satisfy: `active == true` OR `allowSubmit == true`. - -### Service Provider Selection - -- If the facilitator provides a `fee.feeTo` in the requirements, use that as the service provider -- Otherwise, fetch providers from the API and select one (random choice) - -## Client Behavior - -1. Fetch account info from GasFree API -2. Verify account eligibility (active or allowSubmit) -3. Determine service provider -4. Calculate maxFee (see formula above) -5. Verify gasFreeAddress has sufficient balance -6. Clamp deadline to network bounds -7. Sign TIP-712 PermitTransfer message -8. Build PaymentPayload with `gasfreeAddress` in extensions - -## Facilitator Behavior - -1. Verify the TIP-712 signature -2. Validate the service provider is in the allowed provider list -3. Check gasFreeAddress balance on-chain -4. Submit to GasFree API via POST /api/v1/gasfree/submit -5. Poll for success via GET /api/v1/gasfree/{traceId} -6. Return SettleResponse with the actual on-chain transaction hash - -### Field Mapping (PaymentPermit -> PermitTransfer message) - -| PaymentPermit field | PermitTransfer field | -|--------------------|--------------------| -| `payment.payToken` | `token` | -| `fee.feeTo` (caller) | `serviceProvider` | -| `buyer` | `user` | -| `payment.payTo` | `receiver` | -| `payment.payAmount` | `value` | -| `fee.feeAmount` | `maxFee` | -| `meta.validBefore` | `deadline` | diff --git a/legacy/specs/schemes/exact-permit.md b/legacy/specs/schemes/exact-permit.md deleted file mode 100644 index 520bca94..00000000 --- a/legacy/specs/schemes/exact-permit.md +++ /dev/null @@ -1,129 +0,0 @@ -# exact_permit Scheme Specification - -## Overview - -The `exact_permit` scheme uses EIP-712 (EVM) / TIP-712 (TRON) typed-data signatures to authorize token transfers via a **PaymentPermit** smart contract. The buyer signs a structured permit; the facilitator calls the contract's `permitTransferFrom` to execute the transfer on-chain. - -## Scheme Identifier - -`"exact_permit"` - -## EIP-712 Signing Specification - -### Domain - -```json -{ - "name": "PaymentPermit", - "chainId": "", - "verifyingContract": "" -} -``` - -Domain type definition: -``` -[ - { name: "name", type: "string" }, - { name: "chainId", type: "uint256" }, - { name: "verifyingContract", type: "address" } -] -``` - -Note: TRON addresses must be converted to EVM hex format (0x-prefixed) for signing. - -### Types - -``` -PermitMeta: - kind uint8 # KIND_MAP["PAYMENT_ONLY"] = 0 - paymentId bytes16 # 16-byte payment ID - nonce uint256 - validAfter uint256 # Unix seconds - validBefore uint256 # Unix seconds - -Payment: - payToken address - payAmount uint256 - payTo address - -Fee: - feeTo address - feeAmount uint256 - -PaymentPermitDetails: # << Primary Type - meta PermitMeta - buyer address - caller address - payment Payment - fee Fee -``` - -### Primary Type - -`"PaymentPermitDetails"` - -### Type Conversions for Signing - -When converting the PaymentPermit data model to EIP-712 message values: - -| Field | Source type | EIP-712 type | Conversion | -|-------|-----------|--------------|------------| -| `kind` | string `"PAYMENT_ONLY"` | uint8 | Lookup in KIND_MAP -> `0` | -| `paymentId` | hex string `"0x..."` | bytes16 | Hex decode to 16 bytes | -| `nonce` | string | uint256 | Parse as integer | -| `payAmount`, `feeAmount` | string | uint256 | Parse as integer | -| All addresses | Base58 (TRON) or hex (EVM) | address | Convert to 0x-prefixed EVM hex | - -## Client Behavior - -1. Receive `PaymentRequirements` with `scheme: "exact_permit"` and `PaymentPermitContext` from extensions -2. Build a `PaymentPermit` structure: - - `buyer` = client's own address - - `caller` = facilitator's caller address (from `extra.fee.caller`, or zero address) - - `payment` = from requirements (payToken=asset, payAmount=amount, payTo=payTo) - - `fee` = from requirements extra (feeTo, feeAmount) - - `meta` = from PaymentPermitContext (kind, paymentId, nonce, validAfter, validBefore) -3. **Ensure token allowance**: the buyer must have approved the **PaymentPermit contract** to spend at least `payAmount + feeAmount` of the token. If insufficient, send an on-chain `approve` transaction first. - - EVM: approve for `2^256 - 1` (max uint256) - - TRON: approve for `2^160 - 1` (max uint160) -4. Convert permit to EIP-712 typed data message (apply type conversions above) -5. Sign with buyer's private key using `signTypedData(domain, types, message, "PaymentPermitDetails")` -6. Return `PaymentPayload` with the signature and permit - -## Server Behavior - -1. Receive `PaymentPayload` with `PAYMENT-SIGNATURE` header -2. Anti-tampering: verify that `payload.accepted` matches the original requirements issued by this server -3. Recover signer address from the EIP-712 signature -4. Verify recovered address matches `payload.payload.paymentPermit.buyer` -5. Delegate to facilitator for settlement - -## Facilitator Behavior - -### Validation Rules - -Before settlement, the facilitator must validate the permit: - -| Rule | Check | -|------|-------| -| Amount | `payment.payAmount >= required amount` | -| Token | `payment.payToken == required asset` (case-insensitive) | -| Recipient | `payment.payTo == required payTo` (case-insensitive) | -| Fee recipient | `fee.feeTo == facilitator's configured fee address` | -| Fee amount | `fee.feeAmount >= facilitator's configured base fee` | -| Time window | `meta.validAfter <= current_time <= meta.validBefore` | -| Token whitelist | If configured, `payment.payToken` must be in allowed set | - -### Settlement - -1. Verify the EIP-712 signature (recover signer, match against buyer) -2. Call the PaymentPermit contract: `permitTransferFrom(permit, owner, signature)` -3. Wait for the transaction receipt -4. Check transaction status for success -5. Return `SettleResponse` with transaction hash - -## Address Handling - -- **TRON networks**: All addresses in the EIP-712 message must be in EVM hex format (0x-prefixed). The system converts between TRON Base58 and EVM hex as needed. -- **EVM networks**: Addresses use standard checksummed hex format. -- Address comparisons for validation are case-insensitive. diff --git a/legacy/specs/schemes/exact.md b/legacy/specs/schemes/exact.md deleted file mode 100644 index c873fb96..00000000 --- a/legacy/specs/schemes/exact.md +++ /dev/null @@ -1,91 +0,0 @@ -# exact (ERC-3009) Scheme Specification - -## Overview - -The `exact` scheme uses ERC-3009 `TransferWithAuthorization` — a single-use, pre-signed token transfer. The buyer signs an authorization directly against the **token contract** (not a separate permit contract). The facilitator calls `transferWithAuthorization` on the token contract to execute the transfer. - -## Scheme Identifier - -`"exact"` - -## EIP-712 Signing Specification - -### Domain - -```json -{ - "name": "", - "version": "", - "chainId": "", - "verifyingContract": "" -} -``` - -Domain type definition: -``` -[ - { name: "name", type: "string" }, - { name: "version", type: "string" }, - { name: "chainId", type: "uint256" }, - { name: "verifyingContract", type: "address" } -] -``` - -Note: Unlike `exact_permit`, the domain uses the **token contract** as verifyingContract, with the token's own name and version. These values come from the `PaymentRequirements.extra.name` and `extra.version` fields, or from the token registry. - -### Types - -``` -TransferWithAuthorization: # << Primary Type - from address - to address - value uint256 - validAfter uint256 # Unix seconds - validBefore uint256 # Unix seconds - nonce bytes32 # Random 32-byte value -``` - -### Primary Type - -`"TransferWithAuthorization"` - -## Key Differences from exact_permit - -| Aspect | exact_permit | exact | -|--------|-------------|-------| -| Domain verifyingContract | PaymentPermit contract | Token contract | -| Domain name | `"PaymentPermit"` | Token name (e.g., `"Tether USD"`) | -| Domain version | (none) | Token version (e.g., `"1"`) | -| Fee support | Yes (separate Fee struct) | No (feeAmount always `"0"`) | -| Allowance required | Yes (must approve PaymentPermit contract) | No (single-use authorization) | -| Nonce | From PaymentPermitContext (incrementing) | Random 32-byte hex value | -| Validity window | From PaymentPermitContext | Default 1 hour (3600 seconds) | -| Settlement call | `permitTransferFrom(permit, owner, sig)` | `transferWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s)` | - -## Client Behavior - -1. Receive `PaymentRequirements` with `scheme: "exact"` -2. Look up token metadata (name, version) from token registry or `extra` fields -3. Generate a random 32-byte nonce (as hex string) -4. Set validity window: `validAfter = now`, `validBefore = now + 3600` -5. Build EIP-712 domain using the token contract address -6. Sign the `TransferWithAuthorization` message with buyer's key -7. Return `PaymentPayload` with the signature - -## Facilitator Behavior - -### Fee Quoting - -The `exact` scheme does **not** support fees. `feeAmount` is always `"0"`. - -### Settlement - -1. Extract the `TransferWithAuthorization` parameters from the payload -2. Decompose the signature into `v`, `r`, `s` components -3. Call the token contract: `transferWithAuthorization(from, to, value, validAfter, validBefore, nonce, v, r, s)` -4. Wait for the transaction receipt and verify success -5. Return `SettleResponse` with transaction hash - -### Server Verification - -The `exact` scheme delegates all verification to the facilitator. Server-side signature verification returns `true` (passthrough) — the on-chain call itself serves as verification. diff --git a/legacy/specs/transports/facilitator-http.md b/legacy/specs/transports/facilitator-http.md deleted file mode 100644 index 4959625e..00000000 --- a/legacy/specs/transports/facilitator-http.md +++ /dev/null @@ -1,260 +0,0 @@ -# Transport: Facilitator HTTP API - -> Spec for the **server ↔ facilitator** transport. Distinct from the **client ↔ server** HTTP transport defined elsewhere — that one is governed by the x402 protocol headers (`PAYMENT-REQUIRED` / `PAYMENT-SIGNATURE` / `PAYMENT-RESPONSE`) and HTTP 402; this one is the ordinary REST API a server uses to delegate verify / settle / fee-quote / supported queries to a facilitator. - -## Summary - -A facilitator exposes four HTTP endpoints. Clients of these endpoints are **resource servers** (running our middleware or equivalent), not end users. - -| Endpoint | Method | Purpose | -|---|---|---| -| `/verify` | POST | Off-chain signature / replay / timing validation | -| `/settle` | POST | On-chain settlement (broadcast transaction) | -| `/supported` | GET | List supported `(x402Version, scheme, network)` tuples | -| `/fee/quote` | POST | Quote facilitator fee per requirement (optional, scheme-dependent) | - -All endpoints accept and return JSON. Authorization is implementation-defined; both the BankofAI Python client and the TS client forward a configurable `headers` map (typically `Authorization: Bearer …`). - -This spec is **descriptive of current implementation**. Any divergence from x402 Foundation upstream is flagged inline under "Upstream alignment notes" so future patches can converge. - ---- - -## 1. POST /verify - -### Request - -```json -{ - "paymentPayload": { /* PaymentPayload */ }, - "paymentRequirements": { /* PaymentRequirements */ } -} -``` - -| Field | Type | Required | Notes | -|---|---|---|---| -| `paymentPayload` | `PaymentPayload` | yes | The signed payload submitted by the client. See `specs/protocol.md`. | -| `paymentRequirements` | `PaymentRequirements` | yes | The requirement entry from `accepts[]` that the client elected to pay. | - -### Response — success - -```json -{ "isValid": true } -``` - -### Response — failure - -```json -{ - "isValid": false, - "invalidReason": "string" -} -``` - -`invalidReason` is a free-form human-readable string. Common values include: - -- `"unsupported_network_scheme: /"` — facilitator does not have a registered mechanism for this pair -- `"Invalid EVM address for : "` — checksum validation failed -- mechanism-specific reasons (e.g. `"signature mismatch"`, `"validBefore expired"`, `"nonce already used"`) - -### Status codes - -| Code | Meaning | -|---|---| -| 200 | Verification ran (regardless of `isValid` outcome) | -| 4xx / 5xx | Transport / facilitator infrastructure error | - -The `isValid: false` path is **not** a 4xx — verification ran successfully, the result was negative. - -### Upstream alignment notes - -- Upstream `x402-specification-v2.md` §7.1 **wraps** the body with a top-level `x402Version: 2` field. **Our current implementation omits this field.** Both directions are tolerant of the omission today; alignment is tracked in roadmap. -- Upstream successful response includes `payer: "0x…"`. Ours does not currently emit `payer`. - ---- - -## 2. POST /settle - -### Request - -Identical to `/verify`: - -```json -{ - "paymentPayload": { /* PaymentPayload */ }, - "paymentRequirements": { /* PaymentRequirements */ } -} -``` - -### Response — success - -```json -{ - "success": true, - "transaction": "0x…", - "network": "tron:nile" -} -``` - -| Field | Type | Required | Notes | -|---|---|---|---| -| `success` | `boolean` | yes | `true` on settlement | -| `transaction` | `string` | yes (on success) | Transaction hash. EVM = 0x-prefixed hex; TRON = 64-hex (no prefix). | -| `network` | `string` | yes | CAIP-2 identifier (`tron:` or `eip155:`) | - -### Response — failure - -```json -{ - "success": false, - "errorReason": "string", - "network": "tron:nile", - "transaction": "0x…" -} -``` - -`transaction` is optional on failure (e.g. the tx was broadcast but reverted on-chain — the hash is still useful for diagnosis). - -### Status codes - -Same as `/verify`. Mechanism failures surface as `success: false` + `errorReason`, not 4xx / 5xx. - -### Upstream alignment notes - -- Upstream §7.2 includes `payer` on both success and failure responses. Ours does not. - ---- - -## 3. GET /supported - -Used by clients to discover what the facilitator can handle before posting a verify/settle. - -### Response - -```json -{ - "kinds": [ - { "x402Version": 2, "scheme": "exact", "network": "tron:mainnet" }, - { "x402Version": 2, "scheme": "exact_permit", "network": "tron:mainnet" }, - { "x402Version": 2, "scheme": "exact_gasfree", "network": "tron:nile" }, - { "x402Version": 2, "scheme": "exact_permit", "network": "eip155:97" } - ] -} -``` - -| Field | Type | Required | Notes | -|---|---|---|---| -| `kinds` | array | yes | One entry per registered `(x402Version, scheme, network)` | -| `kinds[].x402Version` | number | yes | Always `2` in current code | -| `kinds[].scheme` | string | yes | Scheme identifier (`exact`, `exact_permit`, `exact_gasfree`, ...) | -| `kinds[].network` | string | yes | CAIP-2 identifier | - -### Upstream alignment notes - -- Upstream §7.3 adds two top-level fields: - - `extensions`: array of supported extension keys (e.g. `["payment-identifier", "auth-hints"]`). - - `signers`: map `{ "": ["0x…"] }` advertising the facilitator's signing addresses. -- Both are absent from our current response. Adding them is queued under v0.6.1 (extension framework) — `extensions` will be derivable from registered extensions; `signers` is a config addition. - ---- - -## 4. POST /fee/quote - -Optional endpoint. Returns per-requirement fee quotes. Schemes that don't charge a facilitator fee may return an empty array. - -### Request - -```json -{ - "accepts": [ /* PaymentRequirements[] */ ], - "paymentPermitContext": { /* optional, scheme-defined */ } -} -``` - -| Field | Type | Required | Notes | -|---|---|---|---| -| `accepts` | array | yes | One or more `PaymentRequirements`. Same shape as the `accepts` field in `PaymentRequired`. | -| `paymentPermitContext` | object | no | Forwarded as-is to the mechanism. Used by `exact_permit` to pass `paymentId` / `nonce` / validity window. | - -### Response - -```json -[ - { - "fee": { "feeTo": "T…", "feeAmount": "100000", "facilitatorId": "…", "caller": "T…" }, - "pricing": "fixed", - "scheme": "exact_permit", - "network": "tron:mainnet", - "asset": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", - "expiresAt": 1751234567 - } -] -``` - -The result array length **may be shorter than the input `accepts.length`** — entries the facilitator cannot quote (unsupported `(network, scheme)`, or mechanism returned `null`) are silently dropped. - -| Field | Type | Required | Notes | -|---|---|---|---| -| `fee` | object | yes | Fee structure. `feeTo` = recipient address; `feeAmount` = smallest-unit string. `facilitatorId` is set when the facilitator wants the on-chain proxy to bind a specific signer. `caller` for schemes (e.g. `exact_permit`) where the on-chain caller must equal a specific address. | -| `pricing` | string | yes | Mechanism-defined pricing model identifier. `"fixed"` for a flat fee; mechanisms may add others. | -| `scheme` / `network` / `asset` | string | yes | Echo of the input requirement so the caller can correlate quotes back to entries. | -| `expiresAt` | number | no | Unix seconds after which this quote is no longer authoritative. | - -### Upstream alignment notes - -- Upstream v2 spec does not currently standardize a `/fee/quote` endpoint at the same level. Our endpoint is BankofAI-specific, motivated by `exact_permit` / `exact_gasfree` needing a facilitator fee inserted into payment requirements before signing. - ---- - -## 5. Authorization - -Authentication is implementation-defined. Recommended pattern: HTTP `Authorization: Bearer ` with per-tenant tokens. Both reference clients (`bankofai.x402.facilitator.FacilitatorClient` Python; `FacilitatorClient` TypeScript) accept a `headers` map at construction: - -```python -FacilitatorClient(base_url="https://fac.example", headers={"Authorization": "Bearer abc"}) -``` - -```ts -new FacilitatorClient({ baseUrl: 'https://fac.example', headers: { Authorization: 'Bearer abc' } }) -``` - -The headers are forwarded verbatim on every request. - -## 6. Timeouts and cancellation - -- Default per-request timeout: **120 seconds** in both reference clients. `/settle` may take a non-trivial fraction of this on busy networks. -- Cancellation: TS client uses `AbortController`; Python client uses `httpx`'s timeout. Both surface a transport-level error to the caller — the facilitator does NOT receive a "settle was cancelled" notification. - -## 7. Error handling - -All transport / facilitator-side failures (non-2xx, malformed JSON, network failure) are raised to the caller as a typed exception: - -| Runtime | Exception | -|---|---| -| Python | `httpx.HTTPStatusError` (from `response.raise_for_status()`) for non-2xx | -| TypeScript | `FacilitatorError` (this repo, in `src/errors.ts`) — carries `status` and `body` | - -Mechanism-level failures (signature invalid, insufficient balance, etc.) are returned **inside** a 200 response as `isValid: false` / `success: false`. They are not transport errors. - ---- - -## 8. Reference implementations - -| Runtime | File | -|---|---| -| Python client | `python/x402/src/bankofai/x402/facilitator/facilitator_client.py` | -| Python server engine | `python/x402/src/bankofai/x402/facilitator/x402_facilitator.py` | -| Python server example | `examples/facilitator/server.py` | -| TypeScript client | `typescript/packages/x402/src/facilitator/client.ts` | -| TypeScript server engine | `typescript/packages/x402/src/facilitator/x402Facilitator.ts` | - -The Python and TypeScript clients are byte-compatible against the same facilitator service. Tests in `python/x402/tests/facilitator/` and `typescript/packages/x402/src/facilitator/*.test.ts` cover the wire shapes documented here. - -## 9. Versioning - -This transport spec is implicitly tied to **x402 protocol v2**. A future protocol version that changes the wire shape MAY be carried over the same endpoint paths with a new top-level `x402Version` field discriminating the body shape. - ---- - -## Change log - -- **2026-05** — Initial draft. Captures current behaviour as of v0.6.0. diff --git a/legacy/typescript/CLAUDE.md b/legacy/typescript/CLAUDE.md deleted file mode 100644 index 7ba99df0..00000000 --- a/legacy/typescript/CLAUDE.md +++ /dev/null @@ -1,56 +0,0 @@ -# typescript/ - -TypeScript monorepo (`pnpm` workspace). Targets Node 20+. Published as `@bankofai/*` scoped packages. - -## Build & test - -```bash -# from typescript/ -pnpm install -pnpm -r build # all packages -pnpm -r test # all packages (vitest) -pnpm -r --if-present lint -pnpm -C packages/x402 test # single package -pnpm -C packages/x402 test -- --reporter=verbose config.test -``` - -Node: **>=20**. pnpm: **>=10** (see root `package.json` engines). - -## Workspace layout - -| Package | Purpose | -|---|---| -| `packages/x402` | Public SDK entry. Re-exports from `mechanisms`, `http`, etc. Consumer-facing. | -| `packages/core` | Prebuilt tsbuildinfo / shared types (currently `dist`-only). | -| `packages/mechanisms/evm` | EVM mechanisms (`exact`, `exact_permit`). | -| `packages/mechanisms/tron` | TRON mechanisms (`exact`, `exact_permit`, `exact_gasfree`). | -| `packages/mechanisms/{svm,aptos,stellar}` | Non-EVM scaffolds (no production use yet). | -| `packages/extensions` | Legacy / non-core payload extensions. | -| `packages/http` | Fetch middleware + framework adapters (Express/Hono planned). | -| `packages/mcp` | MCP transport — currently stub. | -| `packages/legacy`, `packages/x402-deprecated` | Old entry points kept for backward compat. **Do not add new code here.** | - -## Conventions - -- **ESM-only.** `"type": "module"` everywhere. No CJS shims. -- **`viem` for EVM** signing / encoding. **`tronweb` for TRON** transactions; **custom TIP-712 signer** in `packages/mechanisms/tron/src/` (do not pull a new lib). -- **Address normalization**: lowercase via `viem`'s `getAddress` only where checksumming is required by the *verifier*. Otherwise lowercase string compare. TRON Base58 → hex via `packages/mechanisms/tron/src/utils.ts::addressToHex` before any typed-data signing. -- **BigInt** for all amounts. Never `number`. Serialization helpers live in `packages/x402/src/utils/`. -- **Errors**: `X402Error` subclasses from `packages/x402/src/errors.ts`. No bare `throw new Error(...)` in the pay path. -- **Tests**: `vitest`, co-located `*.test.ts` in `src/`. Snapshot only for stable wire formats (e.g. `config.test.ts`). -- **No default exports** in public API packages — named only. -- **tsconfig**: extend `tsconfig.base.json`. Don't override `strict`. - -## Publishing - -Each package is independently versioned. `@bankofai/x402` is the documented entry for end users; other packages are primarily internal but are published in case consumers want granular deps. - -## Security-critical modules - -Signing, facilitator settlement, header encoding — route changes through the `security-reviewer` subagent: - -- `packages/mechanisms/*/src/**` — anywhere you touch `signTypedData` or on-chain calls -- `packages/x402/src/http/**` — header encode/decode -- `packages/x402/src/signers/**` - -See [.claude/agents/security-reviewer.md](../.claude/agents/security-reviewer.md). diff --git a/legacy/typescript/README.md b/legacy/typescript/README.md deleted file mode 100644 index 797e963c..00000000 --- a/legacy/typescript/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# x402 TypeScript Client SDK - -TypeScript Client SDK for x402 Payment Protocol. - -## Package - -- `@bankofai/x402` - Complete TypeScript SDK with client, mechanisms, signers, and HTTP adapter - -## Installation - -```bash -# Install the package -pnpm add @bankofai/x402 tronweb -``` - -## Quick Start - -```typescript -import { X402Client, ExactPermitTronClientMechanism, TronClientSigner, X402FetchClient } from '@bankofai/x402'; - -// 1. Create signer -const signer = new TronClientSigner(process.env.TRON_PRIVATE_KEY); - -// 2. Create X402Client and register mechanisms -const x402Client = new X402Client() - .register('tron:*', new ExactPermitTronClientMechanism(signer)); - -// 3. Create HTTP client with automatic 402 handling -const client = new X402FetchClient(x402Client); - -// 4. Make requests - 402 payments handled automatically -const response = await client.get('https://api.example.com/premium-data'); -console.log(await response.json()); -``` - -## Development - -```bash -# Install dependencies -pnpm install - -# Build all packages -pnpm build - -# Run tests -pnpm test -``` - -## License - -MIT License diff --git a/legacy/typescript/package-lock.json b/legacy/typescript/package-lock.json deleted file mode 100644 index b775f978..00000000 --- a/legacy/typescript/package-lock.json +++ /dev/null @@ -1,5179 +0,0 @@ -{ - "name": "x402-typescript", - "version": "0.5.9", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "x402-typescript", - "version": "0.5.9", - "workspaces": [ - "packages/*" - ], - "devDependencies": { - "@types/node": "^20.10.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=20.0.0", - "pnpm": ">=10.0.0" - } - }, - "node_modules/@adraffy/ens-normalize": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz", - "integrity": "sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==", - "license": "MIT" - }, - "node_modules/@babel/runtime": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz", - "integrity": "sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==", - "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.26.10.tgz", - "integrity": "sha512-uITFQYO68pMEYR46AHgQoyBg7KPPJDAbGn4jUTIRgCFJIp88MIBUianVOplhZDEec07bp9zIyr4Kp0FCyQzmWg==", - "license": "MIT", - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bankofai/agent-wallet": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@bankofai/agent-wallet/-/agent-wallet-2.3.0.tgz", - "integrity": "sha512-Jezo0ffhZrsF0HQMV74wTJlLUtHoY4d7TeYbjqjkWketCqBdhiX9/90hS4qwk99QZwnbt+1HRUschOaSA1wkRw==", - "license": "MIT", - "dependencies": { - "@inquirer/prompts": "^8.3.0", - "@noble/curves": "^1.9.1", - "bs58check": "^4.0.0", - "viem": "^2.0.0", - "zod": "^3.22.0" - }, - "bin": { - "agent-wallet": "dist/delivery/bin.js" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@bankofai/agent-wallet/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/@bankofai/agent-wallet/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/@bankofai/x402": { - "resolved": "packages/x402", - "link": true - }, - "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/@ethereumjs/rlp": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-4.0.1.tgz", - "integrity": "sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==", - "license": "MPL-2.0", - "bin": { - "rlp": "bin/rlp" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/util": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.0.3.tgz", - "integrity": "sha512-0apCbwc8xAaie6W7q6QyogfyRS2BMU816a8KwpnpRw9Qrc6Bws+l7J3LfCLMt2iL6Wi8CYb0B29AeIr2N4vHnw==", - "license": "MPL-2.0", - "dependencies": { - "@ethereumjs/rlp": "^4.0.0-beta.2", - "async": "^3.2.4", - "ethereum-cryptography": "^1.1.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@ethereumjs/util/node_modules/@noble/hashes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.2.0.tgz", - "integrity": "sha512-FZfhjEDbT5GRswV3C6uvLPHMiVD6lQBmpoX5+eSiPaMTXte/IKqI5dykDxzZB/WBeK/CDuQRBWarPdi3FNY2zQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip32": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.5.tgz", - "integrity": "sha512-XyNh1rB0SkEqd3tXcXMi+Xe1fvg+kUIcoRIEujP1Jgv7DqW2r9lg3Ah0NkFaCs9sTkQAQA8kw7xiRXzENi9Rtw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.2.0", - "@noble/secp256k1": "~1.7.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@ethereumjs/util/node_modules/@scure/bip39": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.1.tgz", - "integrity": "sha512-t+wDck2rVkh65Hmv280fYdVdY25J9YeEUIgn2LG1WM6gxFkGzcksoDiUkWVpVp3Oex9xGC68JU2dSbUfwZ2jPg==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.2.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", - "integrity": "sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.2.0", - "@noble/secp256k1": "1.7.1", - "@scure/bip32": "1.1.5", - "@scure/bip39": "1.1.1" - } - }, - "node_modules/@gasfree/gasfree-sdk": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@gasfree/gasfree-sdk/-/gasfree-sdk-1.1.2.tgz", - "integrity": "sha512-EDLHaPh/z/9qn3U+DniTrsc2EZ3mQX+QIdx2V97f+53QKLaXmbv0AL5yJ15D2n+wh1Ui8Ftc7K12ZDTAlpq/hQ==", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime-corejs3": "7.26.10", - "@ethereumjs/util": "8.0.3", - "buffer": "6.0.3", - "eth-sig-util": "3.0.1", - "ethereum-cryptography": "1.1.2", - "ethereumjs-abi": "0.6.8", - "jsonschema": "1.4.1", - "tronweb": "6.1.1" - }, - "engines": { - "node": "18.19.0", - "pnpm": "7.32.0" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/@noble/hashes": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", - "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/@noble/secp256k1": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.6.3.tgz", - "integrity": "sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/@scure/bip32": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.1.0.tgz", - "integrity": "sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.1.1", - "@noble/secp256k1": "~1.6.0", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/@scure/bip39": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", - "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.1.1", - "@scure/base": "~1.1.0" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/ethereum-cryptography": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.1.2.tgz", - "integrity": "sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.1.2", - "@noble/secp256k1": "1.6.3", - "@scure/bip32": "1.1.0", - "@scure/bip39": "1.1.0" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/tronweb": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/tronweb/-/tronweb-6.1.1.tgz", - "integrity": "sha512-9i2N+cTkRY7Y1B/V0+ZVwCYZFhdFDalh8sbI8Tpj5O65hMURvjFnaP1u/dTwVnVw07d9M143/19KarxeAzK6pg==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "7.26.10", - "axios": "1.12.2", - "bignumber.js": "9.1.2", - "ethereum-cryptography": "2.2.1", - "ethers": "6.13.5", - "eventemitter3": "5.0.1", - "google-protobuf": "3.21.4", - "semver": "7.7.1", - "validator": "13.15.23" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/tronweb/node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/tronweb/node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/tronweb/node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@gasfree/gasfree-sdk/node_modules/tronweb/node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "license": "MIT", - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/@inquirer/ansi": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.4.tgz", - "integrity": "sha512-DpcZrQObd7S0R/U3bFdkcT5ebRwbTTC4D3tCc1vsJizmgPLxNJBo+AAFmrZwe8zk30P2QzgzGWZ3Q9uJwWuhIg==", - "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - } - }, - "node_modules/@inquirer/checkbox": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.1.2.tgz", - "integrity": "sha512-PubpMPO2nJgMufkoB3P2wwxNXEMUXnBIKi/ACzDUYfaoPuM7gSTmuxJeMscoLVEsR4qqrCMf5p0SiYGWnVJ8kw==", - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/core": "^11.1.7", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/confirm": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.10.tgz", - "integrity": "sha512-tiNyA73pgpQ0FQ7axqtoLUe4GDYjNCDcVsbgcA5anvwg2z6i+suEngLKKJrWKJolT//GFPZHwN30binDIHgSgQ==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/core": { - "version": "11.1.7", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.1.7.tgz", - "integrity": "sha512-1BiBNDk9btIwYIzNZpkikIHXWeNzNncJePPqwDyVMhXhD1ebqbpn1mKGctpoqAbzywZfdG0O4tvmsGIcOevAPQ==", - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4", - "cli-width": "^4.1.0", - "fast-wrap-ansi": "^0.2.0", - "mute-stream": "^3.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/editor": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.0.10.tgz", - "integrity": "sha512-VJx4XyaKea7t8hEApTw5dxeIyMtWXre2OiyJcICCRZI4hkoHsMoCnl/KbUnJJExLbH9csLLHMVR144ZhFE1CwA==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/external-editor": "^2.0.4", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/expand": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.0.10.tgz", - "integrity": "sha512-fC0UHJPXsTRvY2fObiwuQYaAnHrp3aDqfwKUJSdfpgv18QUG054ezGbaRNStk/BKD5IPijeMKWej8VV8O5Q/eQ==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/external-editor": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-2.0.4.tgz", - "integrity": "sha512-Prenuv9C1PHj2Itx0BcAOVBTonz02Hc2Nd2DbU67PdGUaqn0nPCnV34oDyyoaZHnmfRxkpuhh/u51ThkrO+RdA==", - "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.2" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/figures": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.4.tgz", - "integrity": "sha512-eLBsjlS7rPS3WEhmOmh1znQ5IsQrxWzxWDxO51e4urv+iVrSnIHbq4zqJIOiyNdYLa+BVjwOtdetcQx1lWPpiQ==", - "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - } - }, - "node_modules/@inquirer/input": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.10.tgz", - "integrity": "sha512-nvZ6qEVeX/zVtZ1dY2hTGDQpVGD3R7MYPLODPgKO8Y+RAqxkrP3i/3NwF3fZpLdaMiNuK0z2NaYIx9tPwiSegQ==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/number": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.0.10.tgz", - "integrity": "sha512-Ht8OQstxiS3APMGjHV0aYAjRAysidWdwurWEo2i8yI5xbhOBWqizT0+MU1S2GCcuhIBg+3SgWVjEoXgfhY+XaA==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/password": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.0.10.tgz", - "integrity": "sha512-QbNyvIE8q2GTqKLYSsA8ATG+eETo+m31DSR0+AU7x3d2FhaTWzqQek80dj3JGTo743kQc6mhBR0erMjYw5jQ0A==", - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/prompts": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.3.2.tgz", - "integrity": "sha512-yFroiSj2iiBFlm59amdTvAcQFvWS6ph5oKESls/uqPBect7rTU2GbjyZO2DqxMGuIwVA8z0P4K6ViPcd/cp+0w==", - "license": "MIT", - "dependencies": { - "@inquirer/checkbox": "^5.1.2", - "@inquirer/confirm": "^6.0.10", - "@inquirer/editor": "^5.0.10", - "@inquirer/expand": "^5.0.10", - "@inquirer/input": "^5.0.10", - "@inquirer/number": "^4.0.10", - "@inquirer/password": "^5.0.10", - "@inquirer/rawlist": "^5.2.6", - "@inquirer/search": "^4.1.6", - "@inquirer/select": "^5.1.2" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/rawlist": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.2.6.tgz", - "integrity": "sha512-jfw0MLJ5TilNsa9zlJ6nmRM0ZFVZhhTICt4/6CU2Dv1ndY7l3sqqo1gIYZyMMDw0LvE1u1nzJNisfHEhJIxq5w==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/search": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.6.tgz", - "integrity": "sha512-3/6kTRae98hhDevENScy7cdFEuURnSpM3JbBNg8yfXLw88HgTOl+neUuy/l9W0No5NzGsLVydhBzTIxZP7yChQ==", - "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.1.7", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/select": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.1.2.tgz", - "integrity": "sha512-kTK8YIkHV+f02y7bWCh7E0u2/11lul5WepVTclr3UMBtBr05PgcZNWfMa7FY57ihpQFQH/spLMHTcr0rXy50tA==", - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.4", - "@inquirer/core": "^11.1.7", - "@inquirer/figures": "^2.0.4", - "@inquirer/type": "^4.0.4" - }, - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/type": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.4.tgz", - "integrity": "sha512-PamArxO3cFJZoOzspzo6cxVlLeIftyBsZw/S9bKY5DzxqJVZgjoj1oP8d0rskKtp7sZxBycsoer1g6UeJV1BBA==", - "license": "MIT", - "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.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/@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.4.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", - "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.4.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/secp256k1": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", - "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@scure/base": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.9.tgz", - "integrity": "sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==", - "license": "MIT", - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip32": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", - "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@noble/curves": "~1.4.0", - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@scure/bip39": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", - "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@noble/hashes": "~1.4.0", - "@scure/base": "~1.1.6" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.10", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", - "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/express": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.6.tgz", - "integrity": "sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^5.0.0", - "@types/serve-static": "^2" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", - "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.19.32", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.32.tgz", - "integrity": "sha512-Ez8QE4DMfhjjTsES9K2dwfV258qBui7qxUsoaixZDiTzbde4U12e1pXGNu/ECsUIOi5/zoCxAQxIhQnaUQ2VvA==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/secp256k1": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.7.tgz", - "integrity": "sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*" - } - }, - "node_modules/@vitest/expect": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", - "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", - "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "1.6.1", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", - "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", - "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", - "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "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/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/accepts/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.5", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", - "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/aes-js": { - "version": "4.0.0-beta.5", - "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", - "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==", - "license": "MIT" - }, - "node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/async": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", - "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", - "license": "MIT" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", - "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/base-x": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", - "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", - "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/blakejs": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", - "license": "MIT" - }, - "node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", - "license": "MIT" - }, - "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", - "license": "MIT" - }, - "node_modules/browserify-aes": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", - "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", - "license": "MIT", - "dependencies": { - "buffer-xor": "^1.0.3", - "cipher-base": "^1.0.0", - "create-hash": "^1.1.0", - "evp_bytestokey": "^1.0.3", - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/bs58": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", - "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", - "license": "MIT", - "dependencies": { - "base-x": "^5.0.0" - } - }, - "node_modules/bs58check": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", - "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "^1.2.0", - "bs58": "^6.0.0" - } - }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", - "license": "MIT" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chardet": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz", - "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==", - "license": "MIT" - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/cipher-base": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", - "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", - "license": "ISC", - "engines": { - "node": ">= 12" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/core-js-pure": { - "version": "3.49.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.49.0.tgz", - "integrity": "sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" - }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, - "node_modules/create-hmac": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", - "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", - "license": "MIT", - "dependencies": { - "cipher-base": "^1.0.3", - "create-hash": "^1.1.0", - "inherits": "^2.0.1", - "ripemd160": "^2.0.0", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/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/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/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/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eth-sig-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-3.0.1.tgz", - "integrity": "sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==", - "deprecated": "Deprecated in favor of '@metamask/eth-sig-util'", - "license": "ISC", - "dependencies": { - "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^5.1.1", - "tweetnacl": "^1.0.3", - "tweetnacl-util": "^0.15.0" - } - }, - "node_modules/ethereum-cryptography": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", - "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@noble/curves": "1.4.2", - "@noble/hashes": "1.4.0", - "@scure/bip32": "1.4.0", - "@scure/bip39": "1.3.0" - } - }, - "node_modules/ethereumjs-abi": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", - "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", - "deprecated": "This library has been deprecated and usage is discouraged.", - "license": "MIT", - "dependencies": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - } - }, - "node_modules/ethereumjs-abi/node_modules/base-x": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", - "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ethereumjs-abi/node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "license": "MIT", - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/ethereumjs-abi/node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "license": "MIT", - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/ethereumjs-abi/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "license": "MIT", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "license": "MPL-2.0", - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/ethereumjs-util": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.1.tgz", - "integrity": "sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==", - "license": "MPL-2.0", - "dependencies": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "^0.1.3", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/ethereumjs-util/node_modules/base-x": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", - "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ethereumjs-util/node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", - "license": "MIT", - "dependencies": { - "base-x": "^3.0.2" - } - }, - "node_modules/ethereumjs-util/node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", - "license": "MIT", - "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "license": "MIT", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/ethers": { - "version": "6.13.5", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.5.tgz", - "integrity": "sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==", - "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.10.1", - "@noble/curves": "1.2.0", - "@noble/hashes": "1.3.2", - "@types/node": "22.7.5", - "aes-js": "4.0.0-beta.5", - "tslib": "2.7.0", - "ws": "8.17.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/ethers/node_modules/@noble/curves": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", - "integrity": "sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.2" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@noble/hashes": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", - "integrity": "sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ethers/node_modules/@types/node": { - "version": "22.7.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz", - "integrity": "sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/ethers/node_modules/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/ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "license": "MIT", - "dependencies": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "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/evp_bytestokey": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", - "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", - "license": "MIT", - "dependencies": { - "md5.js": "^1.3.4", - "safe-buffer": "^5.1.1" - } - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/fast-string-truncated-width": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", - "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", - "license": "MIT" - }, - "node_modules/fast-string-width": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", - "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", - "license": "MIT", - "dependencies": { - "fast-string-truncated-width": "^3.0.2" - } - }, - "node_modules/fast-wrap-ansi": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", - "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", - "license": "MIT", - "dependencies": { - "fast-string-width": "^3.0.2" - } - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-protobuf": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.4.tgz", - "integrity": "sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==", - "license": "(BSD-3-Clause AND Apache-2.0)" - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hash-base": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "license": "MIT", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, - "node_modules/hono": { - "version": "4.12.18", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.18.tgz", - "integrity": "sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-hex-prefixed": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", - "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", - "license": "MIT", - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/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/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsonschema": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", - "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/keccak": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", - "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^2.0.0", - "node-gyp-build": "^4.2.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/keccak/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/local-pkg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", - "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mlly": "^1.7.3", - "pkg-types": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "license": "ISC" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", - "license": "MIT" - }, - "node_modules/mlly": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.1.tgz", - "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.16.0", - "pathe": "^2.0.3", - "pkg-types": "^1.3.1", - "ufo": "^1.6.3" - } - }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "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/mute-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", - "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", - "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==", - "license": "MIT" - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "license": "MIT", - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ox": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/ox/-/ox-0.14.5.tgz", - "integrity": "sha512-HgmHmBveYO40H/R3K6TMrwYtHsx/u6TAB+GpZlgJCoW0Sq5Ttpjih0IZZiwGQw7T6vdW4IAyobYrE2mdAvyF8Q==", - "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/@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/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/ox/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/ox/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/ox/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/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", - "license": "MIT", - "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "license": "MIT", - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readable-stream/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, - "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", - "license": "MIT", - "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/rlp": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", - "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", - "license": "MPL-2.0", - "dependencies": { - "bn.js": "^5.2.0" - }, - "bin": { - "rlp": "bin/rlp" - } - }, - "node_modules/rlp/node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", - "license": "MIT" - }, - "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/scrypt-js": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", - "license": "MIT" - }, - "node_modules/secp256k1": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz", - "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "elliptic": "^6.5.7", - "node-addon-api": "^5.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/secp256k1/node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/send/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/send/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", - "license": "(MIT AND BSD-3-Clause)", - "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" - }, - "bin": { - "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-hex-prefix": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", - "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", - "license": "MIT", - "dependencies": { - "is-hex-prefixed": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, - "node_modules/strip-literal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", - "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-buffer/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "license": "MIT" - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tronweb": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tronweb/-/tronweb-6.2.0.tgz", - "integrity": "sha512-09kyW6mqiFuSYXkR35ndxCeNF5rW1O18hKAClCLtVHP2xBFPYSGx3lDYC2hRKcuLiq6iLPxOVCrhzoKNGlFuQQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/runtime": "7.26.10", - "axios": "1.12.2", - "bignumber.js": "9.1.2", - "ethereum-cryptography": "2.2.1", - "ethers": "6.13.5", - "eventemitter3": "5.0.1", - "google-protobuf": "3.21.4", - "semver": "7.7.1", - "validator": "13.15.23" - } - }, - "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/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", - "license": "Unlicense" - }, - "node_modules/tweetnacl-util": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", - "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", - "license": "Unlicense" - }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/type-is/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "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==", - "license": "MIT" - }, - "node_modules/validator": { - "version": "13.15.23", - "resolved": "https://registry.npmjs.org/validator/-/validator-13.15.23.tgz", - "integrity": "sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/viem": { - "version": "2.47.5", - "resolved": "https://registry.npmjs.org/viem/-/viem-2.47.5.tgz", - "integrity": "sha512-nVrJEQ8GL4JoVIrMBF3wwpTUZun0cpojfnOZ+96GtDWhqxZkVdy6vOEgu+jwfXqfTA/+wrR+YsN9TBQmhDUk0g==", - "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.5", - "ws": "8.18.3" - }, - "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/@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/viem/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/viem/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/viem/node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "license": "MIT", - "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/vite-node": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", - "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vitest": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", - "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "1.6.1", - "@vitest/runner": "1.6.1", - "@vitest/snapshot": "1.6.1", - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.1", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.1", - "@vitest/ui": "1.6.1", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", - "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yocto-queue": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", - "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "packages/x402": { - "name": "@bankofai/x402", - "version": "0.6.0", - "license": "MIT", - "dependencies": { - "@bankofai/agent-wallet": "^2.3.0", - "@gasfree/gasfree-sdk": "^1.1.2", - "viem": "^2.45.2" - }, - "devDependencies": { - "@types/express": "^5.0.6", - "@types/node": "^20.10.0", - "express": "^5.2.1", - "hono": "^4.12.18", - "typescript": "^5.3.0", - "vitest": "^1.6.1" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "express": "^4.0.0 || ^5.0.0", - "hono": "^4.0.0", - "tronweb": "^5.0.0 || ^6.0.0" - }, - "peerDependenciesMeta": { - "express": { - "optional": true - }, - "hono": { - "optional": true - } - } - } - } -} diff --git a/legacy/typescript/package.json b/legacy/typescript/package.json deleted file mode 100644 index dfd99e7a..00000000 --- a/legacy/typescript/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "x402-typescript", - "version": "0.5.9", - "private": true, - "description": "x402 TypeScript Client SDK", - "workspaces": [ - "packages/*" - ], - "scripts": { - "build": "pnpm -r build", - "test": "pnpm -r test", - "lint": "pnpm -r --if-present lint", - "clean": "pnpm -r clean" - }, - "devDependencies": { - "@types/node": "^20.10.0", - "typescript": "^5.3.0" - }, - "engines": { - "node": ">=20.0.0", - "pnpm": ">=10.0.0" - } -} diff --git a/legacy/typescript/packages/x402/CLAUDE.md b/legacy/typescript/packages/x402/CLAUDE.md deleted file mode 100644 index 62cda8b0..00000000 --- a/legacy/typescript/packages/x402/CLAUDE.md +++ /dev/null @@ -1,43 +0,0 @@ -# @bankofai/x402 - -Public TypeScript SDK entry point. Re-exports from sibling workspace packages (`mechanisms/*`, `extensions`, `core`). - -## Build & test - -```bash -pnpm build # tsc -pnpm test # vitest run -pnpm clean # rm -rf dist -``` - -## Layout - -``` -src/ -├── index.ts — public surface; keep additions minimal, re-export only -├── config.ts — network + contract registry (mirrors specs/config.md) -├── config.test.ts — wire-format snapshot; update when adding networks -├── abi.ts — ERC-3009 + EIP-2612 + GasFreeController ABIs -├── address.ts — address normalization helpers -├── tokens.ts — token metadata registry -├── errors.ts — X402Error hierarchy -├── types/ — protocol types (PaymentRequired, PaymentPayload, PaymentResponse) -├── http/ — header encode/decode, fetch middleware -├── client/ — client-side retry-with-payment loop -├── mechanisms/ — re-exports from ../mechanisms/* -├── signers/ — account abstractions (wraps agent-wallet) -└── utils/ — hex, base64, address conversion -``` - -## Rules for this package - -- **Public surface is precious.** Additions to `index.ts` require a corresponding doc update in `specs/` (if a new wire-format field) and ideally a unit test. Prefer re-export over re-implement. -- **No direct imports from `dist/`**, even in tests. Import from `./src/...` or from the package name. -- **`config.ts` is the single source of truth for network identifiers.** Do not hardcode chain IDs or contract addresses elsewhere in this package. -- **Snapshot tests in `config.test.ts`** will fail if the registry changes — this is intentional. Update the snapshot in the same commit that changes the registry. - -## Dependencies - -- `viem` for EVM typed-data signing -- `@gasfree/gasfree-sdk` for TRON GasFree API calls -- `@bankofai/agent-wallet` for signer abstraction (keeps wallet concerns out of this package) diff --git a/legacy/typescript/packages/x402/README.md b/legacy/typescript/packages/x402/README.md deleted file mode 100644 index e4966941..00000000 --- a/legacy/typescript/packages/x402/README.md +++ /dev/null @@ -1,365 +0,0 @@ -# @bankofai/x402 - -TypeScript SDK for the x402 payment protocol. Supports TRON and EVM (BSC) networks with automatic HTTP 402 payment handling. - -Current release: `@bankofai/x402@0.6.1`. This release keeps TypeScript client, server, and facilitator parity with the Python SDK for `exact`, `exact_permit`, and `exact_gasfree` verify/settle flows. - -## Compatibility Notes - -- The EVM `exact` flow is being aligned to the Coinbase x402 v2 payload shape. -- Exact transfer authorizations are emitted in `payload.authorization`. -- Migration fallback support for the legacy `extensions.transferAuthorization` field remains on the server side while compatibility is rolled out. - -## Features - -- 🔐 **Automatic Payment Handling** - Transparently handles HTTP 402 Payment Required responses -- ⛓️ **Multi-Chain** - TRON (Mainnet, Nile, Shasta) and EVM/BSC (Mainnet, Testnet) -- 🔑 **TIP-712 / EIP-712 Signing** - Secure cryptographic signatures -- 💰 **GasFree Support** - Pay with USDT/USDD on TRON without holding TRX for gas -- 🚀 **Simple Integration** - Just 3 lines of code to get started -- 📦 **Lightweight** - Minimal dependencies (`tronweb` for TRON, `viem` for EVM) - -## Installation - -```bash -npm i @bankofai/x402@0.6.1 tronweb -``` - -## Quick Start - -```typescript -import { - X402Client, - X402FetchClient, - ExactPermitTronClientMechanism, - TronClientSigner, -} from '@bankofai/x402'; - -// 1. Create signer and register payment mechanism -const signer = new TronClientSigner(process.env.TRON_PRIVATE_KEY); -const x402Client = new X402Client().register('tron:*', new ExactPermitTronClientMechanism(signer)); - -// 2. Create HTTP client with automatic 402 handling -const client = new X402FetchClient(x402Client); - -// 3. Make requests - payments are handled automatically! -const response = await client.get('https://api.example.com/premium-data'); -const data = await response.json(); -console.log(data); -``` - -## BSC Testnet Example - -For a smoke-tested BSC testnet `exact` example that uses a local private key and targets the Coinbase-compatible `exact` route, see [`examples/bsc-testnet-smoke/README.md`](../../../examples/bsc-testnet-smoke/README.md). - -The BSC `exact` path in this repository is aligned around ERC-3009. On testnet, the validated asset is `DHLU`, not generic USDT/USDC permit-only flows. - -## Core Concepts - -### Payment Flow - -When you make a request to a protected resource: - -1. **First Request** - Server responds with `402 Payment Required` and payment requirements -2. **Payment Creation** - SDK automatically creates and signs a payment permit -3. **Token Approval** - SDK ensures sufficient token allowance (if needed) -4. **Retry with Payment** - Request is retried with payment signature -5. **Success** - Server validates payment and returns the protected resource - -### Components - -- **`X402Client`** - Core payment client that manages payment mechanisms -- **`X402FetchClient`** - HTTP client wrapper with automatic 402 handling -- **`TronClientSigner`** / **`EvmClientSigner`** - Sign payment permits using TIP-712 / EIP-712 -- **`ExactPermitTronClientMechanism`** - Implements the "exact_permit" payment scheme for TRON -- **`ExactGasFreeClientMechanism`** - Implements the "exact_gasfree" scheme (no TRX gas needed) - -## API Reference - -### X402Client - -Core client for managing payment mechanisms. - -```typescript -const x402Client = new X402Client(); -``` - -#### Methods - -##### `register(networkPattern: string, mechanism: ClientMechanism): X402Client` - -Register a payment mechanism for a network pattern. - -```typescript -x402Client.register('tron:*', new ExactPermitTronClientMechanism(signer)); -x402Client.register('tron:nile', new ExactPermitTronClientMechanism(nileSigner)); -``` - -##### `selectPaymentRequirements(accepts: PaymentRequirements[], filters?: PaymentRequirementsFilter): PaymentRequirements` - -Select payment requirements from available options. - -```typescript -const selected = x402Client.selectPaymentRequirements(accepts, { - network: 'tron:nile', - maxAmount: '1000000', -}); -``` - -##### `createPaymentPayload(requirements: PaymentRequirements, resource: string, extensions?: object): Promise` - -Create a payment payload for the given requirements. - -```typescript -const payload = await x402Client.createPaymentPayload(requirements, '/api/data', extensions); -``` - -### X402FetchClient - -HTTP client with automatic 402 payment handling. - -```typescript -const client = new X402FetchClient(x402Client, selector?); -``` - -#### Methods - -##### `get(url: string, init?: RequestInit): Promise` - -Make a GET request with automatic payment handling. - -```typescript -const response = await client.get('https://api.example.com/data'); -``` - -##### `post(url: string, body?: RequestInit['body'], init?: RequestInit): Promise` - -Make a POST request with automatic payment handling. - -```typescript -const response = await client.post('https://api.example.com/data', JSON.stringify({ key: 'value' })); -``` - -##### `request(url: string, init?: RequestInit): Promise` - -Make any HTTP request with automatic payment handling. - -```typescript -const response = await client.request('https://api.example.com/data', { - method: 'PUT', - body: JSON.stringify({ key: 'value' }), -}); -``` - -### TronClientSigner - -Signer for creating payment permits using TIP-712. - -```typescript -const signer = new TronClientSigner(privateKey); -``` - -#### Instance Methods - -##### `getAddress(): string` - -Get the signer's TRON address (Base58 format). - -```typescript -const address = signer.getAddress(); // "TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf" -``` - -##### `checkAllowance(token: string, amount: bigint, network: string): Promise` - -Check current token allowance for the payment permit contract. - -```typescript -const allowance = await signer.checkAllowance(tokenAddress, BigInt(1000000), 'tron:nile'); -``` - -##### `ensureAllowance(token: string, amount: bigint, network: string, mode?: 'auto' | 'interactive' | 'skip'): Promise` - -Ensure sufficient token allowance, approving if necessary. - -```typescript -await signer.ensureAllowance(tokenAddress, BigInt(1000000), 'tron:nile', 'auto'); -``` - -### EvmClientSigner - -Signer for creating payment permits using EIP-712 (BSC and other EVM networks). - -```typescript -const signer = new EvmClientSigner(privateKey); -``` - -### ExactPermitTronClientMechanism - -Payment mechanism implementing the "exact_permit" scheme for TRON. - -```typescript -const mechanism = new ExactPermitTronClientMechanism(signer); -``` - -### ExactGasFreeClientMechanism - -Payment mechanism implementing the "exact_gasfree" scheme for TRON (no TRX gas needed). - -```typescript -const mechanism = new ExactGasFreeClientMechanism(signer); -``` - -## Usage Examples - -### Basic Usage with Automatic Payment - -```typescript -import { X402Client, X402FetchClient, ExactPermitTronClientMechanism, TronClientSigner } from '@bankofai/x402'; - -const signer = new TronClientSigner(process.env.TRON_PRIVATE_KEY); -const x402Client = new X402Client().register('tron:*', new ExactPermitTronClientMechanism(signer)); -const client = new X402FetchClient(x402Client); - -// Automatic payment handling -const response = await client.get('https://api.example.com/weather'); -const weather = await response.json(); -console.log(weather); -``` - -### Manual Payment Handling - -```typescript -import { X402Client, ExactPermitTronClientMechanism, TronClientSigner, encodePaymentPayload } from '@bankofai/x402'; - -const signer = new TronClientSigner(process.env.TRON_PRIVATE_KEY); -const x402Client = new X402Client().register('tron:*', new ExactPermitTronClientMechanism(signer)); - -// First request -const response = await fetch('https://api.example.com/data'); - -if (response.status === 402) { - // Parse payment requirements - const paymentRequired = await response.json(); - - // Create payment payload - const payload = await x402Client.createPaymentPayload( - paymentRequired.accepts[0], - '/data', - paymentRequired.extensions - ); - - // Retry with payment - const paidResponse = await fetch('https://api.example.com/data', { - headers: { - 'PAYMENT-SIGNATURE': encodePaymentPayload(payload), - }, - }); - - const data = await paidResponse.json(); - console.log(data); -} -``` - -### Custom Payment Selection - -```typescript -import { X402Client, X402FetchClient, ExactPermitTronClientMechanism, TronClientSigner } from '@bankofai/x402'; - -// Custom selector function -const selector = (requirements) => { - // Choose the cheapest option - return requirements.sort((a, b) => BigInt(a.amount) - BigInt(b.amount))[0]; -}; - -const client = new X402FetchClient(x402Client, selector); -const response = await client.get('https://api.example.com/data'); -``` - -### GasFree Usage (No TRX Gas Needed) - -```typescript -import { X402Client, X402FetchClient, ExactGasFreeClientMechanism, TronClientSigner } from '@bankofai/x402'; - -const signer = new TronClientSigner(process.env.TRON_PRIVATE_KEY); -const x402Client = new X402Client().register('tron:*', new ExactGasFreeClientMechanism(signer)); -const client = new X402FetchClient(x402Client); - -// Pay with USDT/USDD without holding TRX -const response = await client.get('https://api.example.com/premium-content'); -``` - -### Multiple Networks - -```typescript -// Support multiple TRON networks -const nileClient = new X402Client() - .register('tron:nile', new ExactPermitTronClientMechanism(nileSigner)) - .register('tron:shasta', new ExactPermitTronClientMechanism(shastaSigner)) - .register('tron:mainnet', new ExactPermitTronClientMechanism(mainnetSigner)); -``` - -## Supported Networks - -- **TRON Mainnet** - `tron:mainnet` -- **TRON Shasta Testnet** - `tron:shasta` -- **TRON Nile Testnet** - `tron:nile` -- **BSC Mainnet** - `eip155:56` -- **BSC Testnet** - `eip155:97` - -## Payment Schemes - -### Exact Permit Scheme (`exact_permit`) - -The standard x402 payment scheme using TIP-712/EIP-712 permits. Requires a pre-deployed `PaymentPermit` contract on the network. - -### GasFree Scheme (`exact_gasfree`) - -Allows users to pay using TRC-20 tokens (USDT/USDD) without holding any TRX for gas. - -- **Accountless**: Uses the official GasFree HTTP Proxy for settlement. -- **Dynamic**: Automatically discovers available service providers. -- **Status Tracking**: Built-in polling for transaction confirmation. - -### Exact Scheme (`exact`) - -Direct payment scheme using ERC-3009 (`TransferWithAuthorization`) where supported by the token contract (primarily for EVM networks like BSC). - -For BSC testnet interoperability, treat token choice as part of the protocol contract. If the endpoint advertises `exact`, the asset must actually implement ERC-3009. The smoke-tested example in this repository uses `DHLU` on `eip155:97`. - -## Security - -- **Never commit private keys** - Use environment variables -- **TIP-712 signatures** - Cryptographically secure payment permits -- **Token allowances** - Explicit approval required before payments -- **Trust-minimizing** - Facilitator cannot move funds outside client authorization - -## Troubleshooting - -### "TronWeb does not support signTypedData" - -Upgrade to TronWeb >= 5.0: - -```bash -npm i tronweb@latest -``` - -### "No mechanism registered for network" - -Ensure you've registered a mechanism for the network: - -```typescript -x402Client.register('tron:nile', new ExactPermitTronClientMechanism(signer)); -``` - -## Links - -- **Repository**: https://github.com/BofAI/x402 -- **Issues**: https://github.com/BofAI/x402/issues -- **Contributing**: https://github.com/BofAI/CONTRIBUTING.md -- **Documentation**: https://docs.bankofai.io/ -- **TRON Documentation**: https://developers.tron.network/ -- **TIP-712 Specification**: https://github.com/tronprotocol/tips/blob/master/tip-712.md - -## License - -MIT diff --git a/legacy/typescript/packages/x402/package.json b/legacy/typescript/packages/x402/package.json deleted file mode 100644 index 42446745..00000000 --- a/legacy/typescript/packages/x402/package.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "name": "@bankofai/x402", - "version": "0.6.1", - "description": "x402 TypeScript SDK (TRON and EVM support)", - "keywords": [ - "x402", - "tron", - "trx", - "ethereum", - "evm", - "payment", - "blockchain" - ], - "homepage": "https://github.com/BofAI/x402#readme", - "bugs": { - "url": "https://github.com/BofAI/x402/issues" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/BofAI/x402.git", - "directory": "typescript/packages/x402" - }, - "engines": { - "node": ">=20.0.0" - }, - "type": "module", - "main": "./dist/index.js", - "module": "./dist/index.js", - "types": "./dist/index.d.ts", - "dependencies": { - "@bankofai/agent-wallet": "^2.3.0", - "@gasfree/gasfree-sdk": "^1.1.2", - "viem": "^2.45.2" - }, - "exports": { - ".": { - "import": "./dist/index.js", - "types": "./dist/index.d.ts" - } - }, - "files": [ - "dist", - "README.md" - ], - "scripts": { - "build": "tsc", - "clean": "rm -rf dist", - "test": "vitest run" - }, - "peerDependencies": { - "tronweb": "^5.0.0 || ^6.0.0", - "hono": "^4.0.0", - "express": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "hono": { - "optional": true - }, - "express": { - "optional": true - } - }, - "devDependencies": { - "@types/express": "^5.0.6", - "@types/node": "^20.10.0", - "express": "^5.2.1", - "hono": "^4.12.18", - "typescript": "^5.3.0", - "vitest": "^1.6.1" - }, - "publishConfig": { - "access": "public" - }, - "license": "MIT" -} diff --git a/legacy/typescript/packages/x402/src/abi.ts b/legacy/typescript/packages/x402/src/abi.ts deleted file mode 100644 index 3cac6c9c..00000000 --- a/legacy/typescript/packages/x402/src/abi.ts +++ /dev/null @@ -1,207 +0,0 @@ -/** - * ABI and EIP-712 type definitions for x402 protocol - * Shared across all mechanisms - */ - -import type { DeliveryKind } from './types/payment.js'; - -/** EIP-712 Primary Type for PaymentPermit */ -export const PAYMENT_PERMIT_PRIMARY_TYPE = 'PaymentPermitDetails'; - -/** EIP-712 Primary Type for GasFree */ -export const GASFREE_PRIMARY_TYPE = 'PermitTransfer'; - -/** - * EIP-712 Domain Type for PaymentPermit - */ -export const PAYMENT_PERMIT_EIP712_DOMAIN_TYPE = [ - { name: 'name', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, -] as const; - -/** - * EIP-712 Domain Type for GasFree - */ -export const GASFREE_DOMAIN_TYPE = [ - { name: 'name', type: 'string' }, - { name: 'version', type: 'string' }, - { name: 'chainId', type: 'uint256' }, - { name: 'verifyingContract', type: 'address' }, -] as const; - -/** - * EIP-712 type definitions for PaymentPermit - * Based on PermitHash.sol from the contract - */ -export const PAYMENT_PERMIT_TYPES = { - PermitMeta: [ - { name: 'kind', type: 'uint8' }, - { name: 'paymentId', type: 'bytes16' }, - { name: 'nonce', type: 'uint256' }, - { name: 'validAfter', type: 'uint256' }, - { name: 'validBefore', type: 'uint256' }, - ], - Payment: [ - { name: 'payToken', type: 'address' }, - { name: 'payAmount', type: 'uint256' }, - { name: 'payTo', type: 'address' }, - ], - Fee: [ - { name: 'feeTo', type: 'address' }, - { name: 'feeAmount', type: 'uint256' }, - ], - PaymentPermitDetails: [ - { name: 'meta', type: 'PermitMeta' }, - { name: 'buyer', type: 'address' }, - { name: 'caller', type: 'address' }, - { name: 'payment', type: 'Payment' }, - { name: 'fee', type: 'Fee' }, - ], -} as const; - -/** Kind mapping for EIP-712 (string to numeric) */ -export const KIND_MAP: Record = { - PAYMENT_ONLY: 0, -}; - -/** ERC20 ABI for allowance/approve calls */ -export const ERC20_ABI = [ - { - name: 'allowance', - type: 'function', - stateMutability: 'view', - inputs: [ - { name: 'owner', type: 'address' }, - { name: 'spender', type: 'address' }, - ], - outputs: [{ name: '', type: 'uint256' }], - }, - { - name: 'approve', - type: 'function', - stateMutability: 'nonpayable', - inputs: [ - { name: 'spender', type: 'address' }, - { name: 'amount', type: 'uint256' }, - ], - outputs: [{ name: '', type: 'bool' }], - }, - { - name: 'balanceOf', - type: 'function', - stateMutability: 'view', - inputs: [{ name: 'account', type: 'address' }], - outputs: [{ name: '', type: 'uint256' }], - }, -] as const; - -/** - * PaymentPermit contract ABI (subset used by facilitator settlement). - * - * Mirrors Python `bankofai.x402.abi.PAYMENT_PERMIT_ABI`. Only the methods - * actually called by the facilitator are included; the on-chain contract - * exposes more (DOMAIN_SEPARATOR, nonceBitmap, nonceUsed) that we surface - * here in case TS callers need them too. - */ -export const PAYMENT_PERMIT_ABI = [ - { - name: 'permitTransferFrom', - type: 'function', - stateMutability: 'nonpayable', - inputs: [ - { - name: 'permit', - type: 'tuple', - components: [ - { - name: 'meta', - type: 'tuple', - components: [ - { name: 'kind', type: 'uint8' }, - { name: 'paymentId', type: 'bytes16' }, - { name: 'nonce', type: 'uint256' }, - { name: 'validAfter', type: 'uint256' }, - { name: 'validBefore', type: 'uint256' }, - ], - }, - { name: 'buyer', type: 'address' }, - { name: 'caller', type: 'address' }, - { - name: 'payment', - type: 'tuple', - components: [ - { name: 'payToken', type: 'address' }, - { name: 'payAmount', type: 'uint256' }, - { name: 'payTo', type: 'address' }, - ], - }, - { - name: 'fee', - type: 'tuple', - components: [ - { name: 'feeTo', type: 'address' }, - { name: 'feeAmount', type: 'uint256' }, - ], - }, - ], - }, - { name: 'owner', type: 'address' }, - { name: 'signature', type: 'bytes' }, - ], - outputs: [], - }, - { - name: 'DOMAIN_SEPARATOR', - type: 'function', - stateMutability: 'view', - inputs: [], - outputs: [{ name: '', type: 'bytes32' }], - }, - { - name: 'nonceUsed', - type: 'function', - stateMutability: 'view', - inputs: [ - { name: 'owner', type: 'address' }, - { name: 'nonce', type: 'uint256' }, - ], - outputs: [{ name: '', type: 'bool' }], - }, -] as const; - -/** - * ERC-3009 `transferWithAuthorization` ABI (v, r, s variant). - * - * Mirrors Python `bankofai.x402.mechanisms._exact_base.types.TRANSFER_WITH_AUTHORIZATION_ABI`. - * Used by `exact` scheme facilitator settle. - */ -export const TRANSFER_WITH_AUTHORIZATION_ABI = [ - { - name: 'transferWithAuthorization', - type: 'function', - stateMutability: 'nonpayable', - inputs: [ - { name: 'from', type: 'address' }, - { name: 'to', type: 'address' }, - { name: 'value', type: 'uint256' }, - { name: 'validAfter', type: 'uint256' }, - { name: 'validBefore', type: 'uint256' }, - { name: 'nonce', type: 'bytes32' }, - { name: 'v', type: 'uint8' }, - { name: 'r', type: 'bytes32' }, - { name: 's', type: 'bytes32' }, - ], - outputs: [], - }, - { - name: 'authorizationState', - type: 'function', - stateMutability: 'view', - inputs: [ - { name: 'authorizer', type: 'address' }, - { name: 'nonce', type: 'bytes32' }, - ], - outputs: [{ name: '', type: 'bool' }], - }, -] as const; diff --git a/legacy/typescript/packages/x402/src/address.ts b/legacy/typescript/packages/x402/src/address.ts deleted file mode 100644 index 75b1ae7c..00000000 --- a/legacy/typescript/packages/x402/src/address.ts +++ /dev/null @@ -1,193 +0,0 @@ -/** - * Address conversion utilities for x402 protocol - * Handles conversion between TRON Base58 and EVM hex formats - */ - -/** Hex address type */ -export type Hex = `0x${string}`; - -/** Base58 alphabet for TRON addresses */ -const BASE58_ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'; - -/** Zero address in EVM hex format */ -export const ZERO_ADDRESS_HEX: Hex = '0x0000000000000000000000000000000000000000'; - -/** - * Address converter interface - */ -export interface AddressConverter { - /** Normalize address to canonical format */ - normalize(address: string): string; - /** Convert to EVM hex format (0x...) */ - toEvmFormat(address: string): Hex; - /** Get zero address for this network type */ - getZeroAddress(): string; - /** Convert all addresses in a message object */ - convertMessageAddresses(message: Record): Record; -} - -/** - * EVM address converter (passthrough) - */ -export class EvmAddressConverter implements AddressConverter { - normalize(address: string): string { - return address.toLowerCase(); - } - - toEvmFormat(address: string): Hex { - if (!address.startsWith('0x')) { - return `0x${address}` as Hex; - } - return address as Hex; - } - - getZeroAddress(): string { - return ZERO_ADDRESS_HEX; - } - - convertMessageAddresses(message: Record): Record { - // EVM addresses are already in correct format - return message; - } -} - -/** - * TRON address converter - */ -export class TronAddressConverter implements AddressConverter { - normalize(address: string): string { - // Return as-is for TRON (Base58 format) - return address; - } - - toEvmFormat(address: string): Hex { - return toEvmHex(address); - } - - getZeroAddress(): string { - return 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb'; - } - - convertMessageAddresses(message: Record): Record { - const result: Record = {}; - - for (const [key, value] of Object.entries(message)) { - if (typeof value === 'string' && this.isAddress(value)) { - result[key] = this.toEvmFormat(value); - } else if (typeof value === 'object' && value !== null && !Array.isArray(value)) { - result[key] = this.convertMessageAddresses(value as Record); - } else { - result[key] = value; - } - } - - return result; - } - - private isAddress(value: string): boolean { - // TRON Base58 address starts with T - if (value.startsWith('T') && value.length === 34) return true; - // TRON hex address starts with 41 - if (value.startsWith('41') && value.length === 42) return true; - // EVM hex address - if (value.startsWith('0x') && value.length === 42) return true; - return false; - } -} - -/** - * Convert TRON address to EVM hex format (0x...) - * Handles: Base58 (T...), hex with 41 prefix, and 0x format - */ -export function toEvmHex(addr: string): Hex { - // Handle null/undefined/empty - if (!addr) { - return ZERO_ADDRESS_HEX; - } - - // Already 0x hex format - if (addr.startsWith('0x')) { - return addr as Hex; - } - - // Handle special case: T followed by all zeros (invalid Base58 placeholder) - if (addr.startsWith('T') && /^T0+$/.test(addr)) { - return ZERO_ADDRESS_HEX; - } - - // Raw hex (all hex characters, no prefix) - check this BEFORE Base58 - if (/^[0-9a-fA-F]+$/.test(addr)) { - // If starts with 41 and is 42 chars, it's TRON hex format - if (addr.startsWith('41') && addr.length === 42) { - const body = addr.slice(2); - return `0x${body}` as Hex; - } - // Otherwise treat as raw hex - const body = addr.slice(-40).padStart(40, '0'); - return `0x${body}` as Hex; - } - - // Base58 format (starts with T) - if (addr.startsWith('T')) { - return base58ToEvmHex(addr); - } - - // Invalid format, return zero address - console.warn(`[toEvmHex] Invalid address format: ${addr}, returning zero address`); - return ZERO_ADDRESS_HEX; -} - -/** - * Convert Base58 address to EVM hex format - */ -function base58ToEvmHex(addr: string): Hex { - const alphabetMap: Record = {}; - for (let i = 0; i < BASE58_ALPHABET.length; i++) { - alphabetMap[BASE58_ALPHABET[i]] = i; - } - - let num = BigInt(0); - for (const char of addr) { - const value = alphabetMap[char]; - if (value === undefined) { - console.warn(`[toEvmHex] Invalid Base58 character: ${char} in address: ${addr}`); - return ZERO_ADDRESS_HEX; - } - num = num * BigInt(58) + BigInt(value); - } - - let hex = num.toString(16); - if (hex.length % 2 !== 0) { - hex = '0' + hex; - } - - // Remove checksum (last 4 bytes = 8 hex chars) and 41 prefix - const withoutChecksum = hex.slice(0, -8); - const body = withoutChecksum.startsWith('41') ? withoutChecksum.slice(2) : withoutChecksum; - return `0x${body.padStart(40, '0')}` as Hex; -} - -/** - * Convert EVM hex address to TRON Base58 format - */ -export function toBase58(addr: string): string { - if (!addr.startsWith('0x')) { - return addr; // Already Base58 or other format - } - - // Add TRON's 41 prefix - const hexWithPrefix = '41' + addr.slice(2); - - // Convert to Base58 (simplified - in production use proper library) - // This is a placeholder implementation - let num = BigInt('0x' + hexWithPrefix); - let result = ''; - - while (num > 0) { - const remainder = Number(num % BigInt(58)); - result = BASE58_ALPHABET[remainder] + result; - num = num / BigInt(58); - } - - return result || 'T'; -} diff --git a/legacy/typescript/packages/x402/src/client/index.ts b/legacy/typescript/packages/x402/src/client/index.ts deleted file mode 100644 index 64e3191c..00000000 --- a/legacy/typescript/packages/x402/src/client/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Client module exports - */ - -export { X402Client } from './x402Client.js'; -export type { - ClientMechanism, - ClientSigner, - PaymentPolicy, - PaymentRequirementsSelector, - PaymentRequirementsFilter, -} from './x402Client.js'; -export { CheapestTokenSelectionStrategy, DefaultTokenSelectionStrategy } from './tokenSelection.js'; -export type { TokenSelectionStrategy } from './tokenSelection.js'; -export { SufficientBalancePolicy } from './policies.js'; diff --git a/legacy/typescript/packages/x402/src/client/policies.test.ts b/legacy/typescript/packages/x402/src/client/policies.test.ts deleted file mode 100644 index 1c3dba20..00000000 --- a/legacy/typescript/packages/x402/src/client/policies.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; -import { SufficientBalancePolicy } from './policies.js'; -import type { ClientMechanism, ClientSigner } from './x402Client.js'; -import { X402Client } from './x402Client.js'; -import type { PaymentRequirements } from '../types/index.js'; - -function makeRequirement(overrides?: Partial): PaymentRequirements { - return { - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1000000', - asset: 'TTestUSDT', - payTo: 'TTestMerchant', - ...overrides, - } as PaymentRequirements; -} - -function makeSigner(balance: bigint): ClientSigner { - return { - getAddress: () => 'TMockAddress', - signMessage: vi.fn(), - signTypedData: vi.fn(), - checkBalance: vi.fn().mockResolvedValue(balance), - checkAllowance: vi.fn(), - ensureAllowance: vi.fn(), - } as unknown as ClientSigner; -} - -function makeMechanism(opts: { - scheme?: string; - signer?: ClientSigner; - checkBalance?: (token: string, network: string) => Promise; -}): ClientMechanism { - const mechanism: ClientMechanism = { - scheme: () => opts.scheme ?? 'exact_permit', - getSigner: () => opts.signer ?? null, - createPaymentPayload: vi.fn(), - }; - if (opts.checkBalance) { - mechanism.checkBalance = opts.checkBalance; - } - return mechanism; -} - -describe('SufficientBalancePolicy', () => { - it('keeps requirement when mechanism.checkBalance returns sufficient balance', async () => { - const client = new X402Client(); - const mechanism = makeMechanism({ - checkBalance: vi.fn().mockResolvedValue(5000000n), - }); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement({ amount: '1000000' })]); - expect(result).toHaveLength(1); - }); - - it('drops requirement when mechanism.checkBalance returns insufficient balance', async () => { - const client = new X402Client(); - const mechanism = makeMechanism({ - checkBalance: vi.fn().mockResolvedValue(500n), - }); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement({ amount: '1000000' })]); - expect(result).toHaveLength(0); - }); - - it('drops requirement when no mechanism is registered', async () => { - const client = new X402Client(); - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement()]); - expect(result).toHaveLength(0); - }); - - it('keeps requirement when mechanism.checkBalance throws', async () => { - const client = new X402Client(); - const mechanism = makeMechanism({ - checkBalance: vi.fn().mockRejectedValue(new Error('network error')), - }); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement()]); - expect(result).toHaveLength(1); - }); - - it('falls back to signer.checkBalance when mechanism has no checkBalance', async () => { - const client = new X402Client(); - const signer = makeSigner(5000000n); - const mechanism = makeMechanism({ signer }); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement({ amount: '1000000' })]); - expect(result).toHaveLength(1); - expect(signer.checkBalance).toHaveBeenCalled(); - }); - - it('keeps requirement when fallback signer.checkBalance throws', async () => { - const client = new X402Client(); - const signer = makeSigner(0n); - (signer.checkBalance as ReturnType).mockRejectedValue(new Error('fail')); - const mechanism = makeMechanism({ signer }); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement()]); - expect(result).toHaveLength(1); - }); - - it('keeps requirement when no checkBalance and no signer (cannot determine balance)', async () => { - const client = new X402Client(); - const mechanism = makeMechanism({}); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([makeRequirement()]); - // No checkBalance, no signer → kept (cannot determine balance) - expect(result).toHaveLength(1); - }); - - it('returns empty array when all requirements are unaffordable', async () => { - const client = new X402Client(); - const mechanism = makeMechanism({ - checkBalance: vi.fn().mockResolvedValue(0n), - }); - client.register('tron:*', mechanism); - - const policy = new SufficientBalancePolicy(client); - const result = await policy.apply([ - makeRequirement({ amount: '1000000' }), - makeRequirement({ amount: '2000000' }), - ]); - expect(result).toHaveLength(0); - }); -}); diff --git a/legacy/typescript/packages/x402/src/client/policies.ts b/legacy/typescript/packages/x402/src/client/policies.ts deleted file mode 100644 index 1dff1f4d..00000000 --- a/legacy/typescript/packages/x402/src/client/policies.ts +++ /dev/null @@ -1,99 +0,0 @@ -/** - * Payment policies for filtering or reordering payment requirements. - * - * Policies are applied in order after mechanism filtering and before token selection. - */ - -import { findByAddress } from '../tokens.js'; -import type { PaymentRequirements } from '../types/index.js'; -import type { PaymentPolicy } from './x402Client.js'; -import type { X402Client } from './x402Client.js'; - -function getDecimals(req: PaymentRequirements): number { - const token = findByAddress(req.network, req.asset); - return token?.decimals ?? 6; -} - -/** - * Policy that filters out requirements with insufficient balance. - * - * When the server accepts multiple tokens (e.g. USDT and USDD), - * this policy checks the balance for each payment option via the - * mechanism's checkBalance() and removes requirements the user - * cannot afford. - * - * Mechanisms are auto-resolved from registered entries via the - * X402Client instance passed at construction time. - * - * Usage: - * x402.registerPolicy(SufficientBalancePolicy); - * - * If no mechanism is registered for a requirement's scheme+network, - * that requirement is skipped (excluded from results). - * - * If all requirements are unaffordable, returns an empty array so the - * caller can raise an appropriate error. - */ -export class SufficientBalancePolicy implements PaymentPolicy { - private client: X402Client; - - constructor(client: X402Client) { - this.client = client; - } - - async apply(requirements: PaymentRequirements[]): Promise { - const affordable: PaymentRequirements[] = []; - for (const req of requirements) { - const mechanism = this.client.resolveMechanism(req.scheme, req.network); - if (!mechanism) { - console.debug(`[x402] No mechanism for scheme=${req.scheme} network=${req.network} (skipped)`); - continue; - } - - let balance: bigint; - try { - if (mechanism.checkBalance) { - balance = await mechanism.checkBalance(req.asset, req.network); - } else { - const signer = mechanism.getSigner?.(); - if (!signer) { - // Cannot determine balance; keep the requirement and let - // createPaymentPayload decide. - affordable.push(req); - continue; - } - balance = await signer.checkBalance(req.asset, req.network); - } - } catch (err) { - console.warn(`[x402] checkBalance raised for ${req.asset} on ${req.network}; keeping requirement.`, err); - affordable.push(req); - continue; - } - - let needed = BigInt(req.amount); - if (req.extra?.fee?.feeAmount) { - needed += BigInt(req.extra.fee.feeAmount); - } - const decimals = getDecimals(req); - const token = findByAddress(req.network, req.asset); - const symbol = token?.symbol ?? req.asset.slice(0, 8); - const divisor = 10 ** decimals; - const hBalance = (Number(balance) / divisor).toFixed(decimals); - const hNeeded = (Number(needed) / divisor).toFixed(decimals); - if (balance >= needed) { - console.log( - `[x402] ${symbol} on ${req.network}: balance=${hBalance} >= needed=${hNeeded} (OK)` - ); - affordable.push(req); - } else { - console.log( - `[x402] ${symbol} on ${req.network}: balance=${hBalance} < needed=${hNeeded} (skipped)` - ); - } - } - if (affordable.length === 0) { - console.error('[x402] All payment requirements filtered: insufficient balance'); - } - return affordable; - } -} diff --git a/legacy/typescript/packages/x402/src/client/tokenSelection.ts b/legacy/typescript/packages/x402/src/client/tokenSelection.ts deleted file mode 100644 index 8205ed06..00000000 --- a/legacy/typescript/packages/x402/src/client/tokenSelection.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Token selection strategies for choosing which token to pay with. - * - * All tokens are assumed to be stablecoins, so selection normalizes raw amounts - * by token decimals to compare real value (lower is better for the payer). - */ - -import { findByAddress } from '../tokens.js'; -import type { PaymentRequirements } from '../types/index.js'; - -/** Strategy for selecting which payment option to use */ -export interface TokenSelectionStrategy { - select(accepts: PaymentRequirements[]): PaymentRequirements; -} - -function getDecimals(req: PaymentRequirements): number { - const token = findByAddress(req.network, req.asset); - return token?.decimals ?? 6; -} - -function normalizedCost(req: PaymentRequirements): number { - const decimals = getDecimals(req); - return Number(BigInt(req.amount)) / 10 ** decimals; -} - -/** - * Default strategy: normalize by token decimals, pick cheapest. - * - * Compares real value (amount / 10^decimals) so that tokens with - * different precisions (e.g. USDT 6, USDD 18) are ranked fairly. - */ -export class CheapestTokenSelectionStrategy implements TokenSelectionStrategy { - select(accepts: PaymentRequirements[]): PaymentRequirements { - if (accepts.length === 0) { - throw new Error('No payment options available'); - } - - let best = accepts[0]; - let bestCost = normalizedCost(best); - - for (let i = 1; i < accepts.length; i++) { - const cost = normalizedCost(accepts[i]); - if (cost < bestCost) { - best = accepts[i]; - bestCost = cost; - } - } - - return best; - } -} - -export const DefaultTokenSelectionStrategy = CheapestTokenSelectionStrategy; diff --git a/legacy/typescript/packages/x402/src/client/x402Client.ts b/legacy/typescript/packages/x402/src/client/x402Client.ts deleted file mode 100644 index 3016a565..00000000 --- a/legacy/typescript/packages/x402/src/client/x402Client.ts +++ /dev/null @@ -1,294 +0,0 @@ -/** - * X402Client - Core payment client for x402 protocol - * - * Manages payment mechanism registry and coordinates payment flows. - */ - -import { ExactGasFreeClientMechanism } from '../mechanisms/tron/exact_gasfree/index.js'; -import { GasFreeAPIClient } from '../utils/gasfree.js'; -import type { - PaymentRequirements, - PaymentPayload, - PaymentPermitContext, -} from '../types/index.js'; -import { DefaultTokenSelectionStrategy } from './tokenSelection.js'; -import type { TokenSelectionStrategy } from './tokenSelection.js'; -import { UnsupportedNetworkError } from '../errors.js'; - -/** Client mechanism interface */ -export interface ClientMechanism { - /** Get payment scheme name */ - scheme(): string; - - /** - * Return the signer used by this mechanism, if any. - * Used by X402Client to auto-register balance-aware policies. - */ - getSigner?(): ClientSigner; - - /** Check token balance for this mechanism's payment scheme */ - checkBalance?(token: string, network: string): Promise; - - /** Create payment payload */ - createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - extensions?: { paymentPermitContext?: PaymentPermitContext } - ): Promise; -} - -/** Client signer interface */ -export interface ClientSigner { - /** Get signer address */ - getAddress(): string; - - /** Sign raw message */ - signMessage(message: Uint8Array): Promise; - - /** Sign typed data (EIP-712) */ - signTypedData( - domain: Record, - types: Record, - message: Record, - primaryType: string - ): Promise; - - /** Check token balance */ - checkBalance(token: string, network: string, address?: string): Promise; - - /** Check token allowance */ - checkAllowance(token: string, amount: bigint, network: string): Promise; - - /** Ensure sufficient allowance */ - ensureAllowance( - token: string, - amount: bigint, - network: string, - mode?: 'auto' | 'interactive' | 'skip' - ): Promise; -} - -/** Payment requirements selector function */ -export type PaymentRequirementsSelector = ( - requirements: PaymentRequirements[] -) => PaymentRequirements; - -/** - * Policy that filters or reorders payment requirements. - * - * Policies are applied in order after mechanism filtering and before token selection. - * Return a subset (or reordered list) of the input requirements. - */ -export interface PaymentPolicy { - apply(requirements: PaymentRequirements[]): PaymentRequirements[] | Promise; -} - -/** Filter options for selecting payment requirements */ -export interface PaymentRequirementsFilter { - scheme?: string; - network?: string; - maxAmount?: string; -} - -/** Registered mechanism entry */ -interface MechanismEntry { - pattern: string; - mechanism: ClientMechanism; - priority: number; -} - -/** - * X402Client - Core payment client - * - * Manages payment mechanisms and coordinates payment flows. - */ -export class X402Client { - private mechanisms: MechanismEntry[] = []; - private policies: PaymentPolicy[] = []; - private tokenStrategy?: TokenSelectionStrategy; - - constructor(options?: { tokenStrategy?: TokenSelectionStrategy }) { - this.tokenStrategy = options?.tokenStrategy; - } - - /** - * Register a payment policy - * - * Policies are applied in order after mechanism filtering - * and before token selection. - * - * @param policy - Function that filters/reorders payment requirements - * @returns this for method chaining - */ - registerPolicy(policy: PaymentPolicy | { new(client: X402Client): PaymentPolicy }): X402Client { - const instance = typeof policy === 'function' - ? new (policy as { new(client: X402Client): PaymentPolicy })(this) - : policy; - this.policies.push(instance); - return this; - } - - /** - * Resolve a signer from registered mechanisms for the given scheme+network. - */ - resolveSigner(scheme: string, network: string): ClientSigner | null { - const mechanism = this.findMechanism(scheme, network); - return mechanism?.getSigner?.() ?? null; - } - - /** - * Resolve a mechanism for the given scheme+network. - */ - resolveMechanism(scheme: string, network: string): ClientMechanism | null { - return this.findMechanism(scheme, network); - } - - /** - * Register payment mechanism for network pattern - * - * @param networkPattern - Network pattern (e.g. "eip155:*", "tron:shasta") - * @param mechanism - Payment mechanism instance - * @returns this for method chaining - */ - register(networkPattern: string, mechanism: ClientMechanism): X402Client { - const priority = this.calculatePriority(networkPattern); - this.mechanisms.push({ - pattern: networkPattern, - mechanism, - priority, - }); - this.mechanisms.sort((a, b) => b.priority - a.priority); - return this; - } - - /** - * Register built-in GasFree mechanism for TRON - * - * @param signer - Client signer instance - * @param clients - Optional GasFree API clients per network - * @returns this for method chaining - */ - registerGasFree(signer: ClientSigner, clients: Record = {}): X402Client { - return this.register('tron:*', new ExactGasFreeClientMechanism(signer, clients)); - } - - /** - * Select payment requirements from available options - * - * @param accepts - Available payment requirements - * @param filters - Optional filters - * @returns Selected payment requirements - */ - async selectPaymentRequirements( - accepts: PaymentRequirements[], - filters?: PaymentRequirementsFilter - ): Promise { - let candidates = accepts; - - if (filters?.scheme) { - candidates = candidates.filter(r => r.scheme === filters.scheme); - } - - if (filters?.network) { - candidates = candidates.filter(r => r.network === filters.network); - } - - if (filters?.maxAmount) { - const max = BigInt(filters.maxAmount); - candidates = candidates.filter(r => BigInt(r.amount) <= max); - } - - candidates = candidates.filter(r => this.findMechanism(r.scheme, r.network) !== null); - - for (const policy of this.policies) { - candidates = await policy.apply(candidates); - } - - if (candidates.length === 0) { - throw new UnsupportedNetworkError('No supported payment requirements found'); - } - - if (this.tokenStrategy) { - return this.tokenStrategy.select(candidates); - } - - return new DefaultTokenSelectionStrategy().select(candidates); - } - - /** - * Create payment payload for given requirements - * - * @param requirements - Selected payment requirements - * @param resource - Resource URL - * @param extensions - Optional extensions - * @returns Payment payload - */ - async createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - extensions?: { paymentPermitContext?: PaymentPermitContext } - ): Promise { - const mechanism = this.findMechanism(requirements.scheme, requirements.network); - if (!mechanism) { - throw new UnsupportedNetworkError( - `No mechanism registered for scheme=${requirements.scheme}, network=${requirements.network}` - ); - } - - return mechanism.createPaymentPayload(requirements, resource, extensions); - } - - /** - * Handle payment required response - * - * @param accepts - Available payment requirements - * @param resource - Resource URL - * @param extensions - Optional extensions - * @param selector - Optional custom selector - * @returns Payment payload - */ - async handlePayment( - accepts: PaymentRequirements[], - resource: string, - extensions?: Record, - selector?: PaymentRequirementsSelector - ): Promise { - const requirements = selector - ? selector(accepts) - : await this.selectPaymentRequirements(accepts); - - return this.createPaymentPayload(requirements, resource, extensions); - } - - /** - * Find mechanism for scheme and network - */ - private findMechanism(scheme: string, network: string): ClientMechanism | null { - for (const entry of this.mechanisms) { - if (entry.mechanism.scheme() === scheme && this.matchPattern(entry.pattern, network)) { - return entry.mechanism; - } - } - return null; - } - - /** - * Match network with pattern - */ - private matchPattern(pattern: string, network: string): boolean { - if (pattern === network) return true; - if (pattern.endsWith(':*')) { - const prefix = pattern.slice(0, -1); - return network.startsWith(prefix); - } - return false; - } - - /** - * Calculate priority for pattern (more specific = higher priority) - */ - private calculatePriority(pattern: string): number { - if (pattern.endsWith(':*')) return 1; - return 10; - } -} diff --git a/legacy/typescript/packages/x402/src/config.test.ts b/legacy/typescript/packages/x402/src/config.test.ts deleted file mode 100644 index 239e365e..00000000 --- a/legacy/typescript/packages/x402/src/config.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { getTronRpcUrl, TRON_RPC_URLS, TRON_FALLBACK_RPC_URLS, resolveRpcUrl } from './config.js'; - -const FALLBACK_URL = TRON_FALLBACK_RPC_URLS['tron:mainnet']; - -describe('getTronRpcUrl', () => { - const originalEnv = process.env; - - beforeEach(() => { - process.env = { ...originalEnv }; - delete process.env.TRON_GRID_API_KEY; - }); - - afterEach(() => { - process.env = originalEnv; - }); - - it('returns fallback URL for mainnet when TRON_GRID_API_KEY is not set', () => { - expect(getTronRpcUrl('tron:mainnet')).toBe(FALLBACK_URL); - }); - - it('returns default TronGrid URL for mainnet when TRON_GRID_API_KEY is set', () => { - process.env.TRON_GRID_API_KEY = 'test-api-key'; - expect(getTronRpcUrl('tron:mainnet')).toBe('https://api.trongrid.io'); - }); - - it('returns fallback URL for nile/shasta when TRON_GRID_API_KEY is not set', () => { - expect(getTronRpcUrl('tron:nile')).toBe(TRON_FALLBACK_RPC_URLS['tron:nile']); - expect(getTronRpcUrl('tron:shasta')).toBe(TRON_FALLBACK_RPC_URLS['tron:shasta']); - }); - - it('returns default URL for non-mainnet networks when TRON_GRID_API_KEY is set', () => { - process.env.TRON_GRID_API_KEY = 'test-api-key'; - expect(getTronRpcUrl('tron:nile')).toBe(TRON_RPC_URLS['tron:nile']); - expect(getTronRpcUrl('tron:shasta')).toBe(TRON_RPC_URLS['tron:shasta']); - }); - - it('returns undefined for unknown networks', () => { - expect(getTronRpcUrl('tron:unknown')).toBeUndefined(); - }); - - it('returns undefined for unknown networks when TRON_GRID_API_KEY is set', () => { - process.env.TRON_GRID_API_KEY = 'test-api-key'; - expect(getTronRpcUrl('tron:unknown')).toBeUndefined(); - }); -}); - -describe('resolveRpcUrl', () => { - const originalEnv = process.env; - - beforeEach(() => { - process.env = { ...originalEnv }; - delete process.env.TRON_GRID_API_KEY; - }); - - afterEach(() => { - process.env = originalEnv; - }); - - it('delegates to getTronRpcUrl for TRON networks', () => { - expect(resolveRpcUrl('tron:mainnet')).toBe(FALLBACK_URL); - }); - - it('returns TronGrid URL for TRON mainnet when API key is set', () => { - process.env.TRON_GRID_API_KEY = 'test-api-key'; - expect(resolveRpcUrl('tron:mainnet')).toBe('https://api.trongrid.io'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/config.ts b/legacy/typescript/packages/x402/src/config.ts deleted file mode 100644 index 3ad0d843..00000000 --- a/legacy/typescript/packages/x402/src/config.ts +++ /dev/null @@ -1,207 +0,0 @@ -/** - * Network configuration for x402 protocol - * Centralized configuration for contract addresses and chain IDs - */ - -import { UnsupportedNetworkError } from './errors.js'; - -/** Chain IDs for supported networks */ -export const CHAIN_IDS: Record = { - // TRON networks - 'tron:mainnet': 728126428, // 0x2b6653dc - 'tron:shasta': 2494104990, // 0x94a9059e - 'tron:nile': 3448148188, // 0xcd8690dc - - // EVM networks - 'eip155:1': 1, // Ethereum Mainnet - 'eip155:11155111': 11155111, // Sepolia - 'eip155:56': 56, // BSC Mainnet - 'eip155:97': 97, // BSC Testnet -}; - -/** Network identifier constants */ -export const NETWORKS = { - TRON_MAINNET: 'tron:mainnet', - TRON_SHASTA: 'tron:shasta', - TRON_NILE: 'tron:nile', - EVM_MAINNET: 'eip155:1', - EVM_SEPOLIA: 'eip155:11155111', - BSC_MAINNET: 'eip155:56', - BSC_TESTNET: 'eip155:97', -} as const; - -/** PaymentPermit contract addresses */ -export const PAYMENT_PERMIT_ADDRESSES: Record = { - 'tron:mainnet': 'TT8rEWbCoNX7vpEUauxb7rWJsTgs8vDLAn', - 'tron:shasta': 'TR2XninQ3jsvRRLGTifFyUHTBysffooUjt', - 'tron:nile': 'TFxDcGvS7zfQrS1YzcCMp673ta2NHHzsiH', - 'eip155:97': '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', - 'eip155:56': '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', -}; - -/** GasFreeController contract addresses */ -export const GASFREE_CONTROLLER_ADDRESSES: Record = { - // Source: @gasfree/gasfree-sdk (TronGasFree assembleGasFreeTransactionJson) for chainId 728126428 - 'tron:mainnet': 'TFFAMQLZybALaLb4uxHA9RBE7pxhUAjF3U', - 'tron:shasta': 'TQghdCeVDA6CnuNVTUhfaAyPfTetqZWNpm', - 'tron:nile': 'THQGuFzL87ZqhxkgqYEryRAd7gqFqL5rdc', -}; - -/** GasFree beacon addresses */ -export const GASFREE_BEACON_ADDRESSES: Record = { - 'tron:mainnet': 'TSP9UW6FQhT76XD2jWA6ipGMx3yGbjDffP', - 'tron:shasta': 'TQ1jvA3nLDMDNbJoMPLzTPoqAg8NvZ5CCW', - 'tron:nile': 'TLtCGmaxH3PbuaF6kbybwteZcHptEdgQGC', -}; - -/** GasFree API Base URLs */ -export const GASFREE_API_BASE_URLS: Record = { - 'tron:mainnet': 'https://facilitator.bankofai.io/mainnet', - 'tron:shasta': 'https://facilitator.bankofai.io/shasta', - 'tron:nile': 'https://facilitator.bankofai.io/nile', -}; - -/** Default RPC URLs for EVM networks */ -export const EVM_RPC_URLS: Record = { - 'eip155:97': 'https://data-seed-prebsc-1-s1.binance.org:8545/', - 'eip155:56': 'https://bsc-dataseed.binance.org/', - // 'eip155:1': 'https://eth.llamarpc.com', -}; - -/** Default TronGrid hosts for TRON networks */ -export const TRON_RPC_URLS: Record = { - 'tron:mainnet': 'https://api.trongrid.io', - 'tron:shasta': 'https://api.shasta.trongrid.io', - 'tron:nile': 'https://nile.trongrid.io', -}; - -/** Fallback RPC URLs used when TRON_GRID_API_KEY is not set */ -export const TRON_FALLBACK_RPC_URLS: Record = { - 'tron:mainnet': 'https://hptg.bankofai.io', - // nileex is the official Nile endpoint and works without a TronGrid key - // (the default nile.trongrid.io host gets rate-limited unkeyed). - 'tron:nile': 'https://api.nileex.io', - 'tron:shasta': 'https://api.shasta.trongrid.io', -}; - -/** - * Get the appropriate TRON RPC URL for a network. - * Uses fallback URLs when TRON_GRID_API_KEY is not set. - */ -const _warnedNetworks = new Set(); - -export function getTronRpcUrl(network: string): string | undefined { - const apiKey = typeof process !== 'undefined' ? process.env?.TRON_GRID_API_KEY : undefined; - if (!apiKey) { - const fallback = TRON_FALLBACK_RPC_URLS[network]; - if (fallback) { - if (!_warnedNetworks.has(network)) { - _warnedNetworks.add(network); - console.warn( - `[x402] TRON_GRID_API_KEY is not set. Routing ${network} RPC calls ` + - `to fallback endpoint: ${fallback}. Set TRON_GRID_API_KEY to use TronGrid.` - ); - } - return fallback; - } - return TRON_RPC_URLS[network]; - } - return TRON_RPC_URLS[network]; -} - -/** - * Resolve a network identifier to an RPC URL. - * Returns the URL from the built-in map, or undefined if not configured. - */ -export function resolveRpcUrl(network: string): string | undefined { - if (network.startsWith('tron:')) { - return getTronRpcUrl(network); - } - return EVM_RPC_URLS[network]; -} - -/** Zero address for TRON */ -export const TRON_ZERO_ADDRESS = 'T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb'; - -/** Zero address for EVM */ -export const EVM_ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'; - -/** - * Get chain ID for network - */ -export function getChainId(network: string): number { - // EVM networks encode chain ID directly in the identifier - if (network.startsWith('eip155:')) { - const id = parseInt(network.split(':')[1], 10); - if (isNaN(id)) { - throw new UnsupportedNetworkError(`Invalid EVM network: ${network}`); - } - return id; - } - - const chainId = CHAIN_IDS[network]; - if (chainId === undefined) { - throw new UnsupportedNetworkError(`Unsupported network: ${network}`); - } - return chainId; -} - -/** - * Get PaymentPermit contract address for network - */ -export function getPaymentPermitAddress(network: string): string { - const addr = PAYMENT_PERMIT_ADDRESSES[network]; - if (addr) return addr; - // EVM fallback: zero address (not yet deployed) - if (network.startsWith('eip155:')) return EVM_ZERO_ADDRESS; - return TRON_ZERO_ADDRESS; -} - -/** - * Get GasFreeController contract address for network - */ -export function getGasFreeControllerAddress(network: string): string { - return GASFREE_CONTROLLER_ADDRESSES[network] ?? TRON_ZERO_ADDRESS; -} - -/** - * Get GasFree beacon address for network - */ -export function getGasFreeBeaconAddress(network: string): string { - return GASFREE_BEACON_ADDRESSES[network] ?? TRON_ZERO_ADDRESS; -} - -/** - * Get GasFree API Base URL for network - */ -export function getGasFreeApiBaseUrl(network: string): string { - const url = GASFREE_API_BASE_URLS[network]; - if (!url) { - throw new UnsupportedNetworkError(`No GasFree API URL configured for network: ${network}`); - } - return url; -} - - -/** - * Check if network is TRON - */ -export function isTronNetwork(network: string): boolean { - return network.startsWith('tron:'); -} - -/** - * Check if network is EVM - */ -export function isEvmNetwork(network: string): boolean { - return network.startsWith('eip155:'); -} - -/** - * Get zero address for network - */ -export function getZeroAddress(network: string): string { - if (isEvmNetwork(network)) return EVM_ZERO_ADDRESS; - if (isTronNetwork(network)) return TRON_ZERO_ADDRESS; - throw new UnsupportedNetworkError(`Unsupported network: ${network}`); -} diff --git a/legacy/typescript/packages/x402/src/errors.ts b/legacy/typescript/packages/x402/src/errors.ts deleted file mode 100644 index 42dfd87c..00000000 --- a/legacy/typescript/packages/x402/src/errors.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * x402 custom error hierarchy - */ - -/** Base error for all x402 errors */ -export class X402Error extends Error { - constructor(message: string) { - super(message); - this.name = 'X402Error'; - } -} - -/** Signature-related error */ -export class SignatureError extends X402Error { - constructor(message: string) { - super(message); - this.name = 'SignatureError'; - } -} - -/** Signature creation failed */ -export class SignatureCreationError extends SignatureError { - constructor(message: string) { - super(message); - this.name = 'SignatureCreationError'; - } -} - -/** Allowance-related error */ -export class AllowanceError extends X402Error { - constructor(message: string) { - super(message); - this.name = 'AllowanceError'; - } -} - -/** Insufficient allowance */ -export class InsufficientAllowanceError extends AllowanceError { - constructor(message: string) { - super(message); - this.name = 'InsufficientAllowanceError'; - } -} - -/** Configuration-related error */ -export class ConfigurationError extends X402Error { - constructor(message: string) { - super(message); - this.name = 'ConfigurationError'; - } -} - -/** Unsupported network */ -export class UnsupportedNetworkError extends ConfigurationError { - constructor(message: string) { - super(message); - this.name = 'UnsupportedNetworkError'; - } -} - -/** Validation-related error */ -export class ValidationError extends X402Error { - constructor(message: string) { - super(message); - this.name = 'ValidationError'; - } -} - -/** Permit validation failed */ -export class PermitValidationError extends ValidationError { - reason: string; - - constructor(reason: string, message?: string) { - super(message || reason); - this.name = 'PermitValidationError'; - this.reason = reason; - } -} - -/** Facilitator HTTP / protocol error */ -export class FacilitatorError extends X402Error { - /** HTTP status code returned by facilitator (0 if request itself failed) */ - status: number; - /** Response body, decoded as text or null if unavailable */ - body: string | null; - - constructor(message: string, status: number, body: string | null = null) { - super(message); - this.name = 'FacilitatorError'; - this.status = status; - this.body = body; - } -} diff --git a/legacy/typescript/packages/x402/src/facilitator/client.test.ts b/legacy/typescript/packages/x402/src/facilitator/client.test.ts deleted file mode 100644 index 181178d7..00000000 --- a/legacy/typescript/packages/x402/src/facilitator/client.test.ts +++ /dev/null @@ -1,195 +0,0 @@ -/** - * Tests for FacilitatorClient. - * - * Uses a fake fetch impl so the suite stays hermetic — no live HTTP, no servers. - */ - -import { describe, expect, it, vi } from 'vitest'; - -import { FacilitatorError } from '../errors.js'; -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentRequirements, - SettleResponse, - SupportedResponse, - VerifyResponse, -} from '../types/index.js'; -import { FacilitatorClient } from './client.js'; - -/** Build a fake fetch that returns a single canned response and records the call. */ -function mockFetch(json: unknown, status = 200): { - fetchImpl: typeof fetch; - calls: Array<{ url: string; init: RequestInit | undefined }>; -} { - const calls: Array<{ url: string; init: RequestInit | undefined }> = []; - const fetchImpl: typeof fetch = vi.fn(async (input, init) => { - calls.push({ - url: typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url, - init, - }); - return new Response(JSON.stringify(json), { - status, - headers: { 'Content-Type': 'application/json' }, - }); - }) as unknown as typeof fetch; - return { fetchImpl, calls }; -} - -const REQUIREMENTS: PaymentRequirements = { - scheme: 'exact', - network: 'tron:nile', - maxAmountRequired: '1000000', - resource: 'http://example.com/api', - description: 'test', - mimeType: 'application/json', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - maxTimeoutSeconds: 60, - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - amount: '1000000', -}; - -const PAYLOAD: PaymentPayload = { - x402Version: 2, - accepted: REQUIREMENTS, - payload: { signature: '0x' + 'aa'.repeat(65) }, -}; - -describe('FacilitatorClient', () => { - it('strips trailing slashes from baseUrl', () => { - const client = new FacilitatorClient({ - baseUrl: 'https://facilitator.example/', - fetchImpl: mockFetch({}).fetchImpl, - }); - expect(client.facilitatorId).toBe('https://facilitator.example'); - }); - - it('uses explicit facilitatorId when provided', () => { - const client = new FacilitatorClient({ - baseUrl: 'https://facilitator.example', - facilitatorId: 'fac-1', - fetchImpl: mockFetch({}).fetchImpl, - }); - expect(client.facilitatorId).toBe('fac-1'); - }); - - it('GETs /supported and parses the response', async () => { - const supported: SupportedResponse = { - kinds: [{ x402Version: 2, scheme: 'exact', network: 'tron:nile' }], - }; - const { fetchImpl, calls } = mockFetch(supported); - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - const result = await client.supported(); - - expect(result).toEqual(supported); - expect(calls).toHaveLength(1); - expect(calls[0]!.url).toBe('https://fac.example/supported'); - expect(calls[0]!.init?.method).toBe('GET'); - }); - - it('POSTs /verify with snake_camelCase payload + requirements wire fields', async () => { - const verify: VerifyResponse = { isValid: true }; - const { fetchImpl, calls } = mockFetch(verify); - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - const result = await client.verify(PAYLOAD, REQUIREMENTS); - - expect(result).toEqual(verify); - expect(calls[0]!.url).toBe('https://fac.example/verify'); - const body = JSON.parse(calls[0]!.init?.body as string); - expect(body.paymentPayload).toEqual(PAYLOAD); - expect(body.paymentRequirements).toEqual(REQUIREMENTS); - }); - - it('POSTs /settle with the same wire shape', async () => { - const settle: SettleResponse = { - success: true, - transaction: '0xdeadbeef', - network: 'tron:nile', - }; - const { fetchImpl, calls } = mockFetch(settle); - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - const result = await client.settle(PAYLOAD, REQUIREMENTS); - - expect(result).toEqual(settle); - expect(calls[0]!.url).toBe('https://fac.example/settle'); - }); - - it('POSTs /fee/quote with optional context', async () => { - const quotes: FeeQuoteResponse[] = [ - { - fee: { feeTo: '0xabc', feeAmount: '0' }, - pricing: 'fixed', - scheme: 'exact', - network: 'tron:nile', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - }, - ]; - const { fetchImpl, calls } = mockFetch(quotes); - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - await client.feeQuote([REQUIREMENTS], { paymentId: '0x' + '11'.repeat(16) }); - - const body = JSON.parse(calls[0]!.init?.body as string); - expect(body.accepts).toHaveLength(1); - expect(body.paymentPermitContext).toEqual({ paymentId: '0x' + '11'.repeat(16) }); - }); - - it('omits paymentPermitContext when no context given', async () => { - const { fetchImpl, calls } = mockFetch([]); - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - await client.feeQuote([REQUIREMENTS]); - - const body = JSON.parse(calls[0]!.init?.body as string); - expect(body).not.toHaveProperty('paymentPermitContext'); - }); - - it('forwards custom headers on every request', async () => { - const { fetchImpl, calls } = mockFetch({ kinds: [] }); - const client = new FacilitatorClient({ - baseUrl: 'https://fac.example', - headers: { Authorization: 'Bearer abc' }, - fetchImpl, - }); - - await client.supported(); - - const headers = calls[0]!.init?.headers as Record; - expect(headers.Authorization).toBe('Bearer abc'); - }); - - it('throws FacilitatorError on non-2xx with body preserved', async () => { - const fetchImpl: typeof fetch = vi.fn(async () => { - return new Response('boom', { status: 500 }); - }) as unknown as typeof fetch; - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - await expect(client.verify(PAYLOAD, REQUIREMENTS)).rejects.toMatchObject({ - name: 'FacilitatorError', - status: 500, - body: 'boom', - }); - }); - - it('throws FacilitatorError on transport failure', async () => { - const fetchImpl: typeof fetch = vi.fn(async () => { - throw new Error('network down'); - }) as unknown as typeof fetch; - const client = new FacilitatorClient({ baseUrl: 'https://fac.example', fetchImpl }); - - const promise = client.supported(); - await expect(promise).rejects.toBeInstanceOf(FacilitatorError); - await expect(promise).rejects.toMatchObject({ status: 0 }); - }); - - it('close() is a no-op safe to call', async () => { - const client = new FacilitatorClient({ - baseUrl: 'https://fac.example', - fetchImpl: mockFetch({}).fetchImpl, - }); - await expect(client.close()).resolves.toBeUndefined(); - }); -}); diff --git a/legacy/typescript/packages/x402/src/facilitator/client.ts b/legacy/typescript/packages/x402/src/facilitator/client.ts deleted file mode 100644 index e062b015..00000000 --- a/legacy/typescript/packages/x402/src/facilitator/client.ts +++ /dev/null @@ -1,197 +0,0 @@ -/** - * FacilitatorClient — TypeScript port of `bankofai.x402.facilitator.FacilitatorClient`. - * - * Talks to a remote x402 facilitator via HTTP. Handles `/supported`, `/fee/quote`, - * `/verify`, `/settle`. Used by server middleware (Hono / Express / etc.) to verify - * payments off-chain and trigger on-chain settlement. - */ - -import { FacilitatorError } from '../errors.js'; -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentRequirements, - SettleResponse, - SupportedResponse, - VerifyResponse, -} from '../types/index.js'; - -/** Configuration for {@link FacilitatorClient}. */ -export interface FacilitatorClientConfig { - /** Facilitator service base URL (trailing slash optional, will be normalized). */ - baseUrl: string; - /** Optional custom HTTP headers (e.g. `Authorization`). */ - headers?: Record; - /** Stable identifier for this facilitator. Defaults to `baseUrl`. */ - facilitatorId?: string; - /** Per-request timeout in milliseconds. Defaults to 120 000 (120 s). */ - timeoutMs?: number; - /** Custom fetch implementation (defaults to global `fetch`). Useful for tests. */ - fetchImpl?: typeof fetch; -} - -const DEFAULT_TIMEOUT_MS = 120_000; - -/** - * Optional payment context forwarded to `/fee/quote`. - * - * Wire field is `paymentPermitContext` to match the facilitator API; the client - * accepts a plain JSON-shaped object and forwards it as-is. - */ -export type FeeQuoteContext = Record; - -/** - * HTTP client for an x402 facilitator service. - * - * Mirrors the Python `FacilitatorClient` interface 1:1 so server middleware on - * either runtime sees the same shape. - */ -export class FacilitatorClient { - private readonly baseUrl: string; - private readonly headers: Record; - private readonly timeoutMs: number; - private readonly fetchImpl: typeof fetch; - - /** Stable identifier for this facilitator (defaults to `baseUrl`). */ - readonly facilitatorId: string; - - constructor(config: FacilitatorClientConfig) { - this.baseUrl = config.baseUrl.replace(/\/+$/, ''); - this.headers = { ...(config.headers ?? {}) }; - this.facilitatorId = config.facilitatorId ?? this.baseUrl; - this.timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS; - this.fetchImpl = config.fetchImpl ?? fetch; - } - - /** - * Query facilitator's supported (`x402Version`, `scheme`, `network`) tuples. - */ - async supported(): Promise { - return this.requestJson('GET', '/supported'); - } - - /** - * Request fee quotes for a list of payment requirements. - * - * @param accepts - The same `accepts[]` you would put in `PaymentRequired`. - * @param context - Optional `paymentPermitContext`. - */ - async feeQuote( - accepts: PaymentRequirements[], - context?: FeeQuoteContext, - ): Promise { - const body: Record = { accepts }; - if (context !== undefined) { - body.paymentPermitContext = context; - } - return this.requestJson('POST', '/fee/quote', body); - } - - /** - * Verify a payment payload off-chain (no on-chain transaction). - * - * Server middleware should call this **before** routing the actual request - * handler — only proceed to settlement if {@link VerifyResponse.isValid} is true. - */ - async verify( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - return this.requestJson('POST', '/verify', { - paymentPayload: payload, - paymentRequirements: requirements, - }); - } - - /** - * Execute on-chain settlement for a verified payment. - * - * Returns a {@link SettleResponse} carrying the transaction hash on success - * or an `errorReason` on failure. - */ - async settle( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - return this.requestJson('POST', '/settle', { - paymentPayload: payload, - paymentRequirements: requirements, - }); - } - - /** - * Symmetry with the Python client. The TS implementation uses the global - * `fetch` (no persistent connection pool to close); this is a no-op kept for - * API parity so callers can write the same teardown logic on both runtimes. - */ - async close(): Promise { - // no-op — `fetch` does not require explicit cleanup - } - - private async requestJson( - method: 'GET' | 'POST', - path: string, - body?: unknown, - ): Promise { - const url = `${this.baseUrl}${path.startsWith('/') ? path : `/${path}`}`; - const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), this.timeoutMs); - - const init: RequestInit = { - method, - headers: { - Accept: 'application/json', - ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}), - ...this.headers, - }, - signal: controller.signal, - }; - if (body !== undefined) { - init.body = JSON.stringify(body); - } - - let response: Response; - try { - response = await this.fetchImpl(url, init); - } catch (err) { - if (err instanceof Error && err.name === 'AbortError') { - throw new FacilitatorError( - `Facilitator request to ${path} timed out after ${this.timeoutMs}ms`, - 0, - ); - } - throw new FacilitatorError( - `Facilitator request to ${path} failed: ${(err as Error).message}`, - 0, - ); - } finally { - clearTimeout(timer); - } - - if (!response.ok) { - const text = await this.safeReadText(response); - throw new FacilitatorError( - `Facilitator returned HTTP ${response.status} for ${path}`, - response.status, - text, - ); - } - - try { - return (await response.json()) as TResponse; - } catch (err) { - throw new FacilitatorError( - `Facilitator response from ${path} was not valid JSON: ${(err as Error).message}`, - response.status, - ); - } - } - - private async safeReadText(response: Response): Promise { - try { - return await response.text(); - } catch { - return null; - } - } -} diff --git a/legacy/typescript/packages/x402/src/facilitator/index.ts b/legacy/typescript/packages/x402/src/facilitator/index.ts deleted file mode 100644 index 9afba51f..00000000 --- a/legacy/typescript/packages/x402/src/facilitator/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Facilitator surface for the x402 payment protocol. - * - * - {@link FacilitatorClient} — talks to a remote facilitator (used by server middleware) - * - {@link X402Facilitator} — in-process payment processor (the engine of a facilitator service) - * - * Re-exported via the package root so consumers can `import { FacilitatorClient, - * X402Facilitator } from '@bankofai/x402'`. - */ - -export { FacilitatorClient } from './client.js'; -export type { FacilitatorClientConfig, FeeQuoteContext } from './client.js'; -export { X402Facilitator } from './x402Facilitator.js'; -export type { FacilitatorMechanism, FacilitatorLogger } from './x402Facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/facilitator/x402Facilitator.test.ts b/legacy/typescript/packages/x402/src/facilitator/x402Facilitator.test.ts deleted file mode 100644 index 951afa87..00000000 --- a/legacy/typescript/packages/x402/src/facilitator/x402Facilitator.test.ts +++ /dev/null @@ -1,277 +0,0 @@ -/** - * Tests for X402Facilitator — the in-process payment processor. - */ - -import { describe, expect, it, vi } from 'vitest'; - -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../types/index.js'; -import { - X402Facilitator, - type FacilitatorLogger, - type FacilitatorMechanism, -} from './x402Facilitator.js'; - -function makeMechanism(opts: { - scheme?: string; - verifyResult?: VerifyResponse; - settleResult?: SettleResponse; - quoteResult?: FeeQuoteResponse | null; - verifyImpl?: () => Promise; - settleImpl?: () => Promise; - quoteImpl?: () => Promise; -} = {}): FacilitatorMechanism { - return { - scheme: () => opts.scheme ?? 'exact', - feeQuote: opts.quoteImpl - ? vi.fn(opts.quoteImpl) - : vi.fn(async () => opts.quoteResult ?? null), - verify: opts.verifyImpl - ? vi.fn(opts.verifyImpl) - : vi.fn(async () => opts.verifyResult ?? { isValid: true }), - settle: opts.settleImpl - ? vi.fn(opts.settleImpl) - : vi.fn(async () => opts.settleResult ?? { success: true, transaction: '0xtx' }), - }; -} - -const TRON_REQ: PaymentRequirements = { - scheme: 'exact', - network: 'tron:nile', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', -}; - -// EVM addresses purposely lowercase so checksum normalization has work to do. -const EVM_REQ: PaymentRequirements = { - scheme: 'exact_permit', - network: 'eip155:97', - amount: '1000000', - asset: '0x64544969ed7ebf5f083679233325356ebe738930', - payTo: '0x1825bb32db3443dec2cc7508b2d818fc13ead878', -}; - -const PAYLOAD: PaymentPayload = { - x402Version: 2, - accepted: TRON_REQ, - payload: { signature: '0x' + 'aa'.repeat(65) }, -}; - -describe('X402Facilitator', () => { - describe('register / supported', () => { - it('registers a mechanism for multiple networks', () => { - const facilitator = new X402Facilitator(); - const mech = makeMechanism({ scheme: 'exact' }); - - const result = facilitator.register(['tron:nile', 'tron:shasta'], mech); - - expect(result).toBe(facilitator); // chainable - expect(facilitator.supported().kinds).toEqual([ - { x402Version: 2, scheme: 'exact', network: 'tron:nile' }, - { x402Version: 2, scheme: 'exact', network: 'tron:shasta' }, - ]); - }); - - it('supports multiple schemes per network', () => { - const facilitator = new X402Facilitator() - .register(['tron:nile'], makeMechanism({ scheme: 'exact' })) - .register(['tron:nile'], makeMechanism({ scheme: 'exact_permit' })); - - const kinds = facilitator.supported().kinds; - expect(kinds).toHaveLength(2); - expect(kinds.map((k) => k.scheme).sort()).toEqual(['exact', 'exact_permit']); - }); - }); - - describe('verify', () => { - it('routes to the registered mechanism and forwards its response', async () => { - const verify = vi.fn(async () => ({ isValid: true })); - const mech: FacilitatorMechanism = { - scheme: () => 'exact', - feeQuote: vi.fn(), - verify, - settle: vi.fn(), - }; - const facilitator = new X402Facilitator().register(['tron:nile'], mech); - - const result = await facilitator.verify(PAYLOAD, TRON_REQ); - - expect(result).toEqual({ isValid: true }); - expect(verify).toHaveBeenCalledOnce(); - }); - - it('returns isValid:false with unsupported_network_scheme when no mechanism', async () => { - const facilitator = new X402Facilitator(); - const result = await facilitator.verify(PAYLOAD, TRON_REQ); - expect(result.isValid).toBe(false); - expect(result.invalidReason).toContain('unsupported_network_scheme'); - }); - - it('catches mechanism exceptions and surfaces them as invalidReason', async () => { - const errorLogger: FacilitatorLogger = { warn: vi.fn(), error: vi.fn() }; - const facilitator = new X402Facilitator({ logger: errorLogger }).register( - ['tron:nile'], - makeMechanism({ - verifyImpl: async () => { - throw new Error('signature mismatch'); - }, - }), - ); - - const result = await facilitator.verify(PAYLOAD, TRON_REQ); - - expect(result).toEqual({ isValid: false, invalidReason: 'signature mismatch' }); - expect(errorLogger.error).toHaveBeenCalledOnce(); - }); - - it('checksums EVM addresses before passing to mechanism', async () => { - const verify = vi.fn(async () => ({ isValid: true })); - const mech: FacilitatorMechanism = { - scheme: () => 'exact_permit', - feeQuote: vi.fn(), - verify, - settle: vi.fn(), - }; - const facilitator = new X402Facilitator().register(['eip155:97'], mech); - - await facilitator.verify(PAYLOAD, EVM_REQ); - - const passed = (verify as ReturnType).mock.calls[0]![1] as PaymentRequirements; - // Checksummed = mixed case - expect(passed.asset).not.toBe(EVM_REQ.asset); - expect(passed.asset.toLowerCase()).toBe(EVM_REQ.asset); - expect(passed.payTo).not.toBe(EVM_REQ.payTo); - }); - - it('returns isValid:false on invalid EVM address (no exception thrown)', async () => { - const facilitator = new X402Facilitator().register( - ['eip155:97'], - makeMechanism({ scheme: 'exact_permit' }), - ); - - const result = await facilitator.verify(PAYLOAD, { - ...EVM_REQ, - asset: '0xnot_an_address', - }); - - expect(result.isValid).toBe(false); - expect(result.invalidReason).toContain('Invalid EVM address'); - }); - }); - - describe('settle', () => { - it('routes to mechanism and returns its response', async () => { - const facilitator = new X402Facilitator().register( - ['tron:nile'], - makeMechanism({ - settleResult: { success: true, transaction: '0xabc', network: 'tron:nile' }, - }), - ); - - const result = await facilitator.settle(PAYLOAD, TRON_REQ); - - expect(result).toEqual({ success: true, transaction: '0xabc', network: 'tron:nile' }); - }); - - it('returns success:false with unsupported_network_scheme on miss', async () => { - const facilitator = new X402Facilitator(); - const result = await facilitator.settle(PAYLOAD, TRON_REQ); - expect(result.success).toBe(false); - expect(result.network).toBe('tron:nile'); - expect(result.errorReason).toContain('unsupported_network_scheme'); - }); - - it('catches mechanism exceptions into errorReason', async () => { - const facilitator = new X402Facilitator({ logger: { warn: vi.fn(), error: vi.fn() } }) - .register( - ['tron:nile'], - makeMechanism({ - settleImpl: async () => { - throw new Error('chain rpc down'); - }, - }), - ); - - const result = await facilitator.settle(PAYLOAD, TRON_REQ); - expect(result).toEqual({ - success: false, - network: 'tron:nile', - errorReason: 'chain rpc down', - }); - }); - }); - - describe('feeQuote', () => { - it('aggregates quotes from registered mechanisms, skips misses', async () => { - const facilitator = new X402Facilitator().register( - ['tron:nile'], - makeMechanism({ - quoteResult: { - fee: { feeTo: 'TFee', feeAmount: '0' }, - pricing: 'fixed', - scheme: 'exact', - network: 'tron:nile', - asset: TRON_REQ.asset, - }, - }), - ); - - const supported = TRON_REQ; - const unsupported: PaymentRequirements = { - ...TRON_REQ, - network: 'eip155:1', - scheme: 'unknown', - }; - - const quotes = await facilitator.feeQuote([supported, unsupported]); - expect(quotes).toHaveLength(1); - expect(quotes[0]!.network).toBe('tron:nile'); - }); - - it('forwards optional context to mechanism', async () => { - const quoteFn = vi.fn(async () => null); - const mech: FacilitatorMechanism = { - scheme: () => 'exact', - feeQuote: quoteFn, - verify: vi.fn(), - settle: vi.fn(), - }; - const facilitator = new X402Facilitator().register(['tron:nile'], mech); - - await facilitator.feeQuote([TRON_REQ], { paymentId: '0x123' }); - - expect(quoteFn).toHaveBeenCalledWith(expect.anything(), { paymentId: '0x123' }); - }); - - it('drops null quotes from result', async () => { - const facilitator = new X402Facilitator().register( - ['tron:nile'], - makeMechanism({ quoteResult: null }), - ); - - const quotes = await facilitator.feeQuote([TRON_REQ]); - expect(quotes).toHaveLength(0); - }); - - it('throws when mechanism feeQuote raises', async () => { - const facilitator = new X402Facilitator().register( - ['tron:nile'], - makeMechanism({ - quoteImpl: async () => { - throw new Error('quote oracle down'); - }, - }), - ); - - await expect(facilitator.feeQuote([TRON_REQ])).rejects.toThrow( - /Fee quote failed for tron:nile\/exact: quote oracle down/, - ); - }); - }); -}); diff --git a/legacy/typescript/packages/x402/src/facilitator/x402Facilitator.ts b/legacy/typescript/packages/x402/src/facilitator/x402Facilitator.ts deleted file mode 100644 index a8d69800..00000000 --- a/legacy/typescript/packages/x402/src/facilitator/x402Facilitator.ts +++ /dev/null @@ -1,276 +0,0 @@ -/** - * X402Facilitator — TypeScript port of `bankofai.x402.facilitator.X402Facilitator`. - * - * The core in-process payment processor for an x402 facilitator service. - * Manages a registry of {@link FacilitatorMechanism}s keyed by `(network, scheme)` - * and routes verify / settle / feeQuote calls to the right implementation. - * - * This is the *engine* — wrap it with an HTTP server (Hono / Express / Fastify) - * to expose `/verify`, `/settle`, `/supported`, `/fee/quote` endpoints. - */ - -import { getAddress, isAddress } from 'viem'; - -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentRequirements, - SettleResponse, - SupportedResponse, - VerifyResponse, -} from '../types/index.js'; - -/** - * Server-side mechanism interface for the facilitator. - * - * One per `(network, scheme)` pair. Implementations live in the chain-specific - * mechanism packages (TRON / EVM / etc.) — this interface keeps the facilitator - * core agnostic of any particular chain. - */ -export interface FacilitatorMechanism { - /** Scheme name this mechanism handles (e.g. `"exact"`, `"exact_permit"`). */ - scheme(): string; - /** - * Optional fee quote for a single requirement. Return `null` when this - * mechanism cannot quote the requirement (e.g. token not in registry). - */ - feeQuote( - accept: PaymentRequirements, - context?: Record, - ): Promise; - /** Off-chain signature / replay / timing verification. */ - verify( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise; - /** On-chain settlement. */ - settle( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise; -} - -/** Optional logger interface for observability hooks. */ -export interface FacilitatorLogger { - warn(msg: string, meta?: Record): void; - error(msg: string, meta?: Record): void; -} - -const consoleLogger: FacilitatorLogger = { - warn: (msg, meta) => console.warn(`[X402Facilitator] ${msg}`, meta ?? ''), - error: (msg, meta) => console.error(`[X402Facilitator] ${msg}`, meta ?? ''), -}; - -/** - * In-process payment processor. Mirrors the Python `X402Facilitator` 1:1. - * - * @example - * ```ts - * const facilitator = new X402Facilitator() - * .register(['tron:nile'], tronExactMechanism) - * .register(['eip155:97'], bscExactPermitMechanism); - * - * const verifyResult = await facilitator.verify(payload, requirements); - * if (verifyResult.isValid) { - * const settleResult = await facilitator.settle(payload, requirements); - * } - * ``` - */ -export class X402Facilitator { - /** network → scheme → mechanism */ - private readonly mechanisms = new Map>(); - - private readonly logger: FacilitatorLogger; - - constructor(opts?: { logger?: FacilitatorLogger }) { - this.logger = opts?.logger ?? consoleLogger; - } - - /** - * Register a mechanism for a list of networks. Returns `this` for chaining. - */ - register(networks: string[], mechanism: FacilitatorMechanism): this { - const scheme = mechanism.scheme(); - for (const network of networks) { - let bucket = this.mechanisms.get(network); - if (!bucket) { - bucket = new Map(); - this.mechanisms.set(network, bucket); - } - bucket.set(scheme, mechanism); - } - return this; - } - - /** Snapshot of registered `(x402Version, scheme, network)` triples. */ - supported(): SupportedResponse { - const kinds: SupportedResponse['kinds'] = []; - for (const [network, schemes] of this.mechanisms) { - for (const scheme of schemes.keys()) { - kinds.push({ x402Version: 2, scheme, network }); - } - } - return { kinds }; - } - - /** - * Fee quotes for a list of requirements. Unsupported `(network, scheme)` / - * mechanisms returning `null` are silently skipped — the result list may be - * shorter than the input. Per-mechanism exceptions surface as a thrown - * `Error` (caller decides whether to 4xx or 5xx the HTTP request). - */ - async feeQuote( - accepts: PaymentRequirements[], - context?: Record, - ): Promise { - const results: FeeQuoteResponse[] = []; - for (const accept of accepts) { - const normalized = this.tryNormalizeEvmRequirements(accept); - const mechanism = this.findMechanism(normalized.network, normalized.scheme); - if (!mechanism) { - continue; - } - try { - const quote = await mechanism.feeQuote(normalized, context); - if (quote !== null) { - results.push(quote); - } - } catch (err) { - throw new Error( - `Fee quote failed for ${normalized.network}/${normalized.scheme}: ${(err as Error).message}`, - { cause: err }, - ); - } - } - return results; - } - - /** - * Verify a payment payload off-chain. Always returns a {@link VerifyResponse}; - * mechanism exceptions become `isValid: false` with the message as - * `invalidReason` and a logger.error entry. - */ - async verify( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const mechanism = this.findMechanism(requirements.network, requirements.scheme); - if (!mechanism) { - return { - isValid: false, - invalidReason: `unsupported_network_scheme: ${requirements.network}/${requirements.scheme}`, - }; - } - let normalized: PaymentRequirements; - try { - normalized = this.normalizeEvmRequirements(requirements); - } catch (err) { - return { isValid: false, invalidReason: (err as Error).message }; - } - try { - return await mechanism.verify(payload, normalized); - } catch (err) { - this.logger.error('verify failed', { - network: normalized.network, - scheme: normalized.scheme, - error: (err as Error).message, - }); - return { isValid: false, invalidReason: (err as Error).message }; - } - } - - /** - * Execute on-chain settlement. Always returns a {@link SettleResponse}; - * exceptions become `success: false` with `errorReason` set. - */ - async settle( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const mechanism = this.findMechanism(requirements.network, requirements.scheme); - if (!mechanism) { - return { - success: false, - network: requirements.network, - errorReason: `unsupported_network_scheme: ${requirements.network}/${requirements.scheme}`, - }; - } - let normalized: PaymentRequirements; - try { - normalized = this.normalizeEvmRequirements(requirements); - } catch (err) { - return { - success: false, - network: requirements.network, - errorReason: (err as Error).message, - }; - } - try { - return await mechanism.settle(payload, normalized); - } catch (err) { - this.logger.error('settle failed', { - network: normalized.network, - scheme: normalized.scheme, - error: (err as Error).message, - }); - return { - success: false, - network: normalized.network, - errorReason: (err as Error).message, - }; - } - } - - private findMechanism(network: string, scheme: string): FacilitatorMechanism | null { - return this.mechanisms.get(network)?.get(scheme) ?? null; - } - - /** - * Strict variant — throws if any EVM address fails checksum. Used in verify / - * settle so the failure message ends up in the response. - */ - private normalizeEvmRequirements(reqs: PaymentRequirements): PaymentRequirements { - if (!reqs.network.startsWith('eip155:')) { - return reqs; - } - return { - ...reqs, - asset: this.checksumAddressStrict(reqs.asset, 'asset'), - payTo: this.checksumAddressStrict(reqs.payTo, 'payTo'), - extra: reqs.extra - ? { - ...reqs.extra, - fee: reqs.extra.fee - ? { - ...reqs.extra.fee, - feeTo: this.checksumAddressStrict(reqs.extra.fee.feeTo, 'extra.fee.feeTo'), - caller: reqs.extra.fee.caller - ? this.checksumAddressStrict(reqs.extra.fee.caller, 'extra.fee.caller') - : reqs.extra.fee.caller, - } - : reqs.extra.fee, - } - : reqs.extra, - }; - } - - /** - * Lenient variant for `feeQuote` — invalid-EVM-input requirements are simply - * skipped (returning the original so they can be filtered out by mechanism - * lookup miss). - */ - private tryNormalizeEvmRequirements(reqs: PaymentRequirements): PaymentRequirements { - try { - return this.normalizeEvmRequirements(reqs); - } catch { - return reqs; - } - } - - private checksumAddressStrict(address: string, fieldName: string): string { - if (!isAddress(address, { strict: false })) { - throw new Error(`Invalid EVM address for ${fieldName}: ${address}`); - } - return getAddress(address); - } -} diff --git a/legacy/typescript/packages/x402/src/http/client.test.ts b/legacy/typescript/packages/x402/src/http/client.test.ts deleted file mode 100644 index 065cf06d..00000000 --- a/legacy/typescript/packages/x402/src/http/client.test.ts +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Tests for X402FetchClient — automatic 402 challenge-retry on the client side. - * - * Uses a fake fetch impl + a stub X402Client.handlePayment so the suite stays - * hermetic. - */ - -import { describe, expect, it, vi } from 'vitest'; - -import type { X402Client } from '../client/index.js'; -import type { - PaymentPayload, - PaymentRequired, - PaymentRequirements, - SettleResponse, -} from '../types/index.js'; -import { encodePaymentPayload } from '../utils/encoding.js'; -import { - PAYMENT_REQUIRED_HEADER, - PAYMENT_RESPONSE_HEADER, - PAYMENT_SIGNATURE_HEADER, - X402FetchClient, - parsePaymentResponseHeader, -} from './client.js'; - -const REQ: PaymentRequirements = { - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', -}; - -const PAYMENT_REQUIRED: PaymentRequired = { - x402Version: 2, - accepts: [REQ], -}; - -const PAYLOAD: PaymentPayload = { - x402Version: 2, - accepted: REQ, - payload: { signature: '0x' + 'aa'.repeat(65) }, -}; - -function makeStubX402Client(payload: PaymentPayload = PAYLOAD): X402Client { - return { - handlePayment: vi.fn(async () => payload), - } as unknown as X402Client; -} - -interface ScriptedFetchCall { - url: string; - init?: RequestInit; -} - -function scriptedFetch(responses: Response[]): { - fetchImpl: typeof fetch; - calls: ScriptedFetchCall[]; -} { - const calls: ScriptedFetchCall[] = []; - let i = 0; - const fetchImpl: typeof fetch = vi.fn(async (input, init) => { - const url = typeof input === 'string' - ? input - : input instanceof URL - ? input.toString() - : input.url; - calls.push({ url, init }); - const next = responses[i++]; - if (!next) throw new Error(`scriptedFetch: no more queued responses (call #${i})`); - return next; - }) as unknown as typeof fetch; - return { fetchImpl, calls }; -} - -describe('X402FetchClient', () => { - it('passes through non-402 responses unchanged', async () => { - const ok = new Response('hello', { status: 200 }); - const { fetchImpl, calls } = scriptedFetch([ok]); - const client = new X402FetchClient(makeStubX402Client(), { fetchImpl }); - - const res = await client.get('https://example.com/api'); - - expect(res.status).toBe(200); - expect(calls).toHaveLength(1); - expect(calls[0]!.init?.method).toBe('GET'); - }); - - it('handles 402 → sign → retry happy path', async () => { - const challenge = new Response(JSON.stringify(PAYMENT_REQUIRED), { - status: 402, - headers: { - 'Content-Type': 'application/json', - [PAYMENT_REQUIRED_HEADER]: encodePaymentPayload(PAYMENT_REQUIRED), - }, - }); - const settled: SettleResponse = { - success: true, - transaction: '0xabc', - network: 'tron:nile', - }; - const success = new Response('paid', { - status: 200, - headers: { [PAYMENT_RESPONSE_HEADER]: encodePaymentPayload(settled) }, - }); - const { fetchImpl, calls } = scriptedFetch([challenge, success]); - const x402 = makeStubX402Client(); - const client = new X402FetchClient(x402, { fetchImpl }); - - const res = await client.get('https://example.com/api'); - - expect(res.status).toBe(200); - expect(calls).toHaveLength(2); - // Retry carried PAYMENT-SIGNATURE header. - const retryHeaders = calls[1]!.init?.headers as Headers; - expect(retryHeaders.get(PAYMENT_SIGNATURE_HEADER)).toBe(encodePaymentPayload(PAYLOAD)); - expect(x402.handlePayment).toHaveBeenCalledWith( - PAYMENT_REQUIRED.accepts, - 'https://example.com/api', - undefined, - undefined, - ); - // PAYMENT-RESPONSE round-trips back through the helper. - expect(parsePaymentResponseHeader(res)).toEqual(settled); - }); - - it('falls back to body-parsing when PAYMENT-REQUIRED header is missing', async () => { - const challenge = new Response(JSON.stringify(PAYMENT_REQUIRED), { - status: 402, - headers: { 'Content-Type': 'application/json' }, - }); - const success = new Response('paid', { status: 200 }); - const { fetchImpl } = scriptedFetch([challenge, success]); - const client = new X402FetchClient(makeStubX402Client(), { fetchImpl }); - - const res = await client.get('https://example.com/api'); - expect(res.status).toBe(200); - }); - - it('returns the original 402 when no PaymentRequired can be parsed', async () => { - const broken = new Response('not json', { - status: 402, - headers: { 'Content-Type': 'text/plain' }, - }); - const { fetchImpl, calls } = scriptedFetch([broken]); - const client = new X402FetchClient(makeStubX402Client(), { fetchImpl }); - - const res = await client.get('https://example.com/api'); - expect(res.status).toBe(402); - expect(calls).toHaveLength(1); - }); - - it('forwards method-specific shorthands correctly', async () => { - const ok = () => new Response('', { status: 200 }); - const { fetchImpl, calls } = scriptedFetch([ok(), ok(), ok(), ok(), ok()]); - const client = new X402FetchClient(makeStubX402Client(), { fetchImpl }); - - await client.get('https://e.com/g'); - await client.post('https://e.com/p', 'body1'); - await client.put('https://e.com/u', 'body2'); - await client.patch('https://e.com/h', 'body3'); - await client.delete('https://e.com/d'); - - expect(calls.map((c) => c.init?.method)).toEqual([ - 'GET', - 'POST', - 'PUT', - 'PATCH', - 'DELETE', - ]); - expect(calls[1]!.init?.body).toBe('body1'); - expect(calls[2]!.init?.body).toBe('body2'); - expect(calls[3]!.init?.body).toBe('body3'); - }); - - it('parsePaymentResponseHeader returns null for missing / malformed headers', () => { - const noHeader = new Response('', { status: 200 }); - expect(parsePaymentResponseHeader(noHeader)).toBeNull(); - - const badHeader = new Response('', { - status: 200, - headers: { [PAYMENT_RESPONSE_HEADER]: 'not-base64-json' }, - }); - expect(parsePaymentResponseHeader(badHeader)).toBeNull(); - }); - - it('legacy positional selector argument is accepted (back-compat surface)', () => { - // Construction with a positional selector keeps the pre-options surface alive. - // Behaviour-wise the legacy path falls back to global fetch (no fetchImpl - // injection slot) — the surface preserved here is the type-level contract. - const selector = vi.fn(); - expect(() => new X402FetchClient(makeStubX402Client(), selector)).not.toThrow(); - }); -}); diff --git a/legacy/typescript/packages/x402/src/http/client.ts b/legacy/typescript/packages/x402/src/http/client.ts deleted file mode 100644 index 4baa111d..00000000 --- a/legacy/typescript/packages/x402/src/http/client.ts +++ /dev/null @@ -1,195 +0,0 @@ -/** - * X402FetchClient — Fetch-based HTTP client with automatic 402 payment handling. - * - * Mirrors `bankofai.x402.clients.X402HttpClient` on the Python side. Wraps the - * global `fetch` (configurable for tests) so agent code can call any URL and - * have 402 challenges silently handled — challenge → sign → retry → return - * the final 200 response, with the settled payment receipt parseable via - * {@link parsePaymentResponseHeader}. - */ - -import { - type PaymentPayload, - type PaymentRequired, - type PaymentRequirementsSelector, - type SettleResponse, - X402Client, - decodePaymentPayload, - encodePaymentPayload, -} from '../index.js'; - -/** Wire-format header names. */ -export const PAYMENT_SIGNATURE_HEADER = 'PAYMENT-SIGNATURE'; -export const PAYMENT_REQUIRED_HEADER = 'PAYMENT-REQUIRED'; -export const PAYMENT_RESPONSE_HEADER = 'PAYMENT-RESPONSE'; - -/** Constructor options for {@link X402FetchClient}. */ -export interface X402FetchClientOptions { - /** Custom payment requirements selector (defaults to library default). */ - selector?: PaymentRequirementsSelector; - /** Custom fetch implementation (defaults to global `fetch`). Useful for tests. */ - fetchImpl?: typeof fetch; -} - -/** - * Fetch-based HTTP client with automatic 402 payment handling. - * - * @example - * ```ts - * const x402Client = new X402Client(...).register(mechanism); - * const httpClient = new X402FetchClient(x402Client); - * - * const res = await httpClient.get('https://api.example.com/llm'); - * if (res.ok) { - * const settled = parsePaymentResponseHeader(res); - * console.log('paid via tx', settled?.transaction); - * } - * ``` - */ -export class X402FetchClient { - private readonly x402Client: X402Client; - private readonly selector?: PaymentRequirementsSelector; - private readonly fetchImpl: typeof fetch; - - constructor( - x402Client: X402Client, - selectorOrOptions?: PaymentRequirementsSelector | X402FetchClientOptions, - ) { - this.x402Client = x402Client; - if (typeof selectorOrOptions === 'function') { - this.selector = selectorOrOptions; - this.fetchImpl = fetch; - } else { - this.selector = selectorOrOptions?.selector; - this.fetchImpl = selectorOrOptions?.fetchImpl ?? fetch; - } - } - - /** - * Issue a request with automatic 402 → pay → retry handling. - * - * If the server returns a non-402 status, the response is passed through. - * If the 402 cannot be parsed (no PAYMENT-REQUIRED header and no parseable - * body), the original 402 is returned to the caller for inspection. - */ - async request(url: string, init?: RequestInit): Promise { - const response = await this.fetchImpl(url, init); - if (response.status !== 402) { - return response; - } - - const paymentRequired = await this.parsePaymentRequired(response); - if (!paymentRequired) { - return response; - } - - const paymentPayload = await this.x402Client.handlePayment( - paymentRequired.accepts, - url, - paymentRequired.extensions, - this.selector, - ); - - return this.retryWithPayment(url, init, paymentPayload); - } - - /** GET shorthand. */ - async get(url: string, init?: RequestInit): Promise { - return this.request(url, { ...init, method: 'GET' }); - } - - /** POST shorthand. */ - async post( - url: string, - body?: RequestInit['body'], - init?: RequestInit, - ): Promise { - return this.request(url, { ...init, method: 'POST', body }); - } - - /** PUT shorthand. */ - async put( - url: string, - body?: RequestInit['body'], - init?: RequestInit, - ): Promise { - return this.request(url, { ...init, method: 'PUT', body }); - } - - /** PATCH shorthand. */ - async patch( - url: string, - body?: RequestInit['body'], - init?: RequestInit, - ): Promise { - return this.request(url, { ...init, method: 'PATCH', body }); - } - - /** DELETE shorthand. */ - async delete(url: string, init?: RequestInit): Promise { - return this.request(url, { ...init, method: 'DELETE' }); - } - - /** - * Try to parse a `PaymentRequired` from the 402 response. - * - * Order: - * 1. `PAYMENT-REQUIRED` header (base64 JSON). - * 2. JSON body fallback when header is missing or undecodable. - * - * Returns `null` if neither path yields a recognizable shape. - */ - private async parsePaymentRequired(response: Response): Promise { - const headerValue = response.headers.get(PAYMENT_REQUIRED_HEADER); - if (headerValue) { - try { - return decodePaymentPayload(headerValue); - } catch { - // Header malformed — fall through to body. - } - } - - try { - const body = (await response.clone().json()) as Record; - if (Array.isArray(body.accepts)) { - return body as unknown as PaymentRequired; - } - } catch { - // Body not parseable — give up. - } - - return null; - } - - /** Re-issue the original request with the encoded payment payload header. */ - private async retryWithPayment( - url: string, - init: RequestInit | undefined, - paymentPayload: PaymentPayload, - ): Promise { - const encoded = encodePaymentPayload(paymentPayload); - const headers = new Headers(init?.headers); - headers.set(PAYMENT_SIGNATURE_HEADER, encoded); - return this.fetchImpl(url, { ...init, headers }); - } -} - -/** - * Pull the {@link SettleResponse} out of a 200 response's PAYMENT-RESPONSE header. - * - * Servers attach this on success so the client can record the settlement tx - * hash / network without making a separate facilitator call. - * - * @returns The decoded settle response, or `null` if the header is absent or malformed. - */ -export function parsePaymentResponseHeader(response: Response): SettleResponse | null { - const headerValue = response.headers.get(PAYMENT_RESPONSE_HEADER); - if (!headerValue) { - return null; - } - try { - return decodePaymentPayload(headerValue); - } catch { - return null; - } -} diff --git a/legacy/typescript/packages/x402/src/http/index.ts b/legacy/typescript/packages/x402/src/http/index.ts deleted file mode 100644 index 4a20c331..00000000 --- a/legacy/typescript/packages/x402/src/http/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -/** - * x402 Fetch HTTP Client Adapter - */ - -export { X402FetchClient } from './client.js'; diff --git a/legacy/typescript/packages/x402/src/index.ts b/legacy/typescript/packages/x402/src/index.ts deleted file mode 100644 index ed5975cf..00000000 --- a/legacy/typescript/packages/x402/src/index.ts +++ /dev/null @@ -1,49 +0,0 @@ -/** - * x402 TypeScript SDK - * - * @packageDocumentation - */ - -// Core -export * from './client/index.js'; -export * from './types/index.js'; -export * from './utils/index.js'; -export * from './abi.js'; -export * from './config.js'; -export * from './errors.js'; -export * from './tokens.js'; -export * from './address.js'; - -// HTTP Client -export * from './http/client.js'; - -// Facilitator client (talks to remote /verify, /settle, /supported, /fee/quote) -export * from './facilitator/index.js'; - -// High-level server API (X402Server, ResourceConfig, ServerMechanism) -export * from './server/index.js'; - -// Server middleware (Hono / Express adapters + framework-agnostic core) -export * from './middleware/index.js'; - -// Mechanisms -export * from './mechanisms/index.js'; - -// EVM ExactPermit Mechanism -export * from './mechanisms/evm/exact_permit/index.js'; - -// TRON Signer -export * from './signers/signer.js'; -// EVM Signer -export * from './signers/evmSigner.js'; -export type { TronWeb, TypedDataDomain, TypedDataField, TronNetwork, TRON_CHAIN_IDS } from './signers/types.js'; - -// Facilitator signers (verify + writeContract + receipt polling) -export { FacilitatorSigner } from './signers/facilitator/base.js'; -export type { - FacilitatorTypedDataDomain, - FacilitatorTypedDataTypes, - FacilitatorTransactionReceipt, -} from './signers/index.js'; -export { TronFacilitatorSigner } from './signers/facilitator/tronSigner.js'; -export { EvmFacilitatorSigner } from './signers/facilitator/evmSigner.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/_base/index.ts b/legacy/typescript/packages/x402/src/mechanisms/_base/index.ts deleted file mode 100644 index df69d42b..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_base/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Base mechanism interfaces — mirrors Python `bankofai.x402.mechanisms._base`. - * - * The three role interfaces (`ClientMechanism`, `ServerMechanism`, - * `FacilitatorMechanism`) currently live close to where they're consumed: - * - * - `ClientMechanism` → `src/client/x402Client.ts` - * - `ServerMechanism` → `src/server/types.ts` - * - `FacilitatorMechanism` → `src/facilitator/x402Facilitator.ts` - * - * This file re-exports them under one mechanism-rooted location so that - * `mechanisms///{client,server,facilitator}.ts` modules import - * their role contract from a single canonical path. Mirrors how Python's - * `_base/{client,server,facilitator}.py` are imported by concrete mechanisms. - */ - -export type { ClientMechanism, ClientSigner } from '../../client/x402Client.js'; -export type { ServerMechanism } from '../../server/types.js'; -export type { - FacilitatorMechanism, - FacilitatorLogger, -} from '../../facilitator/x402Facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/adapter.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/adapter.ts deleted file mode 100644 index fcccf2ee..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/adapter.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * ChainAdapter — pluggable per-chain primitives for the `exact` scheme. - * - * Mirrors Python `mechanisms._exact_base.base.ChainAdapter`. Subclasses - * provide chain-specific parsing / validation / address normalization so - * `ExactBase{Client,Server,Facilitator}Mechanism` can stay chain-agnostic. - */ - -export interface ChainAdapter { - /** Parse chain id from CAIP-2 network (e.g. `"eip155:97"` → `97`). */ - parseChainId(network: string): number; - /** Check the CAIP-2 prefix is valid for this adapter (`"eip155:"` / `"tron:"`). */ - validateNetwork(network: string): boolean; - /** Format check (no on-chain lookup). */ - validateAddress(address: string): boolean; - /** Canonicalize for storage / comparison (lowercase EVM, Base58 TRON, ...). */ - normalizeAddress(address: string): string; - /** - * Convert to the address representation used inside EIP-712 / TIP-712 typed - * data (0x-prefixed hex on both chains). Used by signing path. - */ - toSigningAddress(address: string): string; -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/evmAdapter.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/evmAdapter.ts deleted file mode 100644 index bf2f444d..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/evmAdapter.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { getAddress, isAddress } from 'viem'; - -import type { ChainAdapter } from './adapter.js'; - -/** EVM (`eip155:`) ChainAdapter. */ -export class EvmChainAdapter implements ChainAdapter { - parseChainId(network: string): number { - const parts = network.split(':'); - if (parts.length !== 2 || parts[0] !== 'eip155') { - throw new Error(`Invalid EVM network identifier: ${network}`); - } - const id = parseInt(parts[1]!, 10); - if (!Number.isFinite(id) || id <= 0) { - throw new Error(`Invalid EVM chain id in ${network}`); - } - return id; - } - - validateNetwork(network: string): boolean { - return network.startsWith('eip155:'); - } - - validateAddress(address: string): boolean { - return isAddress(address, { strict: false }); - } - - normalizeAddress(address: string): string { - return this.validateAddress(address) ? address.toLowerCase() : address; - } - - toSigningAddress(address: string): string { - return this.validateAddress(address) ? getAddress(address) : address; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/facilitator.ts deleted file mode 100644 index a8a21b5c..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/facilitator.ts +++ /dev/null @@ -1,316 +0,0 @@ -/** - * Shared base for `exact` scheme facilitator mechanisms. - * - * Mirrors Python `mechanisms._exact_base.base.ExactBaseFacilitatorMechanism`. - * - * Per-chain subclasses provide a {@link ChainAdapter}. The base handles: - * - structural verification (asset / payTo / value match, time window) - * - ERC-3009 EIP-712 signature recovery via the injected FacilitatorSigner - * - `transferWithAuthorization` settle + receipt polling - * - * Subclasses ONLY need to override: - * - `settlePaymentOnly()` — chain-specific contract call dispatch (TRON - * triggerSmartContract vs EVM viem writeContract) - */ - -import type { ChainAdapter } from './adapter.js'; -import type { FacilitatorMechanism } from '../../facilitator/x402Facilitator.js'; -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentRequirements, - SettleResponse, - TransferAuthorization, - VerifyResponse, -} from '../../types/index.js'; -import { FacilitatorSigner } from '../../signers/facilitator/base.js'; -import { findByAddress } from '../../tokens.js'; -import { - SCHEME_EXACT, - TRANSFER_AUTH_EIP712_TYPES, - TRANSFER_AUTH_PRIMARY_TYPE, -} from './types.js'; - -const FEE_QUOTE_EXPIRY_SECONDS = 300; - -function hexToBytes(hex: string): Uint8Array { - const clean = hex.startsWith('0x') ? hex.slice(2) : hex; - const out = new Uint8Array(clean.length / 2); - for (let i = 0; i < out.length; i++) { - out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16); - } - return out; -} - -export abstract class ExactBaseFacilitatorMechanism - implements FacilitatorMechanism -{ - protected readonly signer: FacilitatorSigner; - protected readonly adapter: ChainAdapter; - protected readonly allowedTokens: ReadonlySet | null; - - constructor( - signer: FacilitatorSigner, - adapter: ChainAdapter, - options: { allowedTokens?: ReadonlyArray } = {}, - ) { - this.signer = signer; - this.adapter = adapter; - this.allowedTokens = options.allowedTokens - ? new Set(options.allowedTokens.map((t) => adapter.normalizeAddress(t))) - : null; - } - - scheme(): string { - return SCHEME_EXACT; - } - - /** - * `exact` scheme has no facilitator fee (single transfer per authorization). - * Returns `feeAmount: "0"` for compatibility with the `/fee/quote` flow. - */ - async feeQuote( - accept: PaymentRequirements, - _context?: Record, - ): Promise { - return { - fee: { feeTo: this.signer.getAddress(), feeAmount: '0' }, - pricing: 'flat', - scheme: accept.scheme, - network: accept.network, - asset: accept.asset, - expiresAt: Math.floor(Date.now() / 1000) + FEE_QUOTE_EXPIRY_SECONDS, - } as unknown as FeeQuoteResponse; - } - - /** - * Off-chain verify: structural + timing checks, then EIP-712 signature - * recovery against the token's ERC-3009 domain. - */ - async verify( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const auth = this.extractAuthorization(payload); - if (!auth) { - return { isValid: false, invalidReason: 'missing_transfer_authorization' }; - } - - const validationError = this.validateAuthorization(auth, requirements); - if (validationError) { - return { isValid: false, invalidReason: validationError }; - } - - const validSig = await this.verifySignature( - auth, - payload.payload.signature, - requirements, - ); - if (!validSig) { - return { isValid: false, invalidReason: 'invalid_signature' }; - } - return { isValid: true }; - } - - /** - * Settle: verify, then submit `transferWithAuthorization(v,r,s)` via the - * subclass-provided `settlePaymentOnly`, then poll the receipt. - */ - async settle( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const verifyResult = await this.verify(payload, requirements); - if (!verifyResult.isValid) { - return { - success: false, - network: requirements.network, - errorReason: verifyResult.invalidReason, - }; - } - - const auth = this.extractAuthorization(payload)!; - const signature = payload.payload.signature; - - let txHash: string | null; - try { - txHash = await this.settlePaymentOnly(auth, signature, requirements); - } catch (err) { - return { - success: false, - network: requirements.network, - errorReason: `settle_error: ${err instanceof Error ? err.message : String(err)}`, - }; - } - if (!txHash) { - return { - success: false, - network: requirements.network, - errorReason: 'transaction_failed', - }; - } - - try { - const receipt = await this.signer.waitForTransactionReceipt( - txHash, - requirements.network, - ); - if (receipt.status !== 'confirmed') { - return { - success: false, - network: requirements.network, - transaction: txHash, - errorReason: 'transaction_failed_on_chain', - }; - } - } catch (err) { - return { - success: false, - network: requirements.network, - transaction: txHash, - errorReason: `receipt_timeout: ${err instanceof Error ? err.message : String(err)}`, - }; - } - - return { - success: true, - network: requirements.network, - transaction: txHash, - }; - } - - // ------------------------------------------------------------------------- - // Protected helpers - // ------------------------------------------------------------------------- - - protected validateAuthorization( - auth: TransferAuthorization, - requirements: PaymentRequirements, - ): string | null { - const norm = (s: string) => this.adapter.normalizeAddress(s); - - if ( - this.allowedTokens !== null && - !this.allowedTokens.has(norm(requirements.asset)) - ) { - return 'token_not_allowed'; - } - - try { - if (BigInt(auth.value) < BigInt(requirements.amount)) { - return 'amount_mismatch'; - } - } catch { - return 'invalid_value'; - } - - if (norm(auth.to) !== norm(requirements.payTo)) { - return 'payto_mismatch'; - } - - const now = Math.floor(Date.now() / 1000); - try { - if (BigInt(auth.validBefore) < BigInt(now)) return 'expired'; - if (BigInt(auth.validAfter) > BigInt(now)) return 'not_yet_valid'; - } catch { - return 'invalid_time_window'; - } - return null; - } - - /** - * Verify the buyer's ERC-3009 EIP-712 signature against the token's domain. - * - * Domain shape (ERC-3009): `{ name, version, chainId, verifyingContract: }`. - * Token name / version come from the SDK token registry; addresses are - * converted to signing format (0x EVM hex) for both EVM and TRON. - */ - protected async verifySignature( - auth: TransferAuthorization, - signature: string, - requirements: PaymentRequirements, - ): Promise { - const adapter = this.adapter; - const chainId = adapter.parseChainId(requirements.network); - const tokenInfo = findByAddress(requirements.network, requirements.asset); - const tokenName = tokenInfo?.name ?? 'Unknown Token'; - const tokenVersion = tokenInfo?.version ?? '1'; - - const domain = { - name: tokenName, - version: tokenVersion, - chainId, - verifyingContract: adapter.toSigningAddress(requirements.asset), - }; - const message = { - from: adapter.toSigningAddress(auth.from), - to: adapter.toSigningAddress(auth.to), - value: BigInt(auth.value), - validAfter: BigInt(auth.validAfter), - validBefore: BigInt(auth.validBefore), - // viem accepts hex string for bytes32 types - nonce: auth.nonce.startsWith('0x') ? auth.nonce : `0x${auth.nonce}`, - }; - - return this.signer.verifyTypedData( - adapter.toSigningAddress(auth.from), - domain, - TRANSFER_AUTH_EIP712_TYPES as unknown as Record< - string, - ReadonlyArray<{ name: string; type: string }> - >, - message, - signature, - TRANSFER_AUTH_PRIMARY_TYPE, - ); - } - - /** - * Split a 65-byte signature into v / r / s for the (v, r, s) variant of - * `transferWithAuthorization`. v is normalized to 27 or 28 (some signers - * return 0 / 1). - */ - protected splitSignature(signature: string): { - v: number; - r: `0x${string}`; - s: `0x${string}`; - } { - const sigBytes = hexToBytes(signature); - if (sigBytes.length !== 65) { - throw new Error(`Invalid signature length: ${sigBytes.length}`); - } - const r = - '0x' + - Array.from(sigBytes.slice(0, 32)) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); - const s = - '0x' + - Array.from(sigBytes.slice(32, 64)) - .map((b) => b.toString(16).padStart(2, '0')) - .join(''); - let v = sigBytes[64]!; - if (v < 27) v += 27; - return { v, r: r as `0x${string}`, s: s as `0x${string}` }; - } - - protected extractAuthorization( - payload: PaymentPayload, - ): TransferAuthorization | null { - if (payload.payload.authorization) return payload.payload.authorization; - const ext = (payload.extensions ?? {})['transferAuthorization']; - return (ext as TransferAuthorization) ?? null; - } - - /** - * Submit the authorization on-chain. Chain-specific — subclasses MUST - * implement (TRON via tronweb, EVM via viem). - * - * Returns the tx hash on broadcast success, or `null` on broadcast failure. - */ - protected abstract settlePaymentOnly( - auth: TransferAuthorization, - signature: string, - requirements: PaymentRequirements, - ): Promise; -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/index.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/index.ts deleted file mode 100644 index 4d223c2b..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Shared base for the `exact` scheme — mirrors Python - * `bankofai.x402.mechanisms._exact_base`. - */ - -export { - DEFAULT_VALIDITY_SECONDS, - SCHEME_EXACT, - TRANSFER_AUTH_EIP712_TYPES, - TRANSFER_AUTH_PRIMARY_TYPE, - buildEip712Domain, - buildEip712Message, - createNonce, - createValidityWindow, -} from './types.js'; -export type { TransferAuthorization } from './types.js'; - -export type { ChainAdapter } from './adapter.js'; -export { EvmChainAdapter } from './evmAdapter.js'; -export { TronChainAdapter } from './tronAdapter.js'; -export { ExactBaseServerMechanism } from './server.js'; -export { ExactBaseFacilitatorMechanism } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/server.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/server.ts deleted file mode 100644 index bde08c0e..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/server.ts +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Shared base for `exact` scheme server mechanisms. - * - * Mirrors Python `mechanisms._exact_base.base.ExactBaseServerMechanism`. - * - * Per-chain mechanisms (`evm/exact/server.ts`, `tron/exact/server.ts`) - * subclass this and provide a {@link ChainAdapter}. The base handles: - * - price parsing (delegate to {@link parsePrice}) - * - requirements enhancement (token name / version from registry) - * - basic validation (network + address format) - * - * `verify_signature` requires on-chain or chain-specific signing libs — left - * abstract here for subclasses to implement with their chain's tooling. - */ - -import type { ChainAdapter } from './adapter.js'; -import { parsePrice, findByAddress } from '../../tokens.js'; -import type { ServerMechanism } from '../../server/types.js'; -import type { - PaymentPayload, - PaymentPermit, - PaymentRequirements, -} from '../../types/index.js'; -import { SCHEME_EXACT } from './types.js'; - -export abstract class ExactBaseServerMechanism implements ServerMechanism { - constructor(protected readonly adapter: ChainAdapter) {} - - scheme(): string { - return SCHEME_EXACT; - } - - async parsePrice(price: string, network: string) { - return parsePrice(price, network); - } - - /** - * Attach token name + version to `extra` so clients have everything needed - * to build the EIP-712 / TIP-712 typed-data domain. - */ - async enhancePaymentRequirements( - requirements: PaymentRequirements, - _deliveryMode: string, - ): Promise { - const token = findByAddress(requirements.network, requirements.asset); - if (!token) return requirements; - return { - ...requirements, - extra: { - ...(requirements.extra ?? {}), - name: token.name, - ...(token.version ? { version: token.version } : {}), - }, - }; - } - - validatePaymentRequirements(requirements: PaymentRequirements): boolean { - if (!this.adapter.validateNetwork(requirements.network)) return false; - if (!this.adapter.validateAddress(requirements.asset)) return false; - if (!this.adapter.validateAddress(requirements.payTo)) return false; - return true; - } - - /** - * Server-side signature verification. Chain-specific — subclasses must - * implement using their chain's signature recovery primitives (viem for - * EVM, tron-utils for TRON). - * - * For `exact`, the signed object is the `authorization` (ERC-3009-style). - */ - abstract verifySignature( - permit: PaymentPermit | null | undefined, - signature: string, - network: string, - ): Promise; - - /** Convenience hook to pull the authorization out of a payload. */ - protected extractAuthorization( - payload: PaymentPayload, - ): PaymentPayload['payload']['authorization'] | null { - if (payload.payload.authorization) return payload.payload.authorization; - const ext = (payload.extensions ?? {})['transferAuthorization']; - return (ext as PaymentPayload['payload']['authorization']) ?? null; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/tronAdapter.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/tronAdapter.ts deleted file mode 100644 index 2bb3c9a7..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/tronAdapter.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { TronAddressConverter, toBase58 } from '../../address.js'; -import type { ChainAdapter } from './adapter.js'; - -const TRON_CHAIN_IDS: Record = { - 'tron:mainnet': 728126428, - 'tron:shasta': 2494104990, - 'tron:nile': 3448148188, -}; - -const TRON_CONVERTER = new TronAddressConverter(); - -/** TRON (`tron:`) ChainAdapter. */ -export class TronChainAdapter implements ChainAdapter { - parseChainId(network: string): number { - const id = TRON_CHAIN_IDS[network]; - if (id === undefined) { - throw new Error(`Unknown TRON network: ${network}`); - } - return id; - } - - validateNetwork(network: string): boolean { - return network.startsWith('tron:'); - } - - validateAddress(address: string): boolean { - if (typeof address !== 'string') return false; - // Accept both Base58 (T...) and 0x-prefixed hex forms - if (address.startsWith('T') && address.length === 34) return true; - if (address.startsWith('0x') && address.length === 42) return true; - return false; - } - - normalizeAddress(address: string): string { - if (!this.validateAddress(address)) return address; - if (address.startsWith('0x')) { - try { - return toBase58(address); - } catch { - return address; - } - } - return address; - } - - /** TIP-712 requires 0x-prefixed EVM-hex form for every address field. */ - toSigningAddress(address: string): string { - return TRON_CONVERTER.toEvmFormat(address); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/types.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_base/types.ts deleted file mode 100644 index 024bacd3..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_base/types.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Shared types and helpers for exact mechanism. - * - * exact uses ERC-3009 TransferWithAuthorization for direct token transfers - * without going through a PaymentPermit contract. - */ - -import type { Hex } from '../../address.js'; -import type { TransferAuthorization } from '../../types/payment.js'; - -export type { TransferAuthorization } from '../../types/payment.js'; - -/** Scheme name */ -export const SCHEME_EXACT = 'exact'; - -/** Default validity period (1 hour) */ -export const DEFAULT_VALIDITY_SECONDS = 3600; - -/** - * EIP-712 type definitions for TransferWithAuthorization - * Note: domain includes "version" field (unlike PaymentPermit) - */ -export const TRANSFER_AUTH_EIP712_TYPES = { - TransferWithAuthorization: [ - { name: 'from', type: 'address' }, - { name: 'to', type: 'address' }, - { name: 'value', type: 'uint256' }, - { name: 'validAfter', type: 'uint256' }, - { name: 'validBefore', type: 'uint256' }, - { name: 'nonce', type: 'bytes32' }, - ], -} as const; - -export const TRANSFER_AUTH_PRIMARY_TYPE = 'TransferWithAuthorization'; - -/** - * Build EIP-712 domain for exact - */ -export function buildEip712Domain( - tokenName: string, - tokenVersion: string, - chainId: number, - verifyingContract: string, -): Record { - return { - name: tokenName, - version: tokenVersion, - chainId, - verifyingContract, - }; -} - -/** - * Build EIP-712 message from TransferAuthorization - */ -export function buildEip712Message( - auth: TransferAuthorization, - toSigningAddress: (addr: string) => Hex, -): Record { - return { - from: toSigningAddress(auth.from), - to: toSigningAddress(auth.to), - value: BigInt(auth.value), - validAfter: BigInt(auth.validAfter), - validBefore: BigInt(auth.validBefore), - nonce: auth.nonce, - }; -} - -/** - * Generate a random 32-byte nonce (0x-prefixed hex) - */ -export function createNonce(): string { - const bytes = new Uint8Array(32); - crypto.getRandomValues(bytes); - return '0x' + Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join(''); -} - -/** - * Create (validAfter, validBefore) timestamps. - * Adds a 30-second buffer before now to account for clock skew. - */ -export function createValidityWindow( - duration: number = DEFAULT_VALIDITY_SECONDS, -): [number, number] { - const now = Math.floor(Date.now() / 1000); - return [now - 30, now + duration]; -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/facilitator.ts deleted file mode 100644 index ed19b882..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/facilitator.ts +++ /dev/null @@ -1,396 +0,0 @@ -/** - * Shared base for `exact_permit` scheme facilitator mechanisms. - * - * Mirrors Python `mechanisms._exact_permit_base.facilitator.BaseExactPermitFacilitatorMechanism`. - * - * Subclasses override: - * - {@link getAddressConverter} — chain-specific address normalization - * - {@link settlePaymentOnly} — chain-specific contract call (PaymentPermit.permitTransferFrom) - */ - -import { FacilitatorSigner } from '../../signers/facilitator/base.js'; -import type { FacilitatorMechanism } from '../../facilitator/x402Facilitator.js'; -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentPermit, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../../types/index.js'; -import { - KIND_MAP, - PAYMENT_PERMIT_PRIMARY_TYPE, - PAYMENT_PERMIT_TYPES, -} from '../../abi.js'; -import { findByAddress } from '../../tokens.js'; -import { getChainId, getPaymentPermitAddress } from '../../config.js'; -import type { AddressConverter } from '../../address.js'; - -const SCHEME_EXACT_PERMIT = 'exact_permit'; - -/** Fee policy used by `feeQuote`. */ -export interface BaseExactPermitFee { - /** - * Address that collects the facilitator fee. Defaults to - * `signer.getAddress()` when undefined. - */ - feeTo?: string; - /** Optional caller address that the on-chain contract requires. */ - caller?: string; - /** - * Per-symbol base fee (smallest unit string). Token symbol is uppercased - * before lookup. Tokens not in this map are rejected by `fee_quote` and - * `_validate_permit`. - */ - baseFee?: Record; - /** - * Optional token allowlist (lowercased addresses). If set, only tokens - * in this set are accepted; otherwise all tokens pass the address check. - */ - allowedTokens?: ReadonlyArray; -} - -/** - * Tuple shape passed to `triggerSmartContract` (TRON) or `writeContract` (EVM) - * for `PaymentPermit.permitTransferFrom`. Matches the on-chain ABI tuple. - */ -export type PermitTuple = [ - // meta - [ - number, // kind (uint8) - `0x${string}`, // paymentId (bytes16) - string, // nonce (uint256 string) - number, // validAfter (uint256) - number, // validBefore (uint256) - ], - string, // buyer (address) - string, // caller (address) - // payment - [ - string, // payToken - string, // payAmount (uint256 string) - string, // payTo - ], - // fee - [ - string, // feeTo - string, // feeAmount (uint256 string) - ], -]; - -const FEE_QUOTE_EXPIRY_SECONDS = 300; - -export abstract class BaseExactPermitFacilitatorMechanism - implements FacilitatorMechanism -{ - protected readonly signer: FacilitatorSigner; - protected readonly feeTo: string; - protected readonly caller: string; - protected readonly baseFeeMap: Record; - protected readonly allowedTokens: ReadonlySet | null; - protected readonly addressConverter: AddressConverter; - - constructor(signer: FacilitatorSigner, fee: BaseExactPermitFee = {}) { - this.signer = signer; - this.feeTo = fee.feeTo ?? signer.getAddress(); - this.caller = fee.caller ?? signer.getAddress(); - this.addressConverter = this.getAddressConverter(); - this.baseFeeMap = {}; - if (fee.baseFee) { - for (const [symbol, amount] of Object.entries(fee.baseFee)) { - this.baseFeeMap[symbol.toUpperCase()] = BigInt(amount); - } - } - this.allowedTokens = fee.allowedTokens - ? new Set(fee.allowedTokens.map((t) => this.addressConverter.normalize(t))) - : null; - } - - scheme(): string { - return SCHEME_EXACT_PERMIT; - } - - /** Chain-specific address converter. */ - protected abstract getAddressConverter(): AddressConverter; - - /** - * Look up base fee for a token by symbol. Returns `null` if the token is - * not registered in the SDK token registry or the symbol has no entry - * in `baseFeeMap`. - */ - protected getBaseFee(tokenAddress: string, network: string): bigint | null { - const tokenInfo = findByAddress(network, tokenAddress); - if (!tokenInfo) return null; - const symbol = tokenInfo.symbol.toUpperCase(); - if (!(symbol in this.baseFeeMap)) return null; - return this.baseFeeMap[symbol]!; - } - - async feeQuote( - accept: PaymentRequirements, - _context?: Record, - ): Promise { - const baseFee = this.getBaseFee(accept.asset, accept.network); - if (baseFee === null) { - return null; - } - return { - fee: { - feeTo: this.feeTo, - feeAmount: baseFee.toString(), - caller: this.caller, - }, - pricing: 'flat', - scheme: accept.scheme, - network: accept.network, - asset: accept.asset, - expiresAt: Math.floor(Date.now() / 1000) + FEE_QUOTE_EXPIRY_SECONDS, - } as unknown as FeeQuoteResponse; - } - - /** - * Off-chain verify path: structural + fee + signature checks. - */ - async verify( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const permit = payload.payload.paymentPermit; - if (!permit) { - return { isValid: false, invalidReason: 'missing_permit' }; - } - const validationError = this.validatePermit(permit, requirements); - if (validationError) { - return { isValid: false, invalidReason: validationError }; - } - - const signature = payload.payload.signature; - const validSig = await this.verifySignature( - permit, - signature, - requirements.network, - ); - if (!validSig) { - return { isValid: false, invalidReason: 'invalid_signature' }; - } - return { isValid: true }; - } - - /** - * Settle the permit on-chain: verify, then submit via subclass - * `settlePaymentOnly`, then poll the receipt. - */ - async settle( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const verifyResult = await this.verify(payload, requirements); - if (!verifyResult.isValid) { - return { - success: false, - network: requirements.network, - errorReason: verifyResult.invalidReason, - }; - } - const permit = payload.payload.paymentPermit!; - const signature = payload.payload.signature; - - let txHash: string | null; - try { - txHash = await this.settlePaymentOnly(permit, signature, requirements); - } catch (err) { - return { - success: false, - network: requirements.network, - errorReason: `settle_error: ${err instanceof Error ? err.message : String(err)}`, - }; - } - if (!txHash) { - return { - success: false, - network: requirements.network, - errorReason: 'transaction_failed', - }; - } - - // Poll receipt - try { - const receipt = await this.signer.waitForTransactionReceipt( - txHash, - requirements.network, - ); - if (receipt.status !== 'confirmed') { - return { - success: false, - network: requirements.network, - transaction: txHash, - errorReason: 'transaction_failed_on_chain', - }; - } - } catch (err) { - // Receipt timeout — return tx hash + flag as failed-pending so the - // client can re-check; same shape Python uses. - return { - success: false, - network: requirements.network, - transaction: txHash, - errorReason: `receipt_timeout: ${err instanceof Error ? err.message : String(err)}`, - }; - } - - return { - success: true, - network: requirements.network, - transaction: txHash, - }; - } - - // ------------------------------------------------------------------------- - // Protected helpers used by subclasses + verify/settle - // ------------------------------------------------------------------------- - - /** - * Structural + fee validation. Returns the error reason string, or `null` - * if valid. - */ - protected validatePermit( - permit: PaymentPermit, - requirements: PaymentRequirements, - ): string | null { - const norm = (s: string) => this.addressConverter.normalize(s); - - if (this.allowedTokens !== null && !this.allowedTokens.has(norm(permit.payment.payToken))) { - return 'token_not_allowed'; - } - try { - if (BigInt(permit.payment.payAmount) < BigInt(requirements.amount)) { - return 'amount_mismatch'; - } - } catch { - return 'invalid_amount'; - } - if (norm(permit.payment.payTo) !== norm(requirements.payTo)) { - return 'payto_mismatch'; - } - if (norm(permit.payment.payToken) !== norm(requirements.asset)) { - return 'token_mismatch'; - } - if (norm(permit.fee.feeTo) !== norm(this.feeTo)) { - return 'fee_to_mismatch'; - } - const expectedFee = this.getBaseFee(permit.payment.payToken, requirements.network); - if (expectedFee === null) { - return 'unsupported_token'; - } - try { - if (BigInt(permit.fee.feeAmount) < expectedFee) { - return 'fee_amount_mismatch'; - } - } catch { - return 'invalid_fee'; - } - - const now = Math.floor(Date.now() / 1000); - if (permit.meta.validBefore < now) return 'expired'; - if (permit.meta.validAfter > now) return 'not_yet_valid'; - - return null; - } - - /** - * Verify the buyer's EIP-712 / TIP-712 signature against the permit. - * - * Build the message in the exact shape the buyer signed: - * - `kind` as numeric (0 for PAYMENT_ONLY) - * - `paymentId` as hex string (bytes16 — viem accepts hex) - * - `nonce` / amounts as BigInt strings - * - all addresses converted to 0x EVM hex (required for TRON TIP-712) - */ - protected async verifySignature( - permit: PaymentPermit, - signature: string, - network: string, - ): Promise { - const permitContract = getPaymentPermitAddress(network); - const chainId = getChainId(network); - const converter = this.addressConverter; - - const message: Record = { - meta: { - kind: KIND_MAP[permit.meta.kind], - paymentId: permit.meta.paymentId, // hex string OK - nonce: BigInt(permit.meta.nonce), - validAfter: BigInt(permit.meta.validAfter), - validBefore: BigInt(permit.meta.validBefore), - }, - buyer: converter.toEvmFormat(permit.buyer), - caller: converter.toEvmFormat(permit.caller), - payment: { - payToken: converter.toEvmFormat(permit.payment.payToken), - payAmount: BigInt(permit.payment.payAmount), - payTo: converter.toEvmFormat(permit.payment.payTo), - }, - fee: { - feeTo: converter.toEvmFormat(permit.fee.feeTo), - feeAmount: BigInt(permit.fee.feeAmount), - }, - }; - - return this.signer.verifyTypedData( - permit.buyer, - { - name: 'PaymentPermit', - chainId, - verifyingContract: converter.toEvmFormat(permitContract), - }, - PAYMENT_PERMIT_TYPES as unknown as Record< - string, - ReadonlyArray<{ name: string; type: string }> - >, - message, - signature, - PAYMENT_PERMIT_PRIMARY_TYPE, - ); - } - - /** - * Build the tuple passed to `permitTransferFrom(permit, owner, signature)`. - * Addresses are returned in the chain-canonical format (Base58 for TRON, - * 0x hex for EVM) since each chain's writer accepts both — let the subclass - * normalize further if needed. - */ - protected buildPermitTuple(permit: PaymentPermit): PermitTuple { - const converter = this.addressConverter; - const norm = (s: string) => converter.normalize(s); - return [ - [ - KIND_MAP[permit.meta.kind], - permit.meta.paymentId as `0x${string}`, - permit.meta.nonce, - permit.meta.validAfter, - permit.meta.validBefore, - ], - norm(permit.buyer), - norm(permit.caller), - [ - norm(permit.payment.payToken), - permit.payment.payAmount, - norm(permit.payment.payTo), - ], - [norm(permit.fee.feeTo), permit.fee.feeAmount], - ]; - } - - /** - * Submit the permit on-chain. Chain-specific — subclasses MUST implement. - * - * Returns the tx hash on broadcast success, or `null` on failure (the base - * wraps null into a `SettleResponse{ success: false }`). - */ - protected abstract settlePaymentOnly( - permit: PaymentPermit, - signature: string, - requirements: PaymentRequirements, - ): Promise; -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/index.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/index.ts deleted file mode 100644 index e0c7a092..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Shared base for `exact_permit` scheme — mirrors Python - * `bankofai.x402.mechanisms._exact_permit_base`. - */ - -export { BaseExactPermitServerMechanism } from './server.js'; -export { - BaseExactPermitFacilitatorMechanism, -} from './facilitator.js'; -export type { BaseExactPermitFee } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/server.ts b/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/server.ts deleted file mode 100644 index da339794..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/_exact_permit_base/server.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Shared base for `exact_permit` scheme server mechanisms. - * - * Mirrors Python `mechanisms._exact_permit_base.server.BaseExactPermitServerMechanism`. - */ - -import { findByAddress, parsePrice } from '../../tokens.js'; -import type { ServerMechanism } from '../../server/types.js'; -import type { - PaymentPermit, - PaymentRequirements, -} from '../../types/index.js'; - -const SCHEME_EXACT_PERMIT = 'exact_permit'; - -export abstract class BaseExactPermitServerMechanism implements ServerMechanism { - /** CAIP-2 prefix this mechanism handles (`"eip155:"` or `"tron:"`). */ - protected abstract getNetworkPrefix(): string; - /** Format-only address validation (no on-chain lookup). */ - protected abstract validateAddressFormat(address: string): boolean; - - scheme(): string { - return SCHEME_EXACT_PERMIT; - } - - async parsePrice(price: string, network: string) { - return parsePrice(price, network); - } - - async enhancePaymentRequirements( - requirements: PaymentRequirements, - _deliveryMode: string, - ): Promise { - const token = findByAddress(requirements.network, requirements.asset); - if (!token) return requirements; - return { - ...requirements, - extra: { - ...(requirements.extra ?? {}), - name: token.name, - ...(token.version ? { version: token.version } : {}), - }, - }; - } - - validatePaymentRequirements(requirements: PaymentRequirements): boolean { - if (!requirements.network.startsWith(this.getNetworkPrefix())) return false; - if (!this.validateAddressFormat(requirements.asset)) return false; - if (!this.validateAddressFormat(requirements.payTo)) return false; - return true; - } - - /** - * Verify the EIP-712 / TIP-712 permit signature server-side. - * - * TODO(v0.6.0b): port Python's `verify_signature` — - * - hash the typed-data per chain - * - recover signer from `signature` - * - compare to `permit.buyer` - * - * Until then returns `true` and defers to the facilitator's authoritative - * verification. The interface is present so middleware can call it - * uniformly when full impl lands. - */ - async verifySignature( - _permit: PaymentPermit | null | undefined, - _signature: string, - _network: string, - ): Promise { - return true; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.test.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.test.ts deleted file mode 100644 index 580b1bbd..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { ExactEvmClientMechanism } from './client.js'; -import type { ClientSigner } from '../../../client/x402Client.js'; - -describe('ExactEvmClientMechanism', () => { - const signer: ClientSigner = { - getAddress: () => '0x1111111111111111111111111111111111111111', - signMessage: vi.fn(), - signTypedData: vi.fn().mockResolvedValue('0x' + 'ab'.repeat(65)), - checkBalance: vi.fn(), - checkAllowance: vi.fn(), - ensureAllowance: vi.fn(), - }; - - it('writes exact authorization into payload.authorization', async () => { - const mechanism = new ExactEvmClientMechanism(signer); - - const payload = await mechanism.createPaymentPayload( - { - scheme: 'exact', - network: 'eip155:8453', - amount: '1000000', - asset: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', - payTo: '0x2222222222222222222222222222222222222222', - extra: { - name: 'USD Coin', - version: '2', - }, - }, - 'https://example.com/resource', - ); - - expect(payload.payload.authorization).toBeDefined(); - expect(payload.payload.authorization?.value).toBe('1000000'); - expect(payload.payload.authorization?.to).toBe('0x2222222222222222222222222222222222222222'); - expect(payload.extensions?.transferAuthorization).toEqual(payload.payload.authorization); - }); -}); diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.ts deleted file mode 100644 index 98e018a3..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/client.ts +++ /dev/null @@ -1,104 +0,0 @@ -/** - * ExactEvmClientMechanism - EVM client mechanism for "exact" payment scheme - * - * Uses ERC-3009 TransferWithAuthorization with EIP-712 signing. - * EVM addresses are used directly without conversion. - */ - -import type { - ClientMechanism, - ClientSigner, - PaymentRequirements, - PaymentPayload, -} from '../../../index.js'; -import { - getChainId, - EvmAddressConverter, -} from '../../../index.js'; -import { findByAddress } from '../../../tokens.js'; -import { - SCHEME_EXACT, - TRANSFER_AUTH_EIP712_TYPES, - TRANSFER_AUTH_PRIMARY_TYPE, - buildEip712Domain, - buildEip712Message, - createNonce, - createValidityWindow, -} from '../../_exact_base/types.js'; -import type { TransferAuthorization } from '../../_exact_base/types.js'; - -/** - * EVM client mechanism for "exact" payment scheme - */ -export class ExactEvmClientMechanism implements ClientMechanism { - private signer: ClientSigner; - private addressConverter = new EvmAddressConverter(); - - constructor(signer: ClientSigner) { - this.signer = signer; - } - - getSigner(): ClientSigner { - return this.signer; - } - - scheme(): string { - return SCHEME_EXACT; - } - - async createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - ): Promise { - const converter = this.addressConverter; - const fromAddr = converter.toEvmFormat(this.signer.getAddress()); - const toAddr = converter.toEvmFormat(requirements.payTo); - - const [validAfter, validBefore] = createValidityWindow(); - const nonce = createNonce(); - - const authorization: TransferAuthorization = { - from: fromAddr, - to: toAddr, - value: requirements.amount, - validAfter: String(validAfter), - validBefore: String(validBefore), - nonce, - }; - - // Look up token metadata for EIP-712 domain - const tokenInfo = findByAddress(requirements.network, requirements.asset); - const tokenName = tokenInfo?.name ?? 'Unknown Token'; - const tokenVersion = tokenInfo?.version ?? requirements.extra?.version ?? '1'; - - const chainId = getChainId(requirements.network); - const domain = buildEip712Domain( - tokenName, - tokenVersion, - chainId, - converter.toEvmFormat(requirements.asset), - ); - - const message = buildEip712Message(authorization, (addr) => converter.toEvmFormat(addr)); - - const signature = await this.signer.signTypedData( - domain, - TRANSFER_AUTH_EIP712_TYPES, - message, - TRANSFER_AUTH_PRIMARY_TYPE - ); - - return { - x402Version: 2, - resource: { url: resource }, - accepted: requirements, - payload: { - signature, - authorization, - }, - extensions: { - transferAuthorization: authorization, - }, - }; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact/facilitator.ts deleted file mode 100644 index 09ca5adc..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/facilitator.ts +++ /dev/null @@ -1,54 +0,0 @@ -/** - * EVM (BSC) facilitator mechanism for the `exact` (ERC-3009) scheme. - * - * Mirrors Python `mechanisms.evm.exact.facilitator.ExactEvmFacilitatorMechanism`. - * - * Settles by calling `transferWithAuthorization(from, to, value, validAfter, - * validBefore, nonce, v, r, s)` directly on the ERC20 token contract via - * viem's typed encoding. - */ - -import { ExactBaseFacilitatorMechanism } from '../../_exact_base/facilitator.js'; -import { EvmChainAdapter } from '../../_exact_base/evmAdapter.js'; -import type { - PaymentRequirements, - TransferAuthorization, -} from '../../../types/index.js'; -import { FacilitatorSigner } from '../../../signers/facilitator/base.js'; -import { TRANSFER_WITH_AUTHORIZATION_ABI } from '../../../abi.js'; - -export class ExactEvmFacilitatorMechanism extends ExactBaseFacilitatorMechanism { - constructor( - signer: FacilitatorSigner, - options: { allowedTokens?: ReadonlyArray } = {}, - ) { - super(signer, new EvmChainAdapter(), options); - } - - protected async settlePaymentOnly( - auth: TransferAuthorization, - signature: string, - requirements: PaymentRequirements, - ): Promise { - const adapter = this.adapter; - const { v, r, s } = this.splitSignature(signature); - - return this.signer.writeContract( - requirements.asset, // token contract is the verifying contract for ERC-3009 - TRANSFER_WITH_AUTHORIZATION_ABI as unknown as unknown[], - 'transferWithAuthorization', - [ - adapter.toSigningAddress(auth.from), - adapter.toSigningAddress(auth.to), - BigInt(auth.value), - BigInt(auth.validAfter), - BigInt(auth.validBefore), - auth.nonce.startsWith('0x') ? auth.nonce : `0x${auth.nonce}`, - v, - r, - s, - ], - requirements.network, - ); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/index.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact/index.ts deleted file mode 100644 index 129a0395..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { ExactEvmClientMechanism } from './client.js'; -export { ExactEvmServerMechanism } from './server.js'; -export { ExactEvmFacilitatorMechanism } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/server.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact/server.ts deleted file mode 100644 index 1dab450f..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact/server.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { ExactBaseServerMechanism } from '../../_exact_base/server.js'; -import { EvmChainAdapter } from '../../_exact_base/evmAdapter.js'; -import type { PaymentPermit } from '../../../types/index.js'; - -/** - * BSC / EVM server mechanism for the `exact` scheme. - * - * Mirrors Python `mechanisms.evm.exact.server.ExactEvmServerMechanism`. - */ -export class ExactEvmServerMechanism extends ExactBaseServerMechanism { - constructor() { - super(new EvmChainAdapter()); - } - - /** - * EVM signature verification for ERC-3009 authorizations. - * - * TODO(v0.6.0b): port the EIP-712 typed-data signature recovery from - * Python `ExactBaseServerMechanism._verify_signature`. Until then this - * returns `true` and lets the facilitator be the source of truth. - */ - async verifySignature( - _permit: PaymentPermit | null | undefined, - _signature: string, - _network: string, - ): Promise { - return true; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.test.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.test.ts deleted file mode 100644 index 558a9484..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; -import { ExactPermitEvmClientMechanism } from './client.js'; -import { EvmClientSigner } from '../../../signers/evmSigner.js'; -import type { AgentWallet } from '../../../signers/signer.js'; -import { PermitValidationError } from '../../../errors.js'; - -function createMockWallet(address: string): AgentWallet { - return { - getAddress: vi.fn().mockResolvedValue(address), - signMessage: vi.fn().mockResolvedValue('0xdeadbeef'), - signTypedData: vi.fn().mockResolvedValue('0x' + 'ab'.repeat(65)), - signTransaction: vi.fn().mockResolvedValue('0x1234'), - }; -} - -describe('ExactPermitEvmClientMechanism', () => { - const mockAddress = '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c'; - const wallet = createMockWallet(mockAddress); - const signer = new EvmClientSigner(wallet, mockAddress); - const mechanism = new ExactPermitEvmClientMechanism(signer); - - const requirements = { - scheme: 'exact_permit', - network: 'eip155:1', - amount: '1000000', - asset: '0x1234567890123456789012345678901234567890', - payTo: '0x0987654321098765432109876543210987654321', - }; - - const context = { - meta: { - kind: 'PAYMENT_ONLY' as const, - paymentId: '0x12121212121212121212121212121212', - nonce: '1', - validAfter: 0, - validBefore: Math.floor(Date.now() / 1000) + 3600, - }, - }; - - it('should have correct scheme', () => { - expect(mechanism.scheme()).toBe('exact_permit'); - }); - - it('should create payment payload', async () => { - // Mock ensureAllowance to avoid network calls - vi.spyOn(signer, 'ensureAllowance').mockResolvedValue(true); - - const payload = await mechanism.createPaymentPayload( - requirements, - 'https://api.example.com/resource', - { paymentPermitContext: context }, - ); - - expect(payload.x402Version).toBe(2); - expect(payload.payload.signature).toBeDefined(); - expect(payload.payload.paymentPermit.buyer).toBe(signer.getAddress()); - }); - - it('should throw if context is missing', async () => { - await expect( - mechanism.createPaymentPayload(requirements, 'resource'), - ).rejects.toThrow(PermitValidationError); - }); -}); diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.ts deleted file mode 100644 index 8ab13163..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/client.ts +++ /dev/null @@ -1,134 +0,0 @@ -/** - * ExactPermitEvmClientMechanism - EVM client mechanism for "exact_permit" payment scheme - */ - -import type { - ClientMechanism, - ClientSigner, - PaymentRequirements, - PaymentPayload, - PaymentPermit, - PaymentPermitContext, -} from '../../../index.js'; -import { - KIND_MAP, - PAYMENT_PERMIT_TYPES, - PAYMENT_PERMIT_PRIMARY_TYPE, - getChainId, - getPaymentPermitAddress, - EVM_ZERO_ADDRESS, - EvmAddressConverter, - ZERO_ADDRESS_HEX, - PermitValidationError, -} from '../../../index.js'; - -/** - * EVM client mechanism for "exact_permit" payment scheme - */ -export class ExactPermitEvmClientMechanism implements ClientMechanism { - private signer: ClientSigner; - private addressConverter = new EvmAddressConverter(); - - constructor(signer: ClientSigner) { - this.signer = signer; - } - - getSigner(): ClientSigner { - return this.signer; - } - - scheme(): string { - return 'exact_permit'; - } - - async createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - extensions?: { paymentPermitContext?: PaymentPermitContext } - ): Promise { - const context = extensions?.paymentPermitContext; - if (!context) { - throw new PermitValidationError('missing_context', 'paymentPermitContext is required'); - } - - const buyerAddress = this.signer.getAddress(); - const zeroAddress = EVM_ZERO_ADDRESS; - - const permit: PaymentPermit = { - meta: { - kind: context.meta.kind, - paymentId: context.meta.paymentId, - nonce: context.meta.nonce, - validAfter: context.meta.validAfter, - validBefore: context.meta.validBefore, - }, - buyer: buyerAddress, - caller: requirements.extra?.fee?.caller || zeroAddress, - payment: { - payToken: requirements.asset, - payAmount: requirements.amount, - payTo: requirements.payTo, - }, - fee: { - feeTo: requirements.extra?.fee?.feeTo || zeroAddress, - feeAmount: requirements.extra?.fee?.feeAmount || '0', - }, - }; - - // Ensure allowance - const totalAmount = BigInt(permit.payment.payAmount) + BigInt(permit.fee.feeAmount); - await this.signer.ensureAllowance( - permit.payment.payToken, - totalAmount, - requirements.network - ); - - // Build EIP-712 domain - const permitAddress = getPaymentPermitAddress(requirements.network); - const domain = { - name: 'PaymentPermit', - chainId: getChainId(requirements.network), - verifyingContract: this.addressConverter.toEvmFormat(permitAddress), - }; - - // Convert permit to EIP-712 compatible format - const permitForSigning = { - meta: { - kind: KIND_MAP[permit.meta.kind], - paymentId: permit.meta.paymentId, - nonce: BigInt(permit.meta.nonce), - validAfter: permit.meta.validAfter, - validBefore: permit.meta.validBefore, - }, - buyer: this.addressConverter.toEvmFormat(permit.buyer), - caller: this.addressConverter.toEvmFormat(permit.caller), - payment: { - payToken: this.addressConverter.toEvmFormat(permit.payment.payToken), - payAmount: BigInt(permit.payment.payAmount), - payTo: this.addressConverter.toEvmFormat(permit.payment.payTo), - }, - fee: { - feeTo: this.addressConverter.toEvmFormat(permit.fee.feeTo), - feeAmount: BigInt(permit.fee.feeAmount), - }, - }; - - const signature = await this.signer.signTypedData( - domain, - PAYMENT_PERMIT_TYPES, - permitForSigning as unknown as Record, - PAYMENT_PERMIT_PRIMARY_TYPE - ); - - return { - x402Version: 2, - resource: { url: resource }, - accepted: requirements, - payload: { - signature, - paymentPermit: permit, - }, - extensions: {}, - }; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/facilitator.ts deleted file mode 100644 index 95df2fff..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/facilitator.ts +++ /dev/null @@ -1,77 +0,0 @@ -/** - * EVM facilitator mechanism for the `exact_permit` scheme. - * - * Mirrors Python `mechanisms.evm.exact_permit.facilitator.ExactPermitEvmFacilitatorMechanism`. - * - * Settles by calling `PaymentPermit.permitTransferFrom(permit, owner, signature)` - * via the facilitator's EVM signer (viem). - */ - -import { - BaseExactPermitFacilitatorMechanism, - type BaseExactPermitFee, -} from '../../_exact_permit_base/facilitator.js'; -import type { - PaymentPermit, - PaymentRequirements, -} from '../../../types/index.js'; -import { FacilitatorSigner } from '../../../signers/facilitator/base.js'; -import { EvmAddressConverter, type AddressConverter } from '../../../address.js'; -import { getPaymentPermitAddress } from '../../../config.js'; -import { KIND_MAP, PAYMENT_PERMIT_ABI } from '../../../abi.js'; - -export class ExactPermitEvmFacilitatorMechanism extends BaseExactPermitFacilitatorMechanism { - constructor(signer: FacilitatorSigner, fee: BaseExactPermitFee = {}) { - super(signer, fee); - } - - protected getAddressConverter(): AddressConverter { - return new EvmAddressConverter(); - } - - /** - * Build the permit struct in viem's expected object shape and call - * `permitTransferFrom` via the facilitator's EVM signer. - */ - protected async settlePaymentOnly( - permit: PaymentPermit, - signature: string, - requirements: PaymentRequirements, - ): Promise { - const contractAddress = getPaymentPermitAddress(requirements.network); - const norm = (s: string) => this.addressConverter.toEvmFormat(s); - - // viem `encodeFunctionData` accepts objects mirroring the ABI tuple components. - const permitArg = { - meta: { - kind: KIND_MAP[permit.meta.kind], - paymentId: permit.meta.paymentId as `0x${string}`, - nonce: BigInt(permit.meta.nonce), - validAfter: BigInt(permit.meta.validAfter), - validBefore: BigInt(permit.meta.validBefore), - }, - buyer: norm(permit.buyer), - caller: norm(permit.caller), - payment: { - payToken: norm(permit.payment.payToken), - payAmount: BigInt(permit.payment.payAmount), - payTo: norm(permit.payment.payTo), - }, - fee: { - feeTo: norm(permit.fee.feeTo), - feeAmount: BigInt(permit.fee.feeAmount), - }, - }; - - const owner = norm(permit.buyer); - const sigHex = signature.startsWith('0x') ? signature : `0x${signature}`; - - return this.signer.writeContract( - contractAddress, - PAYMENT_PERMIT_ABI as unknown as unknown[], - 'permitTransferFrom', - [permitArg, owner, sigHex], - requirements.network, - ); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/index.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/index.ts deleted file mode 100644 index 57c775a5..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { ExactPermitEvmClientMechanism } from './client.js'; -export { ExactPermitEvmServerMechanism } from './server.js'; -export { ExactPermitEvmFacilitatorMechanism } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/server.ts b/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/server.ts deleted file mode 100644 index 100f2637..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/evm/exact_permit/server.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isAddress } from 'viem'; - -import { BaseExactPermitServerMechanism } from '../../_exact_permit_base/server.js'; - -/** - * BSC / EVM server mechanism for the `exact_permit` scheme. - * - * Mirrors Python `mechanisms.evm.exact_permit.server.ExactPermitEvmServerMechanism`. - */ -export class ExactPermitEvmServerMechanism extends BaseExactPermitServerMechanism { - protected getNetworkPrefix(): string { - return 'eip155:'; - } - - protected validateAddressFormat(address: string): boolean { - return isAddress(address, { strict: false }); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/index.ts b/legacy/typescript/packages/x402/src/mechanisms/index.ts deleted file mode 100644 index b91d9ebf..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Mechanism registry — public API. - * - * Layout mirrors Python `bankofai.x402.mechanisms` (per-chain subdirs, with - * `_base` / `_exact_base` / `_exact_permit_base` holding shared logic). - */ - -// === Per-(chain, scheme) client mechanisms === -export { ExactEvmClientMechanism } from './evm/exact/index.js'; -export { ExactPermitEvmClientMechanism } from './evm/exact_permit/index.js'; -export { ExactTronClientMechanism } from './tron/exact/index.js'; -export { ExactPermitTronClientMechanism } from './tron/exact_permit/index.js'; -export { ExactGasFreeClientMechanism } from './tron/exact_gasfree/index.js'; - -// === Per-(chain, scheme) server mechanisms === -export { ExactEvmServerMechanism } from './evm/exact/index.js'; -export { ExactPermitEvmServerMechanism } from './evm/exact_permit/index.js'; -export { ExactTronServerMechanism } from './tron/exact/index.js'; -export { ExactPermitTronServerMechanism } from './tron/exact_permit/index.js'; -export { ExactGasFreeServerMechanism } from './tron/exact_gasfree/index.js'; - -// === Per-(chain, scheme) facilitator mechanisms === -export { ExactEvmFacilitatorMechanism } from './evm/exact/index.js'; -export { ExactPermitEvmFacilitatorMechanism } from './evm/exact_permit/index.js'; -export { ExactTronFacilitatorMechanism } from './tron/exact/index.js'; -export { ExactPermitTronFacilitatorMechanism } from './tron/exact_permit/index.js'; -export { ExactGasFreeFacilitatorMechanism } from './tron/exact_gasfree/index.js'; -export type { ExactGasFreeFacilitatorOptions } from './tron/exact_gasfree/index.js'; - -// === Shared base classes (for users wanting to subclass) === -export { - ExactBaseServerMechanism, - ExactBaseFacilitatorMechanism, - EvmChainAdapter, - TronChainAdapter, -} from './_exact_base/index.js'; -export type { ChainAdapter } from './_exact_base/index.js'; -export { - BaseExactPermitServerMechanism, - BaseExactPermitFacilitatorMechanism, -} from './_exact_permit_base/index.js'; -export type { BaseExactPermitFee } from './_exact_permit_base/index.js'; - -// === Shared exact-scheme primitives (EIP-712 / TIP-712 typed-data) === -export { - DEFAULT_VALIDITY_SECONDS, - SCHEME_EXACT, - TRANSFER_AUTH_EIP712_TYPES, - TRANSFER_AUTH_PRIMARY_TYPE, - buildEip712Domain, - buildEip712Message, - createNonce, - createValidityWindow, -} from './_exact_base/index.js'; -export type { TransferAuthorization } from './_exact_base/index.js'; - -// === Role interface re-exports === -export type { - ClientMechanism, - ClientSigner, - ServerMechanism, - FacilitatorMechanism, - FacilitatorLogger, -} from './_base/index.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/registry.test.ts b/legacy/typescript/packages/x402/src/mechanisms/registry.test.ts deleted file mode 100644 index d8a84e85..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/registry.test.ts +++ /dev/null @@ -1,208 +0,0 @@ -/** - * Smoke tests for the 10 new server + facilitator mechanism wrappers. - * - * Verifies registration into X402Server / X402Facilitator and the cheap, - * non-RPC paths (scheme name, feeQuote, parsePrice, validate, structural - * verify). Chain-RPC integration is covered in per-mechanism tests. - */ - -import { describe, expect, it } from 'vitest'; - -import { FacilitatorClient } from '../facilitator/client.js'; -import { X402Facilitator } from '../facilitator/x402Facilitator.js'; -import { X402Server } from '../server/x402Server.js'; -import { - ExactEvmFacilitatorMechanism, - ExactEvmServerMechanism, - ExactGasFreeFacilitatorMechanism, - ExactGasFreeServerMechanism, - ExactPermitEvmFacilitatorMechanism, - ExactPermitEvmServerMechanism, - ExactPermitTronFacilitatorMechanism, - ExactPermitTronServerMechanism, - ExactTronFacilitatorMechanism, - ExactTronServerMechanism, -} from './index.js'; -import { FacilitatorSigner } from '../signers/facilitator/base.js'; -import { GasFreeAPIClient } from '../utils/gasfree.js'; - -/** - * Minimal mock signer that satisfies `FacilitatorSigner`. The registry - * tests never reach `verify`/`settle`/`checkBalance` — they only need - * `getAddress()` so the mechanism constructor doesn't blow up. - */ -class MockSigner extends FacilitatorSigner { - constructor(private readonly addr: string) { - super(); - } - getAddress(): string { - return this.addr; - } - async verifyTypedData(): Promise { - return true; - } - async writeContract(): Promise { - return null; - } - async checkBalance(): Promise { - return BigInt(0); - } - async waitForTransactionReceipt() { - return { hash: '0x', blockNumber: '0', status: 'confirmed' as const }; - } -} - -const MOCK_TRON_SIGNER = new MockSigner('TFeeAddress'); -const MOCK_EVM_SIGNER = new MockSigner('0xFeeAddress'); -const FAKE_GASFREE_FEE = { - clients: { 'tron:nile': new GasFreeAPIClient('https://gasfree.test') }, - baseFee: { USDT: '100' }, -}; - -describe('Server mechanisms register into X402Server', () => { - it('registers all 5 server mechanisms across (chain, scheme)', () => { - const fac = new FacilitatorClient({ baseUrl: 'https://fac.test' }); - const server = new X402Server() - .register('eip155:97', new ExactEvmServerMechanism()) - .register('eip155:97', new ExactPermitEvmServerMechanism()) - .register('tron:nile', new ExactTronServerMechanism()) - .register('tron:nile', new ExactPermitTronServerMechanism()) - .register('tron:nile', new ExactGasFreeServerMechanism()) - .setFacilitator(fac); - // Smoke: server is configured without errors. - expect(server).toBeInstanceOf(X402Server); - }); - - it('each server mechanism reports its scheme correctly', () => { - expect(new ExactEvmServerMechanism().scheme()).toBe('exact'); - expect(new ExactPermitEvmServerMechanism().scheme()).toBe('exact_permit'); - expect(new ExactTronServerMechanism().scheme()).toBe('exact'); - expect(new ExactPermitTronServerMechanism().scheme()).toBe('exact_permit'); - expect(new ExactGasFreeServerMechanism().scheme()).toBe('exact_gasfree'); - }); - - it('parsePrice works on all 5 server mechanisms', async () => { - const evmExact = await new ExactEvmServerMechanism().parsePrice('1 USDT', 'eip155:97'); - expect(evmExact.amount).toBe('1000000000000000000'); // 18 decimals - const tronExact = await new ExactTronServerMechanism().parsePrice('1 USDT', 'tron:mainnet'); - expect(tronExact.amount).toBe('1000000'); // 6 decimals - }); - - it('enhancePaymentRequirements attaches token name', async () => { - const mech = new ExactPermitEvmServerMechanism(); - const enhanced = await mech.enhancePaymentRequirements( - { - scheme: 'exact_permit', - network: 'eip155:97', - amount: '1000000', - asset: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', - payTo: '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', - }, - 'PAYMENT_ONLY', - ); - expect(enhanced.extra?.name).toBe('Tether USD'); - }); - - it('validatePaymentRequirements rejects mismatched network prefix', () => { - const evmMech = new ExactPermitEvmServerMechanism(); - expect( - evmMech.validatePaymentRequirements({ - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - }), - ).toBe(false); - }); -}); - -describe('Facilitator mechanisms register into X402Facilitator', () => { - it('registers all 5 facilitator mechanisms', () => { - const fac = new X402Facilitator() - .register(['eip155:97'], new ExactEvmFacilitatorMechanism(MOCK_EVM_SIGNER)) - .register(['eip155:97'], new ExactPermitEvmFacilitatorMechanism(MOCK_EVM_SIGNER)) - .register(['tron:nile'], new ExactTronFacilitatorMechanism(MOCK_TRON_SIGNER)) - .register(['tron:nile'], new ExactPermitTronFacilitatorMechanism(MOCK_TRON_SIGNER)) - .register( - ['tron:nile'], - new ExactGasFreeFacilitatorMechanism(MOCK_TRON_SIGNER, FAKE_GASFREE_FEE), - ); - - const supported = fac.supported(); - expect(supported.kinds).toHaveLength(5); - const schemes = supported.kinds.map((k) => `${k.network}/${k.scheme}`).sort(); - expect(schemes).toEqual([ - 'eip155:97/exact', - 'eip155:97/exact_permit', - 'tron:nile/exact', - 'tron:nile/exact_gasfree', - 'tron:nile/exact_permit', - ]); - }); - - it('exact feeQuote returns a zero-fee quote', async () => { - const mech = new ExactEvmFacilitatorMechanism(MOCK_EVM_SIGNER); - const quote = await mech.feeQuote({ - scheme: 'exact', - network: 'eip155:97', - amount: '1', - asset: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', - payTo: '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', - }); - expect(quote?.fee.feeAmount).toBe('0'); - expect(quote?.pricing).toBe('flat'); - }); - - it('permit feeQuote returns the configured fee for a known symbol', async () => { - const mech = new ExactPermitEvmFacilitatorMechanism(MOCK_EVM_SIGNER, { - feeTo: '0xFee', - baseFee: { USDT: '5000' }, - }); - const quote = await mech.feeQuote({ - scheme: 'exact_permit', - network: 'eip155:97', - amount: '1', - asset: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', - payTo: '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', - }); - expect(quote?.fee.feeTo).toBe('0xFee'); - expect(quote?.fee.feeAmount).toBe('5000'); - expect(quote?.pricing).toBe('flat'); - }); - - it('permit feeQuote returns null for an unknown symbol', async () => { - const mech = new ExactPermitEvmFacilitatorMechanism(MOCK_EVM_SIGNER, { - feeTo: '0xFee', - baseFee: { /* no entries */ }, - }); - const quote = await mech.feeQuote({ - scheme: 'exact_permit', - network: 'eip155:97', - amount: '1', - asset: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', - payTo: '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', - }); - expect(quote).toBeNull(); - }); - - it('settle returns verify failure when the authorization is invalid', async () => { - const mech = new ExactEvmFacilitatorMechanism(MOCK_EVM_SIGNER); - const result = await mech.settle( - { - x402Version: 2, - accepted: {} as never, - payload: { signature: '0x', authorization: { from: '', to: '', value: '0', validAfter: '0', validBefore: '0', nonce: '0x' } }, - }, - { - scheme: 'exact', - network: 'eip155:97', - amount: '1', - asset: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', - payTo: '0x1825bB32db3443dEc2cc7508b2D818fc13EaD878', - }, - ); - expect(result.success).toBe(false); - expect(result.errorReason).toBe('amount_mismatch'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/client.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact/client.ts deleted file mode 100644 index c23dd425..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/client.ts +++ /dev/null @@ -1,104 +0,0 @@ -/** - * ExactTronClientMechanism - TRON client mechanism for "exact" payment scheme - * - * Uses ERC-3009 TransferWithAuthorization with TIP-712 signing. - * Addresses are converted from TRON Base58 to EVM hex for signing. - */ - -import type { - ClientMechanism, - ClientSigner, - PaymentRequirements, - PaymentPayload, -} from '../../../index.js'; -import { - getChainId, - TronAddressConverter, -} from '../../../index.js'; -import { findByAddress } from '../../../tokens.js'; -import { - SCHEME_EXACT, - TRANSFER_AUTH_EIP712_TYPES, - TRANSFER_AUTH_PRIMARY_TYPE, - buildEip712Domain, - buildEip712Message, - createNonce, - createValidityWindow, -} from '../../_exact_base/types.js'; -import type { TransferAuthorization } from '../../_exact_base/types.js'; - -/** - * TRON client mechanism for "exact" payment scheme - */ -export class ExactTronClientMechanism implements ClientMechanism { - private signer: ClientSigner; - private addressConverter = new TronAddressConverter(); - - constructor(signer: ClientSigner) { - this.signer = signer; - } - - getSigner(): ClientSigner { - return this.signer; - } - - scheme(): string { - return SCHEME_EXACT; - } - - async createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - ): Promise { - const converter = this.addressConverter; - const fromAddr = converter.toEvmFormat(this.signer.getAddress()); - const toAddr = converter.toEvmFormat(requirements.payTo); - - const [validAfter, validBefore] = createValidityWindow(); - const nonce = createNonce(); - - const authorization: TransferAuthorization = { - from: fromAddr, - to: toAddr, - value: requirements.amount, - validAfter: String(validAfter), - validBefore: String(validBefore), - nonce, - }; - - // Look up token metadata for EIP-712 domain - const tokenInfo = findByAddress(requirements.network, requirements.asset); - const tokenName = tokenInfo?.name ?? 'Unknown Token'; - const tokenVersion = tokenInfo?.version ?? requirements.extra?.version ?? '1'; - - const chainId = getChainId(requirements.network); - const domain = buildEip712Domain( - tokenName, - tokenVersion, - chainId, - converter.toEvmFormat(requirements.asset), - ); - - const message = buildEip712Message(authorization, (addr) => converter.toEvmFormat(addr)); - - const signature = await this.signer.signTypedData( - domain, - TRANSFER_AUTH_EIP712_TYPES, - message, - TRANSFER_AUTH_PRIMARY_TYPE - ); - - return { - x402Version: 2, - resource: { url: resource }, - accepted: requirements, - payload: { - signature, - authorization, - }, - extensions: { - transferAuthorization: authorization, - }, - }; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact/facilitator.ts deleted file mode 100644 index fc8fc7f6..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/facilitator.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * TRON facilitator mechanism for the `exact` (ERC-3009) scheme. - * - * Mirrors Python `mechanisms.tron.exact.facilitator.ExactTronFacilitatorMechanism`. - * - * Settles by calling `transferWithAuthorization(from, to, value, validAfter, - * validBefore, nonce, v, r, s)` directly on the TRC20 token contract via the - * facilitator's TRON signer. - */ - -import { ExactBaseFacilitatorMechanism } from '../../_exact_base/facilitator.js'; -import { TronChainAdapter } from '../../_exact_base/tronAdapter.js'; -import type { - PaymentRequirements, - TransferAuthorization, -} from '../../../types/index.js'; -import { FacilitatorSigner } from '../../../signers/facilitator/base.js'; -import { TRANSFER_WITH_AUTHORIZATION_ABI } from '../../../abi.js'; - -/** - * Function selector for tronweb's `triggerSmartContract`. - * Must match the on-chain ABI exactly. - */ -const TRANSFER_WITH_AUTH_SELECTOR = - 'transferWithAuthorization(' + - 'address,address,uint256,uint256,uint256,bytes32,uint8,bytes32,bytes32' + - ')'; - -export class ExactTronFacilitatorMechanism extends ExactBaseFacilitatorMechanism { - constructor( - signer: FacilitatorSigner, - options: { allowedTokens?: ReadonlyArray } = {}, - ) { - super(signer, new TronChainAdapter(), options); - } - - protected async settlePaymentOnly( - auth: TransferAuthorization, - signature: string, - requirements: PaymentRequirements, - ): Promise { - const adapter = this.adapter; - const { v, r, s } = this.splitSignature(signature); - - // tronweb's triggerSmartContract expects address values as 0x EVM hex. - const args = [ - { type: 'address', value: adapter.toSigningAddress(auth.from) }, - { type: 'address', value: adapter.toSigningAddress(auth.to) }, - { type: 'uint256', value: auth.value }, - { type: 'uint256', value: String(auth.validAfter) }, - { type: 'uint256', value: String(auth.validBefore) }, - { - type: 'bytes32', - value: auth.nonce.startsWith('0x') ? auth.nonce : `0x${auth.nonce}`, - }, - { type: 'uint8', value: v }, - { type: 'bytes32', value: r }, - { type: 'bytes32', value: s }, - ]; - - return this.signer.writeContract( - requirements.asset, // TRC20 token is the verifying contract - TRANSFER_WITH_AUTHORIZATION_ABI as unknown as unknown[], - TRANSFER_WITH_AUTH_SELECTOR, - args, - requirements.network, - ); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/index.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact/index.ts deleted file mode 100644 index 7e02eee6..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { ExactTronClientMechanism } from './client.js'; -export { ExactTronServerMechanism } from './server.js'; -export { ExactTronFacilitatorMechanism } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/server.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact/server.ts deleted file mode 100644 index 89a734e3..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact/server.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ExactBaseServerMechanism } from '../../_exact_base/server.js'; -import { TronChainAdapter } from '../../_exact_base/tronAdapter.js'; -import type { PaymentPermit } from '../../../types/index.js'; - -/** - * TRON server mechanism for the `exact` scheme. - * - * Mirrors Python `mechanisms.tron.exact.server.ExactTronServerMechanism`. - */ -export class ExactTronServerMechanism extends ExactBaseServerMechanism { - constructor() { - super(new TronChainAdapter()); - } - - /** - * TRON TIP-712 signature verification for ERC-3009 authorizations. - * - * TODO(v0.6.0b): port TIP-712 signature recovery from Python. Returns - * `true` for now — facilitator side does the authoritative check. - */ - async verifySignature( - _permit: PaymentPermit | null | undefined, - _signature: string, - _network: string, - ): Promise { - return true; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.test.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.test.ts deleted file mode 100644 index bcb4bd1c..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.test.ts +++ /dev/null @@ -1,489 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { ExactGasFreeClientMechanism } from './client.js'; -import { GasFreeAPIClient } from '../../../utils/gasfree.js'; -import { PaymentRequirements, ClientSigner } from '../../../index.js'; - -const assembleGasFreeTransactionJson = vi.fn((params: any) => ({ - domain: { - name: 'GasFreeController', - version: 'V1.0.0', - chainId: 1, - verifyingContract: params.serviceProvider, - }, - types: { - PermitTransfer: [], - }, - message: { - token: params.token, - serviceProvider: params.serviceProvider, - user: params.user, - receiver: params.receiver, - value: params.value, - maxFee: params.maxFee, - deadline: params.deadline, - version: params.version, - nonce: params.nonce, - }, -})); - -vi.mock('@gasfree/gasfree-sdk', () => { - return { - default: { - TronGasFree: class { - assembleGasFreeTransactionJson(params: any) { - return assembleGasFreeTransactionJson(params); - } - }, - }, - }; -}); - -vi.mock('../../../utils/gasfree.js', () => { - return { - GasFreeAPIClient: vi.fn().mockImplementation(() => { - return { - getAddressInfo: vi.fn().mockResolvedValue({ - accountAddress: 'TMVQGm1qAQYVdetCeGRRkTWYYrLXuHK2HC', - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: true, - nonce: 1, - assets: [ - { - tokenAddress: 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf', - balance: '5000000', - transferFee: '1000000', - }, - ], - }), - getProviders: vi.fn().mockResolvedValue([ - { address: 'TKtWbdzEq5ss9vTS9kwRhBp5mXmBfBns3E' } - ]), - }; - }), - }; -}); - - -describe('ExactGasFreeClientMechanism', () => { - const USDT_ADDRESS = 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf'; - const MOCK_ADDR = 'TMVQGm1qAQYVdetCeGRRkTWYYrLXuHK2HC'; - let mockSigner: any; - let mechanism: ExactGasFreeClientMechanism; - let mockApiClient: any; - - beforeEach(() => { - assembleGasFreeTransactionJson.mockClear(); - mockApiClient = new GasFreeAPIClient('url'); - mockSigner = { - getAddress: vi.fn().mockReturnValue(MOCK_ADDR), - signTypedData: vi.fn().mockResolvedValue('0x' + 'ab'.repeat(65)), - checkBalance: vi.fn().mockResolvedValue(5000000n), - }; - mechanism = new ExactGasFreeClientMechanism(mockSigner as unknown as ClientSigner, { "tron:nile": mockApiClient }); - }); - - it('should create a valid payment payload', async () => { - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeTo: MOCK_ADDR, - feeAmount: '0', - }, - }, - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - expect(payload.x402Version).toBe(2); - expect(payload.payload.signature).toBe('0x' + 'ab'.repeat(65)); - expect(payload.extensions?.gasfreeAddress).toBe('TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC'); - - const [domain, _types, message] = mockSigner.signTypedData.mock.calls[0]; - expect(domain.verifyingContract).toMatch(/^0x[0-9a-fA-F]{40}$/); - expect(message.token).toMatch(/^0x[0-9a-fA-F]{40}$/); - expect(message.serviceProvider).toMatch(/^0x[0-9a-fA-F]{40}$/); - expect(message.user).toMatch(/^0x[0-9a-fA-F]{40}$/); - expect(message.receiver).toMatch(/^0x[0-9a-fA-F]{40}$/); - }); - - it('should adjust maxFee to protocol minimum', async () => { - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeAmount: '100000', // 0.1 USDT - feeTo: MOCK_ADDR, - } - } - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // Should be adjusted to 1 USDT (1,000,000) - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('1000000'); - }); - - it('should fallback to fetch providers when extra.fee is missing', async () => { - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - expect(payload.x402Version).toBe(2); - expect(mockApiClient.getProviders).toHaveBeenCalled(); - }); - - it('should include activateFee in maxFee when account is not activated', async () => { - mockApiClient.getAddressInfo.mockResolvedValue({ - accountAddress: MOCK_ADDR, - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: false, - allowSubmit: true, - nonce: 0, - assets: [ - { - tokenAddress: USDT_ADDRESS, - balance: '15000000', - transferFee: '1000000', - activateFee: '2050000', - }, - ], - }); - mockSigner.checkBalance.mockResolvedValue(15000000n); - - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeAmount: '0', - feeTo: MOCK_ADDR, - } - } - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // maxFee should be transferFee (1000000) + activateFee (2050000) = 3050000 - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('3050000'); - }); - - it('should throw when address conversion fails', async () => { - assembleGasFreeTransactionJson.mockImplementationOnce(() => ({ - domain: { - name: 'GasFreeController', - version: 'V1.0.0', - chainId: 1, - verifyingContract: 'invalid', - }, - types: { - PermitTransfer: [], - }, - message: { - token: 'invalid', - serviceProvider: 'invalid', - user: 'invalid', - receiver: 'invalid', - value: '1', - maxFee: '1', - deadline: '1', - version: '1', - nonce: '1', - }, - })); - - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeTo: MOCK_ADDR, - feeAmount: '0', - }, - }, - }; - - await expect( - mechanism.createPaymentPayload(requirements, 'https://example.com/res') - ).rejects.toThrow('GasFree TIP-712: could not convert'); - }); - - it('should NOT include activateFee when account is already activated', async () => { - mockApiClient.getAddressInfo.mockResolvedValue({ - accountAddress: MOCK_ADDR, - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: true, - nonce: 1, - assets: [ - { - tokenAddress: USDT_ADDRESS, - balance: '5000000', - transferFee: '1000000', - activateFee: '2050000', - }, - ], - }); - - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeAmount: '0', - feeTo: MOCK_ADDR, - } - } - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // activateFee should be ignored since account is active - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('1000000'); - }); - - it('should handle zero activateFee when not activated', async () => { - mockApiClient.getAddressInfo.mockResolvedValue({ - accountAddress: MOCK_ADDR, - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: false, - allowSubmit: true, - nonce: 0, - assets: [ - { - tokenAddress: USDT_ADDRESS, - balance: '5000000', - transferFee: '1000000', - activateFee: '0', - }, - ], - }); - - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeAmount: '0', - feeTo: MOCK_ADDR, - } - } - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // activateFee is 0 → maxFee stays as transferFee - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('1000000'); - }); - - it('should handle missing activateFee field gracefully', async () => { - mockApiClient.getAddressInfo.mockResolvedValue({ - accountAddress: MOCK_ADDR, - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: false, - allowSubmit: true, - nonce: 0, - assets: [ - { - tokenAddress: USDT_ADDRESS, - balance: '5000000', - transferFee: '1000000', - // activateFee field missing entirely - }, - ], - }); - - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeAmount: '0', - feeTo: MOCK_ADDR, - } - } - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // No activateFee → defaults to 0 → maxFee = transferFee only - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('1000000'); - }); - - it('should add activateFee on top of higher facilitator fee', async () => { - mockApiClient.getAddressInfo.mockResolvedValue({ - accountAddress: MOCK_ADDR, - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: false, - allowSubmit: true, - nonce: 0, - assets: [ - { - tokenAddress: USDT_ADDRESS, - balance: '20000000', - transferFee: '1000000', - activateFee: '2050000', - }, - ], - }); - mockSigner.checkBalance.mockResolvedValue(20000000n); - - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { - fee: { - feeAmount: '5000000', - feeTo: MOCK_ADDR, - } - } - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // facilitatorFee(5000000) > transferFee(1000000), base = 5000000 - // maxFee = 5000000 + activateFee(2050000) = 7050000 - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('7050000'); - }); - - it('should add activateFee on top of fallback 1-token minimum', async () => { - mockApiClient.getAddressInfo.mockResolvedValue({ - accountAddress: MOCK_ADDR, - gasFreeAddress: 'TLCvf7MktLG7XkbJRyUwnvCeDnaEXYkcbC', - active: false, - allowSubmit: true, - nonce: 0, - assets: [ - { - tokenAddress: USDT_ADDRESS, - balance: '10000000', - transferFee: '0', - activateFee: '2050000', - }, - ], - }); - mockSigner.checkBalance.mockResolvedValue(10000000n); - - // No extra.fee → triggers fallback to 1 token (1000000) - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - }; - - const payload = await mechanism.createPaymentPayload(requirements, 'https://example.com/res'); - - // fallback(1000000) + activateFee(2050000) = 3050000 - expect(payload.payload.paymentPermit?.fee.feeAmount).toBe('3050000'); - }); - - it('should throw error if network is not configured', async () => { - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:mainnet', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - }; - - await expect(mechanism.createPaymentPayload(requirements, 'url')) - .rejects.toThrow('GasFree is not configured for network: tron:mainnet'); - }); - - it('should clamp deadline above max for mainnet and nile', async () => { - vi.useFakeTimers(); - vi.setSystemTime(new Date('2026-03-27T00:00:00Z')); - const now = Math.floor(Date.now() / 1000); - const baseReq: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:mainnet', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { fee: { feeTo: MOCK_ADDR, feeAmount: '0' } }, - }; - - const mainnetClient = new ExactGasFreeClientMechanism( - mockSigner as unknown as ClientSigner, - { 'tron:mainnet': mockApiClient } - ); - const mainnetPayload = await mainnetClient.createPaymentPayload( - baseReq, - 'https://example.com/res', - { paymentPermitContext: { meta: { validBefore: now + 2000 } } } - ); - expect(mainnetPayload.payload.paymentPermit?.meta.validBefore).toBe(now + 595); - - const nileClient = new ExactGasFreeClientMechanism( - mockSigner as unknown as ClientSigner, - { 'tron:nile': mockApiClient } - ); - const nilePayload = await nileClient.createPaymentPayload( - { ...baseReq, network: 'tron:nile' }, - 'https://example.com/res', - { paymentPermitContext: { meta: { validBefore: now + 5000 } } } - ); - expect(nilePayload.payload.paymentPermit?.meta.validBefore).toBe(now + 3595); - - vi.useRealTimers(); - }); - - it('should throw when deadline is too soon', async () => { - vi.useFakeTimers(); - vi.setSystemTime(new Date('2026-03-27T00:00:00Z')); - const now = Math.floor(Date.now() / 1000); - const requirements: PaymentRequirements = { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: USDT_ADDRESS, - payTo: MOCK_ADDR, - extra: { fee: { feeTo: MOCK_ADDR, feeAmount: '0' } }, - }; - - const client = new ExactGasFreeClientMechanism( - mockSigner as unknown as ClientSigner, - { 'tron:nile': mockApiClient } - ); - await expect( - client.createPaymentPayload(requirements, 'https://example.com/res', { - paymentPermitContext: { meta: { validBefore: now + 10 } }, - }) - ).rejects.toThrow('deadline too soon'); - - vi.useRealTimers(); - }); -}); diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.ts deleted file mode 100644 index a6dffbfb..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/client.ts +++ /dev/null @@ -1,289 +0,0 @@ -import gasFreeSDK from '@gasfree/gasfree-sdk'; -const { TronGasFree } = gasFreeSDK; -import { - PaymentPayload, - PaymentRequirements, - PaymentPermit, - DeliveryKind, - ClientMechanism, - ClientSigner, - GASFREE_PRIMARY_TYPE, - getChainId, - UnsupportedNetworkError, -} from '../../../index.js'; -import { GASFREE_TYPES, GasFreeAPIClient, type GasFreeAddressInfo } from '../../../utils/gasfree.js'; -import { findByAddress } from '../../../tokens.js'; -import { TronAddressConverter, ZERO_ADDRESS_HEX } from '../../../address.js'; - -function requireEvmAddress( - raw: unknown, - fieldName: string, - converter: TronAddressConverter -): string { - if (raw === null || raw === undefined) { - throw new Error(`GasFree TIP-712: address field "${fieldName}" is null or undefined`); - } - - const converted = converter.toEvmFormat(String(raw)); - if (converted === ZERO_ADDRESS_HEX) { - throw new Error( - `GasFree TIP-712: could not convert "${fieldName}" value "${raw}" to EVM format` - ); - } - - return converted; -} - -export class ExactGasFreeClientMechanism implements ClientMechanism { - private signer: ClientSigner; - private clients: Record; - - constructor(signer: ClientSigner, clients: Record = {}) { - this.signer = signer; - this.clients = clients; - } - - private getApiClient(network: string): GasFreeAPIClient { - const client = this.clients[network]; - if (client) { - return client; - } - throw new UnsupportedNetworkError(`GasFree is not configured for network: ${network}`); - } - - private getDeadlineBounds(network: string): { minDelta: number; maxDelta: number } { - if (network === 'tron:mainnet') { - // GasFree mainnet bounds: >= 50s, <= 600s. We add 5s to min and subtract 5s from max. - return { minDelta: 55, maxDelta: 595 }; - } - // Non-mainnet bounds: >= 50s, <= 3600s. We add 5s to min and subtract 5s from max. - return { minDelta: 55, maxDelta: 3595 }; - } - - private clampDeadline(network: string, deadlineSeconds: number): number { - const now = Math.floor(Date.now() / 1000); - const { minDelta, maxDelta } = this.getDeadlineBounds(network); - - const minDeadline = now + minDelta; - const maxDeadline = now + maxDelta; - if (deadlineSeconds < minDeadline) { - throw new Error( - `GasFree deadline too soon for ${network}: ${deadlineSeconds} < ${minDeadline}` - ); - } - if (deadlineSeconds > maxDeadline) { - console.warn( - '[GASFREE SIGN] deadline clamped', - { network, from: deadlineSeconds, to: maxDeadline } - ); - return maxDeadline; - } - return deadlineSeconds; - } - - scheme(): string { - return 'exact_gasfree'; - } - - getSigner(): ClientSigner { - return this.signer; - } - - private async checkGasFreeBalance( - token: string, - network: string, - accountInfo?: GasFreeAddressInfo - ): Promise { - if (!accountInfo) { - const apiClient = this.getApiClient(network); - const userAddress = this.signer.getAddress(); - accountInfo = await apiClient.getAddressInfo(userAddress); - } - const gasfreeAddress = accountInfo.gasFreeAddress; - if (!gasfreeAddress) { - throw new Error(`Could not retrieve GasFree address for ${this.signer.getAddress()}`); - } - return this.signer.checkBalance(token, network, gasfreeAddress); - } - - async checkBalance(token: string, network: string): Promise { - return this.checkGasFreeBalance(token, network); - } - - async createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - extensions?: Record - ): Promise { - const chainId = getChainId(requirements.network); - const apiClient = this.getApiClient(requirements.network); - const userAddress = this.signer.getAddress(); - - // 1. Fetch account info - console.debug(`Fetching account info for ${userAddress} from GasFree API...`); - const accountInfo = await apiClient.getAddressInfo(userAddress); - const gasfreeAddress = accountInfo.gasFreeAddress; - - if (!gasfreeAddress) { - throw new Error(`Could not retrieve GasFree address for ${userAddress}`); - } - - // 2. Check activation status - const allowSubmit = (accountInfo as any).allowSubmit || false; - if (!accountInfo.active && !allowSubmit) { - throw new Error(`GasFree account for ${userAddress} (${gasfreeAddress}) is not activated.`); - } - - // 3. Get provider and fee - const feeInfo = requirements.extra?.fee; - let serviceProviderAddr: string; - if (feeInfo?.feeTo) { - // Use provider from facilitator's fee quote - serviceProviderAddr = feeInfo.feeTo; - console.debug(`Using GasFree provider from requirements: ${serviceProviderAddr}`); - } else { - // Fallback: fetch providers from GasFree API directly - console.debug('No provider in requirements, fetching from GasFree API...'); - const providers = await apiClient.getProviders(); - if (!providers || providers.length === 0) { - throw new Error('No GasFree service providers available'); - } - serviceProviderAddr = providers[Math.floor(Math.random() * providers.length)].address; - console.debug(`Selected GasFree provider: ${serviceProviderAddr}`); - } - - // Look up per-user transferFee from account info - const asset = accountInfo.assets.find((a: any) => a.tokenAddress === requirements.asset); - const transferFee = BigInt(asset?.transferFee || '0'); - const activateFee = BigInt(asset?.activateFee || '0'); - - // Determine maxFee - const facilitatorFee = BigInt(feeInfo?.feeAmount || '0'); - let maxFeeBig = transferFee > facilitatorFee ? transferFee : facilitatorFee; - - // Fallback: if both are 0 and no facilitator fee, default to 1 token - if (maxFeeBig === 0n && !feeInfo) { - const tokenInfo = findByAddress(requirements.network, requirements.asset); - const decimals = tokenInfo?.decimals ?? 6; - maxFeeBig = BigInt(10 ** decimals); - } - - // If the account is not yet activated, add activateFee to maxFee - if (!accountInfo.active && activateFee > 0n) { - maxFeeBig = maxFeeBig + activateFee; - console.debug(`GasFree account not activated, adding activateFee ${activateFee} to maxFee`); - } - let maxFee = maxFeeBig.toString(); - - // 4. Balance verification - const skipBalanceCheck = (extensions as any)?.skipBalanceCheck || false; - if (!skipBalanceCheck) { - if (!asset) { - throw new Error(`Asset ${requirements.asset} not found in GasFree account ${gasfreeAddress}.`); - } - const assetBalance = await this.checkGasFreeBalance(requirements.asset, requirements.network, accountInfo); - const requiredTotal = BigInt(requirements.amount) + maxFeeBig; - if (assetBalance < requiredTotal) { - throw new Error(`Insufficient balance in GasFree wallet ${gasfreeAddress}.`); - } - } - - const { maxDelta } = this.getDeadlineBounds(requirements.network); - const deadlineRaw = - (extensions as any)?.paymentPermitContext?.meta?.validBefore || - Math.floor(Date.now() / 1000) + maxDelta; - const deadline = this.clampDeadline(requirements.network, Number(deadlineRaw)); - - const gasFree = new TronGasFree({ chainId }); - const addressConverter = new TronAddressConverter(); - - // 5. Sign TIP-712 typed data - const { domain, types, message } = gasFree.assembleGasFreeTransactionJson({ - token: requirements.asset, - serviceProvider: serviceProviderAddr, - user: userAddress, - receiver: requirements.payTo, - value: requirements.amount, - maxFee: maxFee, - deadline: deadline.toString(), - version: '1', - nonce: accountInfo.nonce.toString(), - }); - - const signingDomain = { - ...domain, - verifyingContract: requireEvmAddress( - domain.verifyingContract, - 'verifyingContract', - addressConverter - ), - }; - const signingMessage = { - ...message, - // Explicitly convert known address fields to EVM 0x format. - // Do not use convertMessageAddresses() here — the message also contains - // numeric fields whose string representations should not be treated - // as addresses. - token: requireEvmAddress(message.token, 'token', addressConverter), - serviceProvider: requireEvmAddress( - message.serviceProvider, - 'serviceProvider', - addressConverter - ), - user: requireEvmAddress(message.user, 'user', addressConverter), - receiver: requireEvmAddress(message.receiver, 'receiver', addressConverter), - }; - - console.debug('[GASFREE SIGN] network', requirements.network, 'chainId', chainId); - console.debug('[GASFREE SIGN] verifyingContract raw', domain.verifyingContract); - console.debug('[GASFREE SIGN] signer', userAddress); - console.debug('[GASFREE SIGN] domain', JSON.stringify(signingDomain)); - console.debug('[GASFREE SIGN] message', JSON.stringify(signingMessage)); - - const signature = await this.signer.signTypedData( - signingDomain, - types, - signingMessage, - GASFREE_PRIMARY_TYPE - ); - - // 6. Build PaymentPermit structure - const paymentPermit: PaymentPermit = { - meta: { - kind: 'PAYMENT_ONLY' as DeliveryKind, - paymentId: (extensions as any)?.paymentPermitContext?.meta?.paymentId || '', - nonce: accountInfo.nonce.toString(), - validAfter: (extensions as any)?.paymentPermitContext?.meta?.validAfter || 0, - validBefore: Number(deadline), - }, - buyer: userAddress, - caller: serviceProviderAddr, - payment: { - payToken: requirements.asset, - payAmount: requirements.amount, - payTo: requirements.payTo, - }, - fee: { - feeTo: serviceProviderAddr, - feeAmount: maxFee, - }, - }; - - const payload: PaymentPayload = { - x402Version: 2, - resource: { url: resource }, - accepted: requirements, - payload: { - signature, - paymentPermit, - }, - extensions: { - ...extensions, - gasfreeAddress, - scheme: 'exact_gasfree', - }, - }; - - return payload; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.test.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.test.ts deleted file mode 100644 index e36a6108..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.test.ts +++ /dev/null @@ -1,203 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { FacilitatorSigner } from '../../../signers/facilitator/base.js'; -import type { PaymentPayload, PaymentRequirements } from '../../../types/index.js'; -import { - GasFreeAPIClient, - type GasFreeProvider, - type GasFreeSubmitResponseData, -} from '../../../utils/gasfree.js'; -import { ExactGasFreeFacilitatorMechanism } from './facilitator.js'; - -class MockSigner extends FacilitatorSigner { - public verifiedMessage: Record | null = null; - - getAddress(): string { - return 'TFeeAddress'; - } - - async verifyTypedData( - _address: string, - _domain: Record, - _types: Record>, - message: Record, - ): Promise { - this.verifiedMessage = message; - return true; - } - - async writeContract(): Promise { - return null; - } - - async checkBalance(): Promise { - return BigInt(2_000_000); - } - - async waitForTransactionReceipt() { - return { hash: '0x', blockNumber: '0', status: 'confirmed' as const }; - } -} - -class MockGasFreeClient extends GasFreeAPIClient { - public submittedMessage: Record | null = null; - - constructor(private readonly providers: GasFreeProvider[]) { - super('https://gasfree.test'); - } - - async getProviders(): Promise { - return this.providers; - } - - async submit( - _domain: unknown, - message: Record, - _signature: string, - ): Promise { - this.submittedMessage = message; - return 'trace-123'; - } - - async waitForSuccess(_traceId: string): Promise { - return { - id: 'trace-123', - state: 'SUCCEED', - createdAt: new Date().toISOString(), - accountAddress: BUYER, - gasFreeAddress: GASFREE_ADDRESS, - providerAddress: PROVIDER, - targetAddress: PAY_TO, - nonce: 7, - tokenAddress: TOKEN, - amount: '1000000', - expiredAt: new Date(Date.now() + 60_000).toISOString(), - txnHash: 'tron-tx-hash', - txnState: 'ON_CHAIN', - }; - } -} - -const TOKEN = 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf'; -const PROVIDER = 'TMVQGm1qAQYVdetCeGRRkTWYYrLXuHK2HC'; -const BUYER = 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx'; -const PAY_TO = 'TT8rEWbCoNX7vpEUauxb7rWJsTgs8vDLAn'; -const GASFREE_ADDRESS = 'TQghdCeVDA6CnuNVTUhfaAyPfTetqZWNpm'; - -const provider: GasFreeProvider = { - address: PROVIDER, - name: 'Provider', - icon: '', - website: '', - config: { - maxPendingTransfer: 10, - minDeadlineDuration: 60, - maxDeadlineDuration: 3600, - defaultDeadlineDuration: 600, - }, -}; - -function makeRequirements(): PaymentRequirements { - return { - scheme: 'exact_gasfree', - network: 'tron:nile', - amount: '1000000', - asset: TOKEN, - payTo: PAY_TO, - }; -} - -function makePayload(): PaymentPayload { - const now = Math.floor(Date.now() / 1000); - return { - x402Version: 2, - accepted: makeRequirements(), - payload: { - signature: '0x' + '11'.repeat(65), - paymentPermit: { - meta: { - kind: 'PAYMENT_ONLY', - paymentId: '0x' + '12'.repeat(16), - nonce: '7', - validAfter: 0, - validBefore: now + 600, - }, - buyer: BUYER, - caller: PROVIDER, - payment: { - payToken: TOKEN, - payAmount: '1000000', - payTo: PAY_TO, - }, - fee: { - feeTo: PROVIDER, - feeAmount: '100000', - }, - }, - }, - extensions: { gasfreeAddress: GASFREE_ADDRESS }, - }; -} - -function makeMechanism(client: MockGasFreeClient, signer = new MockSigner()) { - return { - signer, - mechanism: new ExactGasFreeFacilitatorMechanism(signer, { - clients: { 'tron:nile': client }, - baseFee: { USDT: '100000' }, - }), - }; -} - -describe('ExactGasFreeFacilitatorMechanism', () => { - it('returns provider-backed flat fee quotes', async () => { - const client = new MockGasFreeClient([provider]); - const { mechanism } = makeMechanism(client); - - const quote = await mechanism.feeQuote(makeRequirements()); - - expect(quote?.fee).toMatchObject({ - feeTo: PROVIDER, - feeAmount: '100000', - caller: PROVIDER, - }); - expect(quote?.pricing).toBe('flat'); - }); - - it('verifies GasFree permits with TIP-712 fields', async () => { - const client = new MockGasFreeClient([provider]); - const { mechanism, signer } = makeMechanism(client); - - const result = await mechanism.verify(makePayload(), makeRequirements()); - - expect(result).toEqual({ isValid: true }); - expect(signer.verifiedMessage).toMatchObject({ - value: BigInt(1000000), - maxFee: BigInt(100000), - nonce: BigInt(7), - version: BigInt(1), - }); - }); - - it('settles through GasFree API and returns the TRON transaction hash', async () => { - const client = new MockGasFreeClient([provider]); - const { mechanism } = makeMechanism(client); - - const result = await mechanism.settle(makePayload(), makeRequirements()); - - expect(result).toEqual({ - success: true, - transaction: 'tron-tx-hash', - network: 'tron:nile', - }); - expect(client.submittedMessage).toMatchObject({ - token: TOKEN, - serviceProvider: PROVIDER, - user: BUYER, - receiver: PAY_TO, - value: '1000000', - maxFee: '100000', - nonce: 7, - }); - }); -}); diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.ts deleted file mode 100644 index 754bad2f..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/facilitator.ts +++ /dev/null @@ -1,310 +0,0 @@ -/** - * TRON facilitator mechanism for the `exact_gasfree` scheme. - * - * Mirrors Python `mechanisms.tron.exact_gasfree.facilitator`. - * The buyer signs the GasFree TIP-712 permit, and the facilitator submits it - * through the configured GasFree API proxy. - */ - -import { - BaseExactPermitFacilitatorMechanism, - type BaseExactPermitFee, -} from '../../_exact_permit_base/facilitator.js'; -import type { - FeeQuoteResponse, - PaymentPermit, - PaymentPayload, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../../../types/index.js'; -import { FacilitatorSigner } from '../../../signers/facilitator/base.js'; -import { TronAddressConverter, type AddressConverter } from '../../../address.js'; -import { - GASFREE_TYPES, - GasFreeAPIClient, - type GasFreeProvider, - getGasFreeDomain, -} from '../../../utils/gasfree.js'; -import { GASFREE_PRIMARY_TYPE } from '../../../abi.js'; - -const SCHEME_EXACT_GASFREE = 'exact_gasfree'; -const FEE_QUOTE_EXPIRY_SECONDS = 300; - -export interface ExactGasFreeFacilitatorOptions extends BaseExactPermitFee { - clients: Record; -} - -export class ExactGasFreeFacilitatorMechanism extends BaseExactPermitFacilitatorMechanism { - private readonly clients: Record; - - constructor( - signer: FacilitatorSigner, - options: ExactGasFreeFacilitatorOptions, - ) { - super(signer, options); - this.clients = options.clients; - } - - scheme(): string { - return SCHEME_EXACT_GASFREE; - } - - protected getAddressConverter(): AddressConverter { - return new TronAddressConverter(); - } - - private getApiClient(network: string): GasFreeAPIClient { - const client = this.clients[network]; - if (!client) { - throw new Error(`GasFree is not configured for network: ${network}`); - } - return client; - } - - async feeQuote( - accept: PaymentRequirements, - _context?: Record, - ): Promise { - const baseFee = this.getBaseFee(accept.asset, accept.network); - if (baseFee === null) return null; - - const providers = await this.getApiClient(accept.network).getProviders(); - if (providers.length === 0) return null; - - const selected = providers[Math.floor(Math.random() * providers.length)]!; - return { - fee: { - feeTo: selected.address, - feeAmount: baseFee.toString(), - caller: selected.address, - }, - pricing: 'flat', - scheme: accept.scheme, - network: accept.network, - asset: accept.asset, - expiresAt: Math.floor(Date.now() / 1000) + FEE_QUOTE_EXPIRY_SECONDS, - } as FeeQuoteResponse; - } - - async verify( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const permit = payload.payload.paymentPermit; - if (!permit) { - return { isValid: false, invalidReason: 'missing_permit' }; - } - - const validationError = await this.validateGasFreePermit(permit, requirements); - if (validationError) { - return { isValid: false, invalidReason: validationError }; - } - - const validSig = await this.verifyGasFreeSignature( - permit, - payload.payload.signature, - requirements.network, - ); - if (!validSig) { - return { isValid: false, invalidReason: 'invalid_signature' }; - } - - return { isValid: true }; - } - - async settle( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - const verifyResult = await this.verify(payload, requirements); - if (!verifyResult.isValid) { - return { - success: false, - errorReason: verifyResult.invalidReason ?? 'verification_failed', - network: requirements.network, - }; - } - - const permit = payload.payload.paymentPermit; - const signature = payload.payload.signature; - const gasfreeAddress = payload.extensions?.gasfreeAddress; - if (!permit || !signature || typeof gasfreeAddress !== 'string') { - return { - success: false, - errorReason: 'missing_payload_data', - network: requirements.network, - }; - } - - try { - const balance = await this.signer.checkBalance( - requirements.asset, - requirements.network, - gasfreeAddress, - ); - const requiredTotal = - BigInt(requirements.amount) + BigInt(permit.fee.feeAmount); - if (balance < requiredTotal) { - return { - success: false, - errorReason: `insufficient balance in gasfree wallet ${gasfreeAddress}`, - network: requirements.network, - }; - } - } catch { - // Python treats this as a best-effort preflight; submission can still fail - // with the relayer's exact reason. - } - - const client = this.getApiClient(requirements.network); - try { - const traceId = await this.settlePaymentOnly( - permit, - signature, - requirements, - ); - if (!traceId) { - return { - success: false, - errorReason: 'api_no_response', - network: requirements.network, - }; - } - - const result = await client.waitForSuccess(traceId); - if (!result.txnHash) { - return { - success: false, - errorReason: 'missing_transaction_hash', - network: requirements.network, - }; - } - - return { - success: true, - transaction: result.txnHash, - network: requirements.network, - }; - } catch (err) { - return { - success: false, - errorReason: err instanceof Error ? err.message : String(err), - network: requirements.network, - }; - } - } - - private async validateGasFreePermit( - permit: PaymentPermit, - requirements: PaymentRequirements, - ): Promise { - const norm = (s: string) => this.addressConverter.normalize(s); - - if ( - this.allowedTokens !== null && - !this.allowedTokens.has(norm(permit.payment.payToken)) - ) { - return 'token_not_allowed'; - } - - if (BigInt(permit.payment.payAmount) < BigInt(requirements.amount)) { - return 'amount_mismatch'; - } - if (norm(permit.payment.payToken) !== norm(requirements.asset)) { - return 'token_mismatch'; - } - if (norm(permit.payment.payTo) !== norm(requirements.payTo)) { - return 'payto_mismatch'; - } - - let providers: GasFreeProvider[]; - try { - providers = await this.getApiClient(requirements.network).getProviders(); - } catch { - if (norm(permit.fee.feeTo) !== norm(this.feeTo)) { - return 'fee_to_mismatch'; - } - providers = []; - } - - if (providers.length > 0) { - const allowedProviders = new Set(providers.map((p) => norm(p.address))); - if (!allowedProviders.has(norm(permit.fee.feeTo))) { - return 'fee_to_mismatch'; - } - } - - const expectedFee = this.getBaseFee( - permit.payment.payToken, - requirements.network, - ); - if (expectedFee === null) { - return 'unsupported_token'; - } - if (BigInt(permit.fee.feeAmount) < expectedFee) { - return 'fee_amount_mismatch'; - } - - const now = Math.floor(Date.now() / 1000); - if (permit.meta.validBefore < now) { - return 'expired'; - } - return null; - } - - private async verifyGasFreeSignature( - permit: PaymentPermit, - signature: string, - network: string, - ): Promise { - const converter = this.addressConverter; - const message: Record = { - token: converter.toEvmFormat(permit.payment.payToken), - serviceProvider: converter.toEvmFormat(permit.fee.feeTo), - user: converter.toEvmFormat(permit.buyer), - receiver: converter.toEvmFormat(permit.payment.payTo), - value: BigInt(permit.payment.payAmount), - maxFee: BigInt(permit.fee.feeAmount), - deadline: BigInt(permit.meta.validBefore), - version: BigInt(1), - nonce: BigInt(permit.meta.nonce), - }; - - return this.signer.verifyTypedData( - permit.buyer, - getGasFreeDomain(network), - GASFREE_TYPES as unknown as Record< - string, - ReadonlyArray<{ name: string; type: string }> - >, - message, - signature, - GASFREE_PRIMARY_TYPE, - ); - } - - protected async settlePaymentOnly( - permit: PaymentPermit, - signature: string, - requirements: PaymentRequirements, - ): Promise { - const message = { - token: permit.payment.payToken, - serviceProvider: permit.fee.feeTo, - user: permit.buyer, - receiver: permit.payment.payTo, - value: permit.payment.payAmount, - maxFee: permit.fee.feeAmount, - deadline: permit.meta.validBefore, - version: 1, - nonce: Number(permit.meta.nonce), - }; - - return this.getApiClient(requirements.network).submit( - getGasFreeDomain(requirements.network), - message, - signature, - ); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/index.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/index.ts deleted file mode 100644 index decc11a6..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { ExactGasFreeClientMechanism } from './client.js'; -export { ExactGasFreeServerMechanism } from './server.js'; -export { ExactGasFreeFacilitatorMechanism } from './facilitator.js'; -export type { ExactGasFreeFacilitatorOptions } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/server.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/server.ts deleted file mode 100644 index 030e7979..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_gasfree/server.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { findByAddress, parsePrice } from '../../../tokens.js'; -import type { ServerMechanism } from '../../../server/types.js'; -import type { - PaymentPermit, - PaymentRequirements, -} from '../../../types/index.js'; - -const SCHEME_EXACT_GASFREE = 'exact_gasfree'; - -/** - * TRON server mechanism for the `exact_gasfree` scheme. - * - * Mirrors Python `mechanisms.tron.exact_gasfree.server.ExactGasFreeServerMechanism`. - * GasFree is TRON-only (no EVM counterpart) so there is no shared - * `_exact_gasfree_base/`. - */ -export class ExactGasFreeServerMechanism implements ServerMechanism { - scheme(): string { - return SCHEME_EXACT_GASFREE; - } - - async parsePrice(price: string, network: string) { - return parsePrice(price, network); - } - - async enhancePaymentRequirements( - requirements: PaymentRequirements, - _deliveryMode: string, - ): Promise { - const token = findByAddress(requirements.network, requirements.asset); - if (!token) return requirements; - return { - ...requirements, - extra: { - ...(requirements.extra ?? {}), - name: token.name, - ...(token.version ? { version: token.version } : {}), - }, - }; - } - - validatePaymentRequirements(requirements: PaymentRequirements): boolean { - return requirements.network.startsWith('tron:'); - } - - /** - * TIP-712 GasFree permit signature recovery. - * - * TODO(v0.6.0b): port from Python — TIP-712 hash + signature recovery. - * Returns `true` for now; facilitator authoritative. - */ - async verifySignature( - _permit: PaymentPermit | null | undefined, - _signature: string, - _network: string, - ): Promise { - return true; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/client.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/client.ts deleted file mode 100644 index 844a04c0..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/client.ts +++ /dev/null @@ -1,155 +0,0 @@ -/** - * ExactPermitTronClientMechanism - TRON client mechanism for "exact_permit" payment scheme - * - * Uses TIP-712 (TRON's EIP-712 implementation) for signing PaymentPermit. - */ - -import type { - ClientMechanism, - ClientSigner, - PaymentRequirements, - PaymentPayload, - PaymentPermit, - PaymentPermitContext, -} from '../../../index.js'; -import { - KIND_MAP, - PAYMENT_PERMIT_TYPES, - PAYMENT_PERMIT_PRIMARY_TYPE, - getChainId, - getPaymentPermitAddress, - TronAddressConverter, - TRON_ZERO_ADDRESS, - paymentIdToBytes, - PermitValidationError, -} from '../../../index.js'; - -/** - * TRON client mechanism for "exact_permit" payment scheme - */ -export class ExactPermitTronClientMechanism implements ClientMechanism { - private signer: ClientSigner; - private addressConverter = new TronAddressConverter(); - - constructor(signer: ClientSigner) { - this.signer = signer; - } - - getSigner(): ClientSigner { - return this.signer; - } - - scheme(): string { - return 'exact_permit'; - } - - async createPaymentPayload( - requirements: PaymentRequirements, - resource: string, - extensions?: { paymentPermitContext?: PaymentPermitContext } - ): Promise { - const context = extensions?.paymentPermitContext; - if (!context) { - throw new PermitValidationError('missing_context', 'paymentPermitContext is required'); - } - - const buyerAddress = this.signer.getAddress(); - const zeroAddress = TRON_ZERO_ADDRESS; // Use TRON zero address for consistency with Python - - const permit: PaymentPermit = { - meta: { - kind: context.meta.kind, - paymentId: context.meta.paymentId, - nonce: context.meta.nonce, - validAfter: context.meta.validAfter, - validBefore: context.meta.validBefore, - }, - buyer: buyerAddress, - caller: requirements.extra?.fee?.caller || zeroAddress, - payment: { - payToken: requirements.asset, - payAmount: requirements.amount, - payTo: requirements.payTo, - }, - fee: { - feeTo: requirements.extra?.fee?.feeTo || zeroAddress, - feeAmount: requirements.extra?.fee?.feeAmount || '0', - }, - }; - - // Ensure allowance - const totalAmount = BigInt(permit.payment.payAmount) + BigInt(permit.fee.feeAmount); - await this.signer.ensureAllowance( - permit.payment.payToken, - totalAmount, - requirements.network - ); - - // Build EIP-712 domain (no version field per contract spec) - // Note: domain name is "PaymentPermit", not "PaymentPermitDetails" - const permitAddress = getPaymentPermitAddress(requirements.network); - const domain = { - name: 'PaymentPermit', - chainId: getChainId(requirements.network), - verifyingContract: this.addressConverter.toEvmFormat(permitAddress), - }; - - // Convert permit to EIP-712 compatible format: - // 1. kind: string -> uint8 (number) - // 2. paymentId: keep as hex string (TronWeb expects hex for bytes16) - // 3. uint256 values: string -> BigInt (for proper EIP-712 encoding) - // 4. All addresses: TRON Base58 -> EVM hex - const permitForSigning = { - meta: { - kind: KIND_MAP[permit.meta.kind], - paymentId: permit.meta.paymentId, // Keep as hex string - nonce: BigInt(permit.meta.nonce), - validAfter: permit.meta.validAfter, - validBefore: permit.meta.validBefore, - }, - buyer: this.addressConverter.toEvmFormat(permit.buyer), - caller: this.addressConverter.toEvmFormat(permit.caller), - payment: { - payToken: this.addressConverter.toEvmFormat(permit.payment.payToken), - payAmount: BigInt(permit.payment.payAmount), - payTo: this.addressConverter.toEvmFormat(permit.payment.payTo), - }, - fee: { - feeTo: this.addressConverter.toEvmFormat(permit.fee.feeTo), - feeAmount: BigInt(permit.fee.feeAmount), - }, - }; - - // Debug: log exact message being signed - console.log('[SIGN] Domain:', JSON.stringify(domain)); - console.log('[SIGN] Message:', JSON.stringify(permitForSigning, (key, value) => { - if (value instanceof Uint8Array) { - return '0x' + Array.from(value).map(b => b.toString(16).padStart(2, '0')).join(''); - } - if (typeof value === 'bigint') { - return value.toString(); - } - return value; - })); - - const signature = await this.signer.signTypedData( - domain, - PAYMENT_PERMIT_TYPES, - permitForSigning as unknown as Record, - PAYMENT_PERMIT_PRIMARY_TYPE - ); - - console.log('[SIGN] Signature:', signature); - - return { - x402Version: 2, - resource: { url: resource }, - accepted: requirements, - payload: { - signature, - paymentPermit: permit, - }, - extensions: {}, - }; - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/facilitator.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/facilitator.ts deleted file mode 100644 index 1b9db887..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/facilitator.ts +++ /dev/null @@ -1,124 +0,0 @@ -/** - * TRON facilitator mechanism for the `exact_permit` scheme. - * - * Mirrors Python `mechanisms.tron.exact_permit.facilitator.ExactPermitTronFacilitatorMechanism`. - * - * Settles by calling `PaymentPermit.permitTransferFrom(permit, owner, signature)` - * on the configured PaymentPermit contract via the facilitator's TRON signer. - */ - -import { - BaseExactPermitFacilitatorMechanism, - type BaseExactPermitFee, -} from '../../_exact_permit_base/facilitator.js'; -import type { - PaymentPermit, - PaymentRequirements, -} from '../../../types/index.js'; -import { FacilitatorSigner } from '../../../signers/facilitator/base.js'; -import { TronAddressConverter, type AddressConverter } from '../../../address.js'; -import { getPaymentPermitAddress } from '../../../config.js'; -import { PAYMENT_PERMIT_ABI } from '../../../abi.js'; - -/** - * Function selector with full tuple layout. tronweb's `triggerSmartContract` - * needs the exact bracket signature to compute the 4-byte method ID. - * - * Layout mirrors `PAYMENT_PERMIT_ABI.permitTransferFrom`: - * permit: tuple(meta, buyer, caller, payment, fee) - * meta: tuple(uint8 kind, bytes16 paymentId, uint256 nonce, uint256 validAfter, uint256 validBefore) - * payment: tuple(address payToken, uint256 payAmount, address payTo) - * fee: tuple(address feeTo, uint256 feeAmount) - * owner: address - * signature: bytes - */ -const PERMIT_TRANSFER_FROM_SELECTOR = - 'permitTransferFrom(' + - '(' + - '(uint8,bytes16,uint256,uint256,uint256),' + - 'address,' + - 'address,' + - '(address,uint256,address),' + - '(address,uint256)' + - '),' + - 'address,' + - 'bytes' + - ')'; - -const TUPLE_TYPE = - '(' + - '(uint8,bytes16,uint256,uint256,uint256),' + - 'address,' + - 'address,' + - '(address,uint256,address),' + - '(address,uint256)' + - ')'; - -export class ExactPermitTronFacilitatorMechanism extends BaseExactPermitFacilitatorMechanism { - constructor(signer: FacilitatorSigner, fee: BaseExactPermitFee = {}) { - super(signer, fee); - } - - protected getAddressConverter(): AddressConverter { - return new TronAddressConverter(); - } - - /** - * Call `PaymentPermit.permitTransferFrom` on TRON. - * - * tronweb's `triggerSmartContract` accepts tuple parameters as an array of - * primitive values matching the type layout. Addresses must be 0x EVM hex - * (TRON's internal representation for `address` ABI type). - */ - protected async settlePaymentOnly( - permit: PaymentPermit, - signature: string, - requirements: PaymentRequirements, - ): Promise { - const contractAddress = getPaymentPermitAddress(requirements.network); - const converter = this.addressConverter; - const hex = (s: string) => converter.toEvmFormat(s); - - // Build the tuple as an array of primitive values (NOT objects). - // tronweb's tuple encoder expects the array order to match the type signature. - const permitTupleValue = [ - // meta: (uint8, bytes16, uint256, uint256, uint256) - [ - // kind (PAYMENT_ONLY → 0) - permit.meta.kind === 'PAYMENT_ONLY' ? 0 : 0, - // paymentId — bytes16, accepted as hex string by tronweb - permit.meta.paymentId, - // nonce — uint256, accepted as string - permit.meta.nonce, - permit.meta.validAfter, - permit.meta.validBefore, - ], - hex(permit.buyer), - hex(permit.caller), - // payment: (address, uint256, address) - [ - hex(permit.payment.payToken), - permit.payment.payAmount, - hex(permit.payment.payTo), - ], - // fee: (address, uint256) - [hex(permit.fee.feeTo), permit.fee.feeAmount], - ]; - - const sigBytes = signature.startsWith('0x') ? signature : `0x${signature}`; - - const args = [ - { type: TUPLE_TYPE, value: permitTupleValue }, - { type: 'address', value: hex(permit.buyer) }, - { type: 'bytes', value: sigBytes }, - ]; - - return this.signer.writeContract( - contractAddress, - PAYMENT_PERMIT_ABI as unknown as unknown[], - PERMIT_TRANSFER_FROM_SELECTOR, - args, - requirements.network, - ); - } -} diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/index.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/index.ts deleted file mode 100644 index 5bdeb340..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { ExactPermitTronClientMechanism } from './client.js'; -export { ExactPermitTronServerMechanism } from './server.js'; -export { ExactPermitTronFacilitatorMechanism } from './facilitator.js'; diff --git a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/server.ts b/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/server.ts deleted file mode 100644 index 2e073f9f..00000000 --- a/legacy/typescript/packages/x402/src/mechanisms/tron/exact_permit/server.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { BaseExactPermitServerMechanism } from '../../_exact_permit_base/server.js'; - -/** - * TRON server mechanism for the `exact_permit` scheme. - * - * Mirrors Python `mechanisms.tron.exact_permit.server.ExactPermitTronServerMechanism`. - */ -export class ExactPermitTronServerMechanism extends BaseExactPermitServerMechanism { - protected getNetworkPrefix(): string { - return 'tron:'; - } - - protected validateAddressFormat(address: string): boolean { - if (typeof address !== 'string') return false; - // Accept both Base58 (T...) and 0x-prefixed hex forms - if (address.startsWith('T') && address.length === 34) return true; - if (address.startsWith('0x') && address.length === 42) return true; - return false; - } -} diff --git a/legacy/typescript/packages/x402/src/middleware/core.test.ts b/legacy/typescript/packages/x402/src/middleware/core.test.ts deleted file mode 100644 index a52668a1..00000000 --- a/legacy/typescript/packages/x402/src/middleware/core.test.ts +++ /dev/null @@ -1,230 +0,0 @@ -/** - * Tests for the framework-agnostic middleware core. - */ - -import { describe, expect, it, vi } from 'vitest'; - -import type { FacilitatorClient } from '../facilitator/client.js'; -import type { - PaymentPayload, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../types/index.js'; -import { decodePaymentPayload, encodePaymentPayload } from '../utils/encoding.js'; -import { - PAYMENT_REQUIRED_HEADER, - PAYMENT_RESPONSE_HEADER, - processX402Request, - X402_VERSION, - type X402MiddlewareConfig, -} from './core.js'; - -const TRON_REQ: PaymentRequirements = { - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', -}; - -function makeFacilitator(opts: { - verify?: VerifyResponse | (() => Promise); - settle?: SettleResponse | (() => Promise); -}): FacilitatorClient { - return { - verify: vi.fn(async () => - typeof opts.verify === 'function' - ? await opts.verify() - : (opts.verify ?? { isValid: true }), - ), - settle: vi.fn(async () => - typeof opts.settle === 'function' - ? await opts.settle() - : (opts.settle ?? { success: true, transaction: '0xtx', network: 'tron:nile' }), - ), - } as unknown as FacilitatorClient; -} - -function makePayload(req: PaymentRequirements): PaymentPayload { - return { - x402Version: X402_VERSION, - accepted: req, - payload: { signature: '0x' + 'aa'.repeat(65) }, - }; -} - -describe('processX402Request', () => { - it('returns 402 + PAYMENT-REQUIRED when no signature header', async () => { - const config: X402MiddlewareConfig = { - facilitator: makeFacilitator({}), - accepts: [TRON_REQ], - }; - - const decision = await processX402Request(null, config); - - expect(decision.kind).toBe('paymentRequired'); - if (decision.kind !== 'paymentRequired') return; - expect(decision.status).toBe(402); - expect(decision.headers[PAYMENT_REQUIRED_HEADER]).toBeTypeOf('string'); - expect(decision.paymentRequired.x402Version).toBe(X402_VERSION); - expect(decision.paymentRequired.accepts).toEqual([TRON_REQ]); - - // Header round-trips back to the same body. - const decoded = decodePaymentPayload(decision.headers[PAYMENT_REQUIRED_HEADER]!); - expect(decoded).toEqual(decision.paymentRequired); - }); - - it('echoes resource + extensions when configured', async () => { - const config: X402MiddlewareConfig = { - facilitator: makeFacilitator({}), - accepts: [TRON_REQ], - resource: { url: 'http://example.com/api', description: 'demo' }, - extensions: { 'payment-identifier': { info: { required: false } } }, - enrich: false, // legacy passthrough; don't generate paymentPermitContext - }; - - const decision = await processX402Request(null, config); - if (decision.kind !== 'paymentRequired') throw new Error('expected paymentRequired'); - expect(decision.paymentRequired.resource).toEqual(config.resource); - expect(decision.paymentRequired.extensions).toEqual(config.extensions); - }); - - it('enriches with fresh paymentPermitContext per challenge by default', async () => { - const config: X402MiddlewareConfig = { - facilitator: makeFacilitator({}), - accepts: [TRON_REQ], - }; - const a = await processX402Request(null, config); - const b = await processX402Request(null, config); - if (a.kind !== 'paymentRequired' || b.kind !== 'paymentRequired') { - throw new Error('expected paymentRequired'); - } - const ctxA = a.paymentRequired.extensions?.paymentPermitContext as - | { meta: { paymentId: string; nonce: string } } - | undefined; - const ctxB = b.paymentRequired.extensions?.paymentPermitContext as - | { meta: { paymentId: string; nonce: string } } - | undefined; - expect(ctxA?.meta.paymentId).toMatch(/^0x[0-9a-f]{32}$/); - expect(ctxB?.meta.paymentId).toMatch(/^0x[0-9a-f]{32}$/); - expect(ctxA?.meta.paymentId).not.toBe(ctxB?.meta.paymentId); - expect(ctxA?.meta.nonce).not.toBe(ctxB?.meta.nonce); - }); - - it('returns 400 invalid when signature header is unparseable', async () => { - const config: X402MiddlewareConfig = { - facilitator: makeFacilitator({}), - accepts: [TRON_REQ], - }; - - const decision = await processX402Request('not-base64-json', config); - - expect(decision.kind).toBe('invalid'); - if (decision.kind !== 'invalid') return; - expect(decision.status).toBe(400); - expect(decision.reason).toMatch(/Invalid payment payload/); - }); - - it("returns 400 invalid when client's accepted entry doesn't match offer", async () => { - const config: X402MiddlewareConfig = { - facilitator: makeFacilitator({}), - accepts: [TRON_REQ], - }; - const wrongPayload = makePayload({ ...TRON_REQ, network: 'tron:mainnet' }); - const header = encodePaymentPayload(wrongPayload); - - const decision = await processX402Request(header, config); - - expect(decision.kind).toBe('invalid'); - if (decision.kind !== 'invalid') return; - expect(decision.reason).toMatch(/Unsupported payment/); - }); - - it('returns 500 failed when facilitator.verify rejects', async () => { - const facilitator = makeFacilitator({ - verify: { isValid: false, invalidReason: 'bad signature' }, - }); - const config: X402MiddlewareConfig = { facilitator, accepts: [TRON_REQ] }; - const header = encodePaymentPayload(makePayload(TRON_REQ)); - - const decision = await processX402Request(header, config); - - expect(decision.kind).toBe('failed'); - if (decision.kind !== 'failed') return; - expect(decision.reason).toBe('bad signature'); - }); - - it('returns 500 failed when verify throws', async () => { - const facilitator = makeFacilitator({ - verify: async () => { - throw new Error('connection reset'); - }, - }); - const config: X402MiddlewareConfig = { facilitator, accepts: [TRON_REQ] }; - const header = encodePaymentPayload(makePayload(TRON_REQ)); - - const decision = await processX402Request(header, config); - - expect(decision.kind).toBe('failed'); - if (decision.kind !== 'failed') return; - expect(decision.reason).toMatch(/Verify request failed: connection reset/); - }); - - it('returns 500 failed when settle returns success:false', async () => { - const facilitator = makeFacilitator({ - settle: { - success: false, - errorReason: 'insufficient balance', - transaction: '0xabc', - network: 'tron:nile', - }, - }); - const config: X402MiddlewareConfig = { facilitator, accepts: [TRON_REQ] }; - const header = encodePaymentPayload(makePayload(TRON_REQ)); - - const decision = await processX402Request(header, config); - - expect(decision.kind).toBe('failed'); - if (decision.kind !== 'failed') return; - expect(decision.reason).toBe('insufficient balance'); - expect(decision.transaction).toBe('0xabc'); - expect(decision.network).toBe('tron:nile'); - }); - - it('returns allow + PAYMENT-RESPONSE on success', async () => { - const settled: SettleResponse = { - success: true, - transaction: '0xdeadbeef', - network: 'tron:nile', - }; - const facilitator = makeFacilitator({ settle: settled }); - const config: X402MiddlewareConfig = { facilitator, accepts: [TRON_REQ] }; - const header = encodePaymentPayload(makePayload(TRON_REQ)); - - const decision = await processX402Request(header, config); - - expect(decision.kind).toBe('allow'); - if (decision.kind !== 'allow') return; - expect(decision.settleResult).toEqual(settled); - const decoded = decodePaymentPayload(decision.headers[PAYMENT_RESPONSE_HEADER]!); - expect(decoded).toEqual(settled); - }); - - it('matches accepts with case-insensitive asset / payTo comparison', async () => { - const facilitator = makeFacilitator({}); - const config: X402MiddlewareConfig = { - facilitator, - accepts: [TRON_REQ], - }; - const payload = makePayload({ - ...TRON_REQ, - asset: TRON_REQ.asset.toUpperCase(), - payTo: TRON_REQ.payTo.toUpperCase(), - }); - - const decision = await processX402Request(encodePaymentPayload(payload), config); - - expect(decision.kind).toBe('allow'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/middleware/core.ts b/legacy/typescript/packages/x402/src/middleware/core.ts deleted file mode 100644 index ae1bb76f..00000000 --- a/legacy/typescript/packages/x402/src/middleware/core.ts +++ /dev/null @@ -1,296 +0,0 @@ -/** - * Framework-agnostic core for x402 server middleware. - * - * Implements the verify → settle → header-attach pipeline used by all - * server adapters (Hono, Express, Fastify, ...). Adapters read the request - * headers, hand them to {@link processX402Request}, then translate the - * resulting {@link X402Decision} back into their framework's response shape. - * - * This mirrors `bankofai.x402.fastapi.X402Middleware` on the Python side but - * splits the framework binding from the protocol logic so we can target any - * Node.js HTTP framework with a thin adapter. - */ - -import type { FacilitatorClient } from '../facilitator/client.js'; -import { - PAYMENT_REQUIRED_HEADER, - PAYMENT_RESPONSE_HEADER, - PAYMENT_SIGNATURE_HEADER, -} from '../http/client.js'; -import type { - PaymentPayload, - PaymentRequired, - PaymentRequirements, - SettleResponse, -} from '../types/index.js'; -import { - decodePaymentPayload, - encodePaymentPayload, - generatePaymentId, -} from '../utils/encoding.js'; - -// Re-export header constants from http/client (single source of truth). -export { - PAYMENT_REQUIRED_HEADER, - PAYMENT_RESPONSE_HEADER, - PAYMENT_SIGNATURE_HEADER, -}; - -export const X402_VERSION = 2; - -/** Minimum config needed to protect an endpoint. */ -export interface X402MiddlewareConfig { - /** Facilitator client used for `/verify` and `/settle`. */ - facilitator: FacilitatorClient; - /** - * `accepts` array advertised in the 402 challenge. Multiple entries express - * multi-token / multi-scheme acceptance — clients pick one and pay it. - */ - accepts: PaymentRequirements[]; - /** Optional resource info echoed back in the 402 body. */ - resource?: PaymentRequired['resource']; - /** - * Optional extensions advertised on the 402 (e.g. `payment-identifier`). - * Forwarded as-is into the `PaymentRequired.extensions` field. When - * `enrich` is true (default), `paymentPermitContext` is generated per - * request and merged into this object. - */ - extensions?: PaymentRequired['extensions']; - /** - * When true (default), the middleware enriches the 402 challenge per-request: - * - calls `facilitator.feeQuote()` for permit-style accepts and attaches - * the result to `accept.extra.fee` - * - generates fresh `paymentPermitContext` (paymentId/nonce/validAfter/validBefore) - * - * Set `false` to keep the legacy passthrough behavior — useful when the - * caller has already enriched the requirements via {@link X402Server}. - */ - enrich?: boolean; -} - -/** Outcome of {@link processX402Request}. The adapter renders this. */ -export type X402Decision = - /** No payment header → return a 402 with PAYMENT-REQUIRED set. */ - | { - kind: 'paymentRequired'; - status: 402; - paymentRequired: PaymentRequired; - headers: Record; - } - /** Payload was malformed or doesn't match any acceptable requirement. */ - | { - kind: 'invalid'; - status: 400; - reason: string; - } - /** Verify or settle failed → tell the client. */ - | { - kind: 'failed'; - status: 500; - reason: string; - transaction?: string; - network?: string; - } - /** - * Payment succeeded. Adapter should run the protected handler and attach - * `headers` (which contains `PAYMENT-RESPONSE`) onto the response. - */ - | { - kind: 'allow'; - settleResult: SettleResponse; - headers: Record; - }; - -/** - * Run one x402 protocol iteration against the given config. - * - * @param signatureHeader - Value of the `PAYMENT-SIGNATURE` request header (or - * null/undefined if absent). - * @param config - Server-side payment configuration. - */ -export async function processX402Request( - signatureHeader: string | null | undefined, - config: X402MiddlewareConfig, -): Promise { - if (!signatureHeader) { - const paymentRequired = await buildPaymentRequired(config); - return { - kind: 'paymentRequired', - status: 402, - paymentRequired, - headers: { - [PAYMENT_REQUIRED_HEADER]: encodePaymentPayload(paymentRequired), - }, - }; - } - - let payload: PaymentPayload; - try { - payload = decodePaymentPayload(signatureHeader); - } catch (err) { - return { - kind: 'invalid', - status: 400, - reason: `Invalid payment payload: ${(err as Error).message}`, - }; - } - - const matched = matchAccepts(config.accepts, payload); - if (!matched) { - return { - kind: 'invalid', - status: 400, - reason: 'Unsupported payment token / network / scheme', - }; - } - - let verifyResult; - try { - verifyResult = await config.facilitator.verify(payload, matched); - } catch (err) { - return { - kind: 'failed', - status: 500, - reason: `Verify request failed: ${(err as Error).message}`, - }; - } - if (!verifyResult.isValid) { - return { - kind: 'failed', - status: 500, - reason: verifyResult.invalidReason ?? 'verify rejected payment', - }; - } - - let settleResult: SettleResponse; - try { - settleResult = await config.facilitator.settle(payload, matched); - } catch (err) { - return { - kind: 'failed', - status: 500, - reason: `Settle request failed: ${(err as Error).message}`, - }; - } - if (!settleResult.success) { - return { - kind: 'failed', - status: 500, - reason: settleResult.errorReason ?? 'settle failed', - transaction: settleResult.transaction, - network: settleResult.network, - }; - } - - return { - kind: 'allow', - settleResult, - headers: { - [PAYMENT_RESPONSE_HEADER]: encodePaymentPayload(settleResult), - }, - }; -} - -/** - * Build the 402 challenge body. When `enrich: true`, fetches `feeQuote` from - * the facilitator for permit-style accepts and generates a fresh - * `paymentPermitContext` (paymentId/nonce/validAfter/validBefore) per request. - * - * Mirrors Python `X402Server.create_payment_required_response`. - */ -async function buildPaymentRequired( - config: X402MiddlewareConfig, -): Promise { - let accepts = config.accepts; - let extensions = config.extensions; - - if (config.enrich !== false) { - // Enrich accepts with extra.fee for permit-style schemes - const permitReqs = config.accepts.filter((a) => a.scheme !== 'exact'); - if (permitReqs.length > 0) { - try { - const quotes = await config.facilitator.feeQuote(permitReqs); - const quoteMap = new Map(); - for (const q of quotes) { - quoteMap.set(`${q.scheme}|${q.network}|${q.asset}`, q); - } - accepts = config.accepts - .map((a) => { - if (a.scheme === 'exact') return a; - const quote = quoteMap.get(`${a.scheme}|${a.network}|${a.asset}`); - if (!quote) return null; - return { - ...a, - extra: { - ...(a.extra ?? {}), - fee: { - ...quote.fee, - facilitatorId: config.facilitator.facilitatorId, - }, - }, - }; - }) - .filter((a): a is PaymentRequirements => a !== null); - } catch { - // If feeQuote fails, fall through with un-enriched accepts. Facilitator - // may still accept the request, or signal at verify time. - } - } - - // Generate fresh paymentPermitContext per challenge - const now = Math.floor(Date.now() / 1000); - const validAfter = now; - const validBefore = now + 3600; - extensions = { - ...(extensions ?? {}), - paymentPermitContext: { - meta: { - kind: 'PAYMENT_ONLY', - paymentId: generatePaymentId(), - nonce: generateNonce(), - validAfter, - validBefore, - }, - }, - } as PaymentRequired['extensions']; - } - - return { - x402Version: X402_VERSION, - accepts, - ...(config.resource ? { resource: config.resource } : {}), - ...(extensions ? { extensions } : {}), - }; -} - -function generateNonce(): string { - // 16 random bytes, decimal-encoded — matches Python's `str(uuid.uuid4().int)`. - const bytes = new Uint8Array(16); - crypto.getRandomValues(bytes); - let nonce = 0n; - for (const byte of bytes) { - nonce = (nonce << 8n) | BigInt(byte); - } - return nonce.toString(); -} - -/** - * Pick the `accepts[]` entry that matches the client's chosen payment. - * - * The wire format requires the client to echo `payload.accepted` — we trust - * that as the discriminator and verify it lines up with our offer. - */ -function matchAccepts( - accepts: PaymentRequirements[], - payload: PaymentPayload, -): PaymentRequirements | null { - const want = payload.accepted; - for (const offer of accepts) { - if (offer.network !== want.network) continue; - if (offer.scheme !== want.scheme) continue; - if (offer.asset.toLowerCase() !== want.asset.toLowerCase()) continue; - if (offer.payTo.toLowerCase() !== want.payTo.toLowerCase()) continue; - return offer; - } - return null; -} diff --git a/legacy/typescript/packages/x402/src/middleware/express.test.ts b/legacy/typescript/packages/x402/src/middleware/express.test.ts deleted file mode 100644 index 530c2fcc..00000000 --- a/legacy/typescript/packages/x402/src/middleware/express.test.ts +++ /dev/null @@ -1,183 +0,0 @@ -/** - * Integration tests for the Express adapter. - * - * Drives the middleware via a fake (Request, Response, next) pair so we don't - * need a real listening server. - */ - -import type { NextFunction, Request, Response } from 'express'; -import { describe, expect, it, vi } from 'vitest'; - -import { FacilitatorClient } from '../facilitator/client.js'; -import { - PAYMENT_REQUIRED_HEADER, - PAYMENT_RESPONSE_HEADER, - PAYMENT_SIGNATURE_HEADER, -} from '../http/client.js'; -import type { - PaymentPayload, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../types/index.js'; -import { decodePaymentPayload, encodePaymentPayload } from '../utils/encoding.js'; -import { x402Express } from './express.js'; - -const REQ: PaymentRequirements = { - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', -}; - -function fakeFacilitator( - verify: VerifyResponse, - settle: SettleResponse, -): FacilitatorClient { - const fetchImpl: typeof fetch = vi.fn(async (input) => { - const url = typeof input === 'string' - ? input - : input instanceof URL - ? input.toString() - : input.url; - if (url.endsWith('/verify')) return new Response(JSON.stringify(verify), { status: 200 }); - if (url.endsWith('/settle')) return new Response(JSON.stringify(settle), { status: 200 }); - return new Response('nf', { status: 404 }); - }) as unknown as typeof fetch; - return new FacilitatorClient({ baseUrl: 'https://fac.test', fetchImpl }); -} - -interface FakeResult { - status: number; - body: unknown; - headers: Record; - nextCalled: boolean; -} - -/** Pure-JS stub that records what the middleware did. */ -function makeReqRes(headers: Record = {}): { - req: Request; - res: Response; - next: NextFunction; - result: FakeResult; -} { - const result: FakeResult = { status: 0, body: undefined, headers: {}, nextCalled: false }; - const req = { - headers: Object.fromEntries( - Object.entries(headers).map(([k, v]) => [k.toLowerCase(), v]), - ), - } as unknown as Request; - const res = { - setHeader: vi.fn((k: string, v: string) => { - result.headers[k] = v; - }), - status: vi.fn((code: number) => { - result.status = code; - return res; - }), - json: vi.fn((b: unknown) => { - result.body = b; - if (result.status === 0) result.status = 200; - return res; - }), - } as unknown as Response; - const next: NextFunction = vi.fn(() => { - result.nextCalled = true; - }); - return { req, res, next, result }; -} - -describe('x402Express integration', () => { - it('returns 402 + PAYMENT-REQUIRED when no signature', async () => { - const handler = x402Express({ - facilitator: fakeFacilitator({ isValid: true }, { success: true }), - accepts: [REQ], - }); - const { req, res, next, result } = makeReqRes(); - - await handler(req, res, next); - - expect(result.status).toBe(402); - expect(result.nextCalled).toBe(false); - expect(result.headers[PAYMENT_REQUIRED_HEADER]).toBeTruthy(); - expect((result.body as { accepts: unknown }).accepts).toEqual([REQ]); - }); - - it('calls next() + attaches PAYMENT-RESPONSE on valid payment', async () => { - const settled: SettleResponse = { - success: true, - transaction: '0xabc', - network: 'tron:nile', - }; - const payload: PaymentPayload = { - x402Version: 2, - accepted: REQ, - payload: { signature: '0x' + 'aa'.repeat(65) }, - }; - const handler = x402Express({ - facilitator: fakeFacilitator({ isValid: true }, settled), - accepts: [REQ], - }); - const { req, res, next, result } = makeReqRes({ - [PAYMENT_SIGNATURE_HEADER]: encodePaymentPayload(payload), - }); - - await handler(req, res, next); - - expect(result.nextCalled).toBe(true); - expect(result.headers[PAYMENT_RESPONSE_HEADER]).toBeTruthy(); - expect( - decodePaymentPayload(result.headers[PAYMENT_RESPONSE_HEADER]!), - ).toEqual(settled); - expect(result.status).toBe(0); // handler not invoked, status not set - }); - - it('returns 400 on malformed signature', async () => { - const handler = x402Express({ - facilitator: fakeFacilitator({ isValid: true }, { success: true }), - accepts: [REQ], - }); - const { req, res, next, result } = makeReqRes({ - [PAYMENT_SIGNATURE_HEADER]: 'not-base64-json', - }); - - await handler(req, res, next); - - expect(result.status).toBe(400); - expect(result.nextCalled).toBe(false); - expect((result.body as { error: string }).error).toMatch(/Invalid payment payload/); - }); - - it('returns 500 with txHash + network on settle failure', async () => { - const payload: PaymentPayload = { - x402Version: 2, - accepted: REQ, - payload: { signature: '0x' + 'aa'.repeat(65) }, - }; - const handler = x402Express({ - facilitator: fakeFacilitator( - { isValid: true }, - { - success: false, - errorReason: 'insufficient', - transaction: '0xabc', - network: 'tron:nile', - }, - ), - accepts: [REQ], - }); - const { req, res, next, result } = makeReqRes({ - [PAYMENT_SIGNATURE_HEADER]: encodePaymentPayload(payload), - }); - - await handler(req, res, next); - - expect(result.status).toBe(500); - expect(result.nextCalled).toBe(false); - const body = result.body as Record; - expect(body.error).toBe('insufficient'); - expect(body.txHash).toBe('0xabc'); - expect(body.network).toBe('tron:nile'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/middleware/express.ts b/legacy/typescript/packages/x402/src/middleware/express.ts deleted file mode 100644 index 04b03af0..00000000 --- a/legacy/typescript/packages/x402/src/middleware/express.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Express adapter for the x402 server middleware. - * - * Usage: - * ```ts - * import express from 'express'; - * import { FacilitatorClient, x402Express } from '@bankofai/x402'; - * - * const facilitator = new FacilitatorClient({ baseUrl: 'https://facilitator.example' }); - * const app = express(); - * - * app.use( - * '/api/llm-summary', - * x402Express({ - * facilitator, - * accepts: [{ - * scheme: 'exact_permit', - * network: 'eip155:97', - * amount: '1000000', - * asset: '0x...', - * payTo: '0x...', - * }], - * }), - * ); - * - * app.get('/api/llm-summary', (req, res) => res.json({ summary: '...' })); - * ``` - * - * Express is imported via `peerDependencies`; consumers add it to their app. - */ - -import type { NextFunction, Request, RequestHandler, Response } from 'express'; - -import { - PAYMENT_SIGNATURE_HEADER, - processX402Request, - type X402MiddlewareConfig, -} from './core.js'; - -/** - * Build an Express request handler that gates the route on x402 payment. - * - * Behavior matches the Hono adapter — see {@link X402MiddlewareConfig} and - * {@link processX402Request} for the underlying decision logic. - */ -export function x402Express(config: X402MiddlewareConfig): RequestHandler { - return async (req: Request, res: Response, next: NextFunction) => { - const signature = readHeader(req, PAYMENT_SIGNATURE_HEADER); - let decision; - try { - decision = await processX402Request(signature, config); - } catch (err) { - next(err); - return; - } - - switch (decision.kind) { - case 'paymentRequired': - for (const [k, v] of Object.entries(decision.headers)) { - res.setHeader(k, v); - } - res.status(402).json(decision.paymentRequired); - return; - case 'invalid': - res.status(400).json({ error: decision.reason }); - return; - case 'failed': { - const body: Record = { error: decision.reason }; - if (decision.transaction) body.txHash = decision.transaction; - if (decision.network) body.network = decision.network; - res.status(500).json(body); - return; - } - case 'allow': - for (const [k, v] of Object.entries(decision.headers)) { - res.setHeader(k, v); - } - next(); - return; - } - }; -} - -function readHeader(req: Request, name: string): string | null { - const raw = req.headers[name.toLowerCase()]; - if (Array.isArray(raw)) return raw[0] ?? null; - return raw ?? null; -} diff --git a/legacy/typescript/packages/x402/src/middleware/hono.test.ts b/legacy/typescript/packages/x402/src/middleware/hono.test.ts deleted file mode 100644 index a0fa41d4..00000000 --- a/legacy/typescript/packages/x402/src/middleware/hono.test.ts +++ /dev/null @@ -1,177 +0,0 @@ -/** - * Integration tests for the Hono adapter — proves FacilitatorClient + middleware - * core + Hono adapter compose correctly through the wire. - */ - -import { Hono } from 'hono'; -import { describe, expect, it, vi } from 'vitest'; - -import { FacilitatorClient } from '../facilitator/client.js'; -import { PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER } from '../http/client.js'; -import type { - PaymentPayload, - PaymentRequired, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../types/index.js'; -import { decodePaymentPayload, encodePaymentPayload } from '../utils/encoding.js'; -import { x402Hono } from './hono.js'; - -const REQ: PaymentRequirements = { - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', -}; - -/** Build a FacilitatorClient whose fetch returns canned verify/settle bodies. */ -function fakeFacilitator(verify: VerifyResponse, settle: SettleResponse): FacilitatorClient { - const fetchImpl: typeof fetch = vi.fn(async (input) => { - const url = typeof input === 'string' - ? input - : input instanceof URL - ? input.toString() - : input.url; - if (url.endsWith('/verify')) { - return new Response(JSON.stringify(verify), { status: 200 }); - } - if (url.endsWith('/settle')) { - return new Response(JSON.stringify(settle), { status: 200 }); - } - return new Response('not found', { status: 404 }); - }) as unknown as typeof fetch; - return new FacilitatorClient({ baseUrl: 'https://fac.test', fetchImpl }); -} - -function buildPayload(req: PaymentRequirements = REQ): PaymentPayload { - return { - x402Version: 2, - accepted: req, - payload: { signature: '0x' + 'aa'.repeat(65) }, - }; -} - -describe('x402Hono integration', () => { - it('returns 402 with PAYMENT-REQUIRED on bare request', async () => { - const app = new Hono(); - app.use( - '/api/data', - x402Hono({ - facilitator: fakeFacilitator({ isValid: true }, { success: true }), - accepts: [REQ], - }), - ); - app.get('/api/data', (c) => c.json({ data: 'secret' })); - - const res = await app.request('/api/data'); - - expect(res.status).toBe(402); - const headerValue = res.headers.get(PAYMENT_REQUIRED_HEADER); - expect(headerValue).toBeTruthy(); - const decoded = decodePaymentPayload(headerValue!); - expect(decoded.accepts).toEqual([REQ]); - }); - - it('serves the protected route on valid PAYMENT-SIGNATURE + attaches PAYMENT-RESPONSE', async () => { - const settled: SettleResponse = { - success: true, - transaction: '0xabc', - network: 'tron:nile', - }; - const app = new Hono(); - app.use( - '/api/data', - x402Hono({ - facilitator: fakeFacilitator({ isValid: true }, settled), - accepts: [REQ], - }), - ); - app.get('/api/data', (c) => c.json({ data: 'secret' })); - - const res = await app.request('/api/data', { - headers: { [PAYMENT_SIGNATURE_HEADER]: encodePaymentPayload(buildPayload()) }, - }); - - expect(res.status).toBe(200); - const body = (await res.json()) as { data: string }; - expect(body.data).toBe('secret'); - const settleHeader = res.headers.get(PAYMENT_RESPONSE_HEADER); - expect(settleHeader).toBeTruthy(); - expect(decodePaymentPayload(settleHeader!)).toEqual(settled); - }); - - it('returns 400 when PAYMENT-SIGNATURE is malformed', async () => { - const app = new Hono(); - app.use( - '/api/data', - x402Hono({ - facilitator: fakeFacilitator({ isValid: true }, { success: true }), - accepts: [REQ], - }), - ); - app.get('/api/data', (c) => c.json({ data: 'secret' })); - - const res = await app.request('/api/data', { - headers: { [PAYMENT_SIGNATURE_HEADER]: 'not-base64-json' }, - }); - - expect(res.status).toBe(400); - const body = (await res.json()) as { error: string }; - expect(body.error).toMatch(/Invalid payment payload/); - }); - - it('returns 500 when verify rejects', async () => { - const app = new Hono(); - app.use( - '/api/data', - x402Hono({ - facilitator: fakeFacilitator( - { isValid: false, invalidReason: 'bad sig' }, - { success: true }, - ), - accepts: [REQ], - }), - ); - app.get('/api/data', (c) => c.json({ data: 'secret' })); - - const res = await app.request('/api/data', { - headers: { [PAYMENT_SIGNATURE_HEADER]: encodePaymentPayload(buildPayload()) }, - }); - - expect(res.status).toBe(500); - const body = (await res.json()) as { error: string }; - expect(body.error).toBe('bad sig'); - }); - - it('returns 500 with txHash + network when settle fails', async () => { - const app = new Hono(); - app.use( - '/api/data', - x402Hono({ - facilitator: fakeFacilitator( - { isValid: true }, - { - success: false, - errorReason: 'insufficient balance', - transaction: '0xabc', - network: 'tron:nile', - }, - ), - accepts: [REQ], - }), - ); - app.get('/api/data', (c) => c.json({ data: 'secret' })); - - const res = await app.request('/api/data', { - headers: { [PAYMENT_SIGNATURE_HEADER]: encodePaymentPayload(buildPayload()) }, - }); - - expect(res.status).toBe(500); - const body = (await res.json()) as Record; - expect(body.error).toBe('insufficient balance'); - expect(body.txHash).toBe('0xabc'); - expect(body.network).toBe('tron:nile'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/middleware/hono.ts b/legacy/typescript/packages/x402/src/middleware/hono.ts deleted file mode 100644 index 33b2a557..00000000 --- a/legacy/typescript/packages/x402/src/middleware/hono.ts +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Hono adapter for the x402 server middleware. - * - * Usage: - * ```ts - * import { Hono } from 'hono'; - * import { FacilitatorClient, x402Hono } from '@bankofai/x402'; - * - * const facilitator = new FacilitatorClient({ baseUrl: 'https://facilitator.example' }); - * const app = new Hono(); - * - * app.use( - * '/api/llm-summary', - * x402Hono({ - * facilitator, - * accepts: [{ - * scheme: 'exact_permit', - * network: 'tron:nile', - * amount: '1000000', - * asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - * payTo: 'TJWdoJ...', - * }], - * }), - * ); - * - * app.get('/api/llm-summary', (c) => c.json({ summary: '...' })); - * ``` - * - * Hono is imported via `peerDependencies`; consumers add it to their app. - */ - -import type { Context, MiddlewareHandler, Next } from 'hono'; - -import { - PAYMENT_SIGNATURE_HEADER, - processX402Request, - type X402MiddlewareConfig, -} from './core.js'; - -/** - * Build a Hono middleware that gates the wrapped route on x402 payment. - * - * Behavior: - * - No `PAYMENT-SIGNATURE` header → respond 402 with `PAYMENT-REQUIRED` header + body. - * - Malformed / mismatched payload → 400 JSON error. - * - Verify or settle failure → 500 JSON error. - * - Success → call `next()` and attach `PAYMENT-RESPONSE` header to the response. - */ -export function x402Hono(config: X402MiddlewareConfig): MiddlewareHandler { - return async (c: Context, next: Next) => { - const signature = c.req.header(PAYMENT_SIGNATURE_HEADER); - const decision = await processX402Request(signature, config); - - switch (decision.kind) { - case 'paymentRequired': { - for (const [k, v] of Object.entries(decision.headers)) { - c.header(k, v); - } - return c.json(decision.paymentRequired, 402); - } - case 'invalid': - return c.json({ error: decision.reason }, 400); - case 'failed': { - const body: Record = { error: decision.reason }; - if (decision.transaction) body.txHash = decision.transaction; - if (decision.network) body.network = decision.network; - return c.json(body, 500); - } - case 'allow': { - await next(); - for (const [k, v] of Object.entries(decision.headers)) { - c.header(k, v); - } - return; - } - } - }; -} diff --git a/legacy/typescript/packages/x402/src/middleware/index.ts b/legacy/typescript/packages/x402/src/middleware/index.ts deleted file mode 100644 index cafb5f96..00000000 --- a/legacy/typescript/packages/x402/src/middleware/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * x402 server middleware. - * - * - {@link x402Hono} — Hono adapter - * - {@link x402Express} — Express adapter - * - {@link processX402Request} — framework-agnostic core (build your own adapter) - */ - -export { processX402Request, X402_VERSION } from './core.js'; -export type { X402Decision, X402MiddlewareConfig } from './core.js'; -export { x402Hono } from './hono.js'; -export { x402Express } from './express.js'; diff --git a/legacy/typescript/packages/x402/src/server/index.ts b/legacy/typescript/packages/x402/src/server/index.ts deleted file mode 100644 index 359b99d9..00000000 --- a/legacy/typescript/packages/x402/src/server/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * High-level x402 server API. - * - * For framework-agnostic protocol handling, see also `src/middleware/core.ts`. - * {@link X402Server} sits above that — it owns mechanism registration, price - * parsing, anti-tamper validation, and facilitator coordination. - */ - -export { DefaultServerMechanism, X402Server } from './x402Server.js'; -export type { BuildPaymentRequiredOptions } from './x402Server.js'; -export { PAYMENT_ONLY } from './types.js'; -export type { ResourceConfig, ServerMechanism } from './types.js'; diff --git a/legacy/typescript/packages/x402/src/server/types.ts b/legacy/typescript/packages/x402/src/server/types.ts deleted file mode 100644 index 7c7eae97..00000000 --- a/legacy/typescript/packages/x402/src/server/types.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Server-side type contracts for x402 SDK. - * - * - {@link ResourceConfig} — high-level config for a protected endpoint - * - {@link ServerMechanism} — per-(network, scheme) plugin used by {@link X402Server} - */ - -import type { AssetAmount } from '../tokens.js'; -import type { PaymentPermit, PaymentRequirements } from '../types/index.js'; - -/** - * Delivery modes for a protected resource. Only `PAYMENT_ONLY` ships today; - * future modes (e.g. `RECEIPT_REQUIRED`) plug in here. - */ -export const PAYMENT_ONLY = 'PAYMENT_ONLY'; - -/** - * One protected endpoint's payment configuration. - * - * Mirrors Python `bankofai.x402.server.ResourceConfig`. - * - * @example - * ```ts - * const cfg: ResourceConfig = { - * scheme: 'exact_permit', - * network: 'tron:nile', - * price: '1 USDT', - * payTo: 'TJWdoJ...', - * }; - * ``` - */ -export interface ResourceConfig { - /** Payment scheme (`"exact"`, `"exact_permit"`, `"exact_gasfree"`, ...). */ - scheme: string; - /** CAIP-2 network identifier (`"tron:nile"`, `"eip155:97"`, ...). */ - network: string; - /** Human-readable price string parsed by {@link parsePrice} (e.g. `"1 USDT"`). */ - price: string; - /** Recipient address. */ - payTo: string; - /** Authorization validity window in seconds. Default 3600. */ - validFor?: number; - /** Delivery mode. Default {@link PAYMENT_ONLY}. */ - deliveryMode?: string; -} - -/** - * Server-side mechanism interface. - * - * One instance per `(network, scheme)`. Implementations live in the - * mechanism packages (TRON / EVM / ...) and plug into {@link X402Server} via - * `register(network, mechanism)`. - * - * Mirrors Python `bankofai.x402.server.x402_server.ServerMechanism`. - */ -export interface ServerMechanism { - /** Scheme name (matches `ResourceConfig.scheme`). */ - scheme(): string; - /** - * Resolve a `" "` price string into a typed asset amount. - * The default mechanism implementation delegates to {@link parsePrice}. - */ - parsePrice(price: string, network: string): Promise; - /** - * Hook to attach scheme-specific extra fields onto `PaymentRequirements` - * (e.g. `extra.name` / `extra.version` for permit tokens). Should return - * the requirements (possibly mutated, but a fresh object is preferred). - */ - enhancePaymentRequirements( - requirements: PaymentRequirements, - deliveryMode: string, - ): Promise; - /** Sanity check on requirements (return false to reject the config). */ - validatePaymentRequirements(requirements: PaymentRequirements): boolean; - /** - * Optional server-side signature verification before delegating to facilitator. - * Defense-in-depth — facilitator also verifies, but a misbehaving client / proxy - * should be rejected here too. Return `true` if the signature is valid. - * - * Implementations that don't perform local verification should be omitted entirely; - * {@link X402Server} treats an absent method as "trust the facilitator". - */ - verifySignature?( - permit: PaymentPermit | null | undefined, - signature: string, - network: string, - ): Promise; -} diff --git a/legacy/typescript/packages/x402/src/server/x402Server.test.ts b/legacy/typescript/packages/x402/src/server/x402Server.test.ts deleted file mode 100644 index 2ea90122..00000000 --- a/legacy/typescript/packages/x402/src/server/x402Server.test.ts +++ /dev/null @@ -1,388 +0,0 @@ -/** - * Tests for the high-level X402Server orchestration. - */ - -import { describe, expect, it, vi } from 'vitest'; - -import type { FacilitatorClient } from '../facilitator/client.js'; -import type { - FeeQuoteResponse, - PaymentPayload, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../types/index.js'; -import { DefaultServerMechanism, X402Server } from './x402Server.js'; -import type { ResourceConfig, ServerMechanism } from './types.js'; - -function fakeFacilitator(opts: { - verify?: VerifyResponse; - settle?: SettleResponse; - feeQuotes?: FeeQuoteResponse[]; - facilitatorId?: string; -} = {}): FacilitatorClient { - return { - facilitatorId: opts.facilitatorId ?? 'fac-test', - verify: vi.fn(async () => opts.verify ?? { isValid: true }), - settle: vi.fn(async () => opts.settle ?? { success: true, transaction: '0xtx' }), - feeQuote: vi.fn(async () => opts.feeQuotes ?? []), - } as unknown as FacilitatorClient; -} - -describe('X402Server.buildPaymentRequirements', () => { - it('parses price strings into smallest-unit amounts', async () => { - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - - const reqs = await server.buildPaymentRequirements([ - { - scheme: 'exact', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - }, - ]); - - expect(reqs).toHaveLength(1); - expect(reqs[0]!.amount).toBe('1000000'); - expect(reqs[0]!.asset).toBe('TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'); - expect(reqs[0]!.maxTimeoutSeconds).toBe(3600); - }); - - it('respects validFor override', async () => { - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - const reqs = await server.buildPaymentRequirements([ - { - scheme: 'exact', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - validFor: 60, - }, - ]); - expect(reqs[0]!.maxTimeoutSeconds).toBe(60); - }); - - it('throws when no mechanism registered for (network, scheme)', async () => { - const server = new X402Server().setFacilitator(fakeFacilitator()); - const cfg: ResourceConfig = { - scheme: 'exact', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'T...', - }; - await expect(server.buildPaymentRequirements([cfg])).rejects.toThrow( - /No ServerMechanism registered/, - ); - }); - - it('throws when facilitator is not set', async () => { - const server = new X402Server().register( - 'tron:mainnet', - new DefaultServerMechanism('exact'), - ); - await expect( - server.buildPaymentRequirements([ - { - scheme: 'exact', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'T...', - }, - ]), - ).rejects.toThrow(/Facilitator is not set/); - }); - - it('skips fee_quote for exact scheme (no facilitator fee needed)', async () => { - const facilitator = fakeFacilitator(); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(facilitator); - - await server.buildPaymentRequirements([ - { - scheme: 'exact', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'T...', - }, - ]); - - expect(facilitator.feeQuote).not.toHaveBeenCalled(); - }); - - it('enriches permit-style requirements with facilitator fee', async () => { - const facilitator = fakeFacilitator({ - feeQuotes: [ - { - fee: { feeTo: 'TFee...', feeAmount: '100000' }, - pricing: 'fixed', - scheme: 'exact_permit', - network: 'tron:mainnet', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - }, - ], - facilitatorId: 'fac-1', - }); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact_permit')) - .setFacilitator(facilitator); - - const reqs = await server.buildPaymentRequirements([ - { - scheme: 'exact_permit', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - }, - ]); - - expect(reqs).toHaveLength(1); - expect(reqs[0]!.extra?.fee).toMatchObject({ - feeTo: 'TFee...', - feeAmount: '100000', - facilitatorId: 'fac-1', - }); - }); - - it('drops permit requirements the facilitator cannot quote', async () => { - const facilitator = fakeFacilitator({ feeQuotes: [] }); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact_permit')) - .setFacilitator(facilitator); - - const reqs = await server.buildPaymentRequirements([ - { - scheme: 'exact_permit', - network: 'tron:mainnet', - price: '1 USDT', - payTo: 'T...', - }, - ]); - expect(reqs).toHaveLength(0); - }); -}); - -describe('X402Server.createPaymentRequiredResponse', () => { - it('emits x402Version=2 and paymentPermitContext meta', () => { - const server = new X402Server(); - const reqs: PaymentRequirements[] = [ - { - scheme: 'exact_permit', - network: 'tron:mainnet', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJ...', - }, - ]; - const response = server.createPaymentRequiredResponse(reqs); - expect(response.x402Version).toBe(2); - expect(response.accepts).toBe(reqs); - expect(response.extensions?.paymentPermitContext?.meta.paymentId).toMatch(/^0x[0-9a-f]{32}$/); - expect(response.extensions?.paymentPermitContext?.meta.kind).toBe('PAYMENT_ONLY'); - }); - - it('respects user-supplied paymentId / validity window', () => { - const server = new X402Server(); - const response = server.createPaymentRequiredResponse([], { - paymentId: '0x' + 'aa'.repeat(16), - validAfter: 1700000000, - validBefore: 1700003600, - }); - expect(response.extensions?.paymentPermitContext?.meta).toMatchObject({ - paymentId: '0x' + 'aa'.repeat(16), - validAfter: 1700000000, - validBefore: 1700003600, - }); - }); -}); - -describe('X402Server.verifyPayment / settlePayment', () => { - const baseReq: PaymentRequirements = { - scheme: 'exact_permit', - network: 'tron:mainnet', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - }; - - function makePayload(): PaymentPayload { - return { - x402Version: 2, - accepted: baseReq, - payload: { - signature: '0x' + 'aa'.repeat(65), - paymentPermit: { - meta: { - kind: 'PAYMENT_ONLY', - paymentId: '0x' + '11'.repeat(16), - nonce: '0', - validAfter: 0, - validBefore: 9_999_999_999, - }, - buyer: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - caller: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - payment: { - payToken: baseReq.asset, - payAmount: baseReq.amount, - payTo: baseReq.payTo, - }, - fee: { feeTo: 'TFee', feeAmount: '0' }, - }, - }, - } as PaymentPayload; - } - - it('verifyPayment delegates to facilitator after anti-tamper passes', async () => { - const facilitator = fakeFacilitator({ verify: { isValid: true } }); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact_permit')) - .setFacilitator(facilitator); - - const result = await server.verifyPayment(makePayload(), baseReq); - expect(result.isValid).toBe(true); - expect(facilitator.verify).toHaveBeenCalledOnce(); - }); - - it('verifyPayment rejects payload_mismatch when asset is wrong', async () => { - const facilitator = fakeFacilitator(); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact_permit')) - .setFacilitator(facilitator); - - const payload = makePayload(); - payload.payload.paymentPermit!.payment.payToken = 'WRONG_ASSET'; - - const result = await server.verifyPayment(payload, baseReq); - expect(result.isValid).toBe(false); - expect(result.invalidReason).toBe('payload_mismatch'); - expect(facilitator.verify).not.toHaveBeenCalled(); - }); - - it('verifyPayment returns no_facilitator when facilitator unset', async () => { - const server = new X402Server().register( - 'tron:mainnet', - new DefaultServerMechanism('exact_permit'), - ); - const result = await server.verifyPayment(makePayload(), baseReq); - expect(result).toEqual({ isValid: false, invalidReason: 'no_facilitator' }); - }); - - it('verifyPayment runs mechanism.verifySignature when present', async () => { - const verifySignature = vi.fn(async () => false); - const base = new DefaultServerMechanism('exact_permit'); - const customMech: ServerMechanism = { - scheme: () => base.scheme(), - parsePrice: (p, n) => base.parsePrice(p, n), - enhancePaymentRequirements: (r, d) => base.enhancePaymentRequirements(r, d), - validatePaymentRequirements: (r) => base.validatePaymentRequirements(r), - verifySignature, - }; - const server = new X402Server() - .register('tron:mainnet', customMech) - .setFacilitator(fakeFacilitator()); - - const result = await server.verifyPayment(makePayload(), baseReq); - expect(result).toEqual({ isValid: false, invalidReason: 'invalid_signature_server' }); - expect(verifySignature).toHaveBeenCalledOnce(); - }); - - it('settlePayment returns no_facilitator without facilitator', async () => { - const server = new X402Server(); - const result = await server.settlePayment(makePayload(), baseReq); - expect(result.success).toBe(false); - expect(result.errorReason).toBe('no_facilitator'); - expect(result.network).toBe('tron:mainnet'); - }); - - it('settlePayment delegates to facilitator', async () => { - const facilitator = fakeFacilitator({ - settle: { success: true, transaction: '0xabc', network: 'tron:mainnet' }, - }); - const server = new X402Server().setFacilitator(facilitator); - const result = await server.settlePayment(makePayload(), baseReq); - expect(result.success).toBe(true); - expect(result.transaction).toBe('0xabc'); - }); -}); - -describe('X402Server anti-tamper for exact scheme', () => { - const exactReq: PaymentRequirements = { - scheme: 'exact', - network: 'tron:mainnet', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', - }; - - function exactPayload(overrides: Partial> = {}): PaymentPayload { - const now = Math.floor(Date.now() / 1000); - return { - x402Version: 2, - accepted: exactReq, - payload: { - signature: '0x' + 'aa'.repeat(65), - authorization: { - from: 'TFrom', - to: exactReq.payTo, - value: exactReq.amount, - validAfter: String(now - 10), - validBefore: String(now + 600), - nonce: '0x' + '11'.repeat(32), - ...overrides, - }, - }, - } as PaymentPayload; - } - - it('passes valid exact authorization', async () => { - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - const result = await server.verifyPayment(exactPayload(), exactReq); - expect(result.isValid).toBe(true); - }); - - it('rejects when authorization value < amount', async () => { - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - const result = await server.verifyPayment(exactPayload({ value: '500000' }), exactReq); - expect(result.invalidReason).toBe('payload_mismatch'); - }); - - it('rejects when authorization.to !== payTo', async () => { - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - const result = await server.verifyPayment(exactPayload({ to: 'TWrong' }), exactReq); - expect(result.invalidReason).toBe('payload_mismatch'); - }); - - it('rejects expired authorization (validBefore < now)', async () => { - const now = Math.floor(Date.now() / 1000); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - const result = await server.verifyPayment( - exactPayload({ validBefore: String(now - 60) }), - exactReq, - ); - expect(result.invalidReason).toBe('payload_mismatch'); - }); - - it('rejects not-yet-valid authorization (validAfter > now)', async () => { - const now = Math.floor(Date.now() / 1000); - const server = new X402Server() - .register('tron:mainnet', new DefaultServerMechanism('exact')) - .setFacilitator(fakeFacilitator()); - const result = await server.verifyPayment( - exactPayload({ validAfter: String(now + 600) }), - exactReq, - ); - expect(result.invalidReason).toBe('payload_mismatch'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/server/x402Server.ts b/legacy/typescript/packages/x402/src/server/x402Server.ts deleted file mode 100644 index eedf592b..00000000 --- a/legacy/typescript/packages/x402/src/server/x402Server.ts +++ /dev/null @@ -1,381 +0,0 @@ -/** - * X402Server — TypeScript port of `bankofai.x402.server.X402Server`. - * - * High-level server orchestration: - * - Registry of {@link ServerMechanism}s keyed by `(network, scheme)` - * - Build {@link PaymentRequirements} from {@link ResourceConfig} via `parsePrice` - * + optional facilitator `feeQuote` enrichment for permit-style schemes - * - Anti-tamper validation of incoming `PaymentPayload` against server's - * original requirements - * - Delegates `/verify` and `/settle` to a {@link FacilitatorClient} - * - * This sits **above** the framework-agnostic {@link processX402Request} core - * (see `src/middleware/core.ts`). Framework middleware (Hono / Express) - * can be wired against either: - * - Raw `accepts[]` + `FacilitatorClient` (lower-level, `processX402Request`) - * - `X402Server` + `ResourceConfig[]` (higher-level, this file) - */ - -import { getAddress, isAddress } from 'viem'; - -import type { FacilitatorClient } from '../facilitator/client.js'; -import { parsePrice } from '../tokens.js'; -import type { - PaymentPayload, - PaymentRequired, - PaymentRequirements, - SettleResponse, - VerifyResponse, -} from '../types/index.js'; -import { generatePaymentId } from '../utils/index.js'; -import { PAYMENT_ONLY, type ResourceConfig, type ServerMechanism } from './types.js'; - -/** Resource info echoed back in the 402 response body. */ -export interface ResourceInfo { - url?: string; - description?: string; - mimeType?: string; -} - -/** Optional overrides when building the 402 response. */ -export interface BuildPaymentRequiredOptions { - resource?: ResourceInfo; - paymentId?: string; - nonce?: string; - validAfter?: number; - validBefore?: number; -} - -/** - * Default {@link ServerMechanism} that delegates `parsePrice` to the token - * registry and applies a no-op `enhancePaymentRequirements`. Useful when a - * chain/scheme needs no scheme-specific enrichment. - */ -export class DefaultServerMechanism implements ServerMechanism { - constructor(private readonly schemeName: string) {} - - scheme(): string { - return this.schemeName; - } - - async parsePrice(price: string, network: string) { - return parsePrice(price, network); - } - - async enhancePaymentRequirements( - requirements: PaymentRequirements, - _deliveryMode: string, - ): Promise { - return requirements; - } - - validatePaymentRequirements(_requirements: PaymentRequirements): boolean { - return true; - } -} - -/** - * Core server orchestration. One instance per resource server. - * - * @example - * ```ts - * const facilitator = new FacilitatorClient({ baseUrl: 'https://fac.example' }); - * const server = new X402Server() - * .register('tron:nile', new DefaultServerMechanism('exact_permit')) - * .setFacilitator(facilitator); - * - * const accepts = await server.buildPaymentRequirements([ - * { scheme: 'exact_permit', network: 'tron:nile', price: '1 USDT', payTo: 'T...' }, - * ]); - * const challenge = server.createPaymentRequiredResponse(accepts); - * ``` - */ -export class X402Server { - /** network → scheme → mechanism */ - private readonly mechanisms = new Map>(); - private facilitator: FacilitatorClient | null = null; - - /** Register a {@link ServerMechanism} for one network. Chainable. */ - register(network: string, mechanism: ServerMechanism): this { - const scheme = mechanism.scheme(); - let byScheme = this.mechanisms.get(network); - if (!byScheme) { - byScheme = new Map(); - this.mechanisms.set(network, byScheme); - } - byScheme.set(scheme, mechanism); - return this; - } - - /** Set the facilitator client. Required before {@link verifyPayment} / {@link settlePayment}. */ - setFacilitator(client: FacilitatorClient): this { - this.facilitator = client; - return this; - } - - /** - * Turn a list of {@link ResourceConfig} into ready-to-serve {@link PaymentRequirements}. - * - * Pipeline per config: - * 1. Find mechanism by `(network, scheme)`; throw if not registered. - * 2. Parse `price` → asset + amount via mechanism. - * 3. Build initial `PaymentRequirements`. - * 4. Let mechanism `enhancePaymentRequirements` attach extras (token name/version, etc.). - * 5. Normalize EVM addresses via checksum. - * - * If a facilitator is configured, permit-style requirements (`scheme !== 'exact'`) - * get enriched with `extra.fee` from `/fee/quote`. Unsupported (network, scheme, asset) - * tuples returned by the facilitator are silently dropped from the result. - * - * Mirrors Python `X402Server.build_payment_requirements`. - */ - async buildPaymentRequirements( - configs: ResourceConfig[], - ): Promise { - const built: PaymentRequirements[] = []; - for (const config of configs) { - const mechanism = this.findMechanism(config.network, config.scheme); - if (!mechanism) { - throw new Error( - `No ServerMechanism registered for network=${config.network}, scheme=${config.scheme}`, - ); - } - - const assetInfo = await mechanism.parsePrice(config.price, config.network); - - let requirements: PaymentRequirements = { - scheme: config.scheme, - network: config.network, - amount: assetInfo.amount, - asset: assetInfo.asset, - payTo: config.payTo, - maxTimeoutSeconds: config.validFor ?? 3600, - }; - requirements = await mechanism.enhancePaymentRequirements( - requirements, - config.deliveryMode ?? PAYMENT_ONLY, - ); - requirements = this.normalizeEvmRequirements(requirements); - built.push(requirements); - } - - if (!this.facilitator) { - throw new Error('Facilitator is not set (call setFacilitator first)'); - } - - // Split: exact doesn't need fee quote; everything else (permit-style) does. - const exactReqs = built.filter((r) => r.scheme === 'exact'); - const permitReqs = built.filter((r) => r.scheme !== 'exact'); - - const supported: PaymentRequirements[] = [...exactReqs]; - if (permitReqs.length > 0) { - const quotes = await this.facilitator.feeQuote(permitReqs); - const quoteMap = new Map(); - for (const q of quotes) { - quoteMap.set(`${q.scheme}|${q.network}|${q.asset}`, q); - } - for (const req of permitReqs) { - const quote = quoteMap.get(`${req.scheme}|${req.network}|${req.asset}`); - if (!quote) { - // Facilitator can't quote this (unsupported token / scheme). Silently skip. - continue; - } - const enriched: PaymentRequirements = { - ...req, - extra: { - ...(req.extra ?? {}), - fee: { - ...quote.fee, - facilitatorId: this.facilitator.facilitatorId, - }, - }, - }; - supported.push(this.normalizeEvmRequirements(enriched)); - } - } - return supported; - } - - /** - * Build the 402 PaymentRequired challenge body. The facilitator is not - * consulted here — the caller has already obtained `requirements` via - * {@link buildPaymentRequirements} or constructed them by hand. - */ - createPaymentRequiredResponse( - requirements: PaymentRequirements[], - options: BuildPaymentRequiredOptions = {}, - ): PaymentRequired { - const now = Math.floor(Date.now() / 1000); - const validBefore = options.validBefore ?? now + 3600; - const validAfter = options.validAfter ?? now; - - return { - x402Version: 2, - error: 'Payment required', - ...(options.resource ? { resource: options.resource } : {}), - accepts: requirements, - extensions: { - paymentPermitContext: { - meta: { - kind: PAYMENT_ONLY, - paymentId: options.paymentId ?? generatePaymentId(), - nonce: options.nonce ?? generateNonce(), - validAfter, - validBefore, - }, - }, - }, - } as PaymentRequired; - } - - /** - * Anti-tamper validation + optional server-side signature check, then - * delegate to the facilitator. Mirrors Python `verify_payment`. - */ - async verifyPayment( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - if (!this.validatePayloadMatchesRequirements(payload, requirements)) { - return { isValid: false, invalidReason: 'payload_mismatch' }; - } - - const mechanism = this.findMechanism(requirements.network, requirements.scheme); - if (mechanism?.verifySignature) { - const permit = payload.payload.paymentPermit ?? null; - const signature = payload.payload.signature; - const ok = await mechanism.verifySignature(permit, signature, requirements.network); - if (!ok) { - return { isValid: false, invalidReason: 'invalid_signature_server' }; - } - } - - if (!this.facilitator) { - return { isValid: false, invalidReason: 'no_facilitator' }; - } - return this.facilitator.verify(payload, requirements); - } - - /** Delegate settlement to the facilitator. Mirrors Python `settle_payment`. */ - async settlePayment( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise { - if (!this.facilitator) { - return { - success: false, - network: requirements.network, - errorReason: 'no_facilitator', - }; - } - return this.facilitator.settle(payload, requirements); - } - - /** - * Anti-tampering: the client's `payload.accepted` must match server's - * canonical `requirements`, and the embedded authorization / permit must - * point at the right asset / payTo / amount. - * - * Two flavors: - * - `exact` (ERC-3009): inspects `payload.payload.authorization` - * - other (permit-style): inspects `payload.payload.paymentPermit` - */ - private validatePayloadMatchesRequirements( - payload: PaymentPayload, - requirements: PaymentRequirements, - ): boolean { - if (requirements.scheme === 'exact') { - const auth = - payload.payload.authorization ?? - ((payload.extensions ?? {})['transferAuthorization'] as - | PaymentPayload['payload']['authorization'] - | undefined); - if (!auth) return false; - - if (payload.accepted) { - if (payload.accepted.asset !== requirements.asset) return false; - if (payload.accepted.network !== requirements.network) return false; - } - - try { - if (BigInt(String(auth.value)) < BigInt(requirements.amount)) return false; - } catch { - return false; - } - if (String(auth.to).toLowerCase() !== String(requirements.payTo).toLowerCase()) { - return false; - } - - const now = Math.floor(Date.now() / 1000); - try { - const validBefore = BigInt(String(auth.validBefore ?? '0')); - const validAfter = BigInt(String(auth.validAfter ?? now)); - if (validBefore < BigInt(now)) return false; - if (validAfter > BigInt(now)) return false; - } catch { - return false; - } - return true; - } - - const permit = payload.payload.paymentPermit; - if (!permit) return false; - if (permit.payment.payToken !== requirements.asset) return false; - if (permit.payment.payTo !== requirements.payTo) return false; - try { - if (BigInt(permit.payment.payAmount) < BigInt(requirements.amount)) return false; - } catch { - return false; - } - return true; - } - - private findMechanism(network: string, scheme: string): ServerMechanism | null { - return this.mechanisms.get(network)?.get(scheme) ?? null; - } - - private normalizeEvmRequirements(reqs: PaymentRequirements): PaymentRequirements { - if (!reqs.network.startsWith('eip155:')) { - return reqs; - } - return { - ...reqs, - asset: checksumOrThrow(reqs.asset, 'asset'), - payTo: checksumOrThrow(reqs.payTo, 'payTo'), - extra: reqs.extra - ? { - ...reqs.extra, - ...(reqs.extra.fee - ? { - fee: { - ...reqs.extra.fee, - feeTo: checksumOrThrow(reqs.extra.fee.feeTo, 'extra.fee.feeTo'), - ...(reqs.extra.fee.caller - ? { caller: checksumOrThrow(reqs.extra.fee.caller, 'extra.fee.caller') } - : {}), - }, - } - : {}), - } - : reqs.extra, - }; - } -} - -function checksumOrThrow(address: string, field: string): string { - if (!isAddress(address, { strict: false })) { - throw new Error(`Invalid EVM address for ${field}: ${address}`); - } - return getAddress(address); -} - -function generateNonce(): string { - // 16 random bytes, decimal-encoded — matches Python's str(uuid.uuid4().int) shape. - const bytes = new Uint8Array(16); - crypto.getRandomValues(bytes); - let nonce = 0n; - for (const byte of bytes) { - nonce = (nonce << 8n) | BigInt(byte); - } - return nonce.toString(); -} diff --git a/legacy/typescript/packages/x402/src/signers/evmSigner.test.ts b/legacy/typescript/packages/x402/src/signers/evmSigner.test.ts deleted file mode 100644 index 6756893e..00000000 --- a/legacy/typescript/packages/x402/src/signers/evmSigner.test.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; -import { resolveWalletProvider } from '@bankofai/agent-wallet'; -import { EvmClientSigner } from './evmSigner.js'; -import type { AgentWallet } from './signer.js'; - -/** Creates a mock wallet for testing. */ -function createMockWallet(address: string): AgentWallet { - return { - getAddress: vi.fn().mockResolvedValue(address), - signMessage: vi.fn().mockResolvedValue('0xdeadbeef'), - signTypedData: vi.fn().mockResolvedValue('0xcafebabe'), - signTransaction: vi.fn().mockResolvedValue('0x1234'), - }; -} - -vi.mock('@bankofai/agent-wallet', () => ({ - resolveWalletProvider: vi.fn(), -})); - -describe('EvmClientSigner', () => { - const expectedAddress = '0xFCAd0B19bB29D4674531d6f115237E16AfCE377c'; - - it('should initialize with wallet and address', () => { - const wallet = createMockWallet(expectedAddress); - const signer = new EvmClientSigner(wallet); - signer.setAddress(expectedAddress); - expect(signer.getAddress().toLowerCase()).toBe( - expectedAddress.toLowerCase(), - ); - }); - - it('should create via async factory', async () => { - const wallet = createMockWallet(expectedAddress); - vi.mocked(resolveWalletProvider).mockReturnValue({ - getActiveWallet: vi.fn().mockResolvedValue(wallet), - }); - - const signer = await EvmClientSigner.create(); - expect(signer.getAddress().toLowerCase()).toBe( - expectedAddress.toLowerCase(), - ); - expect(wallet.getAddress).toHaveBeenCalledOnce(); - }); - - it('should delegate signMessage to wallet', async () => { - const wallet = createMockWallet(expectedAddress); - const signer = new EvmClientSigner(wallet); - signer.setAddress(expectedAddress); - const message = new TextEncoder().encode('hello world'); - const signature = await signer.signMessage(message); - - expect(wallet.signMessage).toHaveBeenCalledWith(message); - expect(signature).toBe('0xdeadbeef'); - }); - - it('should delegate signTypedData to wallet', async () => { - const wallet = createMockWallet(expectedAddress); - const signer = new EvmClientSigner(wallet); - signer.setAddress(expectedAddress); - const domain = { - name: 'Test', - version: '1', - chainId: 1, - verifyingContract: '0x0000000000000000000000000000000000000000' as const, - }; - const types = { - Person: [ - { name: 'name', type: 'string' }, - { name: 'wallet', type: 'address' }, - ], - }; - const message = { - name: 'Bob', - wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB' as const, - }; - - const signature = await signer.signTypedData(domain, types, message, 'Person'); - expect(wallet.signTypedData).toHaveBeenCalled(); - expect(signature).toBe('0xcafebabe'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/signers/evmSigner.ts b/legacy/typescript/packages/x402/src/signers/evmSigner.ts deleted file mode 100644 index 3bb97cae..00000000 --- a/legacy/typescript/packages/x402/src/signers/evmSigner.ts +++ /dev/null @@ -1,249 +0,0 @@ -/** - * EvmClientSigner - EVM client signer for x402 protocol - */ - -import { - createPublicClient, - http, - type PublicClient, - type Hex, - parseAbi, - encodeFunctionData, - type Chain, -} from 'viem'; -import { mainnet, sepolia, bsc, bscTestnet } from 'viem/chains'; -import { resolveWalletProvider } from '@bankofai/agent-wallet'; -import type { AgentWallet } from './signer.js'; -import type { ClientSigner } from '../client/x402Client.js'; -import { - getPaymentPermitAddress, - resolveRpcUrl, - InsufficientAllowanceError, - UnsupportedNetworkError, -} from '../index.js'; - -const ERC20_ABI = parseAbi([ - 'function allowance(address owner, address spender) view returns (uint256)', - 'function approve(address spender, uint256 amount) returns (bool)', - 'function balanceOf(address account) view returns (uint256)', -]); - -/** - * EVM client signer implementation. - * - * Accepts any wallet conforming to the AgentWallet interface. - * The signer is agnostic about how the wallet was created - * (private key, hosted, etc.). - */ -export class EvmClientSigner implements ClientSigner { - private wallet!: AgentWallet; - private _address: string = ''; - private publicClients: Map = new Map(); - - /** - * Create signer from a wallet. - * - * Prefer the async factory ``create()``. - */ - constructor(wallet: AgentWallet) { - this.wallet = wallet; - } - - /** Async factory: resolve active agent wallet and create signer. */ - static async create(): Promise { - const provider = resolveWalletProvider({ network: 'eip155' }); - const wallet = await provider.getActiveWallet(); - const signer = new EvmClientSigner(wallet as unknown as AgentWallet); - signer.setAddress(await wallet.getAddress()); - return signer; - } - - setAddress(address: string): void { - this._address = address; - } - - getAddress(): string { - return this._address; - } - - getEvmAddress(): Hex { - return this._address as Hex; - } - - async signMessage(message: Uint8Array): Promise { - return this.wallet.signMessage(message); - } - - async signTypedData( - domain: Record, - types: Record, - message: Record, - primaryType: string - ): Promise { - const fullData = { - types: { EIP712Domain: [], ...types }, - domain, - primaryType, - message, - }; - - return this.wallet.signTypedData(fullData); - } - - async checkBalance(token: string, network: string, address?: string): Promise { - const chainId = this.parseNetworkToChainId(network); - const client = this.getPublicClient(chainId, network); - try { - return await client.readContract({ - address: token as Hex, - abi: ERC20_ABI, - functionName: 'balanceOf', - args: [(address ?? this._address) as Hex], - }); - } catch (error) { - console.error( - `[EvmClientSigner] checkBalance failed for ${token} on ${network}:`, - error, - ); - return 0n; - } - } - - async checkAllowance( - token: string, - _amount: bigint, - network: string, - ): Promise { - const chainId = this.parseNetworkToChainId(network); - const client = this.getPublicClient(chainId, network); - const spender = getPaymentPermitAddress(network) as Hex; - - try { - return await client.readContract({ - address: token as Hex, - abi: ERC20_ABI, - functionName: 'allowance', - args: [this._address as Hex, spender], - }); - } catch (error) { - console.error( - `[EvmClientSigner] checkAllowance failed for ${token} on ${network}:`, - error, - ); - return 0n; - } - } - - async ensureAllowance( - token: string, - amount: bigint, - network: string, - mode: 'auto' | 'interactive' | 'skip' = 'auto', - ): Promise { - if (mode === 'skip') return true; - - const currentAllowance = await this.checkAllowance(token, amount, network); - if (currentAllowance >= amount) return true; - - if (mode === 'interactive') { - throw new InsufficientAllowanceError('Interactive approval required'); - } - - const chainId = this.parseNetworkToChainId(network); - const client = this.getPublicClient(chainId, network); - const spender = getPaymentPermitAddress(network) as Hex; - - try { - // Build approve calldata - const data = encodeFunctionData({ - abi: ERC20_ABI, - functionName: 'approve', - args: [spender, BigInt(2) ** BigInt(256) - BigInt(1)], - }); - - // Prepare transaction via public client - const nonce = await client.getTransactionCount({ address: this._address as Hex }); - const gasPrice = await client.getGasPrice(); - const gas = await client.estimateGas({ - account: this._address as Hex, - to: token as Hex, - data, - }); - - const tx = { - from: this._address, - to: token, - data, - nonce, - gas: Number(gas), - gasPrice: Number(gasPrice), - chainId, - }; - - // Sign via wallet and broadcast - const signedTxHex = await this.wallet.signTransaction(tx); - const hash = await client.sendRawTransaction({ - serializedTransaction: `0x${signedTxHex.replace(/^0x/, '')}` as Hex, - }); - - const receipt = await client.waitForTransactionReceipt({ hash }); - - const success = receipt.status === 'success'; - if (success) { - console.info( - `[EvmClientSigner] ERC20 approval confirmed for ${token}, tx: ${hash}`, - ); - } - return success; - } catch (error) { - console.error( - `[EvmClientSigner] ERC20 approval failed for ${token}:`, - error, - ); - throw new InsufficientAllowanceError( - `ERC20 approval transaction failed for ${token}: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } - - private getPublicClient(chainId: number, network: string): PublicClient { - let client = this.publicClients.get(chainId); - if (!client) { - const rpcUrl = resolveRpcUrl(network); - client = createPublicClient({ - chain: this.getChain(chainId), - transport: http(rpcUrl), - }); - this.publicClients.set(chainId, client); - } - return client; - } - - private getChain(chainId: number): Chain { - const chains: Record = { - 1: mainnet, - 11155111: sepolia, - 56: bsc, - 97: bscTestnet, - }; - - const chain = chains[chainId]; - if (!chain) { - throw new UnsupportedNetworkError(`Unsupported EVM chain ID: ${chainId}`); - } - return chain; - } - - private parseNetworkToChainId(network: string): number { - if (!network.startsWith('eip155:')) { - throw new UnsupportedNetworkError( - `Invalid EVM network format: ${network}`, - ); - } - const chainId = parseInt(network.split(':')[1], 10); - if (isNaN(chainId)) { - throw new UnsupportedNetworkError(`Invalid EVM chain ID in: ${network}`); - } - return chainId; - } -} diff --git a/legacy/typescript/packages/x402/src/signers/facilitator/base.ts b/legacy/typescript/packages/x402/src/signers/facilitator/base.ts deleted file mode 100644 index 455e3e38..00000000 --- a/legacy/typescript/packages/x402/src/signers/facilitator/base.ts +++ /dev/null @@ -1,95 +0,0 @@ -/** - * FacilitatorSigner — abstract base interface for facilitator-side signers. - * - * Mirrors Python `bankofai.x402.signers.facilitator.base.FacilitatorSigner`. - * - * Responsible for verifying signatures and executing on-chain transactions - * on behalf of the facilitator (settle path). - */ - -export interface TypedDataDomain { - name?: string; - version?: string; - chainId?: number; - verifyingContract?: string; - salt?: string; -} - -export type TypedDataTypes = Record< - string, - ReadonlyArray<{ name: string; type: string }> ->; - -export interface TransactionReceipt { - hash: string; - blockNumber: string; - status: 'confirmed' | 'failed'; -} - -export abstract class FacilitatorSigner { - /** Facilitator's account address (Base58 on TRON, hex on EVM). */ - abstract getAddress(): string; - - /** - * Verify EIP-712 / TIP-712 typed-data signature. - * - * @param address Expected signer address (Base58 on TRON; the impl normalizes). - * @param domain EIP-712 domain. - * @param types Type definitions (the impl injects `EIP712Domain` if needed). - * @param message Signed message. - * @param signature Hex signature (with or without `0x`). - * @param primaryType Root type name. - */ - abstract verifyTypedData( - address: string, - domain: TypedDataDomain, - types: TypedDataTypes, - message: Record, - signature: string, - primaryType: string, - ): Promise; - - /** - * Execute a contract write transaction. Returns the tx hash, or `null` on - * broadcast failure (no exception — callers should treat null as failure). - * - * @param contractAddress Contract address (Base58 on TRON, hex on EVM). - * @param abi Contract ABI (JSON string or array). - * @param method Method name. - * @param args Method arguments. For tuple structs, pass nested arrays/objects. - * @param network Network identifier (e.g. `tron:nile`, `eip155:97`). - */ - abstract writeContract( - contractAddress: string, - abi: string | unknown[], - method: string, - args: unknown[], - network: string, - ): Promise; - - /** - * Check ERC20/TRC20 token balance for an address. - * - * @param token Token contract address. - * @param network Network identifier. - * @param address Optional address (defaults to signer's address). - */ - abstract checkBalance( - token: string, - network: string, - address?: string, - ): Promise; - - /** - * Wait for transaction confirmation (poll receipt). - * - * @param txHash Transaction hash. - * @param network Network identifier. - * @param timeoutMs Timeout in milliseconds (default 120s). - */ - abstract waitForTransactionReceipt( - txHash: string, - network: string, - timeoutMs?: number, - ): Promise; -} diff --git a/legacy/typescript/packages/x402/src/signers/facilitator/evmSigner.ts b/legacy/typescript/packages/x402/src/signers/facilitator/evmSigner.ts deleted file mode 100644 index 7ee8ef07..00000000 --- a/legacy/typescript/packages/x402/src/signers/facilitator/evmSigner.ts +++ /dev/null @@ -1,204 +0,0 @@ -/** - * EvmFacilitatorSigner — EVM facilitator signer (EIP-712 verify + contract write). - * - * Mirrors Python `bankofai.x402.signers.facilitator.evm_signer.EvmFacilitatorSigner`. - * - * Uses `viem` for everything: - * - `recoverTypedDataAddress` for verify - * - `PublicClient.simulateContract` + `wallet.signTransaction` + `sendRawTransaction` for write - * - `PublicClient.waitForTransactionReceipt` for receipt polling - */ - -import { - createPublicClient, - encodeFunctionData, - http, - recoverTypedDataAddress, -} from 'viem'; -import type { - Abi, - Hex, - PublicClient, - TypedDataDomain as ViemTypedDataDomain, -} from 'viem'; -import { resolveWalletProvider } from '@bankofai/agent-wallet'; - -import { - FacilitatorSigner, - type TypedDataDomain, - type TypedDataTypes, - type TransactionReceipt, -} from './base.js'; -import { ERC20_ABI } from '../../abi.js'; -import { getChainId, resolveRpcUrl } from '../../config.js'; -import type { AgentWallet } from '../signer.js'; - -export class EvmFacilitatorSigner extends FacilitatorSigner { - private wallet: AgentWallet; - private address: Hex = '0x0000000000000000000000000000000000000000'; - private clients: Map = new Map(); - - constructor(wallet: AgentWallet) { - super(); - this.wallet = wallet; - } - - static async create(): Promise { - const provider = resolveWalletProvider({ network: 'eip155' }); - const wallet = await provider.getActiveWallet(); - const signer = new EvmFacilitatorSigner(wallet as unknown as AgentWallet); - signer.setAddress((await wallet.getAddress()) as Hex); - return signer; - } - - setAddress(address: Hex): void { - this.address = address; - } - - getAddress(): string { - return this.address; - } - - private getPublicClient(network: string): PublicClient { - const chainId = getChainId(network); - let client = this.clients.get(chainId); - if (!client) { - const rpcUrl = resolveRpcUrl(network); - if (!rpcUrl) { - throw new Error(`No RPC URL configured for ${network}`); - } - client = createPublicClient({ transport: http(rpcUrl) }); - this.clients.set(chainId, client); - } - return client; - } - - async verifyTypedData( - address: string, - domain: TypedDataDomain, - types: TypedDataTypes, - message: Record, - signature: string, - primaryType: string, - ): Promise { - try { - const viemDomain: ViemTypedDataDomain = { - name: domain.name, - version: domain.version, - chainId: domain.chainId, - verifyingContract: domain.verifyingContract as Hex | undefined, - ...(domain.salt ? { salt: domain.salt as `0x${string}` } : {}), - }; - const typesNoDomain: TypedDataTypes = { ...types }; - delete (typesNoDomain as Record)['EIP712Domain']; - - const sigBytes = signature.startsWith('0x') - ? (signature as Hex) - : (`0x${signature}` as Hex); - - const recovered = await recoverTypedDataAddress({ - domain: viemDomain, - types: typesNoDomain as Record< - string, - ReadonlyArray<{ name: string; type: string }> - >, - primaryType, - message, - signature: sigBytes, - }); - return recovered.toLowerCase() === address.toLowerCase(); - } catch (err) { - // eslint-disable-next-line no-console - console.error('[EvmFacilitatorSigner] verifyTypedData failed:', err); - return false; - } - } - - async writeContract( - contractAddress: string, - abi: string | unknown[], - method: string, - args: unknown[], - network: string, - ): Promise { - try { - const client = this.getPublicClient(network); - const chainId = getChainId(network); - - const abiArray = (typeof abi === 'string' ? JSON.parse(abi) : abi) as Abi; - - const data = encodeFunctionData({ - abi: abiArray, - functionName: method, - args, - }); - - const nonce = await client.getTransactionCount({ address: this.address }); - const gasPrice = await client.getGasPrice(); - const gas = await client.estimateGas({ - account: this.address, - to: contractAddress as Hex, - data, - }); - - const tx = { - from: this.address, - to: contractAddress, - data, - nonce, - gas: Number(gas), - gasPrice: Number(gasPrice), - chainId, - }; - - const signedTxHex = await this.wallet.signTransaction(tx); - const hash = await client.sendRawTransaction({ - serializedTransaction: `0x${signedTxHex.replace(/^0x/, '')}` as Hex, - }); - return hash; - } catch (err) { - // eslint-disable-next-line no-console - console.error('[EvmFacilitatorSigner] writeContract failed:', err); - return null; - } - } - - async checkBalance( - token: string, - network: string, - address?: string, - ): Promise { - try { - const client = this.getPublicClient(network); - const target = (address ?? this.address) as Hex; - const balance = await client.readContract({ - address: token as Hex, - abi: ERC20_ABI, - functionName: 'balanceOf', - args: [target], - }); - return BigInt(balance as bigint); - } catch (err) { - // eslint-disable-next-line no-console - console.error(`[EvmFacilitatorSigner] checkBalance failed for ${token}:`, err); - return BigInt(0); - } - } - - async waitForTransactionReceipt( - txHash: string, - network: string, - timeoutMs: number = 120_000, - ): Promise { - const client = this.getPublicClient(network); - const receipt = await client.waitForTransactionReceipt({ - hash: txHash as Hex, - timeout: timeoutMs, - }); - return { - hash: txHash, - blockNumber: String(receipt.blockNumber), - status: receipt.status === 'success' ? 'confirmed' : 'failed', - }; - } -} diff --git a/legacy/typescript/packages/x402/src/signers/facilitator/tronSigner.ts b/legacy/typescript/packages/x402/src/signers/facilitator/tronSigner.ts deleted file mode 100644 index 138fa3ea..00000000 --- a/legacy/typescript/packages/x402/src/signers/facilitator/tronSigner.ts +++ /dev/null @@ -1,384 +0,0 @@ -/** - * TronFacilitatorSigner — TRON facilitator signer (TIP-712 verify + contract write). - * - * Mirrors Python `bankofai.x402.signers.facilitator.tron_signer.TronFacilitatorSigner`. - * - * Uses: - * - `tronweb` v6 for transaction building, signing wrap, broadcasting, receipt polling - * - `viem` for cross-chain EIP-712 signature recovery (TRON TIP-712 is structurally - * identical to EIP-712 once addresses are normalized to 0x hex) - * - `@bankofai/agent-wallet` for the signing wallet abstraction - */ - -import { recoverTypedDataAddress } from 'viem'; -import type { TypedDataDomain as ViemTypedDataDomain } from 'viem'; -import { resolveWalletProvider } from '@bankofai/agent-wallet'; -import { TronWeb as TronWebClass } from 'tronweb'; - -import { - FacilitatorSigner, - type TypedDataDomain, - type TypedDataTypes, - type TransactionReceipt, -} from './base.js'; -import type { TronWeb } from '../types.js'; -import { toEvmHex } from '../../address.js'; -import { getTronRpcUrl } from '../../config.js'; -import type { AgentWallet } from '../signer.js'; - -/** - * Buffer-like check that works in both Node and bundled environments without - * requiring `Buffer` to be in the global scope. - */ -function hexToBytes(hex: string): Uint8Array { - const clean = hex.startsWith('0x') ? hex.slice(2) : hex; - if (clean.length % 2 !== 0) { - throw new Error(`Invalid hex string length: ${clean.length}`); - } - const out = new Uint8Array(clean.length / 2); - for (let i = 0; i < out.length; i++) { - out[i] = parseInt(clean.slice(i * 2, i * 2 + 2), 16); - } - return out; -} - -/** - * TRON facilitator signer. - * - * The wallet is responsible for signing transactions; the signer wraps tronweb - * for building and broadcasting them. For verify, we use viem's typed-data - * recovery directly — it does not need the wallet. - */ -export class TronFacilitatorSigner extends FacilitatorSigner { - private wallet: AgentWallet; - private address: string = ''; // Base58 format - private tronWebInstances: Map = new Map(); - /** - * Raw private key (hex, no `0x`) read from `TRON_FACILITATOR_PRIVATE_KEY` - * or `TRON_PRIVATE_KEY`. When present, signs transactions directly via - * `tronweb.trx.sign(tx, privateKey)` — mirrors Python's tronpy direct-sign - * path that bypasses agent-wallet (because agent-wallet's TRON sign_transaction - * round-trip can drift the tx's raw_data and invalidate the txID/signature). - */ - private privateKey: string | null = null; - private privateKeyAddress: string | null = null; - /** - * TRON permission id used when building transactions. - * Default `2` = active permission (required for multi-sig facilitator - * accounts with owner threshold > 1). Override via `TRON_PERMISSION_ID` env. - */ - private permissionId: number = 2; - - constructor(wallet: AgentWallet) { - super(); - this.wallet = wallet; - if (typeof process !== 'undefined') { - const pk = - process.env?.TRON_FACILITATOR_PRIVATE_KEY ?? - process.env?.TRON_PRIVATE_KEY ?? - null; - if (pk) { - this.privateKey = pk.startsWith('0x') ? pk.slice(2) : pk; - const derived = TronWebClass.address.fromPrivateKey(this.privateKey); - if (!derived) { - throw new Error('Invalid TRON facilitator private key'); - } - this.privateKeyAddress = derived; - } - const permId = process.env?.TRON_PERMISSION_ID; - if (permId) { - const parsed = parseInt(permId, 10); - if (!isNaN(parsed)) this.permissionId = parsed; - } - } - } - - /** Async factory: resolve active agent wallet and create signer. */ - static async create(): Promise { - const provider = resolveWalletProvider({ network: 'tron' }); - const wallet = await provider.getActiveWallet(); - const signer = new TronFacilitatorSigner(wallet as unknown as AgentWallet); - const walletAddress = await wallet.getAddress(); - if (signer.privateKeyAddress) { - signer.setAddress(signer.privateKeyAddress); - if (walletAddress !== signer.privateKeyAddress) { - // eslint-disable-next-line no-console - console.warn( - `[TronFacilitatorSigner] TRON_FACILITATOR_PRIVATE_KEY/TRON_PRIVATE_KEY address ` + - `${signer.privateKeyAddress} differs from agent-wallet active address ${walletAddress}; ` + - `using the private-key address for facilitator settlement.`, - ); - } - } else { - signer.setAddress(walletAddress); - } - return signer; - } - - setAddress(address: string): void { - this.address = address; - } - - getAddress(): string { - if (!this.address) { - throw new Error('TronFacilitatorSigner address has not been initialized'); - } - return this.address; - } - - /** - * Extract signature hex from agent-wallet's signTransaction result. - * agent-wallet TronWallet returns a JSON string with the full signed tx. - */ - private extractTronSignature(result: string): string { - if (typeof result === 'string' && result.trim().startsWith('{')) { - const signed = JSON.parse(result); - const sigs = signed.signature; - if (!Array.isArray(sigs) || sigs.length === 0) { - throw new Error('Wallet returned signed tx without signature'); - } - return sigs[0]; - } - return result; - } - - /** Get or create a TronWeb instance for the given network. */ - private getTronWeb(network: string): TronWeb { - const host = getTronRpcUrl(network); - if (!host) { - throw new Error(`No TRON RPC URL configured for network: ${network}`); - } - let tw = this.tronWebInstances.get(host); - if (!tw) { - const apiKey = - typeof process !== 'undefined' ? process.env?.TRON_GRID_API_KEY : undefined; - const headers = apiKey ? { 'TRON-PRO-API-KEY': apiKey } : undefined; - // Dummy private key — facilitator signing routes via wallet.signTransaction, - // not via TronWeb's defaultPrivateKey. - const dummyKey = - '0000000000000000000000000000000000000000000000000000000000000001'; - tw = new TronWebClass({ - fullHost: host, - privateKey: dummyKey, - headers, - }) as unknown as TronWeb; - this.tronWebInstances.set(host, tw); - } - return tw; - } - - /** - * Verify EIP-712 / TIP-712 signature. - * - * Strategy: convert all TRON Base58 addresses in domain.verifyingContract - * and the message to 0x EVM hex, then use viem's `recoverTypedDataAddress` - * to recover the signer. Compare against the expected address (also - * converted to hex). - * - * Domain types are NOT included in the `types` arg here — viem injects - * `EIP712Domain` automatically. - */ - async verifyTypedData( - address: string, - domain: TypedDataDomain, - types: TypedDataTypes, - message: Record, - signature: string, - primaryType: string, - ): Promise { - try { - // viem expects hex domain and hex addresses; convert anything Base58. - const viemDomain: ViemTypedDataDomain = { - name: domain.name, - version: domain.version, - chainId: domain.chainId, - verifyingContract: domain.verifyingContract - ? (toEvmHex(domain.verifyingContract) as `0x${string}`) - : undefined, - ...(domain.salt ? { salt: domain.salt as `0x${string}` } : {}), - }; - - // Strip an `EIP712Domain` entry if a caller mistakenly added it; viem - // injects this from the domain object. - const typesNoDomain: TypedDataTypes = { ...types }; - delete (typesNoDomain as Record)['EIP712Domain']; - - const sigBytes = signature.startsWith('0x') - ? (signature as `0x${string}`) - : (`0x${signature}` as `0x${string}`); - - const recovered = await recoverTypedDataAddress({ - domain: viemDomain, - types: typesNoDomain as Record>, - primaryType, - message, - signature: sigBytes, - }); - - const expectedHex = toEvmHex(address).toLowerCase(); - return recovered.toLowerCase() === expectedHex; - } catch (err) { - // eslint-disable-next-line no-console - console.error('[TronFacilitatorSigner] verifyTypedData failed:', err); - return false; - } - } - - /** - * Write contract on TRON: build via tronweb's `triggerSmartContract`, sign - * via the wallet, broadcast. - * - * The function selector must match the on-chain ABI exactly, including - * tuple bracket types. Example for PaymentPermit: - * - * permitTransferFrom(((uint8,bytes16,uint256,uint256,uint256), - * address,address,(address,uint256,address),(address,uint256)), - * address,bytes) - * - * @param contractAddress Base58 (T...) or hex (41...) contract address. - * @param _abi Unused for TRON (we use function selector directly); kept for interface parity. - * @param method Method signature string with full type bracket layout (see note above). - * @param args Parameter array shaped per tronweb's `triggerSmartContract` schema: - * `[{ type: 'address', value: '0x...' }, { type: 'tuple(...)', value: [...] }, ...]`. - */ - async writeContract( - contractAddress: string, - _abi: string | unknown[], - method: string, - args: unknown[], - network: string, - ): Promise { - try { - const tw = this.getTronWeb(network); - - const tx = await tw.transactionBuilder.triggerSmartContract( - contractAddress, - method, - { - feeLimit: 1_000_000_000, // 1000 TRX cap - callValue: 0, - // Active permission (id=2) required for multi-sig facilitator - // accounts whose owner threshold is > 1. - permissionId: this.permissionId, - }, - args, - this.getAddress(), - ); - - if (!tx.result?.result) { - // eslint-disable-next-line no-console - console.error( - `[TronFacilitatorSigner] triggerSmartContract failed: ${JSON.stringify(tx)}`, - ); - return null; - } - - // Sign: prefer direct private-key signing via tronweb (matches Python's - // tronpy direct-sign path). agent-wallet's TRON signTransaction can - // round-trip the raw_data and produce an invalid signature. - let signedTx: unknown; - if (this.privateKey) { - if (this.privateKeyAddress && this.privateKeyAddress !== this.getAddress()) { - throw new Error( - `TRON private key address ${this.privateKeyAddress} does not match transaction owner ${this.getAddress()}`, - ); - } - signedTx = await (tw.trx as unknown as { - sign: (txObj: unknown, pk: string) => Promise; - }).sign(tx.transaction, this.privateKey); - } else { - const rawResult = await this.wallet.signTransaction( - tx.transaction as Record, - ); - const sigHex = this.extractTronSignature(rawResult); - signedTx = { - ...(tx.transaction as Record), - signature: [sigHex], - }; - } - - // Broadcast - const broadcast = await tw.trx.sendRawTransaction(signedTx); - if (!broadcast.result) { - // eslint-disable-next-line no-console - console.error( - `[TronFacilitatorSigner] sendRawTransaction failed: ${JSON.stringify(broadcast)}`, - ); - return null; - } - return broadcast.txid; - } catch (err) { - // eslint-disable-next-line no-console - console.error('[TronFacilitatorSigner] writeContract error:', err); - return null; - } - } - - /** - * Check TRC20 balance via `triggerConstantContract` (read-only call). - */ - async checkBalance( - token: string, - network: string, - address?: string, - ): Promise { - try { - const targetAddress = address ?? this.getAddress(); - const ownerHex = toEvmHex(targetAddress); - - const tw = this.getTronWeb(network); - const result = await tw.transactionBuilder.triggerConstantContract( - token, - 'balanceOf(address)', - {}, - [{ type: 'address', value: ownerHex }], - this.getAddress(), - ); - - if (result.result?.result && result.constant_result?.length) { - return BigInt('0x' + result.constant_result[0]); - } - // Suppress unused vars from helper imports - void hexToBytes; - } catch (err) { - // eslint-disable-next-line no-console - console.error(`[TronFacilitatorSigner] checkBalance failed for ${token}:`, err); - } - return BigInt(0); - } - - /** - * Poll tronpy `getTransactionInfo` until the tx has a blockNumber. - * - * Returns `{status: 'confirmed' | 'failed'}` based on `receipt.result`. - */ - async waitForTransactionReceipt( - txHash: string, - network: string, - timeoutMs: number = 120_000, - ): Promise { - const tw = this.getTronWeb(network); - const deadline = Date.now() + timeoutMs; - - while (Date.now() < deadline) { - try { - const info = await tw.trx.getTransactionInfo(txHash); - if (info && info.blockNumber) { - const success = info.receipt?.result === 'SUCCESS'; - return { - hash: txHash, - blockNumber: String(info.blockNumber), - status: success ? 'confirmed' : 'failed', - }; - } - } catch { - // Not yet propagated to the queried node — keep polling. - } - await new Promise((resolve) => setTimeout(resolve, 3_000)); - } - - throw new Error( - `Transaction ${txHash} not confirmed within ${Math.round(timeoutMs / 1000)}s`, - ); - } -} diff --git a/legacy/typescript/packages/x402/src/signers/index.ts b/legacy/typescript/packages/x402/src/signers/index.ts deleted file mode 100644 index f359efd1..00000000 --- a/legacy/typescript/packages/x402/src/signers/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Signers for x402 protocol - */ - -export type { AgentWallet } from './signer.js'; -export { TronClientSigner } from './signer.js'; -export { EvmClientSigner } from './evmSigner.js'; -export type { - TronWeb, - TypedDataDomain, - TypedDataField, - TronNetwork, -} from './types.js'; -export { TRON_CHAIN_IDS } from './types.js'; - -// Facilitator signers (verify + write_contract + receipt polling) -export { FacilitatorSigner } from './facilitator/base.js'; -export type { - TypedDataDomain as FacilitatorTypedDataDomain, - TypedDataTypes as FacilitatorTypedDataTypes, - TransactionReceipt as FacilitatorTransactionReceipt, -} from './facilitator/base.js'; -export { TronFacilitatorSigner } from './facilitator/tronSigner.js'; -export { EvmFacilitatorSigner } from './facilitator/evmSigner.js'; diff --git a/legacy/typescript/packages/x402/src/signers/signer.ts b/legacy/typescript/packages/x402/src/signers/signer.ts deleted file mode 100644 index fe13db5f..00000000 --- a/legacy/typescript/packages/x402/src/signers/signer.ts +++ /dev/null @@ -1,297 +0,0 @@ -/** - * TronClientSigner - TRON client signer for x402 protocol - * - * Uses TronWeb's signTypedData (TIP-712) for EIP-712 compatible signing. - */ - -import type { ClientSigner } from '../index.js'; -import { - getPaymentPermitAddress, - toEvmHex, - type Hex, - SignatureCreationError, - InsufficientAllowanceError, - UnsupportedNetworkError, - getTronRpcUrl, -} from '../index.js'; -import { resolveWalletProvider } from '@bankofai/agent-wallet'; -import { TronWeb as TronWebClass } from 'tronweb'; -import type { TronWeb, TypedDataDomain, TypedDataField } from './types.js'; - -/** - * Minimal wallet interface expected by signers. - * Compatible with agent-wallet's Wallet + Eip712Capable. - */ -export interface AgentWallet { - getAddress(): Promise; - signMessage(msg: Uint8Array): Promise; - signTypedData(data: Record): Promise; - signTransaction(payload: Record): Promise; -} - -/** ERC20 function selectors */ -const ERC20_ALLOWANCE_SELECTOR = 'allowance(address,address)'; -const ERC20_APPROVE_SELECTOR = 'approve(address,uint256)'; - -/** - * TRON client signer implementation. - * - * Accepts any wallet conforming to the AgentWallet interface. - * The signer is agnostic about how the wallet was created - * (private key, hosted, etc.). - */ -export class TronClientSigner implements ClientSigner { - private wallet!: AgentWallet; - private address: string = ''; // Base58 format - private tronWebInstances: Map = new Map(); - - /** - * Create signer from a wallet. - * - * Prefer the async factory ``create()``. - */ - constructor(wallet: AgentWallet) { - this.wallet = wallet; - } - - /** Async factory: resolve active agent wallet and create signer. */ - static async create(): Promise { - const provider = resolveWalletProvider({ network: 'tron' }); - const wallet = await provider.getActiveWallet(); - const signer = new TronClientSigner(wallet as unknown as AgentWallet); - signer.setAddress(await wallet.getAddress()); - return signer; - } - - setAddress(address: string): void { - this.address = address; - } - - /** - * Extract signature hex from agent-wallet's signTransaction result. - * agent-wallet's TronWallet returns a JSON string with the full signed tx. - */ - private extractTronSignature(result: string): string { - if (typeof result === 'string' && result.trim().startsWith('{')) { - const signed = JSON.parse(result); - const sigs = signed.signature; - if (!Array.isArray(sigs) || sigs.length === 0) { - throw new Error('Wallet returned signed tx without signature'); - } - return sigs[0]; - } - return result; - } - - /** - * Get or create a TronWeb instance for the given network. - */ - private getTronWeb(network?: string): TronWeb { - const host = network ? getTronRpcUrl(network) : undefined; - const key = host ?? '__default__'; - let tw = this.tronWebInstances.get(key); - if (!tw) { - if (!host) { - throw new UnsupportedNetworkError(`No RPC URL configured for network: ${network}`); - } - tw = this.createTronWeb(host); - this.tronWebInstances.set(key, tw); - } - return tw; - } - - private getDefaultTronWeb(): TronWeb { - let tw = this.tronWebInstances.get('__default__'); - if (!tw) { - tw = this.createTronWeb('https://nile.trongrid.io'); - this.tronWebInstances.set('__default__', tw); - } - return tw; - } - - private createTronWeb(fullHost: string): TronWeb { - const apiKey = typeof process !== 'undefined' ? process.env?.TRON_GRID_API_KEY : undefined; - const headers = apiKey ? { 'TRON-PRO-API-KEY': apiKey } : undefined; - // TronWeb needs a private key for initialization, use a dummy key for read-only operations - const dummyKey = '0000000000000000000000000000000000000000000000000000000000000001'; - return new TronWebClass({ fullHost, privateKey: dummyKey, headers }) as unknown as TronWeb; - } - - getAddress(): string { - return this.address; - } - - getEvmAddress(): Hex { - return toEvmHex(this.address); - } - - async signMessage(message: Uint8Array): Promise { - return this.wallet.signMessage(message); - } - - /** - * Sign EIP-712 typed data using Wallet abstraction - */ - async signTypedData( - domain: Record, - types: Record, - message: Record, - _primaryType: string - ): Promise { - const fullData = { - types: { EIP712Domain: [], ...types }, - domain, - primaryType: types.PaymentPermitDetails - ? 'PaymentPermitDetails' - : Object.keys(types).pop(), - message, - }; - - return this.wallet.signTypedData(fullData); - } - - async checkBalance(token: string, network: string, address?: string): Promise { - try { - const targetAddress = address || this.address; - const ownerHex = toEvmHex(targetAddress); - - const tw = this.getTronWeb(network); - const result = await tw.transactionBuilder.triggerConstantContract( - token, - 'balanceOf(address)', - {}, - [{ type: 'address', value: ownerHex }], - this.address - ); - - if (result.result?.result && result.constant_result?.length) { - return BigInt('0x' + result.constant_result[0]); - } - } catch (error) { - console.error(`[TronClientSigner] Failed to check balance: ${error}`); - } - - return BigInt(0); - } - - async checkAllowance(token: string, _amount: bigint, network: string): Promise { - const spender = getPaymentPermitAddress(network); - - try { - const ownerHex = toEvmHex(this.address); - const spenderHex = toEvmHex(spender); - - const tw = this.getTronWeb(network); - const result = await tw.transactionBuilder.triggerConstantContract( - token, - ERC20_ALLOWANCE_SELECTOR, - {}, - [ - { type: 'address', value: ownerHex }, - { type: 'address', value: spenderHex }, - ], - this.address - ); - - if (result.result?.result && result.constant_result?.length) { - return BigInt('0x' + result.constant_result[0]); - } - } catch (error) { - console.error(`[TronClientSigner] Failed to check allowance: ${error}`); - } - - return BigInt(0); - } - - async ensureAllowance( - token: string, - amount: bigint, - network: string, - mode: 'auto' | 'interactive' | 'skip' = 'auto' - ): Promise { - if (mode === 'skip') { - return true; - } - - const currentAllowance = await this.checkAllowance(token, amount, network); - if (currentAllowance >= amount) { - console.log(`[ALLOWANCE] Sufficient allowance: ${currentAllowance} >= ${amount}`); - return true; - } - - if (mode === 'interactive') { - throw new InsufficientAllowanceError('Interactive approval not implemented - use wallet UI'); - } - - // Auto mode: send approve transaction - console.log(`[ALLOWANCE] Insufficient allowance: ${currentAllowance} < ${amount}, sending approve...`); - - const spender = getPaymentPermitAddress(network); - const spenderHex = toEvmHex(spender); - - // Use maxUint160 (2^160 - 1) to avoid repeated approvals - const maxUint160 = (BigInt(2) ** BigInt(160)) - BigInt(1); - - try { - // Build approve transaction - const tw = this.getTronWeb(network); - const tx = await tw.transactionBuilder.triggerSmartContract( - token, - ERC20_APPROVE_SELECTOR, - { - feeLimit: 100_000_000, - callValue: 0, - }, - [ - { type: 'address', value: spenderHex }, - { type: 'uint256', value: maxUint160.toString() }, - ], - this.address - ); - - if (!tx.result?.result) { - throw new InsufficientAllowanceError('Failed to build approve transaction'); - } - - // Sign transaction via wallet and extract signature - const rawResult = await this.wallet.signTransaction(tx.transaction as Record); - const sigHex = this.extractTronSignature(rawResult); - const signedTx = { ...(tx.transaction as Record), signature: [sigHex] }; - - // Broadcast transaction - const broadcast = await tw.trx.sendRawTransaction(signedTx); - - if (!broadcast.result) { - throw new InsufficientAllowanceError( - `Failed to broadcast approve transaction: ${JSON.stringify(broadcast)}`, - ); - } - - console.log(`[ALLOWANCE] Approve transaction sent: ${broadcast.txid}`); - - // Wait for confirmation (poll for ~30 seconds) - const txid = broadcast.txid; - for (let i = 0; i < 10; i++) { - await new Promise(resolve => setTimeout(resolve, 3000)); - try { - const info = await tw.trx.getTransactionInfo(txid); - if (info && info.blockNumber) { - const success = info.receipt?.result === 'SUCCESS'; - console.log(`[ALLOWANCE] Approve confirmed: ${success ? 'SUCCESS' : 'FAILED'}`); - return success; - } - } catch { - // Not confirmed yet, continue polling - } - } - - console.log('[ALLOWANCE] Approve transaction not confirmed within timeout, assuming success'); - return true; - } catch (error) { - if (error instanceof InsufficientAllowanceError) throw error; - throw new InsufficientAllowanceError( - `Approve transaction failed: ${error instanceof Error ? error.message : String(error)}`, - ); - } - } -} diff --git a/legacy/typescript/packages/x402/src/signers/tronSigner.test.ts b/legacy/typescript/packages/x402/src/signers/tronSigner.test.ts deleted file mode 100644 index d621e2d7..00000000 --- a/legacy/typescript/packages/x402/src/signers/tronSigner.test.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; -import { TronClientSigner } from './signer.js'; -import type { AgentWallet } from './signer.js'; -import * as config from '../config.js'; -import { TRON_FALLBACK_RPC_URLS } from '../config.js'; - -vi.mock('@bankofai/agent-wallet', () => ({ - resolveWalletProvider: vi.fn(), -})); - -// USDT on TRON mainnet -const MAINNET_USDT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'; -const FALLBACK_URL = TRON_FALLBACK_RPC_URLS['tron:mainnet']; - -function createMockWallet(address: string): AgentWallet { - return { - getAddress: vi.fn().mockResolvedValue(address), - signMessage: vi.fn().mockResolvedValue('0xdeadbeef'), - signTypedData: vi.fn().mockResolvedValue('0x' + 'ab'.repeat(65)), - signTransaction: vi.fn().mockResolvedValue('0x1234'), - }; -} - -describe('TronClientSigner fallback RPC', () => { - const originalEnv = process.env; - - beforeEach(() => { - process.env = { ...originalEnv }; - delete process.env.TRON_GRID_API_KEY; - }); - - afterEach(() => { - process.env = originalEnv; - }); - - it('uses fallback RPC URL and checkBalance succeeds on tron:mainnet without TRON_GRID_API_KEY', async () => { - const rpcSpy = vi.spyOn(config, 'getTronRpcUrl'); - const errorSpy = vi.spyOn(console, 'error'); - - const wallet = createMockWallet(MAINNET_USDT); - const signer = new TronClientSigner(wallet); - signer.setAddress(MAINNET_USDT); - - const balance = await signer.checkBalance(MAINNET_USDT, 'tron:mainnet'); - - // Verify getTronRpcUrl was called with mainnet and returned the fallback URL - expect(rpcSpy).toHaveBeenCalledWith('tron:mainnet'); - expect(rpcSpy).toHaveReturnedWith(FALLBACK_URL); - - // Verify no error was logged (i.e. the RPC call didn't silently fail) - expect(errorSpy).not.toHaveBeenCalled(); - - // Verify the RPC call actually succeeded and returned a valid bigint - expect(typeof balance).toBe('bigint'); - expect(balance).toBeGreaterThanOrEqual(BigInt(0)); - - rpcSpy.mockRestore(); - errorSpy.mockRestore(); - }); -}); diff --git a/legacy/typescript/packages/x402/src/signers/types.ts b/legacy/typescript/packages/x402/src/signers/types.ts deleted file mode 100644 index 711dc266..00000000 --- a/legacy/typescript/packages/x402/src/signers/types.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * TronWeb type definitions for x402 protocol - */ - -export type Hex = `0x${string}`; - -/** EIP-712 Domain type */ -export interface TypedDataDomain { - name?: string; - version?: string; - chainId?: number | string; - verifyingContract?: string; -} - -/** EIP-712 Type definition */ -export interface TypedDataField { - name: string; - type: string; -} - -/** TronWeb instance type (from tronweb package) */ -export interface TronWeb { - address: { - fromPrivateKey(privateKey: string): string; - toHex(address: string): string; - fromHex(address: string): string; - }; - trx: { - sign(transaction: unknown, privateKey?: string): Promise; - signMessageV2(message: string, privateKey?: string): Promise; - /** TIP-712 typed data signing (stable API) */ - signTypedData( - domain: TypedDataDomain, - types: Record, - value: Record, - privateKey?: string - ): Promise; - /** TIP-712 typed data signing (legacy API, kept for backward compatibility) */ - _signTypedData( - domain: TypedDataDomain, - types: Record, - value: Record, - privateKey?: string - ): Promise; - /** Broadcast signed transaction */ - sendRawTransaction(signedTransaction: unknown): Promise<{ result: boolean; txid: string }>; - /** Get transaction info by txid */ - getTransactionInfo(txid: string): Promise<{ blockNumber?: number; receipt?: { result: string } }>; - }; - transactionBuilder: { - triggerSmartContract( - contractAddress: string, - functionSelector: string, - options: Record, - parameters: unknown[], - issuerAddress: string - ): Promise<{ transaction: unknown; result: { result: boolean } }>; - triggerConstantContract( - contractAddress: string, - functionSelector: string, - options: Record, - parameters: unknown[], - issuerAddress?: string - ): Promise<{ - result: { result: boolean }; - constant_result?: string[]; - }>; - }; - contract(): { - at(address: string): Promise; - }; - defaultPrivateKey?: string; -} - -/** TRON network chain IDs */ -export const TRON_CHAIN_IDS = { - mainnet: 728126428, - shasta: 2494104990, - nile: 3448148188, -} as const; - -export type TronNetwork = keyof typeof TRON_CHAIN_IDS; diff --git a/legacy/typescript/packages/x402/src/tokens.test.ts b/legacy/typescript/packages/x402/src/tokens.test.ts deleted file mode 100644 index 7b73cb0b..00000000 --- a/legacy/typescript/packages/x402/src/tokens.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -/** - * Tests for {@link parsePrice} — the price-string → smallest-unit asset amount - * helper used by ResourceConfig-style server configuration. - */ - -import { describe, expect, it } from 'vitest'; - -import { parsePrice, registerToken } from './tokens.js'; - -describe('parsePrice', () => { - it('parses an integer amount on a 6-decimal TRON token', () => { - const result = parsePrice('1 USDT', 'tron:mainnet'); - expect(result).toMatchObject({ - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - decimals: 6, - symbol: 'USDT', - }); - }); - - it('parses a fractional amount with full decimal precision', () => { - const result = parsePrice('1.25 USDT', 'tron:mainnet'); - expect(result.amount).toBe('1250000'); - }); - - it('parses zero', () => { - const result = parsePrice('0 USDT', 'tron:mainnet'); - expect(result.amount).toBe('0'); - }); - - it('parses 0.000001 (smallest USDT unit)', () => { - const result = parsePrice('0.000001 USDT', 'tron:mainnet'); - expect(result.amount).toBe('1'); - }); - - it('handles an 18-decimal EVM token', () => { - const result = parsePrice('0.5 USDC', 'eip155:97'); - expect(result.amount).toBe('500000000000000000'); - expect(result.decimals).toBe(18); - }); - - it('is case-insensitive on the symbol lookup', () => { - const result = parsePrice('1 usdt', 'tron:mainnet'); - expect(result.symbol).toBe('USDT'); - }); - - it('tolerates extra whitespace', () => { - expect(parsePrice(' 1.25 USDT ', 'tron:mainnet').amount).toBe('1250000'); - }); - - it('returns the token version when present (DHLU on BSC testnet)', () => { - const result = parsePrice('1 DHLU', 'eip155:97'); - expect(result.version).toBe('1'); - }); - - it('omits version when the token has none', () => { - const result = parsePrice('1 USDT', 'tron:mainnet'); - expect(result).not.toHaveProperty('version'); - }); - - it('throws on malformed price (single token)', () => { - expect(() => parsePrice('1USDT', 'tron:mainnet')).toThrow(/Invalid price format/); - }); - - it('throws on negative or non-numeric amount', () => { - expect(() => parsePrice('-1 USDT', 'tron:mainnet')).toThrow(/Invalid amount/); - expect(() => parsePrice('abc USDT', 'tron:mainnet')).toThrow(/Invalid amount/); - }); - - it('throws on unknown token symbol', () => { - expect(() => parsePrice('1 NOTOKEN', 'tron:mainnet')).toThrow(/Unknown token/); - }); - - it('throws when amount precision exceeds token decimals', () => { - // USDT has 6 decimals; 0.0000001 is 7 places - expect(() => parsePrice('0.0000001 USDT', 'tron:mainnet')).toThrow(/more decimal places/); - }); - - it('picks up custom tokens registered at runtime', () => { - registerToken('eip155:1', { - address: '0xdAC17F958D2ee523a2206206994597C13D831ec7', - decimals: 6, - name: 'Custom USDT', - symbol: 'CUSDT', - }); - const result = parsePrice('2 CUSDT', 'eip155:1'); - expect(result.asset).toBe('0xdAC17F958D2ee523a2206206994597C13D831ec7'); - expect(result.amount).toBe('2000000'); - }); -}); diff --git a/legacy/typescript/packages/x402/src/tokens.ts b/legacy/typescript/packages/x402/src/tokens.ts deleted file mode 100644 index eea1ef19..00000000 --- a/legacy/typescript/packages/x402/src/tokens.ts +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Token registry - Centralized management of token configurations for all networks - */ - -export interface TokenInfo { - address: string; - decimals: number; - name: string; - symbol: string; - version?: string; -} - -const TOKENS: Record> = { - 'eip155:97': { - USDT: { - address: '0x337610d27c682E347C9cD60BD4b3b107C9d34dDd', - decimals: 18, - name: 'Tether USD', - symbol: 'USDT', - }, - USDC: { - address: '0x64544969ed7EBf5f083679233325356EbE738930', - decimals: 18, - name: 'USD Coin', - symbol: 'USDC', - }, - DHLU: { - address: '0x375cADdd2cB68cE82e3D9B075D551067a7b4B816', - decimals: 6, - name: 'DA HULU', - symbol: 'DHLU', - version: '1', - }, - }, - 'eip155:56': { - USDC: { - address: '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', - decimals: 18, - name: 'USD Coin', - symbol: 'USDC', - }, - USDT: { - address: '0x55d398326f99059fF775485246999027B3197955', - decimals: 18, - name: 'Tether USD', - symbol: 'USDT', - }, - EPS: { - address: '0xA7f552078dcC247C2684336020c03648500C6d9F', - decimals: 18, - name: 'Ellipsis', - symbol: 'EPS', - }, - }, - 'tron:mainnet': { - USDT: { - address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - decimals: 6, - name: 'Tether USD', - symbol: 'USDT', - }, - USDD: { - address: 'TXDk8mbtRbXeYuMNS83CfKPaYYT8XWv9Hz', - decimals: 18, - name: 'Decentralized USD', - symbol: 'USDD', - }, - }, - 'tron:shasta': { - USDT: { - address: 'TG3XXyExBkPp9nzdajDZsozEu4BkaSJozs', - decimals: 6, - name: 'Tether USD', - symbol: 'USDT', - }, - }, - 'tron:nile': { - USDT: { - address: 'TXYZopYRdj2D9XRtbG411XZZ3kM5VkAeBf', - decimals: 6, - name: 'Tether USD', - symbol: 'USDT', - }, - USDD: { - address: 'TGjgvdTWWrybVLaVeFqSyVqJQWjxqRYbaK', - decimals: 18, - name: 'Decentralized USD', - symbol: 'USDD', - }, - }, -}; - -/** Get token info by network and symbol */ -export function getToken(network: string, symbol: string): TokenInfo | undefined { - return TOKENS[network]?.[symbol.toUpperCase()]; -} - -/** Find token info by network and contract address */ -export function findByAddress(network: string, address: string): TokenInfo | undefined { - const tokens = TOKENS[network]; - if (!tokens) return undefined; - const lower = address.toLowerCase(); - return Object.values(tokens).find(t => t.address.toLowerCase() === lower); -} - -/** Get all tokens for a network */ -export function getNetworkTokens(network: string): Record { - return TOKENS[network] ?? {}; -} - -/** Register a custom token */ -export function registerToken(network: string, token: TokenInfo): void { - if (!TOKENS[network]) { - TOKENS[network] = {}; - } - TOKENS[network][token.symbol.toUpperCase()] = token; -} - -/** Parsed asset amount returned by {@link parsePrice}. */ -export interface AssetAmount { - /** Amount in smallest unit (e.g. "1000000" for 1 USDT with 6 decimals). */ - amount: string; - /** Token contract address on the network. */ - asset: string; - /** Token decimals. */ - decimals: number; - /** Token symbol (e.g. "USDT"). */ - symbol: string; - /** Token display name. */ - name: string; - /** EIP-712 / TIP-712 contract version (for permit) when applicable. */ - version?: string; -} - -/** - * Parse a human-readable price string into a typed asset amount. - * - * @param price - `" "` (e.g. `"1.25 USDT"` or `"100 USDC"`). - * Whitespace-tolerant. `` lookup is case-insensitive. - * @param network - CAIP-2 network identifier (e.g. `"tron:nile"`, `"eip155:97"`). - * - * @throws if the price format is invalid, the amount cannot be parsed, - * the token is not registered on `network`, or the amount has more - * decimal places than the token supports. - * - * Mirrors `bankofai.x402.tokens.TokenRegistry.parse_price`. - */ -export function parsePrice(price: string, network: string): AssetAmount { - const parts = price.trim().split(/\s+/); - if (parts.length !== 2) { - throw new Error( - `Invalid price format: "${price}". Expected " " (e.g. "1.25 USDT").`, - ); - } - const [amountStr, symbol] = parts as [string, string]; - - if (!/^\d+(\.\d+)?$/.test(amountStr)) { - throw new Error(`Invalid amount in price "${price}": "${amountStr}" is not a non-negative decimal.`); - } - - const token = getToken(network, symbol); - if (!token) { - throw new Error(`Unknown token "${symbol}" on network "${network}".`); - } - - // BigInt-safe smallest-unit conversion. Reject precision overflow. - const [intPart, fracPart = ''] = amountStr.split('.') as [string, string?]; - if (fracPart.length > token.decimals) { - throw new Error( - `Amount "${amountStr}" has more decimal places (${fracPart.length}) than ${symbol} supports (${token.decimals}).`, - ); - } - const paddedFrac = fracPart.padEnd(token.decimals, '0'); - // strip leading zeros to keep canonical numeric string - const combined = `${intPart}${paddedFrac}`.replace(/^0+(?=\d)/, ''); - const amount = combined === '' ? '0' : combined; - - return { - amount, - asset: token.address, - decimals: token.decimals, - symbol: token.symbol, - name: token.name, - ...(token.version !== undefined ? { version: token.version } : {}), - }; -} diff --git a/legacy/typescript/packages/x402/src/types/index.ts b/legacy/typescript/packages/x402/src/types/index.ts deleted file mode 100644 index 6cb0927a..00000000 --- a/legacy/typescript/packages/x402/src/types/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Type definitions for x402 protocol - */ - -export * from './payment.js'; -export * from './responses.js'; diff --git a/legacy/typescript/packages/x402/src/types/payment.ts b/legacy/typescript/packages/x402/src/types/payment.ts deleted file mode 100644 index aaf89337..00000000 --- a/legacy/typescript/packages/x402/src/types/payment.ts +++ /dev/null @@ -1,131 +0,0 @@ -/** - * Payment-related type definitions for x402 protocol - */ - -/** Delivery mode for payment */ -export type DeliveryKind = 'PAYMENT_ONLY'; - -/** Payment permit metadata */ -export interface PermitMeta { - /** Delivery type: PAYMENT_ONLY */ - kind: DeliveryKind; - /** Business order ID for reconciliation */ - paymentId: string; - /** Idempotency key (isolated by owner address) */ - nonce: string; - /** Effective time (Unix seconds) */ - validAfter: number; - /** Expiry time (Unix seconds) */ - validBefore: number; -} - -/** Payment information */ -export interface Payment { - /** Payment token address */ - payToken: string; - /** Maximum deductible amount */ - payAmount: string; - /** Primary recipient address */ - payTo: string; -} - -/** Fee information */ -export interface Fee { - /** Fee recipient address */ - feeTo: string; - /** Fee amount */ - feeAmount: string; -} - -/** Payment permit structure */ -export interface PaymentPermit { - /** Permit metadata */ - meta: PermitMeta; - /** Payer address (signer) */ - buyer: string; - /** Caller address (who can call permitTransferFrom) */ - caller: string; - /** Payment information */ - payment: Payment; - /** Fee information */ - fee: Fee; -} - -/** TransferWithAuthorization payload for the exact scheme */ -export interface TransferAuthorization { - from: string; - to: string; - value: string; - validAfter: string; - validBefore: string; - nonce: string; -} - -/** Payment requirements from server */ -export interface PaymentRequirements { - /** Payment scheme (e.g., "exact", "upto") */ - scheme: string; - /** Network identifier (e.g., "tron:shasta", "eip155:8453") */ - network: string; - /** Payment amount (in smallest unit) */ - amount: string; - /** Payment asset address */ - asset: string; - /** Recipient address */ - payTo: string; - /** Maximum timeout in seconds */ - maxTimeoutSeconds?: number; - /** Extra information */ - extra?: PaymentRequirementsExtra; -} - -/** Extra information in payment requirements */ -export interface PaymentRequirementsExtra { - /** Token name */ - name?: string; - /** Token version */ - version?: string; - /** Fee information */ - fee?: { - facilitatorId?: string; - feeTo: string; - feeAmount: string; - caller?: string; - }; -} - -/** Payment permit context from extensions */ -export interface PaymentPermitContext { - meta: { - kind: DeliveryKind; - paymentId: string; - nonce: string; - validAfter: number; - validBefore: number; - }; -} - -/** Payment payload sent by client */ -export interface PaymentPayload { - /** x402 protocol version */ - x402Version: number; - /** Resource information */ - resource?: { - url?: string; - description?: string; - mimeType?: string; - }; - /** Accepted payment requirements */ - accepted: PaymentRequirements; - /** Payment payload data */ - payload: { - /** Buyer's EIP-712 signature */ - signature: string; - /** Payment permit */ - paymentPermit?: PaymentPermit; - /** Transfer authorization for the exact scheme */ - authorization?: TransferAuthorization; - }; - /** Extensions */ - extensions?: Record; -} diff --git a/legacy/typescript/packages/x402/src/types/responses.ts b/legacy/typescript/packages/x402/src/types/responses.ts deleted file mode 100644 index cc4c47b6..00000000 --- a/legacy/typescript/packages/x402/src/types/responses.ts +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Response type definitions for x402 protocol - */ - -import type { PaymentRequirements, PaymentPermitContext } from './payment.js'; - -/** Resource information */ -export interface ResourceInfo { - /** Resource URL */ - url?: string; - /** Resource description */ - description?: string; - /** MIME type */ - mimeType?: string; -} - -/** Payment required response (402) */ -export interface PaymentRequired { - /** x402 protocol version */ - x402Version: number; - /** Error message */ - error?: string; - /** Resource information */ - resource?: ResourceInfo; - /** Accepted payment options */ - accepts: PaymentRequirements[]; - /** Extensions */ - extensions?: { - paymentPermitContext?: PaymentPermitContext; - [key: string]: unknown; - }; -} - -/** Verify response from facilitator */ -export interface VerifyResponse { - /** Whether the payment is valid */ - isValid: boolean; - /** Invalid reason (if not valid) */ - invalidReason?: string; -} - -/** Settlement response from facilitator */ -export interface SettleResponse { - /** Whether settlement succeeded */ - success: boolean; - /** Transaction hash */ - transaction?: string; - /** Network identifier */ - network?: string; - /** Error reason (if failed) */ - errorReason?: string; -} - -/** Supported response from facilitator */ -export interface SupportedResponse { - /** Supported payment kinds */ - kinds: Array<{ - x402Version: number; - scheme: string; - network: string; - }>; -} - -/** Fee quote response from facilitator */ -export interface FeeQuoteResponse { - /** Fee information */ - fee: { - feeTo: string; - feeAmount: string; - }; - /** Pricing model */ - pricing: string; - /** Payment scheme */ - scheme: string; - /** Network identifier */ - network: string; - /** Token asset address */ - asset: string; - /** Quote expiry time */ - expiresAt?: number; -} diff --git a/legacy/typescript/packages/x402/src/utils/encoding.ts b/legacy/typescript/packages/x402/src/utils/encoding.ts deleted file mode 100644 index e69cc9a7..00000000 --- a/legacy/typescript/packages/x402/src/utils/encoding.ts +++ /dev/null @@ -1,132 +0,0 @@ -/** - * Encoding utilities for x402 protocol - */ - -/** - * Encode data to base64 (works in both Node.js and browser) - */ -export function encodeBase64(data: string | Uint8Array): string { - if (typeof Buffer !== 'undefined') { - if (typeof data === 'string') { - return Buffer.from(data, 'utf-8').toString('base64'); - } - return Buffer.from(data).toString('base64'); - } - if (typeof data === 'string') { - return globalThis.btoa(data); - } - return globalThis.btoa(String.fromCharCode(...data)); -} - -/** - * Decode base64 to string (works in both Node.js and browser) - */ -export function decodeBase64(data: string): string { - if (typeof Buffer !== 'undefined') { - return Buffer.from(data, 'base64').toString('utf-8'); - } - return globalThis.atob(data); -} - -/** - * Decode base64 to Uint8Array - */ -export function decodeBase64ToBytes(data: string): Uint8Array { - if (typeof Buffer !== 'undefined') { - return new Uint8Array(Buffer.from(data, 'base64')); - } - const binary = globalThis.atob(data); - const bytes = new Uint8Array(binary.length); - for (let i = 0; i < binary.length; i++) { - bytes[i] = binary.charCodeAt(i); - } - return bytes; -} - -/** - * Encode an object to JSON string - */ -export function encodeJSON(data: unknown): string { - return JSON.stringify(data); -} - -/** - * Decode a JSON string to object - */ -export function decodeJSON(data: string): T { - return JSON.parse(data) as T; -} - -/** - * Encode payment payload to base64 for HTTP header - */ -export function encodePaymentPayload(payload: unknown): string { - const json = JSON.stringify(payload); - return encodeBase64(json); -} - -/** - * Decode payment payload from base64 HTTP header - */ -export function decodePaymentPayload(encoded: string): T { - const json = decodeBase64(encoded); - return JSON.parse(json) as T; -} - -/** - * Generate a random 16-byte payment ID, formatted as `0x` + 32 hex chars. - * - * Used by `X402Server.createPaymentRequiredResponse` when the caller doesn't - * supply an explicit `paymentId`. Mirrors Python `generate_payment_id`. - */ -export function generatePaymentId(): string { - const bytes = new Uint8Array(16); - crypto.getRandomValues(bytes); - let hex = ''; - for (const byte of bytes) { - hex += byte.toString(16).padStart(2, '0'); - } - return `0x${hex}`; -} - -/** - * Convert hex string to Uint8Array - */ -export function hexToBytes(hex: string): Uint8Array { - const cleanHex = hex.startsWith('0x') ? hex.slice(2) : hex; - const bytes = new Uint8Array(cleanHex.length / 2); - for (let i = 0; i < bytes.length; i++) { - bytes[i] = parseInt(cleanHex.slice(i * 2, i * 2 + 2), 16); - } - return bytes; -} - -/** - * Convert Uint8Array to hex string - */ -export function bytesToHex(bytes: Uint8Array, prefix = true): string { - const hex = Array.from(bytes) - .map(b => b.toString(16).padStart(2, '0')) - .join(''); - return prefix ? `0x${hex}` : hex; -} - -/** - * Convert payment ID from hex string to bytes16 for EIP-712 signing - * - * @param paymentId - Hex string with 0x prefix (e.g., "0x1234...abcd") - * @returns 16-byte Uint8Array - * @throws Error if format is invalid - */ -export function paymentIdToBytes(paymentId: string): Uint8Array { - if (!paymentId.startsWith('0x')) { - throw new Error(`Invalid payment ID format: ${paymentId}. Expected hex string with 0x prefix`); - } - - const paymentIdHex = paymentId.slice(2); - if (paymentIdHex.length !== 32) { - throw new Error(`Invalid payment ID length: ${paymentIdHex.length}. Expected 32 hex characters (16 bytes)`); - } - - return hexToBytes(paymentId); -} diff --git a/legacy/typescript/packages/x402/src/utils/gasfree.test.ts b/legacy/typescript/packages/x402/src/utils/gasfree.test.ts deleted file mode 100644 index ce8b262b..00000000 --- a/legacy/typescript/packages/x402/src/utils/gasfree.test.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { GasFreeAPIClient } from './gasfree.js'; - -describe('GasFreeAPIClient', () => { - const baseUrl = 'https://api.example.com'; - let client: GasFreeAPIClient; - - beforeEach(() => { - client = new GasFreeAPIClient(baseUrl); - vi.stubGlobal('fetch', vi.fn()); - }); - - it('should get address info', async () => { - const mockResponse = { - code: 200, - data: { - accountAddress: '0x123', - gasFreeAddress: '0x456', - active: true, - nonce: 5, - assets: [], - }, - }; - - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify(mockResponse), - }); - - const info = await client.getAddressInfo('0x123'); - expect(info.gasFreeAddress).toBe('0x456'); - expect(info.nonce).toBe(5); - expect(fetch).toHaveBeenCalledWith( - expect.stringContaining('/api/v1/address/0x123'), - expect.objectContaining({ - headers: expect.objectContaining({ - 'Content-Type': 'application/json', - }) - }) - ); - }); - - it('should submit transaction', async () => { - const mockResponse = { - code: 200, - data: { id: 'trace-123' }, - }; - - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify(mockResponse), - }); - - const message = { - token: '0xtoken', - serviceProvider: '0xprovider', - user: '0xuser', - receiver: '0xreceiver', - value: 100, - maxFee: 10, - deadline: 1000, - version: 1, - nonce: 1, - }; - - const traceId = await client.submit({}, message, '0xabc'); - expect(traceId).toBe('trace-123'); - expect(fetch).toHaveBeenCalledWith( - expect.stringContaining('/api/v1/gasfree/submit'), - expect.objectContaining({ - method: 'POST', - headers: expect.objectContaining({ - 'Content-Type': 'application/json', - }), - }) - ); - }); - - it('should get transaction status', async () => { - const mockResponse = { - code: 200, - data: { id: 'trace-123', state: 'SUCCEED' }, - }; - - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify(mockResponse), - }); - - const status = await client.getStatus('trace-123'); - expect(status).not.toBeNull(); - expect(status!.state).toBe('SUCCEED'); - expect(fetch).toHaveBeenCalledWith( - expect.stringContaining('/api/v1/gasfree/trace-123'), - expect.objectContaining({ - headers: expect.objectContaining({ - 'Content-Type': 'application/json', - }), - }) - ); - }); - - it('should wait for success', async () => { - const mockResponse = { - code: 200, - data: { id: 'trace-123', state: 'SUCCEED' }, - }; - - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify(mockResponse), - }); - - const result = await client.waitForSuccess('trace-123', 1000, 100); - expect(result.state).toBe('SUCCEED'); - }); - - it('should handle null status data in waitForSuccess', async () => { - let callCount = 0; - (fetch as any).mockImplementation(async () => { - callCount++; - if (callCount === 1) { - // First poll returns null data - return { - ok: true, - text: async () => JSON.stringify({ code: 200, data: null }), - }; - } - // Second poll returns success - return { - ok: true, - text: async () => JSON.stringify({ - code: 200, - data: { id: 'trace-123', state: 'SUCCEED', txnHash: '0xabc' }, - }), - }; - }); - - const result = await client.waitForSuccess('trace-123', 5000, 100); - expect(result.state).toBe('SUCCEED'); - expect(callCount).toBe(2); - }); - - it('should retry on transient error in waitForSuccess', async () => { - let callCount = 0; - (fetch as any).mockImplementation(async () => { - callCount++; - if (callCount === 1) { - // First poll throws a transient network error - return { - ok: false, - status: 503, - text: async () => 'Service Unavailable', - }; - } - // Second poll returns success - return { - ok: true, - text: async () => JSON.stringify({ - code: 200, - data: { id: 'trace-123', state: 'SUCCEED', txnHash: '0xabc' }, - }), - }; - }); - - const result = await client.waitForSuccess('trace-123', 5000, 100); - expect(result.state).toBe('SUCCEED'); - expect(callCount).toBe(2); - }); - - it('should abort polling after max consecutive errors', async () => { - (fetch as any).mockImplementation(async () => ({ - ok: false, - status: 500, - text: async () => 'Internal Server Error', - })); - - await expect(client.waitForSuccess('trace-123', 10000, 100, 2)) - .rejects.toThrow('aborted after 2 consecutive errors'); - }); - - it('should reset error count after successful poll', async () => { - let callCount = 0; - (fetch as any).mockImplementation(async () => { - callCount++; - // fail, succeed (WAITING), fail, fail → should NOT abort at maxErrors=2 - // because the success in between resets the counter - if (callCount === 1 || callCount === 3 || callCount === 4) { - return { ok: false, status: 503, text: async () => 'Service Unavailable' }; - } - if (callCount === 2) { - return { - ok: true, - text: async () => JSON.stringify({ - code: 200, - data: { id: 'trace-123', state: 'WAITING' }, - }), - }; - } - // 5th call succeeds - return { - ok: true, - text: async () => JSON.stringify({ - code: 200, - data: { id: 'trace-123', state: 'SUCCEED', txnHash: '0xabc' }, - }), - }; - }); - - const result = await client.waitForSuccess('trace-123', 10000, 100, 3); - expect(result.state).toBe('SUCCEED'); - expect(callCount).toBe(5); - }); - - it('should throw on null data from getAddressInfo', async () => { - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify({ code: 200, data: null }), - }); - - await expect(client.getAddressInfo('0x123')) - .rejects.toThrow('null data'); - }); - - it('should throw on null data from getProviders', async () => { - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify({ code: 200, data: null }), - }); - - await expect(client.getProviders()) - .rejects.toThrow('null data'); - }); - - it('should return [] from getProviders on 404 (network unsupported)', async () => { - (fetch as any).mockResolvedValue({ - ok: false, - status: 404, - text: async () => 'Not Found', - }); - - await expect(client.getProviders()).resolves.toEqual([]); - }); - - it('should throw on null data from submit', async () => { - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify({ code: 200, data: null }), - }); - - const message = { - token: '0xtoken', serviceProvider: '0xprovider', user: '0xuser', - receiver: '0xreceiver', value: 100, maxFee: 10, deadline: 1000, - version: 1, nonce: 1, - }; - - await expect(client.submit({}, message, '0xabc')) - .rejects.toThrow('null data'); - }); - - it('should throw on submit data without id field', async () => { - (fetch as any).mockResolvedValue({ - ok: true, - text: async () => JSON.stringify({ code: 200, data: { state: 'WAITING' } }), - }); - - const message = { - token: '0xtoken', serviceProvider: '0xprovider', user: '0xuser', - receiver: '0xreceiver', value: 100, maxFee: 10, deadline: 1000, - version: 1, nonce: 1, - }; - - await expect(client.submit({}, message, '0xabc')) - .rejects.toThrow('without id field'); - }); - - it('should get nonce', async () => { - vi.spyOn(client, 'getAddressInfo').mockResolvedValue({ - nonce: 42, - } as any); - - const nonce = await client.getNonce('0x123'); - expect(nonce).toBe(42); - }); -}); diff --git a/legacy/typescript/packages/x402/src/utils/gasfree.ts b/legacy/typescript/packages/x402/src/utils/gasfree.ts deleted file mode 100644 index 8bea7fb3..00000000 --- a/legacy/typescript/packages/x402/src/utils/gasfree.ts +++ /dev/null @@ -1,306 +0,0 @@ -import { - GASFREE_PRIMARY_TYPE, -} from '../abi.js'; -import { getChainId, getGasFreeControllerAddress } from '../config.js'; -import { toEvmHex } from '../address.js'; - -/** - * GasFree utility functions for API interaction and domain helpers. - */ - -export interface GasFreeResponse { - code: number; - reason: string | null; - message: string | null; - data: T | null; -} - -export interface GasFreeAsset { - tokenAddress: string; - tokenSymbol: string; - activateFee: number; - transferFee: number; - decimal: number; - frozen: number; - balance?: string | number; -} - -export interface GasFreeAddressInfo { - accountAddress: string; - gasFreeAddress: string; - active: boolean; - nonce: number; - allowSubmit: boolean; - assets: GasFreeAsset[]; -} - -export interface GasFreeSubmitResponseData { - id: string; - state: 'WAITING' | 'INPROGRESS' | 'CONFIRMING' | 'SUCCEED' | 'FAILED'; - createdAt: string; - accountAddress: string; - gasFreeAddress: string; - providerAddress: string; - targetAddress: string; - nonce: number; - tokenAddress: string; - amount: string; - expiredAt: string; - reason?: string; - txnHash?: string; - txnState?: 'INIT' | 'NOT_ON_CHAIN' | 'ON_CHAIN' | 'SOLIDITY' | 'ON_CHAIN_FAILED'; -} - -export interface GasFreeProvider { - address: string; - name: string; - icon: string; - website: string; - config: { - maxPendingTransfer: number; - minDeadlineDuration: number; - maxDeadlineDuration: number; - defaultDeadlineDuration: number; - }; -} - -// GasFree TIP-712 Types -export const GASFREE_TYPES = { - [GASFREE_PRIMARY_TYPE]: [ - { name: 'token', type: 'address' }, - { name: 'serviceProvider', type: 'address' }, - { name: 'user', type: 'address' }, - { name: 'receiver', type: 'address' }, - { name: 'value', type: 'uint256' }, - { name: 'maxFee', type: 'uint256' }, - { name: 'deadline', type: 'uint256' }, - { name: 'version', type: 'uint256' }, - { name: 'nonce', type: 'uint256' }, - ], -} as const; - -export function getGasFreeDomain(network: string) { - return { - name: 'GasFreeController', - version: 'V1.0.0', - chainId: getChainId(network), - verifyingContract: toEvmHex(getGasFreeControllerAddress(network)), - }; -} - -const DEFAULT_TIMEOUT_MS = 30000; - -export class GasFreeAPIClient { - private baseUrl: string; - - constructor(baseUrl: string) { - this.baseUrl = baseUrl.replace(/\/$/, ''); - } - - /** - * Get headers for API requests - */ - private getHeaders(): Record { - return { - 'Content-Type': 'application/json', - }; - } - - /** - * Get all supported service providers - */ - async getProviders(): Promise { - const path = '/api/v1/config/provider/all'; - const url = `${this.baseUrl}${path}`; - const headers = this.getHeaders(); - - const response = await fetch(url, { headers, signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS) }); - const bodyText = await response.text(); - - if (response.status === 404) { - // Network not supported by GasFree service — return empty list gracefully - // instead of crashing fee/quote with a 500. Mirrors Python's get_providers. - console.warn(`GasFree service not available for this network (404): ${url}`); - return []; - } - if (!response.ok) { - console.error(`GasFree config API HTTP error ${response.status} at ${url}: ${bodyText}`); - throw new Error(`GasFree config API error: ${response.status}`); - } - const result = JSON.parse(bodyText) as GasFreeResponse<{ providers: GasFreeProvider[] }>; - if (result.code !== 200) { - console.error(`GasFree config API business error at ${url}: ${result.message || result.reason}`); - throw new Error(`GasFree config API error: ${result.message || result.reason}`); - } - if (result.data == null) { - throw new Error('GasFree config API returned null data'); - } - return result.data.providers; - } - - /** - * Get the current recommended nonce for a user - */ - async getNonce(user: string): Promise { - try { - const data = await this.getAddressInfo(user); - return data.nonce ?? 0; - } catch (error) { - console.warn(`Failed to get nonce from GasFree API: ${error}. Defaulting to 0.`); - return 0; - } - } - - /** - * Get full account info (activation, balance, nonce) for a user - */ - async getAddressInfo(user: string): Promise { - const path = `/api/v1/address/${user}`; - const url = `${this.baseUrl}${path}`; - const headers = this.getHeaders(); - - const response = await fetch(url, { headers, signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS) }); - const bodyText = await response.text(); - - if (!response.ok) { - console.error(`GasFree API HTTP error ${response.status} at ${url}: ${bodyText}`); - throw new Error(`GasFree API HTTP error: ${response.status} - Body: ${bodyText}`); - } - const result = JSON.parse(bodyText) as GasFreeResponse; - if (result.code !== 200) { - console.error(`GasFree API business error at ${url}: ${result.message || result.reason} - Body: ${bodyText}`); - throw new Error(`GasFree API error: ${result.message || result.reason} - Body: ${bodyText}`); - } - if (result.data == null) { - throw new Error(`GasFree API returned null data for address ${user}`); - } - return result.data; - } - - /** - * Get status of a submitted GasFree transaction - */ - async getStatus(traceId: string): Promise { - const path = `/api/v1/gasfree/${traceId}`; - const url = `${this.baseUrl}${path}`; - const headers = this.getHeaders(); - const response = await fetch(url, { headers, signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS) }); - const bodyText = await response.text(); - - if (!response.ok) { - console.error(`GasFree status API HTTP error ${response.status} at ${url}: ${bodyText}`); - throw new Error(`GasFree status API error: ${response.status}`); - } - const result = JSON.parse(bodyText) as GasFreeResponse; - if (result.code !== 200) { - console.error(`GasFree status API business error at ${url}: ${result.message || result.reason}`); - throw new Error(`GasFree status API error: ${result.message || result.reason}`); - } - return result.data; - } - - /** - * Wait for a GasFree transaction to reach a terminal state or ON_CHAIN state - */ - async waitForSuccess( - traceId: string, - timeout: number = 120000, - pollInterval: number = 5000, - maxErrors: number = 3 - ): Promise { - const startTime = Date.now(); - let errorCount = 0; - - while (Date.now() - startTime < timeout) { - let statusData: GasFreeSubmitResponseData | null; - try { - statusData = await this.getStatus(traceId); - errorCount = 0; // reset on successful poll - } catch (err) { - errorCount++; - console.warn(`GasFree status poll failed for ${traceId} (error #${errorCount}): ${err}, retrying...`); - if (errorCount >= maxErrors) { - throw new Error(`GasFree status polling aborted after ${errorCount} consecutive errors: ${err}`); - } - await new Promise((resolve) => setTimeout(resolve, pollInterval)); - continue; - } - if (statusData == null) { - console.debug(`GasFree transaction ${traceId} status not yet available, waiting...`); - await new Promise((resolve) => setTimeout(resolve, pollInterval)); - continue; - } - const state = (statusData.state ?? '').toUpperCase(); - const txnState = (statusData.txnState || '').toUpperCase(); - - // 1. Immediate return for successful or "good enough" states - if (state === 'SUCCEED' || (statusData.txnHash && ['ON_CHAIN', 'SOLIDITY'].includes(txnState))) { - return statusData; - } - - if (state === 'FAILED' || txnState === 'ON_CHAIN_FAILED') { - throw new Error(`GasFree transaction failed. Reason: ${statusData.reason || 'Unknown'}`); - } - - console.debug(`GasFree transaction ${traceId} is ${state} (${txnState}), waiting...`); - await new Promise((resolve) => setTimeout(resolve, pollInterval)); - } - - throw new Error(`GasFree transaction ${traceId} timed out after ${timeout / 1000}s (${errorCount} errors encountered)`); - } - - /** - * Submit a signed GasFree transaction to the official relayer - */ - async submit(domain: any, message: any, signature: string): Promise { - const path = '/api/v1/gasfree/submit'; - const url = `${this.baseUrl}${path}`; - - const payload = { - token: message.token, - serviceProvider: message.serviceProvider, - user: message.user, - receiver: message.receiver, - value: message.value.toString(), - maxFee: message.maxFee.toString(), - deadline: Number(message.deadline), - version: 1, - nonce: Number(message.nonce), - sig: signature.startsWith('0x') ? signature.slice(2) : signature, - requestId: `x402-${Date.now()}-${signature.slice(2, 10)}`, - }; - - try { - const headers = this.getHeaders(); - const response = await fetch(url, { - method: 'POST', - headers, - body: JSON.stringify(payload), - signal: AbortSignal.timeout(DEFAULT_TIMEOUT_MS), - }); - - const bodyText = await response.text(); - - if (!response.ok) { - console.error(`GasFree submit HTTP error ${response.status} at ${url}: ${bodyText}`); - throw new Error(`GasFree submit HTTP error: ${response.status} - Body: ${bodyText}`); - } - - const result = JSON.parse(bodyText) as GasFreeResponse; - if (result.code !== 200) { - console.error(`GasFree submit API business error at ${url}: ${result.message || result.reason} - Body: ${bodyText}`); - throw new Error(`GasFree submit API error: ${result.message || result.reason} - Body: ${bodyText}`); - } - if (result.data == null) { - throw new Error('GasFree submit API returned null data'); - } - if (result.data.id == null) { - throw new Error('GasFree submit API returned data without id field'); - } - return result.data.id; - } catch (error) { - console.error(`Failed to submit GasFree transaction: ${error}`); - throw error; - } - } -} diff --git a/legacy/typescript/packages/x402/src/utils/index.ts b/legacy/typescript/packages/x402/src/utils/index.ts deleted file mode 100644 index 0aaa2016..00000000 --- a/legacy/typescript/packages/x402/src/utils/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Utility exports - */ - -export * from './encoding.js'; -export { - encodeBase64, - decodeBase64, - decodeBase64ToBytes, - generatePaymentId, - hexToBytes, - bytesToHex, - paymentIdToBytes, -} from './encoding.js'; -export * from './gasfree.js'; diff --git a/legacy/typescript/packages/x402/src/utils/tx_verification.test.ts b/legacy/typescript/packages/x402/src/utils/tx_verification.test.ts deleted file mode 100644 index 09b00e16..00000000 --- a/legacy/typescript/packages/x402/src/utils/tx_verification.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -/** - * Tests for transaction verification base + factory. - */ - -import { afterEach, describe, expect, it } from 'vitest'; - -import type { PaymentPayload, PaymentRequirements } from '../types/index.js'; -import { - BaseTransactionVerifier, - type TransactionInfo, - type TransferEvent, - getVerifierForNetwork, - registerVerifierFactory, -} from './tx_verification.js'; - -const REQ: PaymentRequirements = { - scheme: 'exact_permit', - network: 'tron:nile', - amount: '1000000', - asset: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t', - payTo: 'TJWdoJk8KyrfxZ2iDUqz7fwpXaMkNqPehx', -}; -const PAYLOAD: PaymentPayload = { - x402Version: 2, - accepted: REQ, - payload: { signature: '0x' + 'aa'.repeat(65) }, -} as PaymentPayload; - -/** Minimal verifier subclass driven by a canned `getTransactionInfo`. */ -class StubVerifier extends BaseTransactionVerifier { - constructor(private readonly info: TransactionInfo | (() => Promise)) { - super(); - } - async getTransactionInfo() { - return typeof this.info === 'function' ? this.info() : this.info; - } - async getTransactionTransfers(): Promise { - return []; - } - normalizeAddress(addr: string): string { - return addr; - } -} - -describe('BaseTransactionVerifier.verifyTransaction', () => { - it('returns success when transaction status is "success"', async () => { - const verifier = new StubVerifier({ status: 'success', blockNumber: '12345' }); - const result = await verifier.verifyTransaction('0xtx', PAYLOAD, REQ); - expect(result.success).toBe(true); - expect(result.statusVerified).toBe(true); - expect(result.blockNumber).toBe('12345'); - expect(result.txHash).toBe('0xtx'); - }); - - it('returns failure when status is "failed"', async () => { - const verifier = new StubVerifier({ status: 'failed', blockNumber: '12345' }); - const result = await verifier.verifyTransaction('0xtx', PAYLOAD, REQ); - expect(result.success).toBe(false); - expect(result.errorReason).toBe('transaction_failed_on_chain'); - expect(result.statusVerified).toBe(false); - }); - - it('returns failure when status is "0" (numeric-as-string)', async () => { - const verifier = new StubVerifier({ status: '0' }); - const result = await verifier.verifyTransaction('0xtx', PAYLOAD, REQ); - expect(result.success).toBe(false); - }); - - it('returns failure when status is missing / empty', async () => { - const verifier = new StubVerifier({ blockNumber: '1' }); - const result = await verifier.verifyTransaction('0xtx', PAYLOAD, REQ); - expect(result.success).toBe(false); - }); - - it('catches getTransactionInfo errors into verification_error', async () => { - const verifier = new StubVerifier(async () => { - throw new Error('rpc down'); - }); - const result = await verifier.verifyTransaction('0xtx', PAYLOAD, REQ); - expect(result.success).toBe(false); - expect(result.errorReason).toMatch(/verification_error: rpc down/); - }); - - it('paymentVerified / feeVerified default false at base level', async () => { - const verifier = new StubVerifier({ status: 'success' }); - const result = await verifier.verifyTransaction('0xtx', PAYLOAD, REQ); - expect(result.paymentVerified).toBe(false); - expect(result.feeVerified).toBe(false); - }); -}); - -describe('getVerifierForNetwork / registerVerifierFactory', () => { - // Snapshot/restore is overkill — these tests use a unique prefix. - const TEST_PREFIX = 'testnet:'; - afterEach(() => { - // No public unregister; just leave the test factory in place — prefix is unique. - }); - - it('throws when no factory matches the network prefix', () => { - expect(() => getVerifierForNetwork('unknown:42')).toThrow( - /No transaction verifier registered/, - ); - }); - - it('returns a verifier from a registered factory', () => { - const fakeVerifier = { - verifyTransaction: async () => { - throw new Error('not implemented'); - }, - getTransactionTransfers: async () => [], - }; - registerVerifierFactory(TEST_PREFIX, () => fakeVerifier); - const v = getVerifierForNetwork(`${TEST_PREFIX}foo`); - expect(v).toBe(fakeVerifier); - }); - - it('forwards options to the factory', () => { - let receivedOpts: { rpcUrl?: string } | undefined; - registerVerifierFactory('opts-test:', (_network, opts) => { - receivedOpts = opts; - return { - verifyTransaction: async () => ({} as never), - getTransactionTransfers: async () => [], - }; - }); - getVerifierForNetwork('opts-test:1', { rpcUrl: 'https://rpc.example' }); - expect(receivedOpts).toEqual({ rpcUrl: 'https://rpc.example' }); - }); -}); diff --git a/legacy/typescript/packages/x402/src/utils/tx_verification.ts b/legacy/typescript/packages/x402/src/utils/tx_verification.ts deleted file mode 100644 index d6dd9238..00000000 --- a/legacy/typescript/packages/x402/src/utils/tx_verification.ts +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Transaction Verification Utilities - * - * Generic functionality to verify blockchain transaction results after the - * facilitator reports settlement, ensuring on-chain transfers match expected - * parameters. Mirrors `bankofai.x402.utils.tx_verification`. - * - * This module provides the **base contracts**. Chain-specific implementations - * (TRON via tronweb, EVM via viem) subclass {@link BaseTransactionVerifier} - * and plug in via {@link getVerifierForNetwork}. - */ - -import type { PaymentPayload, PaymentRequirements } from '../types/index.js'; - -/** A single token transfer event extracted from a transaction. */ -export interface TransferEvent { - /** Token contract address. */ - token: string; - /** Sender address. */ - fromAddr: string; - /** Recipient address. */ - toAddr: string; - /** Transfer amount in smallest unit (as a BigInt-safe string). */ - amount: string; -} - -/** Outcome of {@link TransactionVerifier.verifyTransaction}. */ -export interface TransactionVerificationResult { - success: boolean; - txHash: string; - blockNumber?: string; - errorReason?: string; - transfers?: TransferEvent[]; - /** Whether the on-chain transaction status was "success". */ - statusVerified: boolean; - /** Whether the payment transfer (amount + recipient) was verified. */ - paymentVerified: boolean; - /** Whether the facilitator fee transfer was verified (when applicable). */ - feeVerified: boolean; -} - -/** - * Interface for transaction verification implementations. One per chain family. - * - * Wraps the chain's transaction-info / transfer-events RPC and applies the - * canonical "did the right transfer happen" check. - */ -export interface TransactionVerifier { - verifyTransaction( - txHash: string, - payload: PaymentPayload, - requirements: PaymentRequirements, - ): Promise; - getTransactionTransfers( - txHash: string, - tokenAddress: string, - ): Promise; -} - -/** Generic transaction-info shape returned by chain-specific RPC adapters. */ -export interface TransactionInfo { - status?: string | number; - blockNumber?: string; -} - -/** - * Abstract base class for transaction verifiers. Subclasses implement the - * chain-specific RPC calls; the canonical verification flow lives here. - * - * Mirrors Python `BaseTransactionVerifier`. Like the Python base, the default - * {@link verifyTransaction} only checks that the on-chain transaction - * succeeded — chain-specific subclasses MAY override for richer transfer + - * fee verification. - */ -export abstract class BaseTransactionVerifier implements TransactionVerifier { - /** Chain-specific: pull transaction info (status, blockNumber) from RPC. */ - abstract getTransactionInfo(txHash: string): Promise; - - /** Chain-specific: pull token transfer events from the transaction. */ - abstract getTransactionTransfers( - txHash: string, - tokenAddress: string, - ): Promise; - - /** Chain-specific: normalize an address for equality comparison. */ - abstract normalizeAddress(address: string): string; - - /** - * Canonical verification flow: pull transaction info, check status. - * - * Subclasses can override to additionally verify transfer amounts / - * fee transfers — set `paymentVerified` / `feeVerified` accordingly. - */ - async verifyTransaction( - txHash: string, - _payload: PaymentPayload, - _requirements: PaymentRequirements, - ): Promise { - try { - const info = await this.getTransactionInfo(txHash); - const status = String(info.status ?? '').toLowerCase(); - if (status === 'failed' || status === '0' || status === '') { - return { - success: false, - txHash, - ...(info.blockNumber ? { blockNumber: info.blockNumber } : {}), - errorReason: 'transaction_failed_on_chain', - statusVerified: false, - paymentVerified: false, - feeVerified: false, - }; - } - return { - success: true, - txHash, - ...(info.blockNumber ? { blockNumber: info.blockNumber } : {}), - statusVerified: true, - // Base impl doesn't check transfers — subclasses set these when they do. - paymentVerified: false, - feeVerified: false, - }; - } catch (err) { - return { - success: false, - txHash, - errorReason: `verification_error: ${(err as Error).message}`, - statusVerified: false, - paymentVerified: false, - feeVerified: false, - }; - } - } -} - -/** - * Registry of (network-prefix → verifier factory) entries. - * - * Chain-specific verifiers register themselves at module load (e.g. a TRON - * verifier package would call `registerVerifierFactory('tron:', ...)`); the - * core `@bankofai/x402` package ships no concrete verifiers itself. - */ -type VerifierFactory = (network: string, opts?: { rpcUrl?: string }) => TransactionVerifier; -const verifierFactories = new Map(); - -/** - * Register a verifier factory for a network prefix (e.g. `"tron:"`, `"eip155:"`). - * Calls override any prior registration for the same prefix. - */ -export function registerVerifierFactory(prefix: string, factory: VerifierFactory): void { - verifierFactories.set(prefix, factory); -} - -/** - * Resolve a {@link TransactionVerifier} for a given network. - * - * Throws if no factory has been registered for the network's prefix. Callers - * that want optional verification (e.g. server middleware) should catch this - * and skip verification gracefully. - * - * @example - * ```ts - * try { - * const verifier = getVerifierForNetwork('tron:nile'); - * const result = await verifier.verifyTransaction(txHash, payload, requirements); - * } catch { - * // No verifier registered → skip on-chain re-check (facilitator is trusted). - * } - * ``` - */ -export function getVerifierForNetwork( - network: string, - opts?: { rpcUrl?: string }, -): TransactionVerifier { - for (const [prefix, factory] of verifierFactories) { - if (network.startsWith(prefix)) { - return factory(network, opts); - } - } - throw new Error(`No transaction verifier registered for network: ${network}`); -} diff --git a/legacy/typescript/packages/x402/tsconfig.json b/legacy/typescript/packages/x402/tsconfig.json deleted file mode 100644 index e4acc2f7..00000000 --- a/legacy/typescript/packages/x402/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "./dist", - "rootDir": "./src" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "src/**/*.test.ts"] -} diff --git a/legacy/typescript/pnpm-lock.yaml b/legacy/typescript/pnpm-lock.yaml deleted file mode 100644 index f9d25ee7..00000000 --- a/legacy/typescript/pnpm-lock.yaml +++ /dev/null @@ -1,3153 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - '@types/node': - specifier: ^20.10.0 - version: 20.19.31 - typescript: - specifier: ^5.3.0 - version: 5.9.3 - - packages/x402: - dependencies: - '@bankofai/agent-wallet': - specifier: ^2.3.0 - version: 2.3.0(@types/node@20.19.31)(typescript@5.9.3) - '@gasfree/gasfree-sdk': - specifier: ^1.1.2 - version: 1.1.2 - tronweb: - specifier: ^5.0.0 || ^6.0.0 - version: 6.1.1 - viem: - specifier: ^2.45.2 - version: 2.45.2(typescript@5.9.3)(zod@3.25.76) - devDependencies: - '@types/express': - specifier: ^5.0.6 - version: 5.0.6 - '@types/node': - specifier: ^20.10.0 - version: 20.19.31 - express: - specifier: ^5.2.1 - version: 5.2.1 - hono: - specifier: ^4.12.18 - version: 4.12.18 - typescript: - specifier: ^5.3.0 - version: 5.9.3 - vitest: - specifier: ^1.6.1 - version: 1.6.1(@types/node@20.19.31) - -packages: - - '@adraffy/ens-normalize@1.10.1': - resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} - - '@adraffy/ens-normalize@1.11.1': - resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} - - '@babel/runtime-corejs3@7.26.10': - resolution: {integrity: sha512-uITFQYO68pMEYR46AHgQoyBg7KPPJDAbGn4jUTIRgCFJIp88MIBUianVOplhZDEec07bp9zIyr4Kp0FCyQzmWg==} - engines: {node: '>=6.9.0'} - - '@babel/runtime@7.26.10': - resolution: {integrity: sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw==} - engines: {node: '>=6.9.0'} - - '@bankofai/agent-wallet@2.3.0': - resolution: {integrity: sha512-Jezo0ffhZrsF0HQMV74wTJlLUtHoY4d7TeYbjqjkWketCqBdhiX9/90hS4qwk99QZwnbt+1HRUschOaSA1wkRw==} - engines: {node: '>=18.0.0'} - hasBin: true - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@ethereumjs/rlp@4.0.1': - resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} - engines: {node: '>=14'} - hasBin: true - - '@ethereumjs/util@8.0.3': - resolution: {integrity: sha512-0apCbwc8xAaie6W7q6QyogfyRS2BMU816a8KwpnpRw9Qrc6Bws+l7J3LfCLMt2iL6Wi8CYb0B29AeIr2N4vHnw==} - engines: {node: '>=14'} - - '@gasfree/gasfree-sdk@1.1.2': - resolution: {integrity: sha512-EDLHaPh/z/9qn3U+DniTrsc2EZ3mQX+QIdx2V97f+53QKLaXmbv0AL5yJ15D2n+wh1Ui8Ftc7K12ZDTAlpq/hQ==} - engines: {node: 18.19.0, pnpm: 7.32.0} - - '@inquirer/ansi@2.0.4': - resolution: {integrity: sha512-DpcZrQObd7S0R/U3bFdkcT5ebRwbTTC4D3tCc1vsJizmgPLxNJBo+AAFmrZwe8zk30P2QzgzGWZ3Q9uJwWuhIg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - - '@inquirer/checkbox@5.1.2': - resolution: {integrity: sha512-PubpMPO2nJgMufkoB3P2wwxNXEMUXnBIKi/ACzDUYfaoPuM7gSTmuxJeMscoLVEsR4qqrCMf5p0SiYGWnVJ8kw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/confirm@6.0.10': - resolution: {integrity: sha512-tiNyA73pgpQ0FQ7axqtoLUe4GDYjNCDcVsbgcA5anvwg2z6i+suEngLKKJrWKJolT//GFPZHwN30binDIHgSgQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/core@11.1.7': - resolution: {integrity: sha512-1BiBNDk9btIwYIzNZpkikIHXWeNzNncJePPqwDyVMhXhD1ebqbpn1mKGctpoqAbzywZfdG0O4tvmsGIcOevAPQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/editor@5.0.10': - resolution: {integrity: sha512-VJx4XyaKea7t8hEApTw5dxeIyMtWXre2OiyJcICCRZI4hkoHsMoCnl/KbUnJJExLbH9csLLHMVR144ZhFE1CwA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/expand@5.0.10': - resolution: {integrity: sha512-fC0UHJPXsTRvY2fObiwuQYaAnHrp3aDqfwKUJSdfpgv18QUG054ezGbaRNStk/BKD5IPijeMKWej8VV8O5Q/eQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/external-editor@2.0.4': - resolution: {integrity: sha512-Prenuv9C1PHj2Itx0BcAOVBTonz02Hc2Nd2DbU67PdGUaqn0nPCnV34oDyyoaZHnmfRxkpuhh/u51ThkrO+RdA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/figures@2.0.4': - resolution: {integrity: sha512-eLBsjlS7rPS3WEhmOmh1znQ5IsQrxWzxWDxO51e4urv+iVrSnIHbq4zqJIOiyNdYLa+BVjwOtdetcQx1lWPpiQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - - '@inquirer/input@5.0.10': - resolution: {integrity: sha512-nvZ6qEVeX/zVtZ1dY2hTGDQpVGD3R7MYPLODPgKO8Y+RAqxkrP3i/3NwF3fZpLdaMiNuK0z2NaYIx9tPwiSegQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/number@4.0.10': - resolution: {integrity: sha512-Ht8OQstxiS3APMGjHV0aYAjRAysidWdwurWEo2i8yI5xbhOBWqizT0+MU1S2GCcuhIBg+3SgWVjEoXgfhY+XaA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/password@5.0.10': - resolution: {integrity: sha512-QbNyvIE8q2GTqKLYSsA8ATG+eETo+m31DSR0+AU7x3d2FhaTWzqQek80dj3JGTo743kQc6mhBR0erMjYw5jQ0A==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/prompts@8.3.2': - resolution: {integrity: sha512-yFroiSj2iiBFlm59amdTvAcQFvWS6ph5oKESls/uqPBect7rTU2GbjyZO2DqxMGuIwVA8z0P4K6ViPcd/cp+0w==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/rawlist@5.2.6': - resolution: {integrity: sha512-jfw0MLJ5TilNsa9zlJ6nmRM0ZFVZhhTICt4/6CU2Dv1ndY7l3sqqo1gIYZyMMDw0LvE1u1nzJNisfHEhJIxq5w==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/search@4.1.6': - resolution: {integrity: sha512-3/6kTRae98hhDevENScy7cdFEuURnSpM3JbBNg8yfXLw88HgTOl+neUuy/l9W0No5NzGsLVydhBzTIxZP7yChQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/select@5.1.2': - resolution: {integrity: sha512-kTK8YIkHV+f02y7bWCh7E0u2/11lul5WepVTclr3UMBtBr05PgcZNWfMa7FY57ihpQFQH/spLMHTcr0rXy50tA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/type@4.0.4': - resolution: {integrity: sha512-PamArxO3cFJZoOzspzo6cxVlLeIftyBsZw/S9bKY5DzxqJVZgjoj1oP8d0rskKtp7sZxBycsoer1g6UeJV1BBA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@jest/schemas@29.6.3': - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@noble/ciphers@1.3.0': - resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.2.0': - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - - '@noble/curves@1.4.2': - resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - - '@noble/curves@1.9.1': - resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.1.2': - resolution: {integrity: sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==} - - '@noble/hashes@1.3.2': - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - - '@noble/hashes@1.8.0': - resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} - engines: {node: ^14.21.3 || >=16} - - '@noble/secp256k1@1.6.3': - resolution: {integrity: sha512-T04e4iTurVy7I8Sw4+c5OSN9/RkPlo1uKxAomtxQNLq8j1uPAqnsqG1bqvY3Jv7c13gyr6dui0zmh/I3+f/JaQ==} - - '@rollup/rollup-android-arm-eabi@4.57.1': - resolution: {integrity: sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.57.1': - resolution: {integrity: sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.57.1': - resolution: {integrity: sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.57.1': - resolution: {integrity: sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.57.1': - resolution: {integrity: sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.57.1': - resolution: {integrity: sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.57.1': - resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.57.1': - resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.57.1': - resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.57.1': - resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.57.1': - resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.57.1': - resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.57.1': - resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.57.1': - resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.57.1': - resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.57.1': - resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.57.1': - resolution: {integrity: sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.57.1': - resolution: {integrity: sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.57.1': - resolution: {integrity: sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.57.1': - resolution: {integrity: sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.57.1': - resolution: {integrity: sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==} - cpu: [x64] - os: [win32] - - '@scure/base@1.1.9': - resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} - - '@scure/base@1.2.6': - resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} - - '@scure/bip32@1.1.0': - resolution: {integrity: sha512-ftTW3kKX54YXLCxH6BB7oEEoJfoE2pIgw7MINKAs5PsS6nqKPuKk1haTF/EuHmYqG330t5GSrdmtRuHaY1a62Q==} - - '@scure/bip32@1.4.0': - resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} - - '@scure/bip32@1.7.0': - resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} - - '@scure/bip39@1.1.0': - resolution: {integrity: sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==} - - '@scure/bip39@1.3.0': - resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} - - '@scure/bip39@1.6.0': - resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - - '@sinclair/typebox@0.27.10': - resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} - - '@types/bn.js@4.11.6': - resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} - - '@types/body-parser@1.19.6': - resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/express-serve-static-core@5.1.1': - resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} - - '@types/express@5.0.6': - resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==} - - '@types/http-errors@2.0.5': - resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - - '@types/node@20.19.31': - resolution: {integrity: sha512-5jsi0wpncvTD33Sh1UCgacK37FFwDn+EG7wCmEvs62fCvBL+n8/76cAYDok21NF6+jaVWIqKwCZyX7Vbu8eB3A==} - - '@types/node@22.7.5': - resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} - - '@types/pbkdf2@3.1.2': - resolution: {integrity: sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==} - - '@types/qs@6.15.1': - resolution: {integrity: sha512-GZHUBZR9hckSUhrxmp1nG6NwdpM9fCunJwyThLW1X3AyHgd9IlHb6VANpQQqDr2o/qQp6McZ3y/IA2rVzKzSbw==} - - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - - '@types/secp256k1@4.0.7': - resolution: {integrity: sha512-Rcvjl6vARGAKRO6jHeKMatGrvOMGrR/AR11N1x2LqintPCyDZ7NBhrh238Z2VZc7aM7KIwnFpFQ7fnfK4H/9Qw==} - - '@types/send@1.2.1': - resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} - - '@types/serve-static@2.2.0': - resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} - - '@vitest/expect@1.6.1': - resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} - - '@vitest/runner@1.6.1': - resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} - - '@vitest/snapshot@1.6.1': - resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} - - '@vitest/spy@1.6.1': - resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} - - '@vitest/utils@1.6.1': - resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} - - abitype@1.2.3: - resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} - engines: {node: '>=0.4.0'} - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - - aes-js@4.0.0-beta.5: - resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - assertion-error@1.1.0: - resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - axios@1.12.2: - resolution: {integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==} - - base-x@3.0.11: - resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} - - base-x@5.0.1: - resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - bignumber.js@9.1.2: - resolution: {integrity: sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==} - - blakejs@1.2.1: - resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - - bn.js@4.12.3: - resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} - - bn.js@5.2.3: - resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} - - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - - browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} - - bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} - - bs58@6.0.0: - resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} - - bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} - - bs58check@4.0.0: - resolution: {integrity: sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==} - - buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - chai@4.5.0: - resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} - engines: {node: '>=4'} - - chardet@2.1.1: - resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} - - check-error@1.0.3: - resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} - - cipher-base@1.0.7: - resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} - engines: {node: '>= 0.10'} - - cli-width@4.1.0: - resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} - engines: {node: '>= 12'} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - - content-disposition@1.1.0: - resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - core-js-pure@3.48.0: - resolution: {integrity: sha512-1slJgk89tWC51HQ1AEqG+s2VuwpTRr8ocu4n20QUcH1v9lAN0RXen0Q0AABa/DK1I7RrNWLucplOHMx8hfTGTw==} - - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} - - create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - deep-eql@4.1.4: - resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} - engines: {node: '>=6'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - eth-sig-util@3.0.1: - resolution: {integrity: sha512-0Us50HiGGvZgjtWTyAI/+qTzYPMLy5Q451D0Xy68bxq1QMWdoOddDwGvsqcFT27uohKgalM9z/yxplyt+mY2iQ==} - deprecated: Deprecated in favor of '@metamask/eth-sig-util' - - ethereum-cryptography@0.1.3: - resolution: {integrity: sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==} - - ethereum-cryptography@1.1.2: - resolution: {integrity: sha512-XDSJlg4BD+hq9N2FjvotwUET9Tfxpxc3kWGE2AqUG5vcbeunnbImVk3cj6e/xT3phdW21mE8R5IugU4fspQDcQ==} - - ethereum-cryptography@2.2.1: - resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} - - ethereumjs-abi@0.6.8: - resolution: {integrity: sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==} - deprecated: This library has been deprecated and usage is discouraged. - - ethereumjs-util@5.2.1: - resolution: {integrity: sha512-v3kT+7zdyCm1HIqWlLNrHGqHGLpGYIhjeHxQjnDXjLT2FyGJDsd3LWMYUo7pAFRrk86CR3nUJfhC81CCoJNNGQ==} - - ethereumjs-util@6.2.1: - resolution: {integrity: sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==} - - ethers@6.13.5: - resolution: {integrity: sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==} - engines: {node: '>=14.0.0'} - - ethjs-util@0.1.6: - resolution: {integrity: sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==} - engines: {node: '>=6.5.0', npm: '>=3'} - - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - - evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - - execa@8.0.1: - resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} - engines: {node: '>=16.17'} - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - - fast-string-truncated-width@3.0.3: - resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} - - fast-string-width@3.0.2: - resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - - fast-wrap-ansi@0.2.0: - resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} - - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - get-func-name@2.0.2: - resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@8.0.1: - resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} - engines: {node: '>=16'} - - google-protobuf@3.21.4: - resolution: {integrity: sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ==} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hash-base@3.1.2: - resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} - engines: {node: '>= 0.8'} - - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - - hono@4.12.18: - resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==} - engines: {node: '>=16.9.0'} - - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - - human-signals@5.0.0: - resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} - engines: {node: '>=16.17.0'} - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-hex-prefixed@1.0.0: - resolution: {integrity: sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==} - engines: {node: '>=6.5.0', npm: '>=3'} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-stream@3.0.0: - resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isows@1.0.7: - resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} - peerDependencies: - ws: '*' - - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - - jsonschema@1.4.1: - resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} - - keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} - - local-pkg@0.5.1: - resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} - engines: {node: '>=14'} - - loupe@2.3.7: - resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - - mimic-fn@4.0.0: - resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} - engines: {node: '>=12'} - - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mute-stream@3.0.0: - resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} - engines: {node: ^20.17.0 || >=22.9.0} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - - node-addon-api@5.1.0: - resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} - - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - npm-run-path@5.3.0: - resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@6.0.0: - resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} - engines: {node: '>=12'} - - ox@0.11.3: - resolution: {integrity: sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - p-limit@5.0.0: - resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} - engines: {node: '>=18'} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-to-regexp@8.4.2: - resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pathval@1.1.1: - resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - - pbkdf2@3.1.5: - resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} - engines: {node: '>= 0.10'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - qs@6.15.1: - resolution: {integrity: sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==} - engines: {node: '>=0.6'} - - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - - ripemd160@2.0.3: - resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} - engines: {node: '>= 0.8'} - - rlp@2.2.7: - resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} - hasBin: true - - rollup@4.57.1: - resolution: {integrity: sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - scrypt-js@3.0.1: - resolution: {integrity: sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==} - - secp256k1@4.0.4: - resolution: {integrity: sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==} - engines: {node: '>=18.0.0'} - - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} - engines: {node: '>=10'} - hasBin: true - - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.12: - resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} - engines: {node: '>= 0.10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-final-newline@3.0.0: - resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} - engines: {node: '>=12'} - - strip-hex-prefix@1.0.0: - resolution: {integrity: sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==} - engines: {node: '>=6.5.0', npm: '>=3'} - - strip-literal@2.1.1: - resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinypool@0.8.4: - resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} - engines: {node: '>=14.0.0'} - - tinyspy@2.2.1: - resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} - engines: {node: '>=14.0.0'} - - to-buffer@1.2.2: - resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} - engines: {node: '>= 0.4'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - tronweb@6.1.1: - resolution: {integrity: sha512-9i2N+cTkRY7Y1B/V0+ZVwCYZFhdFDalh8sbI8Tpj5O65hMURvjFnaP1u/dTwVnVw07d9M143/19KarxeAzK6pg==} - - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - - tweetnacl-util@0.15.1: - resolution: {integrity: sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==} - - tweetnacl@1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - - type-detect@4.1.0: - resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} - engines: {node: '>=4'} - - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} - - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - validator@13.15.23: - resolution: {integrity: sha512-4yoz1kEWqUjzi5zsPbAS/903QXSYp0UOtHsPpp7p9rHAw/W+dkInskAE386Fat3oKRROwO98d9ZB0G4cObgUyw==} - engines: {node: '>= 0.10'} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - viem@2.45.2: - resolution: {integrity: sha512-GXPMmj0ukqFNL87sgpsZBy4CjGvsFQk42/EUdsn8dv3ZWtL4ukDXNCM0nME2hU0IcuS29CuUbrwbZN6iWxAipw==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - vite-node@1.6.1: - resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - - vite@5.4.21: - resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - 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 - - vitest@1.6.1: - resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/node': ^18.0.0 || >=20.0.0 - '@vitest/browser': 1.6.1 - '@vitest/ui': 1.6.1 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - 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 - - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - 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 - - yocto-queue@1.2.2: - resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} - engines: {node: '>=12.20'} - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - -snapshots: - - '@adraffy/ens-normalize@1.10.1': {} - - '@adraffy/ens-normalize@1.11.1': {} - - '@babel/runtime-corejs3@7.26.10': - dependencies: - core-js-pure: 3.48.0 - regenerator-runtime: 0.14.1 - - '@babel/runtime@7.26.10': - dependencies: - regenerator-runtime: 0.14.1 - - '@bankofai/agent-wallet@2.3.0(@types/node@20.19.31)(typescript@5.9.3)': - dependencies: - '@inquirer/prompts': 8.3.2(@types/node@20.19.31) - '@noble/curves': 1.9.1 - bs58check: 4.0.0 - viem: 2.45.2(typescript@5.9.3)(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - '@types/node' - - bufferutil - - typescript - - utf-8-validate - - '@esbuild/aix-ppc64@0.21.5': - optional: true - - '@esbuild/android-arm64@0.21.5': - optional: true - - '@esbuild/android-arm@0.21.5': - optional: true - - '@esbuild/android-x64@0.21.5': - optional: true - - '@esbuild/darwin-arm64@0.21.5': - optional: true - - '@esbuild/darwin-x64@0.21.5': - optional: true - - '@esbuild/freebsd-arm64@0.21.5': - optional: true - - '@esbuild/freebsd-x64@0.21.5': - optional: true - - '@esbuild/linux-arm64@0.21.5': - optional: true - - '@esbuild/linux-arm@0.21.5': - optional: true - - '@esbuild/linux-ia32@0.21.5': - optional: true - - '@esbuild/linux-loong64@0.21.5': - optional: true - - '@esbuild/linux-mips64el@0.21.5': - optional: true - - '@esbuild/linux-ppc64@0.21.5': - optional: true - - '@esbuild/linux-riscv64@0.21.5': - optional: true - - '@esbuild/linux-s390x@0.21.5': - optional: true - - '@esbuild/linux-x64@0.21.5': - optional: true - - '@esbuild/netbsd-x64@0.21.5': - optional: true - - '@esbuild/openbsd-x64@0.21.5': - optional: true - - '@esbuild/sunos-x64@0.21.5': - optional: true - - '@esbuild/win32-arm64@0.21.5': - optional: true - - '@esbuild/win32-ia32@0.21.5': - optional: true - - '@esbuild/win32-x64@0.21.5': - optional: true - - '@ethereumjs/rlp@4.0.1': {} - - '@ethereumjs/util@8.0.3': - dependencies: - '@ethereumjs/rlp': 4.0.1 - async: 3.2.6 - ethereum-cryptography: 1.1.2 - - '@gasfree/gasfree-sdk@1.1.2': - dependencies: - '@babel/runtime-corejs3': 7.26.10 - '@ethereumjs/util': 8.0.3 - buffer: 6.0.3 - eth-sig-util: 3.0.1 - ethereum-cryptography: 1.1.2 - ethereumjs-abi: 0.6.8 - jsonschema: 1.4.1 - tronweb: 6.1.1 - transitivePeerDependencies: - - bufferutil - - debug - - utf-8-validate - - '@inquirer/ansi@2.0.4': {} - - '@inquirer/checkbox@5.1.2(@types/node@20.19.31)': - dependencies: - '@inquirer/ansi': 2.0.4 - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/figures': 2.0.4 - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/confirm@6.0.10(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/core@11.1.7(@types/node@20.19.31)': - dependencies: - '@inquirer/ansi': 2.0.4 - '@inquirer/figures': 2.0.4 - '@inquirer/type': 4.0.4(@types/node@20.19.31) - cli-width: 4.1.0 - fast-wrap-ansi: 0.2.0 - mute-stream: 3.0.0 - signal-exit: 4.1.0 - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/editor@5.0.10(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/external-editor': 2.0.4(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/expand@5.0.10(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/external-editor@2.0.4(@types/node@20.19.31)': - dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/figures@2.0.4': {} - - '@inquirer/input@5.0.10(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/number@4.0.10(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/password@5.0.10(@types/node@20.19.31)': - dependencies: - '@inquirer/ansi': 2.0.4 - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/prompts@8.3.2(@types/node@20.19.31)': - dependencies: - '@inquirer/checkbox': 5.1.2(@types/node@20.19.31) - '@inquirer/confirm': 6.0.10(@types/node@20.19.31) - '@inquirer/editor': 5.0.10(@types/node@20.19.31) - '@inquirer/expand': 5.0.10(@types/node@20.19.31) - '@inquirer/input': 5.0.10(@types/node@20.19.31) - '@inquirer/number': 4.0.10(@types/node@20.19.31) - '@inquirer/password': 5.0.10(@types/node@20.19.31) - '@inquirer/rawlist': 5.2.6(@types/node@20.19.31) - '@inquirer/search': 4.1.6(@types/node@20.19.31) - '@inquirer/select': 5.1.2(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/rawlist@5.2.6(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/search@4.1.6(@types/node@20.19.31)': - dependencies: - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/figures': 2.0.4 - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/select@5.1.2(@types/node@20.19.31)': - dependencies: - '@inquirer/ansi': 2.0.4 - '@inquirer/core': 11.1.7(@types/node@20.19.31) - '@inquirer/figures': 2.0.4 - '@inquirer/type': 4.0.4(@types/node@20.19.31) - optionalDependencies: - '@types/node': 20.19.31 - - '@inquirer/type@4.0.4(@types/node@20.19.31)': - optionalDependencies: - '@types/node': 20.19.31 - - '@jest/schemas@29.6.3': - dependencies: - '@sinclair/typebox': 0.27.10 - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@noble/ciphers@1.3.0': {} - - '@noble/curves@1.2.0': - dependencies: - '@noble/hashes': 1.3.2 - - '@noble/curves@1.4.2': - dependencies: - '@noble/hashes': 1.4.0 - - '@noble/curves@1.9.1': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/hashes@1.1.2': {} - - '@noble/hashes@1.3.2': {} - - '@noble/hashes@1.4.0': {} - - '@noble/hashes@1.8.0': {} - - '@noble/secp256k1@1.6.3': {} - - '@rollup/rollup-android-arm-eabi@4.57.1': - optional: true - - '@rollup/rollup-android-arm64@4.57.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.57.1': - optional: true - - '@rollup/rollup-darwin-x64@4.57.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.57.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.57.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.57.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.57.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.57.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.57.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.57.1': - optional: true - - '@rollup/rollup-openbsd-x64@4.57.1': - optional: true - - '@rollup/rollup-openharmony-arm64@4.57.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.57.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.57.1': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.57.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.57.1': - optional: true - - '@scure/base@1.1.9': {} - - '@scure/base@1.2.6': {} - - '@scure/bip32@1.1.0': - dependencies: - '@noble/hashes': 1.1.2 - '@noble/secp256k1': 1.6.3 - '@scure/base': 1.1.9 - - '@scure/bip32@1.4.0': - dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.9 - - '@scure/bip32@1.7.0': - dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - - '@scure/bip39@1.1.0': - dependencies: - '@noble/hashes': 1.1.2 - '@scure/base': 1.1.9 - - '@scure/bip39@1.3.0': - dependencies: - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.9 - - '@scure/bip39@1.6.0': - dependencies: - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - - '@sinclair/typebox@0.27.10': {} - - '@types/bn.js@4.11.6': - dependencies: - '@types/node': 20.19.31 - - '@types/body-parser@1.19.6': - dependencies: - '@types/connect': 3.4.38 - '@types/node': 20.19.31 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 20.19.31 - - '@types/estree@1.0.8': {} - - '@types/express-serve-static-core@5.1.1': - dependencies: - '@types/node': 20.19.31 - '@types/qs': 6.15.1 - '@types/range-parser': 1.2.7 - '@types/send': 1.2.1 - - '@types/express@5.0.6': - dependencies: - '@types/body-parser': 1.19.6 - '@types/express-serve-static-core': 5.1.1 - '@types/serve-static': 2.2.0 - - '@types/http-errors@2.0.5': {} - - '@types/node@20.19.31': - dependencies: - undici-types: 6.21.0 - - '@types/node@22.7.5': - dependencies: - undici-types: 6.19.8 - - '@types/pbkdf2@3.1.2': - dependencies: - '@types/node': 20.19.31 - - '@types/qs@6.15.1': {} - - '@types/range-parser@1.2.7': {} - - '@types/secp256k1@4.0.7': - dependencies: - '@types/node': 20.19.31 - - '@types/send@1.2.1': - dependencies: - '@types/node': 20.19.31 - - '@types/serve-static@2.2.0': - dependencies: - '@types/http-errors': 2.0.5 - '@types/node': 20.19.31 - - '@vitest/expect@1.6.1': - dependencies: - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 - chai: 4.5.0 - - '@vitest/runner@1.6.1': - dependencies: - '@vitest/utils': 1.6.1 - p-limit: 5.0.0 - pathe: 1.1.2 - - '@vitest/snapshot@1.6.1': - dependencies: - magic-string: 0.30.21 - pathe: 1.1.2 - pretty-format: 29.7.0 - - '@vitest/spy@1.6.1': - dependencies: - tinyspy: 2.2.1 - - '@vitest/utils@1.6.1': - dependencies: - diff-sequences: 29.6.3 - estree-walker: 3.0.3 - loupe: 2.3.7 - pretty-format: 29.7.0 - - abitype@1.2.3(typescript@5.9.3)(zod@3.25.76): - optionalDependencies: - typescript: 5.9.3 - zod: 3.25.76 - - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - - acorn-walk@8.3.4: - dependencies: - acorn: 8.15.0 - - acorn@8.15.0: {} - - aes-js@4.0.0-beta.5: {} - - ansi-styles@5.2.0: {} - - assertion-error@1.1.0: {} - - async@3.2.6: {} - - asynckit@0.4.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - axios@1.12.2: - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - base-x@3.0.11: - dependencies: - safe-buffer: 5.2.1 - - base-x@5.0.1: {} - - base64-js@1.5.1: {} - - bignumber.js@9.1.2: {} - - blakejs@1.2.1: {} - - bn.js@4.12.3: {} - - bn.js@5.2.3: {} - - body-parser@2.2.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.15.1 - raw-body: 3.0.2 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - - brorand@1.1.0: {} - - browserify-aes@1.2.0: - dependencies: - buffer-xor: 1.0.3 - cipher-base: 1.0.7 - create-hash: 1.2.0 - evp_bytestokey: 1.0.3 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - bs58@4.0.1: - dependencies: - base-x: 3.0.11 - - bs58@6.0.0: - dependencies: - base-x: 5.0.1 - - bs58check@2.1.2: - dependencies: - bs58: 4.0.1 - create-hash: 1.2.0 - safe-buffer: 5.2.1 - - bs58check@4.0.0: - dependencies: - '@noble/hashes': 1.8.0 - bs58: 6.0.0 - - buffer-xor@1.0.3: {} - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bytes@3.1.2: {} - - cac@6.7.14: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - chai@4.5.0: - dependencies: - assertion-error: 1.1.0 - check-error: 1.0.3 - deep-eql: 4.1.4 - get-func-name: 2.0.2 - loupe: 2.3.7 - pathval: 1.1.1 - type-detect: 4.1.0 - - chardet@2.1.1: {} - - check-error@1.0.3: - dependencies: - get-func-name: 2.0.2 - - cipher-base@1.0.7: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - cli-width@4.1.0: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - confbox@0.1.8: {} - - content-disposition@1.1.0: {} - - content-type@1.0.5: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - core-js-pure@3.48.0: {} - - core-util-is@1.0.3: {} - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.7 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.3 - sha.js: 2.4.12 - - create-hmac@1.1.7: - dependencies: - cipher-base: 1.0.7 - create-hash: 1.2.0 - inherits: 2.0.4 - ripemd160: 2.0.3 - safe-buffer: 5.2.1 - sha.js: 2.4.12 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - deep-eql@4.1.4: - dependencies: - type-detect: 4.1.0 - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - delayed-stream@1.0.0: {} - - depd@2.0.0: {} - - diff-sequences@29.6.3: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - ee-first@1.1.1: {} - - elliptic@6.6.1: - dependencies: - bn.js: 4.12.3 - brorand: 1.1.0 - hash.js: 1.1.7 - hmac-drbg: 1.0.1 - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - encodeurl@2.0.0: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.21.5: - 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 - - escape-html@1.0.3: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - etag@1.8.1: {} - - eth-sig-util@3.0.1: - dependencies: - ethereumjs-abi: 0.6.8 - ethereumjs-util: 5.2.1 - tweetnacl: 1.0.3 - tweetnacl-util: 0.15.1 - - ethereum-cryptography@0.1.3: - dependencies: - '@types/pbkdf2': 3.1.2 - '@types/secp256k1': 4.0.7 - blakejs: 1.2.1 - browserify-aes: 1.2.0 - bs58check: 2.1.2 - create-hash: 1.2.0 - create-hmac: 1.1.7 - hash.js: 1.1.7 - keccak: 3.0.4 - pbkdf2: 3.1.5 - randombytes: 2.1.0 - safe-buffer: 5.2.1 - scrypt-js: 3.0.1 - secp256k1: 4.0.4 - setimmediate: 1.0.5 - - ethereum-cryptography@1.1.2: - dependencies: - '@noble/hashes': 1.1.2 - '@noble/secp256k1': 1.6.3 - '@scure/bip32': 1.1.0 - '@scure/bip39': 1.1.0 - - ethereum-cryptography@2.2.1: - dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 - '@scure/bip32': 1.4.0 - '@scure/bip39': 1.3.0 - - ethereumjs-abi@0.6.8: - dependencies: - bn.js: 4.12.3 - ethereumjs-util: 6.2.1 - - ethereumjs-util@5.2.1: - dependencies: - bn.js: 4.12.3 - create-hash: 1.2.0 - elliptic: 6.6.1 - ethereum-cryptography: 0.1.3 - ethjs-util: 0.1.6 - rlp: 2.2.7 - safe-buffer: 5.2.1 - - ethereumjs-util@6.2.1: - dependencies: - '@types/bn.js': 4.11.6 - bn.js: 4.12.3 - create-hash: 1.2.0 - elliptic: 6.6.1 - ethereum-cryptography: 0.1.3 - ethjs-util: 0.1.6 - rlp: 2.2.7 - - ethers@6.13.5: - dependencies: - '@adraffy/ens-normalize': 1.10.1 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@types/node': 22.7.5 - aes-js: 4.0.0-beta.5 - tslib: 2.7.0 - ws: 8.17.1 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - ethjs-util@0.1.6: - dependencies: - is-hex-prefixed: 1.0.0 - strip-hex-prefix: 1.0.0 - - eventemitter3@5.0.1: {} - - evp_bytestokey@1.0.3: - dependencies: - md5.js: 1.3.5 - safe-buffer: 5.2.1 - - execa@8.0.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 8.0.1 - human-signals: 5.0.0 - is-stream: 3.0.0 - merge-stream: 2.0.0 - npm-run-path: 5.3.0 - onetime: 6.0.0 - signal-exit: 4.1.0 - strip-final-newline: 3.0.0 - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.1.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.15.1 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - fast-string-truncated-width@3.0.3: {} - - fast-string-width@3.0.2: - dependencies: - fast-string-truncated-width: 3.0.3 - - fast-wrap-ansi@0.2.0: - dependencies: - fast-string-width: 3.0.2 - - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - follow-redirects@1.15.11: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - forwarded@0.2.0: {} - - fresh@2.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - get-func-name@2.0.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stream@8.0.1: {} - - google-protobuf@3.21.4: {} - - gopd@1.2.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hash-base@3.1.2: - dependencies: - inherits: 2.0.4 - readable-stream: 2.3.8 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - hash.js@1.1.7: - dependencies: - inherits: 2.0.4 - minimalistic-assert: 1.0.1 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hmac-drbg@1.0.1: - dependencies: - hash.js: 1.1.7 - minimalistic-assert: 1.0.1 - minimalistic-crypto-utils: 1.0.1 - - hono@4.12.18: {} - - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - - human-signals@5.0.0: {} - - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: {} - - inherits@2.0.4: {} - - ipaddr.js@1.9.1: {} - - is-callable@1.2.7: {} - - is-hex-prefixed@1.0.0: {} - - is-promise@4.0.0: {} - - is-stream@3.0.0: {} - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.20 - - isarray@1.0.0: {} - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - isows@1.0.7(ws@8.18.3): - dependencies: - ws: 8.18.3 - - js-tokens@9.0.1: {} - - jsonschema@1.4.1: {} - - keccak@3.0.4: - dependencies: - node-addon-api: 2.0.2 - node-gyp-build: 4.8.4 - readable-stream: 3.6.2 - - local-pkg@0.5.1: - dependencies: - mlly: 1.8.0 - pkg-types: 1.3.1 - - loupe@2.3.7: - dependencies: - get-func-name: 2.0.2 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - math-intrinsics@1.1.0: {} - - md5.js@1.3.5: - dependencies: - hash-base: 3.1.2 - inherits: 2.0.4 - safe-buffer: 5.2.1 - - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - - merge-stream@2.0.0: {} - - mime-db@1.52.0: {} - - mime-db@1.54.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - - mimic-fn@4.0.0: {} - - minimalistic-assert@1.0.1: {} - - minimalistic-crypto-utils@1.0.1: {} - - mlly@1.8.0: - dependencies: - acorn: 8.15.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.3 - - ms@2.1.3: {} - - mute-stream@3.0.0: {} - - nanoid@3.3.11: {} - - negotiator@1.0.0: {} - - node-addon-api@2.0.2: {} - - node-addon-api@5.1.0: {} - - node-gyp-build@4.8.4: {} - - npm-run-path@5.3.0: - dependencies: - path-key: 4.0.0 - - object-inspect@1.13.4: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@6.0.0: - dependencies: - mimic-fn: 4.0.0 - - ox@0.11.3(typescript@5.9.3)(zod@3.25.76): - dependencies: - '@adraffy/ens-normalize': 1.11.1 - '@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(typescript@5.9.3)(zod@3.25.76) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - zod - - p-limit@5.0.0: - dependencies: - yocto-queue: 1.2.2 - - parseurl@1.3.3: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-to-regexp@8.4.2: {} - - pathe@1.1.2: {} - - pathe@2.0.3: {} - - pathval@1.1.1: {} - - pbkdf2@3.1.5: - dependencies: - create-hash: 1.2.0 - create-hmac: 1.1.7 - ripemd160: 2.0.3 - safe-buffer: 5.2.1 - sha.js: 2.4.12 - to-buffer: 1.2.2 - - picocolors@1.1.1: {} - - pkg-types@1.3.1: - dependencies: - confbox: 0.1.8 - mlly: 1.8.0 - pathe: 2.0.3 - - possible-typed-array-names@1.1.0: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - pretty-format@29.7.0: - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - - process-nextick-args@2.0.1: {} - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - proxy-from-env@1.1.0: {} - - qs@6.15.1: - dependencies: - side-channel: 1.1.0 - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - - react-is@18.3.1: {} - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - regenerator-runtime@0.14.1: {} - - ripemd160@2.0.3: - dependencies: - hash-base: 3.1.2 - inherits: 2.0.4 - - rlp@2.2.7: - dependencies: - bn.js: 5.2.3 - - rollup@4.57.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.57.1 - '@rollup/rollup-android-arm64': 4.57.1 - '@rollup/rollup-darwin-arm64': 4.57.1 - '@rollup/rollup-darwin-x64': 4.57.1 - '@rollup/rollup-freebsd-arm64': 4.57.1 - '@rollup/rollup-freebsd-x64': 4.57.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.57.1 - '@rollup/rollup-linux-arm-musleabihf': 4.57.1 - '@rollup/rollup-linux-arm64-gnu': 4.57.1 - '@rollup/rollup-linux-arm64-musl': 4.57.1 - '@rollup/rollup-linux-loong64-gnu': 4.57.1 - '@rollup/rollup-linux-loong64-musl': 4.57.1 - '@rollup/rollup-linux-ppc64-gnu': 4.57.1 - '@rollup/rollup-linux-ppc64-musl': 4.57.1 - '@rollup/rollup-linux-riscv64-gnu': 4.57.1 - '@rollup/rollup-linux-riscv64-musl': 4.57.1 - '@rollup/rollup-linux-s390x-gnu': 4.57.1 - '@rollup/rollup-linux-x64-gnu': 4.57.1 - '@rollup/rollup-linux-x64-musl': 4.57.1 - '@rollup/rollup-openbsd-x64': 4.57.1 - '@rollup/rollup-openharmony-arm64': 4.57.1 - '@rollup/rollup-win32-arm64-msvc': 4.57.1 - '@rollup/rollup-win32-ia32-msvc': 4.57.1 - '@rollup/rollup-win32-x64-gnu': 4.57.1 - '@rollup/rollup-win32-x64-msvc': 4.57.1 - fsevents: 2.3.3 - - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.4.2 - transitivePeerDependencies: - - supports-color - - safe-buffer@5.1.2: {} - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - scrypt-js@3.0.1: {} - - secp256k1@4.0.4: - dependencies: - elliptic: 6.6.1 - node-addon-api: 5.1.0 - node-gyp-build: 4.8.4 - - semver@7.7.1: {} - - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - setimmediate@1.0.5: {} - - setprototypeof@1.2.0: {} - - sha.js@2.4.12: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.2 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - siginfo@2.0.0: {} - - signal-exit@4.1.0: {} - - source-map-js@1.2.1: {} - - stackback@0.0.2: {} - - statuses@2.0.2: {} - - std-env@3.10.0: {} - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-final-newline@3.0.0: {} - - strip-hex-prefix@1.0.0: - dependencies: - is-hex-prefixed: 1.0.0 - - strip-literal@2.1.1: - dependencies: - js-tokens: 9.0.1 - - tinybench@2.9.0: {} - - tinypool@0.8.4: {} - - tinyspy@2.2.1: {} - - to-buffer@1.2.2: - dependencies: - isarray: 2.0.5 - safe-buffer: 5.2.1 - typed-array-buffer: 1.0.3 - - toidentifier@1.0.1: {} - - tronweb@6.1.1: - dependencies: - '@babel/runtime': 7.26.10 - axios: 1.12.2 - bignumber.js: 9.1.2 - ethereum-cryptography: 2.2.1 - ethers: 6.13.5 - eventemitter3: 5.0.1 - google-protobuf: 3.21.4 - semver: 7.7.1 - validator: 13.15.23 - transitivePeerDependencies: - - bufferutil - - debug - - utf-8-validate - - tslib@2.7.0: {} - - tweetnacl-util@0.15.1: {} - - tweetnacl@1.0.3: {} - - type-detect@4.1.0: {} - - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.2 - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typescript@5.9.3: {} - - ufo@1.6.3: {} - - undici-types@6.19.8: {} - - undici-types@6.21.0: {} - - unpipe@1.0.0: {} - - util-deprecate@1.0.2: {} - - validator@13.15.23: {} - - vary@1.1.2: {} - - viem@2.45.2(typescript@5.9.3)(zod@3.25.76): - 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(typescript@5.9.3)(zod@3.25.76) - isows: 1.0.7(ws@8.18.3) - ox: 0.11.3(typescript@5.9.3)(zod@3.25.76) - ws: 8.18.3 - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - vite-node@1.6.1(@types/node@20.19.31): - dependencies: - cac: 6.7.14 - debug: 4.4.3 - pathe: 1.1.2 - picocolors: 1.1.1 - vite: 5.4.21(@types/node@20.19.31) - transitivePeerDependencies: - - '@types/node' - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - vite@5.4.21(@types/node@20.19.31): - dependencies: - esbuild: 0.21.5 - postcss: 8.5.6 - rollup: 4.57.1 - optionalDependencies: - '@types/node': 20.19.31 - fsevents: 2.3.3 - - vitest@1.6.1(@types/node@20.19.31): - dependencies: - '@vitest/expect': 1.6.1 - '@vitest/runner': 1.6.1 - '@vitest/snapshot': 1.6.1 - '@vitest/spy': 1.6.1 - '@vitest/utils': 1.6.1 - acorn-walk: 8.3.4 - chai: 4.5.0 - debug: 4.4.3 - execa: 8.0.1 - local-pkg: 0.5.1 - magic-string: 0.30.21 - pathe: 1.1.2 - picocolors: 1.1.1 - std-env: 3.10.0 - strip-literal: 2.1.1 - tinybench: 2.9.0 - tinypool: 0.8.4 - vite: 5.4.21(@types/node@20.19.31) - vite-node: 1.6.1(@types/node@20.19.31) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 20.19.31 - transitivePeerDependencies: - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - which-typed-array@1.1.20: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - wrappy@1.0.2: {} - - ws@8.17.1: {} - - ws@8.18.3: {} - - yocto-queue@1.2.2: {} - - zod@3.25.76: {} diff --git a/legacy/typescript/pnpm-workspace.yaml b/legacy/typescript/pnpm-workspace.yaml deleted file mode 100644 index c17b60ef..00000000 --- a/legacy/typescript/pnpm-workspace.yaml +++ /dev/null @@ -1,3 +0,0 @@ -packages: - - 'packages/x402' - - '../examples/typescript/client' diff --git a/legacy/typescript/scripts/publish-npm.sh b/legacy/typescript/scripts/publish-npm.sh deleted file mode 100755 index 3a583c71..00000000 --- a/legacy/typescript/scripts/publish-npm.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if [[ -z "${BASH_VERSION:-}" ]]; then - exec bash "$0" "$@" -fi - -root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" - -if ! command -v pnpm >/dev/null 2>&1; then - echo "pnpm not found. Install pnpm >= 8." >&2 - exit 1 -fi -if ! command -v node >/dev/null 2>&1; then - echo "node not found. Install Node.js >= 18." >&2 - exit 1 -fi - -registry_url="${NPM_REGISTRY:-https://registry.npmjs.org}" -package_version="$(node -p "require('./packages/x402/package.json').version")" -default_tag="latest" -if [[ "${package_version}" == *-* ]]; then - default_tag="beta" -fi -tag="${NPM_TAG:-${default_tag}}" - -publish_args=(--tag "${tag}" --access public) -if [[ "${NO_GIT_CHECKS:-1}" == "1" ]]; then - publish_args+=(--no-git-checks) -fi -if [[ "${DRY_RUN:-0}" == "1" ]]; then - publish_args+=(--dry-run) -fi - -export npm_config_registry="${registry_url}" - -cd "${root_dir}" - -pnpm install -pnpm -r clean -pnpm -r build - -if command -v npm >/dev/null 2>&1; then - npm whoami >/dev/null 2>&1 || { - echo "Error: npm is not authenticated. Ensure your token is in ~/.npmrc" >&2 - exit 1 - } -fi - -pnpm -r publish --filter "./packages/x402" "${publish_args[@]}" diff --git a/legacy/typescript/tsconfig.base.json b/legacy/typescript/tsconfig.base.json deleted file mode 100644 index 7556965d..00000000 --- a/legacy/typescript/tsconfig.base.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "NodeNext", - "moduleResolution": "NodeNext", - "lib": ["ES2022"], - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": false, - "outDir": "./dist", - "rootDir": "./src" - } -}