From d51e74c9e0bee19dd5186d3df8479c62e9a9d7f1 Mon Sep 17 00:00:00 2001 From: Jim Toth Date: Tue, 28 Jul 2026 10:54:35 -0400 Subject: [PATCH 1/5] Port onto @anyone-protocol/ao-client (D15/D16/D17) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fourth W4 port. Replaces @permaweb/aoconnect 0.0.59, the local send-aos-message.ts wrapper, and the vendored src/util/arbundles-lite with the shared client and the maintained @dha-team/arbundles. D17 — explicit endpoints. CU_URL is gone, replaced by a single HB_URL with NO default (nodeUrlFromEnv fails closed). This service's surface is claims, not rounds, so the mapping differs again from the three ports before it: - `Get-Rewards` (dryrun) -> the `rewards?address=` view. The view returns { address, reward }, so the amount is now a FIELD; the legacy dryrun made it the entire response body. An address with no rewards yields no `reward` key. - `Claim-Rewards` stays an action and still passes the beneficiary as a tag: the facilitator claims ON BEHALF of an address, so ctx.from is the facilitator and the handler is role-gated. Its return is the message output now, not Messages[1].Data. - relay returns a single claimed amount; staking returns the hodler's PER-OPERATOR map which the service sums. That asymmetry is in the contracts and is preserved. The "no rewards" path is the interesting one. Both contracts assert 'No rewards for ', which arrives as an AoContractError — an HTTP 200 whose reason lives only in the message's own slot output. The old code inferred it from a missing Messages[1] and a substring match on result.Error; it is now an explicit branch on the error type, and still distinguishes "no rewards" (noReward: true) from a genuine rejection. Both services build a READ-ONLY client when their controller key is absent rather than refusing to start — the key is optional on a non-hodler deploy, and getAllocation is a read. Previously the signer was simply left undefined. Integration specs, 8/8 green against a local node holding the real migrated relay -rewards and staking-rewards state: allocations read back for a seeded address, claims return the real amounts (relay single, staking summed across operators and checked against the dump), an unknown address reads as undefined, and both services report noReward for one the contract has nothing for. Typecheck goes from 1 pre-existing error to zero. --- README.md | 2 +- operations/facilitator-controller-live.hcl | 5 +- operations/facilitator-controller-stage.hcl | 5 +- package-lock.json | 1945 ++++++++++++++--- package.json | 3 +- .../relay-rewards.service.spec.ts | 91 + src/relay-rewards/relay-rewards.service.ts | 124 +- .../staking-rewards.service.spec.ts | 64 + .../staking-rewards.service.ts | 102 +- src/util/arbundles-lite/Bundle.ts | 192 -- src/util/arbundles-lite/BundleInterface.ts | 19 - src/util/arbundles-lite/BundleItem.ts | 28 - src/util/arbundles-lite/DataItem.ts | 313 --- src/util/arbundles-lite/ar-data-base.ts | 25 - src/util/arbundles-lite/ar-data-bundle.ts | 95 - src/util/arbundles-lite/ar-data-create.ts | 96 - src/util/arbundles-lite/constants.ts | 53 - src/util/arbundles-lite/deepHash.ts | 88 - src/util/arbundles-lite/index.ts | 19 - src/util/arbundles-lite/signing/Signer.ts | 24 - .../signing/chains/ArweaveSigner.ts | 31 - .../signing/chains/ethereumSigner.ts | 40 - .../arbundles-lite/signing/chains/index.ts | 16 - src/util/arbundles-lite/signing/constants.ts | 49 - src/util/arbundles-lite/signing/index.ts | 5 - src/util/arbundles-lite/signing/keccak256.ts | 109 - .../arbundles-lite/signing/keys/Rsa4096Pss.ts | 44 - src/util/arbundles-lite/signing/keys/index.ts | 2 - .../arbundles-lite/signing/keys/secp256k1.ts | 54 - src/util/arbundles-lite/tags.ts | 208 -- src/util/arbundles-lite/types.ts | 1 - src/util/arbundles-lite/utils.ts | 85 - src/util/create-ethereum-data-item-signer.ts | 22 - src/util/send-aos-message.ts | 144 -- 34 files changed, 2005 insertions(+), 2098 deletions(-) create mode 100644 src/relay-rewards/relay-rewards.service.spec.ts create mode 100644 src/staking-rewards/staking-rewards.service.spec.ts delete mode 100644 src/util/arbundles-lite/Bundle.ts delete mode 100644 src/util/arbundles-lite/BundleInterface.ts delete mode 100644 src/util/arbundles-lite/BundleItem.ts delete mode 100644 src/util/arbundles-lite/DataItem.ts delete mode 100644 src/util/arbundles-lite/ar-data-base.ts delete mode 100644 src/util/arbundles-lite/ar-data-bundle.ts delete mode 100644 src/util/arbundles-lite/ar-data-create.ts delete mode 100644 src/util/arbundles-lite/constants.ts delete mode 100644 src/util/arbundles-lite/deepHash.ts delete mode 100644 src/util/arbundles-lite/index.ts delete mode 100644 src/util/arbundles-lite/signing/Signer.ts delete mode 100644 src/util/arbundles-lite/signing/chains/ArweaveSigner.ts delete mode 100644 src/util/arbundles-lite/signing/chains/ethereumSigner.ts delete mode 100644 src/util/arbundles-lite/signing/chains/index.ts delete mode 100644 src/util/arbundles-lite/signing/constants.ts delete mode 100644 src/util/arbundles-lite/signing/index.ts delete mode 100644 src/util/arbundles-lite/signing/keccak256.ts delete mode 100644 src/util/arbundles-lite/signing/keys/Rsa4096Pss.ts delete mode 100644 src/util/arbundles-lite/signing/keys/index.ts delete mode 100644 src/util/arbundles-lite/signing/keys/secp256k1.ts delete mode 100644 src/util/arbundles-lite/tags.ts delete mode 100644 src/util/arbundles-lite/types.ts delete mode 100644 src/util/arbundles-lite/utils.ts delete mode 100644 src/util/create-ethereum-data-item-signer.ts delete mode 100644 src/util/send-aos-message.ts diff --git a/README.md b/README.md index e60b2c3..2969ad0 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ The most important variables: | `RELAY_REWARDS_CONTROLLER_KEY` | Signing key for relay-rewards AO messages. | | `STAKING_REWARDS_PROCESS_ID` | AO process ID for staking rewards. | | `STAKING_REWARDS_CONTROLLER_KEY` | Signing key for staking-rewards AO messages. | -| `CU_URL` | AO Compute Unit URL used by aoconnect. | +| `HB_URL` | Our HyperBEAM node, e.g. `https://hb.anyone.tech`. No default — the service refuses to start without it. | ### MongoDB & Redis diff --git a/operations/facilitator-controller-live.hcl b/operations/facilitator-controller-live.hcl index d7cb089..efa0462 100644 --- a/operations/facilitator-controller-live.hcl +++ b/operations/facilitator-controller-live.hcl @@ -41,7 +41,10 @@ job "facilitator-controller-live" { DO_CLEAN="true" # FACILITY_CONTRACT_DEPLOYED_BLOCK="5674945" FACILITY_CONTRACT_DEPLOYED_BLOCK="24025391" - CU_URL="https://cu.anyone.tech" + # Our own HyperBEAM node — replaces CU_URL (D17). The edge whitelists + # `/~meta@1.0` and `^/{contract-pid}`, covering both the `~process@1.0/now/...` + # reads and the `~process@1.0/push` writes. + HB_URL="https://hb.anyone.tech" USE_HODLER="true" USE_FACILITY="false" HODLER_CONTRACT_DEPLOYED_BLOCK="9257000" diff --git a/operations/facilitator-controller-stage.hcl b/operations/facilitator-controller-stage.hcl index 77dbe28..7ee2751 100644 --- a/operations/facilitator-controller-stage.hcl +++ b/operations/facilitator-controller-stage.hcl @@ -41,7 +41,10 @@ job "facilitator-controller-stage" { DO_CLEAN="true" # FACILITY_CONTRACT_DEPLOYED_BLOCK="5674945" FACILITY_CONTRACT_DEPLOYED_BLOCK="9000000" - CU_URL="https://cu-stage.anyone.tech" + # Our own HyperBEAM node — replaces CU_URL (D17). The edge whitelists + # `/~meta@1.0` and `^/{contract-pid}`, covering both the `~process@1.0/now/...` + # reads and the `~process@1.0/push` writes. + HB_URL="https://hb-stage.anyone.tech" USE_HODLER="true" USE_FACILITY="false" HODLER_CONTRACT_DEPLOYED_BLOCK="9170000" diff --git a/package-lock.json b/package-lock.json index e8f023b..596ec84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,8 @@ "version": "0.4.5", "license": "AGPL-3.0-only", "dependencies": { + "@anyone-protocol/ao-client": "github:anyone-protocol/ao-client#v0.1.2", + "@dha-team/arbundles": "^1.0.4", "@nestjs/axios": "^4.0.1", "@nestjs/bullmq": "^11.0.1", "@nestjs/common": "^11.0.1", @@ -16,7 +18,6 @@ "@nestjs/core": "^11.0.1", "@nestjs/mongoose": "^11.0.3", "@nestjs/platform-express": "^11.0.1", - "@permaweb/aoconnect": "0.0.59", "arweave": "^1.15.5", "base64url": "^3.0.1", "bignumber.js": "^9.1.2", @@ -189,6 +190,17 @@ "tslib": "^2.1.0" } }, + "node_modules/@anyone-protocol/ao-client": { + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/anyone-protocol/ao-client.git#4e18519624cfc1b7e067b311e5b41e3fd684037d", + "license": "AGPL-3.0-only", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@dha-team/arbundles": "^1.0.3" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -771,6 +783,69 @@ "kuler": "^2.0.0" } }, + "node_modules/@dha-team/arbundles": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@dha-team/arbundles/-/arbundles-1.0.4.tgz", + "integrity": "sha512-T/4pv6bosp4caV32EubHTqDzLAqL6481Bsqd348JO0h+HSaMysloY/pFSLwZf9U3IvkJngIZ4njrYQUkjSkkwA==", + "license": "Apache-2.0", + "dependencies": { + "@ethersproject/bytes": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@noble/ed25519": "1.6.1", + "arweave": "1.15.7", + "base64url": "3.0.1", + "bs58": "4.0.1", + "keccak": "3.0.2", + "secp256k1": "5.0.0" + }, + "optionalDependencies": { + "@randlabs/myalgo-connect": "1.1.2", + "algosdk": "1.13.1", + "arweave-stream-tx": "1.1.0", + "multistream": "4.1.0", + "tmp-promise": "3.0.2" + } + }, + "node_modules/@dha-team/arbundles/node_modules/keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "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/@dha-team/arbundles/node_modules/secp256k1": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz", + "integrity": "sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@dha-team/arbundles/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/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -856,175 +931,1278 @@ "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", + "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "9.39.2", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", + "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-provider/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-provider/node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/abstract-provider/node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/abstract-signer/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" + } + }, + "node_modules/@ethersproject/address/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0" + } + }, + "node_modules/@ethersproject/base64/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", + "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/properties": "^5.8.0" + } + }, + "node_modules/@ethersproject/basex/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bignumber/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.8.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.8.0.tgz", + "integrity": "sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" + } + }, + "node_modules/@ethersproject/hdnode/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/hdnode/node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/hdnode/node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz", + "integrity": "sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/@ethersproject/signing-key": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "bn.js": "^5.2.1", + "elliptic": "6.6.1", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/@ethersproject/transactions": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" + } + }, + "node_modules/@ethersproject/json-wallets/node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "license": "MIT" + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/keccak256/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", + "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/sha2": "^5.8.0" + } + }, + "node_modules/@ethersproject/pbkdf2/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/random": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", + "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/random/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/rlp/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "hash.js": "1.1.7" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", + "node_modules/@ethersproject/sha2/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ethersproject/signing-key/node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "license": "MIT", "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "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/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, + "node_modules/@ethersproject/signing-key/node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "license": "MIT" + }, + "node_modules/@ethersproject/strings": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "license": "MIT", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, + "node_modules/@ethersproject/strings/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" } }, - "node_modules/@eslint/eslintrc/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, + "node_modules/@ethersproject/web/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "dependencies": { + "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node_modules/@ethersproject/wordlists": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.8.0.tgz", + "integrity": "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", + "node_modules/@ethersproject/wordlists/node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "@ethersproject/logger": "^5.8.0" } }, - "node_modules/@fastify/busboy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", - "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", + "node_modules/@ethersproject/wordlists/node_modules/@ethersproject/hash": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], "license": "MIT", - "engines": { - "node": ">=14" + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@humanfs/core": { @@ -2516,6 +3694,18 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@noble/ed25519": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.6.1.tgz", + "integrity": "sha512-Gptpue6qPmg7p1E5LBO5GDtXw5WMc2DVtUmu4EQequOcoCvum1dT9sY6s9M8aSJWq9YopCN4jmTOAvqMdw3q7w==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT" + }, "node_modules/@noble/hashes": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.2.tgz", @@ -2538,37 +3728,6 @@ "@noble/hashes": "^1.1.5" } }, - "node_modules/@permaweb/ao-scheduler-utils": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@permaweb/ao-scheduler-utils/-/ao-scheduler-utils-0.0.29.tgz", - "integrity": "sha512-tzuNsy2NUcATLMG+SKaO1PxbXaDpfoQikEfI7BABkNWk6AyQoBLy0Zwuu0eypGEHeNP6gugXEo1j8oZez/8fXA==", - "dependencies": { - "lru-cache": "^10.2.2", - "ramda": "^0.30.0", - "zod": "^3.23.5" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@permaweb/aoconnect": { - "version": "0.0.59", - "resolved": "https://registry.npmjs.org/@permaweb/aoconnect/-/aoconnect-0.0.59.tgz", - "integrity": "sha512-AgnUv50hp3BVvqWk2IOw3p9ksF2GblFwQHCIWqwTYjvdViCPlsL4gx/BefxFqbMABXQ5q2QJItMJLlPelqC2CQ==", - "dependencies": { - "@permaweb/ao-scheduler-utils": "~0.0.23", - "buffer": "^6.0.3", - "debug": "^4.3.6", - "hyper-async": "^1.1.2", - "mnemonist": "^0.39.8", - "ramda": "^0.30.1", - "warp-arbundles": "^1.0.4", - "zod": "^3.23.8" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -2593,6 +3752,23 @@ "url": "https://opencollective.com/pkgr" } }, + "node_modules/@randlabs/communication-bridge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@randlabs/communication-bridge/-/communication-bridge-1.0.1.tgz", + "integrity": "sha512-CzS0U8IFfXNK7QaJFE4pjbxDGfPjbXBEsEaCn9FN15F+ouSAEUQkva3Gl66hrkBZOGexKFEWMwUHIDKpZ2hfVg==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/@randlabs/myalgo-connect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@randlabs/myalgo-connect/-/myalgo-connect-1.1.2.tgz", + "integrity": "sha512-UPsdWfZmnRvEuGL83MNolSzVRDfCo4cURA5Bxi9whRcoglEte3hUgEwbxesaeCnpByvgLNYM9YBbjBb8Bh9PqQ==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@randlabs/communication-bridge": "^1.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.34.49", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz", @@ -3883,6 +5059,110 @@ "ajv": "^8.8.2" } }, + "node_modules/algo-msgpack-with-bigint": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz", + "integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/algosdk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-1.13.1.tgz", + "integrity": "sha512-htyJI1/zVcOzpNZVT8PHn4K0yXXTS+b7RXplc7nmFqGVThbM8+ufbnBLChxVPh3BVxqqpqS13VTsQcNArK10jg==", + "license": "MIT", + "optional": true, + "dependencies": { + "algo-msgpack-with-bigint": "^2.1.1", + "buffer": "^6.0.2", + "hi-base32": "^0.5.1", + "js-sha256": "^0.9.0", + "js-sha3": "^0.8.0", + "js-sha512": "^0.8.0", + "json-bigint": "^1.0.0", + "superagent": "^6.1.0", + "tweetnacl": "^1.0.3", + "url-parse": "^1.5.1" + } + }, + "node_modules/algosdk/node_modules/form-data": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.5.tgz", + "integrity": "sha512-j23EibVLnp4zNXGW7LjryXYa2X6U/M96yoOX+ybZxwkYajdxRNEqYY3zhh7y0i6kfISKS2jr+EJq1YTUDEv5+w==", + "license": "MIT", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/algosdk/node_modules/formidable": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz", + "integrity": "sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "license": "MIT", + "optional": true, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/algosdk/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/algosdk/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/algosdk/node_modules/superagent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "deprecated": "Please upgrade to superagent v10.2.2+, see release notes at https://github.com/forwardemail/superagent/releases/tag/v10.2.2 - maintenance is supported by Forward Email @ https://forwardemail.net", + "license": "MIT", + "optional": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 7.0.0" + } + }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -4022,6 +5302,19 @@ "node": ">=18" } }, + "node_modules/arweave-stream-tx": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arweave-stream-tx/-/arweave-stream-tx-1.1.0.tgz", + "integrity": "sha512-1BEYGFSP+FP1ACfclTjSjSTWx5PV/7a+0TwGZu+MlkmnnZTQ3hCOr5Md2Pi/T6dc69Fj+BRezSckiIhKFwTc3g==", + "optional": true, + "dependencies": { + "exponential-backoff": "^3.1.0", + "stream-chunker": "^1.2.8" + }, + "peerDependencies": { + "arweave": "^1.10.0" + } + }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", @@ -4180,6 +5473,15 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "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/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -4219,6 +5521,12 @@ "baseline-browser-mapping": "dist/cli.js" } }, + "node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "license": "MIT" + }, "node_modules/bignumber.js": { "version": "9.3.1", "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", @@ -4384,6 +5692,15 @@ "node": ">= 6" } }, + "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/bser": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", @@ -4422,6 +5739,7 @@ } ], "license": "MIT", + "optional": true, "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.2.1" @@ -4866,7 +6184,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz", "integrity": "sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==", - "dev": true, + "devOptional": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4968,9 +6286,16 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", - "dev": true, + "devOptional": true, "license": "MIT" }, + "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", + "optional": true + }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", @@ -5839,6 +7164,13 @@ "node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0" } }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0", + "optional": true + }, "node_modules/express": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", @@ -6620,6 +7952,13 @@ "node": ">= 0.4" } }, + "node_modules/hi-base32": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz", + "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==", + "license": "MIT", + "optional": true + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -6682,15 +8021,6 @@ "node": ">=10.17.0" } }, - "node_modules/hyper-async": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/hyper-async/-/hyper-async-1.2.0.tgz", - "integrity": "sha512-7wvJxzAEBREKotXGuHOSri8/J+D0oURqCbNmn8g7Ym8hVMJQkGCMMS9y2/GktMtRyxPVcw2xWFh2oPa970PmXQ==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -6950,6 +8280,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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", + "optional": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -7732,6 +9069,26 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==", + "license": "MIT", + "optional": true + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, + "node_modules/js-sha512": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", + "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==", + "license": "MIT", + "optional": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7781,6 +9138,16 @@ "node": ">=6" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -8052,6 +9419,7 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, "license": "ISC" }, "node_modules/luxon": { @@ -8167,7 +9535,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -8204,7 +9572,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", - "dev": true, + "devOptional": true, "license": "MIT", "bin": { "mime": "cli.js" @@ -8296,15 +9664,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mnemonist": { - "version": "0.39.8", - "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.8.tgz", - "integrity": "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==", - "license": "MIT", - "dependencies": { - "obliterator": "^2.0.1" - } - }, "node_modules/mongodb": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz", @@ -8505,6 +9864,31 @@ "node": ">= 0.6" } }, + "node_modules/multistream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/multistream/-/multistream-4.1.0.tgz", + "integrity": "sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0", + "readable-stream": "^3.6.0" + } + }, "node_modules/mute-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", @@ -8674,12 +10058,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/obliterator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.5.tgz", - "integrity": "sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==", - "license": "MIT" - }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -9127,6 +10505,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "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", + "optional": true + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -9191,15 +10576,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ramda": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz", - "integrity": "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==", + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ramda" - } + "optional": true }, "node_modules/range-parser": { "version": "1.2.1", @@ -9318,6 +10700,13 @@ "node": ">=0.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "license": "MIT", + "optional": true + }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -9541,6 +10930,12 @@ "dev": true, "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": "5.0.1", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.1.tgz", @@ -9843,6 +11238,16 @@ "node": ">= 0.8" } }, + "node_modules/stream-chunker": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/stream-chunker/-/stream-chunker-1.2.8.tgz", + "integrity": "sha512-1j0PRZxgxJ8pPRyLlFu6Eer2imfhx1f++644xu/ZGRReDanv4frTSTWwNidtZOHJKwi86ue2KOWHFyikkQWN8w==", + "license": "MIT", + "optional": true, + "dependencies": { + "through2": "~2.0.0" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -10291,6 +11696,50 @@ "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "license": "MIT" }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/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", + "optional": true, + "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/through2/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", + "optional": true + }, + "node_modules/through2/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", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -10308,6 +11757,26 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.2.tgz", + "integrity": "sha512-OyCLAKU1HzBjL6Ev3gxUeraJNlbNingmi8IrHHEsYH8LTmEuhvYfqvhn2F/je+mjf4N58UmZ96OMEy1JanSCpA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tmp": "^0.2.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -10567,6 +12036,13 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "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", + "optional": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -10692,18 +12168,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/undici": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", - "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", - "license": "MIT", - "dependencies": { - "@fastify/busboy": "^2.0.0" - }, - "engines": { - "node": ">=14.0" - } - }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -10809,6 +12273,17 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -10870,31 +12345,6 @@ "makeerror": "1.0.12" } }, - "node_modules/warp-arbundles": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/warp-arbundles/-/warp-arbundles-1.0.4.tgz", - "integrity": "sha512-KeRac/EJ7VOK+v5+PSMh2SrzpCKOAFnJICLlqZWt6qPkDCzVwcrNE5wFxOlEk5U170ewMDAB3e86UHUblevXpw==", - "license": "ISC", - "dependencies": { - "arweave": "^1.13.7", - "base64url": "^3.0.1", - "buffer": "^6.0.3", - "warp-isomorphic": "^1.0.7" - } - }, - "node_modules/warp-isomorphic": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/warp-isomorphic/-/warp-isomorphic-1.0.7.tgz", - "integrity": "sha512-fXHbUXwdYqPm9fRPz8mjv5ndPco09aMQuTe4kXfymzOq8V6F3DLsg9cIafxvjms9/mc6eijzkLBJ63yjEENEjA==", - "license": "MIT", - "dependencies": { - "buffer": "^6.0.3", - "undici": "^5.19.1" - }, - "engines": { - "node": ">=16.8.0" - } - }, "node_modules/watchpack": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", @@ -11229,6 +12679,16 @@ } } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.4" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -11320,15 +12780,6 @@ "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" - } } } } diff --git a/package.json b/package.json index 0659bed..3fe71fe 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,8 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "dependencies": { + "@anyone-protocol/ao-client": "github:anyone-protocol/ao-client#v0.1.2", + "@dha-team/arbundles": "^1.0.4", "@nestjs/axios": "^4.0.1", "@nestjs/bullmq": "^11.0.1", "@nestjs/common": "^11.0.1", @@ -36,7 +38,6 @@ "@nestjs/core": "^11.0.1", "@nestjs/mongoose": "^11.0.3", "@nestjs/platform-express": "^11.0.1", - "@permaweb/aoconnect": "0.0.59", "arweave": "^1.15.5", "base64url": "^3.0.1", "bignumber.js": "^9.1.2", diff --git a/src/relay-rewards/relay-rewards.service.spec.ts b/src/relay-rewards/relay-rewards.service.spec.ts new file mode 100644 index 0000000..fe2013b --- /dev/null +++ b/src/relay-rewards/relay-rewards.service.spec.ts @@ -0,0 +1,91 @@ +/** + * INTEGRATION test — talks to a real HyperBEAM node holding a real relay-rewards process. + * + * Requires: + * HB_URL, RELAY_REWARDS_PROCESS_ID, RELAY_REWARDS_CONTROLLER_KEY (owner/admin, or a + * Claim-Rewards role holder — the facilitator claims ON BEHALF of an address). + * + * To stand one up locally see smart-contracts/ao/scripts/run-e2e.ts. + */ +import { Logger } from '@nestjs/common' +import { ConfigModule } from '@nestjs/config' +import { Test, TestingModule } from '@nestjs/testing' + +import { RelayRewardsService } from './relay-rewards.service' + +const HAVE_NODE = !!process.env.RELAY_REWARDS_PROCESS_ID && !!process.env.HB_URL +const itNode = HAVE_NODE ? it : it.skip + +describe('RelayRewardsService', () => { + let module: TestingModule + let service: RelayRewardsService + + beforeEach(async () => { + module = await Test.createTestingModule({ + imports: [ConfigModule.forRoot({ isGlobal: true })], + providers: [RelayRewardsService] + }) + .setLogger(new Logger()) + .compile() + service = module.get(RelayRewardsService) + await service.onApplicationBootstrap() + }) + + afterEach(async () => { + await module.close() + }) + + it('should be defined', () => { + expect(service).toBeDefined() + }) + + itNode('reads an allocation for a seeded address', async () => { + // Pick a real rewarded address out of the migrated state rather than inventing one. + const rewards: any = await (service as any).ao.readView( + process.env.RELAY_REWARDS_PROCESS_ID, + 'dump' + ) + const [address] = Object.keys(rewards.TotalAddressReward) + expect(address).toBeDefined() + + const allocation = await service.getAllocation(address) + + // The `rewards` view returns { address, reward } — the amount is a FIELD now, where the + // legacy Get-Rewards dryrun made it the whole response body. + expect(allocation).toBeDefined() + expect(allocation.address).toBe(address) + expect(allocation.amount).toMatch(/^\d+$/) + expect(BigInt(allocation.amount)).toBeGreaterThan(0n) + }, 120_000) + + itNode('returns undefined for an address with no allocation', async () => { + const allocation = await service.getAllocation('0x' + '9'.repeat(40)) + + expect(allocation).toBeUndefined() + }, 120_000) + + itNode('claims rewards for a seeded address', async () => { + const rewards: any = await (service as any).ao.readView( + process.env.RELAY_REWARDS_PROCESS_ID, + 'dump' + ) + const [address] = Object.keys(rewards.TotalAddressReward) + + const claimed = await service.claimRewards(address) + + expect(claimed.kind).toBe('relay') + expect(claimed.noReward).toBeUndefined() + expect(BigInt(claimed.amount)).toBeGreaterThan(0n) + }, 180_000) + + itNode('reports noReward when the contract says there is none', async () => { + // The contract asserts 'No rewards for '. That arrives as an AoContractError, NOT + // as an HTTP failure — a client trusting the status code would report a successful claim + // of nothing here. + const claimed = await service.claimRewards('0x' + '8'.repeat(40)) + + expect(claimed.noReward).toBe(true) + expect(claimed.amount).toBe('0') + expect(claimed.kind).toBe('relay') + }, 180_000) +}) diff --git a/src/relay-rewards/relay-rewards.service.ts b/src/relay-rewards/relay-rewards.service.ts index 5913ee4..22fec3f 100644 --- a/src/relay-rewards/relay-rewards.service.ts +++ b/src/relay-rewards/relay-rewards.service.ts @@ -3,13 +3,13 @@ import { ConfigService } from '@nestjs/config' import BigNumber from 'bignumber.js' import _ from 'lodash' +import { EthereumSigner } from '@dha-team/arbundles' import { - AosSigningFunction, - sendAosDryRun, - sendAosMessage -} from '../util/send-aos-message' -import { createEthereumDataItemSigner } from '../util/create-ethereum-data-item-signer' -import { EthereumSigner } from '../util/arbundles-lite' + AoClient, + AoContractError, + createAoClient, + nodeUrlFromEnv +} from '@anyone-protocol/ao-client' import { Wallet } from 'ethers' import { ClaimedRewardsData } from 'src/events/dto/claimed-rewards-data' @@ -22,8 +22,9 @@ export class RelayRewardsService { private readonly relayRewardsProcessId: string private readonly relayRewardsControllerKey: string + private readonly hbUrl: string - private signer!: AosSigningFunction + private ao!: AoClient constructor( @@ -31,6 +32,7 @@ export class RelayRewardsService { IS_LIVE: string RELAY_REWARDS_PROCESS_ID: string RELAY_REWARDS_CONTROLLER_KEY: string + HB_URL: string }> ) { this.isLive = config.get('IS_LIVE', { infer: true }) @@ -51,37 +53,58 @@ export class RelayRewardsService { if (this.relayRewardsControllerKey == undefined) { this.logger.warn('Missing RELAY_REWARDS_CONTROLLER_KEY. This is ok only if this is non-hodler deploy') } + + // Fail closed, no default. Replaces CU_URL. + this.hbUrl = nodeUrlFromEnv({ + HB_URL: this.config.get('HB_URL', { infer: true }) + }) } async onApplicationBootstrap() { + // The key is optional on a non-hodler deploy, and getAllocation is a read. Build a + // read-only client when there is no key rather than refusing to start. + this.ao = createAoClient({ + url: this.hbUrl, + ...(this.relayRewardsControllerKey + ? { signer: new EthereumSigner(this.relayRewardsControllerKey) } + : {}), + logger: { + debug: (m, ...meta) => this.logger.debug(m, ...meta), + warn: (m, ...meta) => this.logger.warn(m, ...meta), + error: (m, ...meta) => this.logger.error(m, ...meta) + } + }) + if (this.relayRewardsControllerKey) { - this.signer = await createEthereumDataItemSigner( - new EthereumSigner(this.relayRewardsControllerKey) - ) const wallet = new Wallet(this.relayRewardsControllerKey) const address = await wallet.getAddress() - this.logger.log(`Bootstrapped with signer address ${address}`) + this.logger.log(`Bootstrapped with signer address ${address} against node ${this.hbUrl}`) + } else { + this.logger.log(`Bootstrapped READ-ONLY (no controller key) against node ${this.hbUrl}`) } } + /** + * Cumulative reward owed to an address. + * + * Was a `Get-Rewards` dryrun whose response body WAS the bare amount. The native contract + * serves this as the `rewards` view, which returns `{ address, reward }` — so the amount is + * a field, not the whole body. An address with no rewards yields no `reward` key at all. + */ public async getAllocation( address: string ): Promise<{ address: string, amount: string }> { - const { result } = await sendAosDryRun({ - processId: this.relayRewardsProcessId, - tags: [ - { name: 'Action', value: 'Get-Rewards' }, - { name: 'Address', value: address } - ] - }) - - this.logger.log(`Get-Rewards response from AO for ${address}: ${result.Messages[0].Data}`) + const result = await this.ao.readView<{ address: string, reward?: string }>( + this.relayRewardsProcessId, + 'rewards', + { address } + ) - const amount = BigNumber(JSON.parse(result.Messages[0].Data)).toFixed(0) + const amount = BigNumber(result?.reward).toFixed(0) if (amount === 'NaN') { this.logger.warn( - `Undefined amount for ${address}: ${result.Messages[0].Data} -> ${amount}` + `Undefined amount for ${address}: ${JSON.stringify(result)} -> ${amount}` ) return undefined @@ -95,33 +118,24 @@ export class RelayRewardsService { public async claimRewards( address: string ): Promise { - const { result } = await sendAosMessage({ - processId: this.relayRewardsProcessId, - signer: this.signer as any, - tags: [ - { name: 'Action', value: 'Claim-Rewards' }, - { name: 'Address', value: address }, - { name: 'Claim-Rewards-Timestamp', value: Date.now().toString() } - ] - }) - - this.logger.debug(`Claim-Rewards response from AO for ${address}: ${result}`) - - if (!result.Messages || result.Messages.length < 2 || !result.Messages[1]?.Data) { - if (result.Error && !result.Error.includes('No rewards for ')) { - this.logger.error(`No messages in Claim-Rewards response from AO for ${address}, Response: ${JSON.stringify(result.Error)}`) - return { address, amount: '0', kind: 'relay' } - } else { - this.logger.warn(`No rewards for ${address} -> error: ${result.Error}, messages: ${JSON.stringify(result.Messages)}`) - return { address, amount: '0', kind: 'relay', noReward: true } - } - } else { - const amount = BigNumber(JSON.parse(result.Messages[1].Data)).toFixed(0) + try { + // `Claim-Rewards` is role-gated and takes the beneficiary as a tag — the facilitator + // claims ON BEHALF of an address, so `ctx.from` is us, not them. Claim-Rewards-Timestamp + // is not read by the contract; kept for the audit trail on the message. + const { output } = await this.ao.sendMessage({ + processId: this.relayRewardsProcessId, + action: 'Claim-Rewards', + tags: [ + { name: 'address', value: address }, + { name: 'claim-rewards-timestamp', value: Date.now().toString() } + ] + }) + + // The handler returns the claimed total as a JSON-encoded string. + const amount = BigNumber(JSON.parse(output ?? 'null')).toFixed(0) if (amount === 'NaN') { - this.logger.warn( - `Undefined amount for ${address}: ${result.Messages[1].Data} -> ${amount}` - ) + this.logger.warn(`Undefined amount for ${address}: ${output} -> ${amount}`) return { address, amount: '0', kind: 'relay' } } @@ -129,6 +143,22 @@ export class RelayRewardsService { this.logger.log(`Claimed rewards for ${address}: ${amount}`) return { address, amount, kind: 'relay' } + } catch (error) { + // "No rewards for " is the contract's own assert and an expected outcome, not a + // fault — it is what `noReward` has always meant here. Anything else is a real failure. + if (error instanceof AoContractError) { + if (error.reason.includes('No rewards for ')) { + this.logger.warn(`No rewards for ${address}: ${error.reason}`) + + return { address, amount: '0', kind: 'relay', noReward: true } + } + + this.logger.error(`Claim-Rewards rejected for ${address}: ${error.reason}`) + } else { + this.logger.error(`Exception claiming rewards for ${address}`, error.stack) + } + + return { address, amount: '0', kind: 'relay' } } } } diff --git a/src/staking-rewards/staking-rewards.service.spec.ts b/src/staking-rewards/staking-rewards.service.spec.ts new file mode 100644 index 0000000..8e243cf --- /dev/null +++ b/src/staking-rewards/staking-rewards.service.spec.ts @@ -0,0 +1,64 @@ +/** + * INTEGRATION test — talks to a real HyperBEAM node holding a real staking-rewards process. + * + * Requires: HB_URL, STAKING_REWARDS_PROCESS_ID, STAKING_REWARDS_CONTROLLER_KEY. + */ +import { Logger } from '@nestjs/common' +import { ConfigModule } from '@nestjs/config' +import { Test, TestingModule } from '@nestjs/testing' + +import { StakingRewardsService } from './staking-rewards.service' + +const HAVE_NODE = !!process.env.STAKING_REWARDS_PROCESS_ID && !!process.env.HB_URL +const itNode = HAVE_NODE ? it : it.skip + +describe('StakingRewardsService', () => { + let module: TestingModule + let service: StakingRewardsService + + beforeEach(async () => { + module = await Test.createTestingModule({ + imports: [ConfigModule.forRoot({ isGlobal: true })], + providers: [StakingRewardsService] + }) + .setLogger(new Logger()) + .compile() + service = module.get(StakingRewardsService) + await service.onApplicationBootstrap() + }) + + afterEach(async () => { + await module.close() + }) + + it('should be defined', () => { + expect(service).toBeDefined() + }) + + itNode('claims rewards for a seeded hodler and sums across operators', async () => { + const dump: any = await (service as any).ao.readView( + process.env.STAKING_REWARDS_PROCESS_ID, + 'dump' + ) + const [hodler] = Object.keys(dump.Rewarded) + expect(hodler).toBeDefined() + + const claimed = await service.claimRewards(hodler) + + // Staking returns the PER-OPERATOR map, which the service sums — unlike relay, which + // returns a single amount. That difference is the contract's, not the client's. + expect(claimed.kind).toBe('staking') + expect(claimed.noReward).toBeUndefined() + const expected = Object.values(dump.Rewarded[hodler] as Record) + .reduce((acc, v) => acc + BigInt(v), 0n) + expect(BigInt(claimed.amount)).toBe(expected) + }, 180_000) + + itNode('reports noReward when the contract says there is none', async () => { + const claimed = await service.claimRewards('0x' + '8'.repeat(40)) + + expect(claimed.noReward).toBe(true) + expect(claimed.amount).toBe('0') + expect(claimed.kind).toBe('staking') + }, 180_000) +}) diff --git a/src/staking-rewards/staking-rewards.service.ts b/src/staking-rewards/staking-rewards.service.ts index 175759e..3379a0e 100644 --- a/src/staking-rewards/staking-rewards.service.ts +++ b/src/staking-rewards/staking-rewards.service.ts @@ -3,13 +3,13 @@ import { ConfigService } from '@nestjs/config' import BigNumber from 'bignumber.js' import _ from 'lodash' +import { EthereumSigner } from '@dha-team/arbundles' import { - AosSigningFunction, - sendAosDryRun, - sendAosMessage -} from '../util/send-aos-message' -import { createEthereumDataItemSigner } from '../util/create-ethereum-data-item-signer' -import { EthereumSigner } from '../util/arbundles-lite' + AoClient, + AoContractError, + createAoClient, + nodeUrlFromEnv +} from '@anyone-protocol/ao-client' import { Wallet } from 'ethers' import { ClaimedRewardsData } from 'src/events/dto/claimed-rewards-data' @@ -22,14 +22,16 @@ export class StakingRewardsService implements OnApplicationBootstrap { private readonly stakingRewardsProcessId: string private readonly stakingRewardsControllerKey: string + private readonly hbUrl: string - private signer!: AosSigningFunction + private ao!: AoClient constructor( private readonly config: ConfigService<{ IS_LIVE: string STAKING_REWARDS_PROCESS_ID: string STAKING_REWARDS_CONTROLLER_KEY: string + HB_URL: string }> ) { this.isLive = config.get('IS_LIVE', { infer: true }) @@ -50,56 +52,65 @@ export class StakingRewardsService implements OnApplicationBootstrap { if (this.stakingRewardsControllerKey == undefined) { this.logger.warn('Missing STAKING_REWARDS_CONTROLLER_KEY. This is ok only if this is non-hodler deploy') } + + // Fail closed, no default. Replaces CU_URL. + this.hbUrl = nodeUrlFromEnv({ + HB_URL: this.config.get('HB_URL', { infer: true }) + }) } async onApplicationBootstrap() { + // The key is optional on a non-hodler deploy. Build a read-only client without one + // rather than refusing to start. + this.ao = createAoClient({ + url: this.hbUrl, + ...(this.stakingRewardsControllerKey + ? { signer: new EthereumSigner(this.stakingRewardsControllerKey) } + : {}), + logger: { + debug: (m, ...meta) => this.logger.debug(m, ...meta), + warn: (m, ...meta) => this.logger.warn(m, ...meta), + error: (m, ...meta) => this.logger.error(m, ...meta) + } + }) + if (this.stakingRewardsControllerKey) { - this.signer = await createEthereumDataItemSigner( - new EthereumSigner(this.stakingRewardsControllerKey) - ) const wallet = new Wallet(this.stakingRewardsControllerKey) const address = await wallet.getAddress() - this.logger.log(`Bootstrapped with signer address ${address}`) + this.logger.log(`Bootstrapped with signer address ${address} against node ${this.hbUrl}`) + } else { + this.logger.log(`Bootstrapped READ-ONLY (no controller key) against node ${this.hbUrl}`) } } public async claimRewards( address: string ): Promise { - const { result } = await sendAosMessage({ - processId: this.stakingRewardsProcessId, - signer: this.signer as any, - tags: [ - { name: 'Action', value: 'Claim-Rewards' }, - { name: 'Address', value: address }, - { name: 'Claim-Rewards-Timestamp', value: Date.now().toString() } - ] - }) - - this.logger.debug(`Claim-Rewards response from AO for ${address}: ${result}`) - - if (!result.Messages || result.Messages.length < 2 || !result.Messages[1]?.Data) { - if (result.Error && !result.Error.includes('No rewards for ')) { - this.logger.error(`No messages in Claim-Rewards response from AO for ${address}, Response: ${JSON.stringify(result.Error)}`) - return { address, amount: '0', kind: 'staking' } - } else { - this.logger.warn(`No rewards for ${address} -> error: ${result.Error}, messages: ${JSON.stringify(result.Messages)}`) - return { address, amount: '0', kind: 'staking', noReward: true } - } - } else { + try { + // Role-gated, and takes the beneficiary as a tag — the facilitator claims ON BEHALF of + // an address, so `ctx.from` is us. Claim-Rewards-Timestamp is not read by the contract; + // kept for the audit trail on the message. + const { output } = await this.ao.sendMessage({ + processId: this.stakingRewardsProcessId, + action: 'Claim-Rewards', + tags: [ + { name: 'address', value: address }, + { name: 'claim-rewards-timestamp', value: Date.now().toString() } + ] + }) + + // Unlike relay, staking returns the hodler's PER-OPERATOR reward map, which the caller + // wants as one total. That shape is the contract's, not a client artefact. + const rewardsPerOperator = JSON.parse(output ?? 'null') ?? {} let totalRewards = BigNumber(0) - const rewardsPerOperator = JSON.parse(result.Messages[1].Data) for (const operator of Object.keys(rewardsPerOperator)) { - const amount = BigNumber(rewardsPerOperator[operator]) - totalRewards = totalRewards.plus(amount) + totalRewards = totalRewards.plus(BigNumber(rewardsPerOperator[operator])) } const rewarded = totalRewards.toFixed(0) if (rewarded === 'NaN') { - this.logger.warn( - `Undefined amount for ${address}: ${result.Messages[1].Data}` - ) + this.logger.warn(`Undefined amount for ${address}: ${output}`) return { address, amount: '0', kind: 'staking' } } @@ -107,6 +118,21 @@ export class StakingRewardsService implements OnApplicationBootstrap { this.logger.log(`Got allocation for ${address}: ${rewarded}`) return { address, amount: rewarded, kind: 'staking' } + } catch (error) { + // "No rewards for " is the contract's own assert and an expected outcome. + if (error instanceof AoContractError) { + if (error.reason.includes('No rewards for ')) { + this.logger.warn(`No rewards for ${address}: ${error.reason}`) + + return { address, amount: '0', kind: 'staking', noReward: true } + } + + this.logger.error(`Claim-Rewards rejected for ${address}: ${error.reason}`) + } else { + this.logger.error(`Exception claiming rewards for ${address}`, error.stack) + } + + return { address, amount: '0', kind: 'staking' } } } } diff --git a/src/util/arbundles-lite/Bundle.ts b/src/util/arbundles-lite/Bundle.ts deleted file mode 100644 index c9f62bb..0000000 --- a/src/util/arbundles-lite/Bundle.ts +++ /dev/null @@ -1,192 +0,0 @@ -import base64url from 'base64url' -import { byteArrayToLong } from './utils' -import DataItem from './DataItem' -import type Arweave from 'arweave' -import type { BundleInterface } from './BundleInterface' -import type { JWKInterface } from 'arweave/node/lib/wallet' -import { createHash } from 'crypto' -import type { CreateTransactionInterface, Transaction } from './utils' - -const HEADER_START = 32 - -export class Bundle implements BundleInterface { - public length: number - public items: DataItem[] - protected binary: Buffer - - constructor(binary: Buffer) { - this.binary = binary - this.length = this.getDataItemCount() - this.items = this.getItems() - } - - public getRaw(): Buffer { - return this.binary - } - - /** - * Get a DataItem by index (`number`) or by txId (`string`) - * @param index - */ - public get(index: number | string): DataItem { - if (typeof index === 'number') { - if (index >= this.length) { - throw new RangeError('Index out of range') - } - - return this.getByIndex(index) - } else { - return this.getById(index) - } - } - - public getSizes(): number[] { - const ids: number[] = [] - for (let i = HEADER_START; i < HEADER_START + 64 * this.length; i += 64) { - ids.push(byteArrayToLong(this.binary.subarray(i, i + 32))) - } - - return ids - } - - public getIds(): string[] { - const ids: string[] = [] - for (let i = HEADER_START; i < HEADER_START + 64 * this.length; i += 64) { - const bundleId = this.binary.subarray(i + 32, i + 64) - if (bundleId.length === 0) { - throw new Error("Invalid bundle, id specified in headers doesn't exist") - } - ids.push(base64url.encode(bundleId)) - } - - return ids - } - - public getIdBy(index: number): string { - if (index > this.length - 1) { - throw new RangeError('Index of bundle out of range') - } - - const start = 64 + 64 * index - return base64url.encode(this.binary.subarray(start, start + 32)) - } - - public async toTransaction( - attributes: Partial>, - arweave: Arweave, - jwk: JWKInterface - ): Promise { - const tx = await arweave.createTransaction( - { data: this.binary, ...attributes }, - jwk - ) - tx.addTag('Bundle-Format', 'binary') - tx.addTag('Bundle-Version', '2.0.0') - return tx - } - - public async verify(): Promise { - for (const item of this.items) { - const valid = await item.isValid() - const expected = base64url( - createHash('sha256').update(item.rawSignature).digest() - ) - if (!(valid && item.id === expected)) { - return false - } - } - - return true - } - - private getOffset(id: Uint8Array): { startOffset: number; size: number } { - let offset = 0 - for (let i = HEADER_START; i < HEADER_START + 64 * this.length; i += 64) { - const _offset = byteArrayToLong(this.binary.subarray(i, i + 32)) - offset += _offset - const _id = this.binary.subarray(i + 32, i + 64) - - if (Buffer.compare(_id, id) === 0) { - return { startOffset: offset, size: _offset } - } - } - - return { startOffset: -1, size: -1 } - } - - // TODO: Test this - /** - * UNSAFE! Assumes index < length - * @param index - * @private - */ - private getByIndex(index: number): DataItem { - let offset = 0 - const bundleStart = this.getBundleStart() - let counter = 0 - let _offset, _id - for (let i = HEADER_START; i < HEADER_START + 64 * this.length; i += 64) { - _offset = byteArrayToLong(this.binary.subarray(i, i + 32)) - if (counter++ === index) { - _id = this.binary.subarray(i + 32, i + 64) - break - } - offset += _offset - } - const dataItemStart = bundleStart + offset - const slice = this.binary.subarray(dataItemStart, dataItemStart + _offset) - const item = new DataItem(slice) - item.rawId = _id - return item - } - - private getById(id: string): DataItem { - const _id = base64url.toBuffer(id) - - const offset = this.getOffset(_id) - if (offset.startOffset === -1) { - throw new Error('Transaction not found') - } - - const bundleStart = this.getBundleStart() - const dataItemStart = bundleStart + offset.startOffset - return new DataItem( - this.binary.subarray(dataItemStart, dataItemStart + offset.size) - ) - } - - private getDataItemCount(): number { - return byteArrayToLong(this.binary.subarray(0, 32)) - } - - private getBundleStart(): number { - return 32 + 64 * this.length - } - - private getItems(): DataItem[] { - const items = new Array(this.length) - let offset = 0 - const bundleStart = this.getBundleStart() - - let counter = 0 - for (let i = HEADER_START; i < HEADER_START + 64 * this.length; i += 64) { - const _offset = byteArrayToLong(this.binary.subarray(i, i + 32)) - const _id = this.binary.subarray(i + 32, i + 64) - if (_id.length === 0) { - throw new Error("Invalid bundle, id specified in headers doesn't exist") - } - const dataItemStart = bundleStart + offset - const bytes = this.binary.subarray(dataItemStart, dataItemStart + _offset) - - offset += _offset - - const item = new DataItem(bytes) - item.rawId = _id - items[counter] = item - - counter++ - } - return items - } -} -export default Bundle diff --git a/src/util/arbundles-lite/BundleInterface.ts b/src/util/arbundles-lite/BundleInterface.ts deleted file mode 100644 index bdf7423..0000000 --- a/src/util/arbundles-lite/BundleInterface.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { BundleItem } from './BundleItem' -import type Arweave from 'arweave' -import type { JWKInterface } from 'arweave/node/lib/wallet' -import type { CreateTransactionInterface, Transaction } from './utils' - -type ResolvesTo = T | Promise | ((...args: any[]) => Promise) - -export interface BundleInterface { - readonly length: ResolvesTo - readonly items: BundleItem[] | AsyncGenerator - get(index: number | string): BundleItem | Promise - getIds(): string[] | Promise - getRaw(): ResolvesTo - toTransaction( - attributes: Partial, - arweave: Arweave, - jwk: JWKInterface - ): Promise -} diff --git a/src/util/arbundles-lite/BundleItem.ts b/src/util/arbundles-lite/BundleItem.ts deleted file mode 100644 index bef77e1..0000000 --- a/src/util/arbundles-lite/BundleItem.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Signer } from './signing/index' -import type { Buffer } from 'buffer' - -type ResolvesTo = T | Promise | ((...args: any[]) => Promise) - -export abstract class BundleItem { - readonly signatureType: ResolvesTo - readonly rawSignature: ResolvesTo - readonly signature: ResolvesTo - readonly signatureLength: ResolvesTo - readonly rawOwner: ResolvesTo - readonly owner: ResolvesTo - readonly ownerLength: ResolvesTo - readonly rawTarget: ResolvesTo - readonly target: ResolvesTo - readonly rawAnchor: ResolvesTo - readonly anchor: ResolvesTo - readonly rawTags: ResolvesTo - readonly tags: ResolvesTo<{ name: string; value: string }[]> - readonly rawData: ResolvesTo - readonly data: ResolvesTo - abstract sign(signer: Signer): Promise - abstract isValid(): Promise - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - static async verify(..._: any[]): Promise { - throw new Error('You must implement `verify`') - } -} diff --git a/src/util/arbundles-lite/DataItem.ts b/src/util/arbundles-lite/DataItem.ts deleted file mode 100644 index e37219c..0000000 --- a/src/util/arbundles-lite/DataItem.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { byteArrayToLong } from './utils' -import base64url from 'base64url' -import { Buffer } from 'buffer' -import { sign } from './ar-data-bundle' -import type { BundleItem } from './BundleItem' -import type { Signer } from './signing' -import { indexToType } from './signing' -import getSignatureData from './ar-data-base' -import { SIG_CONFIG, SignatureConfig } from './constants' -import { getCryptoDriver } from './utils' -import { deserializeTags } from './tags' -import { createHash } from 'crypto' -import type { Base64URLString } from './types' - -export const MIN_BINARY_SIZE = 80 -export const MAX_TAG_BYTES = 4096 - -export class DataItem implements BundleItem { - private readonly binary: Buffer - private _id: Buffer - - constructor(binary: Buffer) { - this.binary = binary - } - - static isDataItem(obj: any): obj is DataItem { - return obj.binary !== undefined - } - - get signatureType(): SignatureConfig { - const signatureTypeVal: number = byteArrayToLong(this.binary.subarray(0, 2)) - if (SignatureConfig?.[signatureTypeVal] !== undefined) { - return signatureTypeVal - } - throw new Error('Unknown signature type: ' + signatureTypeVal) - } - - async isValid(): Promise { - return DataItem.verify(this.binary) - } - - get id(): Base64URLString { - return base64url.encode(this.rawId) - } - - set id(id: string) { - this._id = base64url.toBuffer(id) - } - - get rawId(): Buffer { - return createHash('sha256').update(this.rawSignature).digest() - } - - set rawId(id: Buffer) { - this._id = id - } - - get rawSignature(): Buffer { - return this.binary.subarray(2, 2 + this.signatureLength) - } - - get signature(): Base64URLString { - return base64url.encode(this.rawSignature) - } - - set rawOwner(pubkey: Buffer) { - if (pubkey.byteLength != this.ownerLength) - throw new Error( - `Expected raw owner (pubkey) to be ${this.ownerLength} bytes, got ${pubkey.byteLength} bytes.` - ) - this.binary.set(pubkey, 2 + this.signatureLength) - } - - get rawOwner(): Buffer { - return this.binary.subarray( - 2 + this.signatureLength, - 2 + this.signatureLength + this.ownerLength - ) - } - - get signatureLength(): number { - return SIG_CONFIG[this.signatureType].sigLength - } - - get owner(): Base64URLString { - return base64url.encode(this.rawOwner) - } - - get ownerLength(): number { - return SIG_CONFIG[this.signatureType].pubLength - } - - get rawTarget(): Buffer { - const targetStart = this.getTargetStart() - const isPresent = this.binary[targetStart] == 1 - return isPresent - ? this.binary.subarray(targetStart + 1, targetStart + 33) - : Buffer.alloc(0) - } - - get target(): Base64URLString { - return base64url.encode(this.rawTarget) - } - - get rawAnchor(): Buffer { - const anchorStart = this.getAnchorStart() - const isPresent = this.binary[anchorStart] == 1 - - return isPresent - ? this.binary.subarray(anchorStart + 1, anchorStart + 33) - : Buffer.alloc(0) - } - - get anchor(): Base64URLString { - return base64url.encode(this.rawAnchor) /* .toString(); */ - } - - get rawTags(): Buffer { - const tagsStart = this.getTagsStart() - const tagsSize = byteArrayToLong( - this.binary.subarray(tagsStart + 8, tagsStart + 16) - ) - return this.binary.subarray(tagsStart + 16, tagsStart + 16 + tagsSize) - } - - get tags(): { name: string; value: string }[] { - const tagsStart = this.getTagsStart() - const tagsCount = byteArrayToLong( - this.binary.subarray(tagsStart, tagsStart + 8) - ) - if (tagsCount == 0) { - return [] - } - - const tagsSize = byteArrayToLong( - this.binary.subarray(tagsStart + 8, tagsStart + 16) - ) - - return deserializeTags( - Buffer.from( - this.binary.subarray(tagsStart + 16, tagsStart + 16 + tagsSize) - ) - ) - } - - get tagsB64Url(): { name: Base64URLString; value: Base64URLString }[] { - const _tags = this.tags - return _tags.map((t) => ({ - name: base64url.encode(t.name), - value: base64url.encode(t.value) - })) - } - - getStartOfData(): number { - const tagsStart = this.getTagsStart() - - const numberOfTagBytesArray = this.binary.subarray( - tagsStart + 8, - tagsStart + 16 - ) - const numberOfTagBytes = byteArrayToLong(numberOfTagBytesArray) - return tagsStart + 16 + numberOfTagBytes - } - - get rawData(): Buffer { - const tagsStart = this.getTagsStart() - - const numberOfTagBytesArray = this.binary.subarray( - tagsStart + 8, - tagsStart + 16 - ) - const numberOfTagBytes = byteArrayToLong(numberOfTagBytesArray) - const dataStart = tagsStart + 16 + numberOfTagBytes - - return this.binary.subarray(dataStart, this.binary.length) - } - - get data(): Base64URLString { - return base64url.encode(this.rawData) - } - - /** - * UNSAFE!! - * DO NOT MUTATE THE BINARY ARRAY. THIS WILL CAUSE UNDEFINED BEHAVIOUR. - */ - getRaw(): Buffer { - return this.binary - } - - public async sign(signer: Signer): Promise { - this._id = await sign(this, signer) - return this.rawId - } - - public async setSignature(signature: Buffer): Promise { - this.binary.set(signature, 2) - this._id = Buffer.from(await getCryptoDriver().hash(signature)) - } - - public isSigned(): boolean { - return (this._id?.length ?? 0) > 0 - } - - /** - * Returns a JSON representation of a DataItem - */ - - public toJSON(): { - owner: string - data: string - signature: string - target: string - tags: { name: Base64URLString; value: Base64URLString }[] - } { - return { - signature: this.signature, - owner: this.owner, - target: this.target, - tags: this.tags.map((t) => ({ - name: base64url.encode(t.name), - value: base64url.encode(t.value) - })), - data: this.data - } - } - - /** - * Verifies a `Buffer` and checks it fits the format of a DataItem - * - * A binary is valid iff: - * - the tags are encoded correctly - */ - static async verify(buffer: Buffer): Promise { - if (buffer.byteLength < MIN_BINARY_SIZE) { - return false - } - const item = new DataItem(buffer) - const sigType = item.signatureType - const tagsStart = item.getTagsStart() - - const numberOfTags = byteArrayToLong( - buffer.subarray(tagsStart, tagsStart + 8) - ) - const numberOfTagBytesArray = buffer.subarray(tagsStart + 8, tagsStart + 16) - const numberOfTagBytes = byteArrayToLong(numberOfTagBytesArray) - - if (numberOfTagBytes > MAX_TAG_BYTES) return false - - if (numberOfTags > 0) { - try { - const tags: { name: string; value: string }[] = deserializeTags( - Buffer.from( - buffer.subarray(tagsStart + 16, tagsStart + 16 + numberOfTagBytes) - ) - ) - - if (tags.length !== numberOfTags) { - return false - } - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - } catch (e) { - return false - } - } - - const Signer = indexToType[sigType] - - const signatureData = await getSignatureData(item) - return await Signer.verify(item.rawOwner, signatureData, item.rawSignature) - } - - public async getSignatureData(): Promise { - return getSignatureData(this) - } - - /** - * Returns the start byte of the tags section (number of tags) - * - * @private - */ - private getTagsStart(): number { - const targetStart = this.getTargetStart() - const targetPresent = this.binary[targetStart] == 1 - let tagsStart = targetStart + (targetPresent ? 33 : 1) - const anchorPresent = this.binary[tagsStart] == 1 - tagsStart += anchorPresent ? 33 : 1 - - return tagsStart - } - - /** - * Returns the start byte of the tags section (number of tags) - * - * @private - */ - private getTargetStart(): number { - return 2 + this.signatureLength + this.ownerLength - } - - /** - * Returns the start byte of the tags section (number of tags) - * - * @private - */ - private getAnchorStart(): number { - let anchorStart = this.getTargetStart() + 1 - const targetPresent = this.binary[this.getTargetStart()] == 1 - anchorStart += targetPresent ? 32 : 0 - - return anchorStart - } -} -export default DataItem diff --git a/src/util/arbundles-lite/ar-data-base.ts b/src/util/arbundles-lite/ar-data-base.ts deleted file mode 100644 index 257d70f..0000000 --- a/src/util/arbundles-lite/ar-data-base.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type DataItem from './DataItem' -import { deepHash, stringToBuffer } from './utils' -/** - * Options for creation of a DataItem - */ -export interface DataItemCreateOptions { - target?: string - anchor?: string - tags?: { name: string; value: string }[] -} - -async function getSignatureData(item: DataItem): Promise { - return deepHash([ - stringToBuffer('dataitem'), - stringToBuffer('1'), - stringToBuffer(item.signatureType.toString()), - item.rawOwner, - item.rawTarget, - item.rawAnchor, - item.rawTags, - item.rawData - ]) -} - -export default getSignatureData diff --git a/src/util/arbundles-lite/ar-data-bundle.ts b/src/util/arbundles-lite/ar-data-bundle.ts deleted file mode 100644 index d818536..0000000 --- a/src/util/arbundles-lite/ar-data-bundle.ts +++ /dev/null @@ -1,95 +0,0 @@ -import getSignatureData from './ar-data-base' -import { longTo32ByteArray } from './utils' -import type DataItem from './DataItem' -import Bundle from './Bundle' -import type { Signer } from './signing/Signer' -import { getCryptoDriver } from './utils' - -/** - * Unbundles a transaction into an Array of DataItems. - * - * Takes either a json string or object. Will throw if given an invalid json - * string but otherwise, it will return an empty array if - * - * a) the json object is the wrong format - * b) the object contains no valid DataItems. - * - * It will verify all DataItems and discard ones that don't pass verification. - * - * @param txData - */ -export function unbundleData(txData: Buffer): Bundle { - return new Bundle(txData) -} - -/** - * Verifies all data items and returns a json object with an items array. - * Throws if any of the data items fail verification. - * - * @param dataItems - * @param signer - */ -export async function bundleAndSignData( - dataItems: DataItem[], - signer: Signer -): Promise { - const headers = new Uint8Array(64 * dataItems.length) - - const binaries = await Promise.all( - dataItems.map(async (d, index) => { - // Sign DataItem - const id = d.isSigned() ? d.rawId : await sign(d, signer) - // Create header array - const header = new Uint8Array(64) - // Set offset - header.set(longTo32ByteArray(d.getRaw().byteLength), 0) - // Set id - header.set(id, 32) - // Add header to array of headers - headers.set(header, 64 * index) - // Convert to array for flattening - return d.getRaw() - }) - ).then((a) => { - return Buffer.concat(a) - }) - - const buffer = Buffer.concat([ - Buffer.from(longTo32ByteArray(dataItems.length)), - Buffer.from(headers), - binaries - ]) - - return new Bundle(buffer) -} - -/** - * Signs a single - * - * @param item - * @param signer - * @returns signings - signature and id in byte-arrays - */ -export async function getSignatureAndId( - item: DataItem, - signer: Signer -): Promise<{ signature: Buffer; id: Buffer }> { - const signatureData = await getSignatureData(item) - - const signatureBytes = await signer.sign(signatureData) - const idBytes = await getCryptoDriver().hash(signatureBytes) - - return { signature: Buffer.from(signatureBytes), id: Buffer.from(idBytes) } -} - -/** - * Signs and returns item id - * - * @param item - * @param jwk - */ -export async function sign(item: DataItem, signer: Signer): Promise { - const { signature, id } = await getSignatureAndId(item, signer) - item.getRaw().set(signature, 2) - return id -} diff --git a/src/util/arbundles-lite/ar-data-create.ts b/src/util/arbundles-lite/ar-data-create.ts deleted file mode 100644 index 013ac59..0000000 --- a/src/util/arbundles-lite/ar-data-create.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { DataItemCreateOptions } from './ar-data-base' - -import base64url from 'base64url' -import { longTo8ByteArray, shortTo2ByteArray } from './utils' -import DataItem from './DataItem' -import type { Tag } from './tags' -import { serializeTags } from './tags' -import type { Signer } from './signing/index' - -/** - * This will create a single DataItem in binary format (Uint8Array) - * - * @param data - * @param opts - Options involved in creating data items - * @param signer - */ -export function createData( - data: string | Uint8Array, - signer: Signer, - opts?: DataItemCreateOptions -): DataItem { - // TODO: Add asserts - // Parse all values to a buffer and - const _owner = signer.publicKey - - const _target = opts?.target ? base64url.toBuffer(opts.target) : null - const target_length = 1 + (_target?.byteLength ?? 0) - const _anchor = opts?.anchor ? Buffer.from(opts.anchor) : null - const anchor_length = 1 + (_anchor?.byteLength ?? 0) - const _tags = - (opts?.tags?.length ?? 0) > 0 ? serializeTags(opts?.tags as Tag[]) : null - const tags_length = 16 + (_tags ? _tags.byteLength : 0) - const _data = typeof data === 'string' ? Buffer.from(data) : Buffer.from(data) - const data_length = _data.byteLength - - // See [https://github.com/joshbenaron/arweave-standards/blob/ans104/ans/ANS-104.md#13-dataitem-format] - const length = - 2 + - signer.signatureLength + - signer.ownerLength + - target_length + - anchor_length + - tags_length + - data_length - // Create array with set length - const bytes = Buffer.alloc(length) - - bytes.set(shortTo2ByteArray(signer.signatureType), 0) - // Push bytes for `signature` - bytes.set(new Uint8Array(signer.signatureLength).fill(0), 2) - // // Push bytes for `id` - // bytes.set(EMPTY_ARRAY, 32); - // Push bytes for `owner` - - if (_owner.byteLength !== signer.ownerLength) - throw new Error( - `Owner must be ${signer.ownerLength} bytes, but was incorrectly ${_owner.byteLength}` - ) - bytes.set(_owner, 2 + signer.signatureLength) - - const position = 2 + signer.signatureLength + signer.ownerLength - // Push `presence byte` and push `target` if present - // 64 + OWNER_LENGTH - bytes[position] = _target ? 1 : 0 - if (_target) { - if (_target.byteLength !== 32) - throw new Error( - `Target must be 32 bytes but was incorrectly ${_target.byteLength}` - ) - bytes.set(_target, position + 1) - } - - // Push `presence byte` and push `anchor` if present - // 64 + OWNER_LENGTH - const anchor_start = position + target_length - let tags_start = anchor_start + 1 - bytes[anchor_start] = _anchor ? 1 : 0 - if (_anchor) { - tags_start += _anchor.byteLength - if (_anchor.byteLength !== 32) throw new Error('Anchor must be 32 bytes') - bytes.set(_anchor, anchor_start + 1) - } - - bytes.set(longTo8ByteArray(opts?.tags?.length ?? 0), tags_start) - const bytesCount = longTo8ByteArray(_tags?.byteLength ?? 0) - bytes.set(bytesCount, tags_start + 8) - if (_tags) { - bytes.set(_tags, tags_start + 16) - } - - const data_start = tags_start + tags_length - - bytes.set(_data, data_start) - - return new DataItem(bytes) -} diff --git a/src/util/arbundles-lite/constants.ts b/src/util/arbundles-lite/constants.ts deleted file mode 100644 index 9d4782e..0000000 --- a/src/util/arbundles-lite/constants.ts +++ /dev/null @@ -1,53 +0,0 @@ -export enum SignatureConfig { - ARWEAVE = 1, - ED25519, - ETHEREUM, - SOLANA, - INJECTEDAPTOS = 5, - MULTIAPTOS = 6, - TYPEDETHEREUM = 7 -} - -export interface SignatureMeta { - sigLength: number - pubLength: number - sigName: string -} - -export const SIG_CONFIG: Record = { - [SignatureConfig.ARWEAVE]: { - sigLength: 512, - pubLength: 512, - sigName: 'arweave' - }, - [SignatureConfig.ED25519]: { - sigLength: 64, - pubLength: 32, - sigName: 'ed25519' - }, - [SignatureConfig.ETHEREUM]: { - sigLength: 65, - pubLength: 65, - sigName: 'ethereum' - }, - [SignatureConfig.SOLANA]: { - sigLength: 64, - pubLength: 32, - sigName: 'solana' - }, - [SignatureConfig.INJECTEDAPTOS]: { - sigLength: 64, - pubLength: 32, - sigName: 'injectedAptos' - }, - [SignatureConfig.MULTIAPTOS]: { - sigLength: 64 * 32 + 4, // max 32 64 byte signatures, +4 for 32-bit bitmap - pubLength: 32 * 32 + 1, // max 64 32 byte keys, +1 for 8-bit threshold value - sigName: 'multiAptos' - }, - [SignatureConfig.TYPEDETHEREUM]: { - sigLength: 65, - pubLength: 42, - sigName: 'typedEthereum' - } -} diff --git a/src/util/arbundles-lite/deepHash.ts b/src/util/arbundles-lite/deepHash.ts deleted file mode 100644 index e323abe..0000000 --- a/src/util/arbundles-lite/deepHash.ts +++ /dev/null @@ -1,88 +0,0 @@ -// In TypeScript 3.7, could be written as a single type: -// `type DeepHashChunk = Uint8Array | DeepHashChunk[];` -import { getCryptoDriver, concatBuffers, stringToBuffer } from './utils' -import { createHash } from 'crypto' - -export type DeepHashChunk = Uint8Array | AsyncIterable | DeepHashChunks -export type DeepHashChunks = DeepHashChunk[] - -export async function deepHash(data: DeepHashChunk): Promise { - if ( - typeof data[Symbol.asyncIterator as keyof AsyncIterable] === - 'function' - ) { - const _data = data as AsyncIterable - - const context = createHash('sha384') - - let length = 0 - - for await (const chunk of _data) { - length += chunk.byteLength - context.update(chunk) - } - - const tag = concatBuffers([ - stringToBuffer('blob'), - stringToBuffer(length.toString()) - ]) - - const taggedHash = concatBuffers([ - await getCryptoDriver().hash(tag, 'SHA-384'), - context.digest() - ]) - - return await getCryptoDriver().hash(taggedHash, 'SHA-384') - } else if (Array.isArray(data)) { - const tag = concatBuffers([ - stringToBuffer('list'), - stringToBuffer(data.length.toString()) - ]) - - return await deepHashChunks( - data, - await getCryptoDriver().hash(tag, 'SHA-384') - ) - } - - const _data = data as Uint8Array - - const tag = concatBuffers([ - stringToBuffer('blob'), - stringToBuffer(_data.byteLength.toString()) - ]) - - const taggedHash = concatBuffers([ - await getCryptoDriver().hash(tag, 'SHA-384'), - await getCryptoDriver().hash(_data, 'SHA-384') - ]) - - return await getCryptoDriver().hash(taggedHash, 'SHA-384') -} - -export async function deepHashChunks( - chunks: DeepHashChunks, - acc: Uint8Array -): Promise { - if (chunks.length < 1) { - return acc - } - - const hashPair = concatBuffers([acc, await deepHash(chunks[0])]) - const newAcc = await getCryptoDriver().hash(hashPair, 'SHA-384') - return await deepHashChunks(chunks.slice(1), newAcc) -} - -export async function hashStream( - stream: AsyncIterable -): Promise { - const context = createHash('sha384') - - for await (const chunk of stream) { - context.update(chunk) - } - - return context.digest() -} - -export default deepHash diff --git a/src/util/arbundles-lite/index.ts b/src/util/arbundles-lite/index.ts deleted file mode 100644 index 370d00c..0000000 --- a/src/util/arbundles-lite/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * This stuff is copied from arbundles: - * https://github.com/Irys-xyz/arbundles - * Thanks! - */ -export * from './signing' -export * from './ar-data-base' -export * from './ar-data-bundle' -export * from './ar-data-create' -export * from './Bundle' -export * from './BundleInterface' -export * from './BundleItem' -export * from './constants' -export * from './DataItem' -// export * from "./error"; -// export * from "./interface-jwk"; -export * from './tags' -export * from './utils' -// export * from "$/utils"; diff --git a/src/util/arbundles-lite/signing/Signer.ts b/src/util/arbundles-lite/signing/Signer.ts deleted file mode 100644 index 89bac65..0000000 --- a/src/util/arbundles-lite/signing/Signer.ts +++ /dev/null @@ -1,24 +0,0 @@ -export abstract class Signer { - readonly publicKey: Buffer - readonly signatureType: number - readonly signatureLength: number - readonly ownerLength: number - readonly pem?: string | Buffer - - abstract sign( - message: Uint8Array, - _opts?: any - ): Promise | Uint8Array - static verify( - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - _pk: string | Buffer, - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - _message: Uint8Array, - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - _signature: Uint8Array, - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - _opts?: any - ): boolean { - throw new Error('You must implement verify method on child') - } -} diff --git a/src/util/arbundles-lite/signing/chains/ArweaveSigner.ts b/src/util/arbundles-lite/signing/chains/ArweaveSigner.ts deleted file mode 100644 index 00bdacd..0000000 --- a/src/util/arbundles-lite/signing/chains/ArweaveSigner.ts +++ /dev/null @@ -1,31 +0,0 @@ -import Rsa4096Pss from '../keys/Rsa4096Pss' -import type { JWKInterface } from 'arweave/node/lib/wallet' -// import { jwkTopem } from 'arweave/node/lib/crypto/node-driver' -import base64url from 'base64url' -import { getCryptoDriver } from '../../utils' - -export default class ArweaveSigner extends Rsa4096Pss { - protected jwk: JWKInterface - - constructor(jwk: JWKInterface) { - super(getCryptoDriver().jwkToPem(jwk), jwk.n) - this.jwk = jwk - } - - get publicKey(): Buffer { - if (!this.pk) throw new Error('ArweaveSigner - pk is undefined') - return base64url.toBuffer(this.pk) - } - - sign(message: Uint8Array): Uint8Array { - return getCryptoDriver().sign(this.jwk, message) as any - } - - static async verify( - pk: string, - message: Uint8Array, - signature: Uint8Array - ): Promise { - return await getCryptoDriver().verify(pk, message, signature) - } -} diff --git a/src/util/arbundles-lite/signing/chains/ethereumSigner.ts b/src/util/arbundles-lite/signing/chains/ethereumSigner.ts deleted file mode 100644 index d4afc71..0000000 --- a/src/util/arbundles-lite/signing/chains/ethereumSigner.ts +++ /dev/null @@ -1,40 +0,0 @@ -import Secp256k1 from '../keys/secp256k1' -import * as secp256k1 from 'secp256k1' -import base64url from 'base64url' -import { Wallet, toBeArray, hashMessage } from 'ethers' - -export default class EthereumSigner extends Secp256k1 { - public get publicKey(): Buffer { - return Buffer.from(this.pk, 'hex') - } - - constructor(key: string) { - if (key.startsWith('0x')) key = key.slice(2) - const b = Buffer.from(key, 'hex') - const pub = secp256k1.publicKeyCreate(b, false) - super(key, Buffer.from(pub)) - } - - async sign(message: Uint8Array): Promise { - const wallet = new Wallet(this._key) - return wallet - .signMessage(message) - .then((r) => Buffer.from(r.slice(2), 'hex')) as any - // below doesn't work due to lacking correct v derivation. - // return Buffer.from(joinSignature(Buffer.from(secp256k1.ecdsaSign(arrayify(hashMessage(message)), this.key).signature)).slice(2), "hex"); - } - - static async verify( - pk: string | Buffer, - message: Uint8Array, - signature: Uint8Array - ): Promise { - // const address = ethers.utils.computeAddress(pk); - // return ethers.utils.verifyMessage(message, signature) === address; - return secp256k1.ecdsaVerify( - signature.length === 65 ? signature.slice(0, -1) : signature, - toBeArray(hashMessage(message)), - typeof pk === 'string' ? base64url.toBuffer(pk) : pk - ) - } -} diff --git a/src/util/arbundles-lite/signing/chains/index.ts b/src/util/arbundles-lite/signing/chains/index.ts deleted file mode 100644 index d730e27..0000000 --- a/src/util/arbundles-lite/signing/chains/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -export { default as ArweaveSigner } from './ArweaveSigner' -// export { default as InjectedSolanaSigner } from "./injectedSolanaSigner"; -// export * from "./injectedEthereumSigner"; -// export { default as SolanaSigner } from "./SolanaSigner"; -// export { default as PolygonSigner } from "./PolygonSigner"; -// export { default as NearSigner } from "./NearSigner"; -export { default as EthereumSigner } from './ethereumSigner' -// export { default as AlgorandSigner } from "./AlgorandSigner"; -// export { default as HexInjectedSolanaSigner } from "./HexInjectedSolanaSigner"; -// export { default as HexSolanaSigner } from "./HexSolanaSigner"; -// export { default as AptosSigner } from "./AptosSigner"; -// export { default as InjectedAptosSigner } from "./InjectedAptosSigner"; -// export { default as MultiSignatureAptosSigner } from "./multiSignatureAptos"; -// export { default as TypedEthereumSigner } from "./TypedEthereumSigner"; -// export * from "./InjectedTypedEthereumSigner"; -// export { default as ArconnectSigner } from "./arconnectSigner"; diff --git a/src/util/arbundles-lite/signing/constants.ts b/src/util/arbundles-lite/signing/constants.ts deleted file mode 100644 index 5fe87c3..0000000 --- a/src/util/arbundles-lite/signing/constants.ts +++ /dev/null @@ -1,49 +0,0 @@ -import type { Signer } from './Signer' -// import Curve25519 from "./keys/curve25519"; - -import { - ArweaveSigner, - EthereumSigner - // HexInjectedSolanaSigner, - // InjectedAptosSigner, - // MultiSignatureAptosSigner, - // TypedEthereumSigner, -} from './chains/index' - -export type IndexToType = Record< - number, - { - new (...args): Signer - readonly signatureLength: number - readonly ownerLength: number - verify( - pk: string | Uint8Array, - message: Uint8Array, - signature: Uint8Array - ): Promise - } -> - -export const indexToType: IndexToType = { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - 1: ArweaveSigner, - // // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // // @ts-expect-error - // 2: Curve25519, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - 3: EthereumSigner - // // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // // @ts-expect-error - // 4: HexInjectedSolanaSigner, - // // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // // @ts-expect-error - // 5: InjectedAptosSigner, - // // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // // @ts-expect-error - // 6: MultiSignatureAptosSigner, - // // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // // @ts-expect-error - // 7: TypedEthereumSigner, -} diff --git a/src/util/arbundles-lite/signing/index.ts b/src/util/arbundles-lite/signing/index.ts deleted file mode 100644 index 21ab563..0000000 --- a/src/util/arbundles-lite/signing/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './Signer' -export * from './constants' -export * from './keys/index' -export * from './chains/index' -export * from './keccak256' // TODO: just use ethers bundled ver diff --git a/src/util/arbundles-lite/signing/keccak256.ts b/src/util/arbundles-lite/signing/keccak256.ts deleted file mode 100644 index 8158a58..0000000 --- a/src/util/arbundles-lite/signing/keccak256.ts +++ /dev/null @@ -1,109 +0,0 @@ -import BN from 'bn.js' -import { Buffer } from 'buffer' -import createKeccakHash from 'keccak' - -export function keccak256(value: Buffer | BN | string | number) { - value = toBuffer(value) - return createKeccakHash('keccak256') - .update(value as Buffer) - .digest() -} - -function toBuffer(value: any) { - if (!Buffer.isBuffer(value)) { - if (Array.isArray(value)) { - value = Buffer.from(value) - } else if (typeof value === 'string') { - if (isHexString(value)) { - value = Buffer.from(padToEven(stripHexPrefix(value)), 'hex') - } else { - value = Buffer.from(value) - } - } else if (typeof value === 'number') { - value = intToBuffer(value) - } else if (value === null || value === undefined) { - value = Buffer.allocUnsafe(0) - } else if (BN.isBN(value)) { - value = value.toArrayLike(Buffer) - } else if (value.toArray) { - // converts a BN to a Buffer - value = Buffer.from(value.toArray()) - } else { - throw new Error('invalid type') - } - } - - return value -} - -function isHexString(value: any, length?: number) { - if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) { - return false - } - - if (length && value.length !== 2 + 2 * length) { - return false - } - - return true -} - -function padToEven(value: any) { - if (typeof value !== 'string') { - throw new Error( - `while padding to even, value must be string, is currently ${typeof value}, while padToEven.` - ) - } - - if (value.length % 2) { - value = `0${value}` - } - - return value -} - -function stripHexPrefix(value: any) { - if (typeof value !== 'string') { - return value - } - - return isHexPrefixed(value) ? value.slice(2) : value -} - -function isHexPrefixed(value: any) { - if (typeof value !== 'string') { - throw new Error( - "value must be type 'string', is currently type " + - typeof value + - ', while checking isHexPrefixed.' - ) - } - - return value.startsWith('0x') -} - -function intToBuffer(i: number) { - const hex = intToHex(i) - return Buffer.from(padToEven(hex.slice(2)), 'hex') -} - -function intToHex(i: number) { - const hex = i.toString(16) - return `0x${hex}` -} - -if (typeof window !== 'undefined') { - ;(window as any).keccak256 = keccak256 -} - -export default keccak256 - -export const exportForTesting = { - intToBuffer, - intToHex, - isHexPrefixed, - stripHexPrefix, - padToEven, - isHexString, - toBuffer -} diff --git a/src/util/arbundles-lite/signing/keys/Rsa4096Pss.ts b/src/util/arbundles-lite/signing/keys/Rsa4096Pss.ts deleted file mode 100644 index a26dd05..0000000 --- a/src/util/arbundles-lite/signing/keys/Rsa4096Pss.ts +++ /dev/null @@ -1,44 +0,0 @@ -import type { Signer } from '../Signer' -import { getCryptoDriver } from '../../utils' -import base64url from 'base64url' -import { SIG_CONFIG } from '../../constants' -import { constants, createSign, verify } from 'crypto' - -export default class Rsa4096Pss implements Signer { - readonly signatureType: number = 1 - readonly ownerLength: number = SIG_CONFIG[1].pubLength - readonly signatureLength: number = SIG_CONFIG[1].sigLength - private readonly _publicKey: Buffer - public get publicKey(): Buffer { - return this._publicKey - } - - constructor( - private _key: string, - public pk?: string - ) { - if (!pk) { - this.pk = getCryptoDriver().getPublicKey(JSON.parse(_key)) - } - } - - sign(message: Uint8Array): Uint8Array { - return createSign('sha256').update(message).sign({ - key: this._key, - padding: constants.RSA_PKCS1_PSS_PADDING - }) - } - - static async verify( - pk: string | Buffer, - message: Uint8Array, - signature: Uint8Array - ): Promise { - return verify( - 'rsa-pss', - message, - Buffer.isBuffer(pk) ? base64url.encode(pk) : pk, - signature - ) - } -} diff --git a/src/util/arbundles-lite/signing/keys/index.ts b/src/util/arbundles-lite/signing/keys/index.ts deleted file mode 100644 index de67fba..0000000 --- a/src/util/arbundles-lite/signing/keys/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as Rsa4096 } from './Rsa4096Pss' -export { default as secp256k1 } from './secp256k1' diff --git a/src/util/arbundles-lite/signing/keys/secp256k1.ts b/src/util/arbundles-lite/signing/keys/secp256k1.ts deleted file mode 100644 index acaa537..0000000 --- a/src/util/arbundles-lite/signing/keys/secp256k1.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { Signer } from '../Signer' -import base64url from 'base64url' -import secp256k1 from 'secp256k1' -import { SignatureConfig, SIG_CONFIG } from '../../constants' -import keccak256 from '../keccak256' - -export default class Secp256k1 implements Signer { - readonly ownerLength: number = SIG_CONFIG[SignatureConfig.ETHEREUM].pubLength - readonly signatureLength: number = - SIG_CONFIG[SignatureConfig.ETHEREUM].sigLength - readonly signatureType: SignatureConfig = SignatureConfig.ETHEREUM - public readonly pk: string - - constructor( - protected _key: string, - pk: Buffer - ) { - this.pk = pk.toString('hex') - } - - public get publicKey(): Buffer { - throw new Error('You must implement `publicKey`') - } - - public get key(): Uint8Array { - return Buffer.from(this._key, 'hex') - } - - static async verify( - pk: string | Buffer, - message: Uint8Array, - signature: Uint8Array - ): Promise { - let p = pk - if (typeof pk === 'string') p = base64url.toBuffer(pk) - let verified = false - try { - verified = secp256k1.ecdsaVerify( - signature, - keccak256(Buffer.from(message)), - p as Buffer - ) - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - } catch (e) {} - return verified - } - - async sign(message: Uint8Array): Promise { - return secp256k1.ecdsaSign( - keccak256(Buffer.from(message)), - Buffer.from(this.key) - ).signature - } -} diff --git a/src/util/arbundles-lite/tags.ts b/src/util/arbundles-lite/tags.ts deleted file mode 100644 index 95a87df..0000000 --- a/src/util/arbundles-lite/tags.ts +++ /dev/null @@ -1,208 +0,0 @@ -import { MAX_TAG_BYTES } from './DataItem' - -export interface Tag { - name: string - value: string -} - -export class AVSCTap { - protected buf: Buffer - protected pos: number - - constructor(buf = Buffer.alloc(MAX_TAG_BYTES), pos = 0) { - this.buf = buf - this.pos = pos - } - - public writeTags(tags: Tag[]): void { - if (!Array.isArray(tags)) { - throw new Error('input must be array') - } - - const n = tags.length - let i - if (n) { - this.writeLong(n) - for (i = 0; i < n; i++) { - // for this use case, assume tags/strings. - const tag = tags[i] - if (typeof tag?.name !== 'string' || typeof tag?.value !== 'string') - throw new Error( - `Invalid tag format for ${tag}, expected {name:string, value: string}` - ) - this.writeString(tag.name) - this.writeString(tag.value) - // this.itemsType._write(tap, val[i]); - } - } - this.writeLong(0) - } - - public toBuffer(): Buffer { - const buffer = Buffer.alloc(this.pos) - if (this.pos > this.buf.length) - throw new Error(`Too many tag bytes (${this.pos} > ${this.buf.length})`) - this.buf.copy(buffer, 0, 0, this.pos) - return buffer - } - - protected writeLong(n: number): void { - const buf = this.buf - let f, m - - if (n >= -1073741824 && n < 1073741824) { - // Won't overflow, we can use integer arithmetic. - m = n >= 0 ? n << 1 : (~n << 1) | 1 - do { - buf[this.pos] = m & 0x7f - m >>= 7 - } while (m && (buf[this.pos++] |= 0x80)) - } else { - // We have to use slower floating arithmetic. - f = n >= 0 ? n * 2 : -n * 2 - 1 - do { - buf[this.pos] = f & 0x7f - f /= 128 - } while (f >= 1 && (buf[this.pos++] |= 0x80)) - } - this.pos++ - this.buf = buf - } - - // for some reason using setters/getters with ++ doesn't work right. - // set pos(newPos: number) { - // const d = newPos + 1 - this.buf.length; - // if (d > 0) this.buf = Buffer.concat([this.buf, Buffer.alloc(d)]); - // this._pos = newPos; - // } - - // get pos(): number { - // return this._pos; - // } - - // protected safeRead(position): number { - // return position > this.buf.length ? 0 : this.buf[position]; - // } - // protected safeWrite(position, value): Buffer { - // if (position > this.buf.length) this.buf = Buffer.concat([this.buf, Buffer.alloc(1)]); - // this.buf[position] = value; - // return this.buf; - // } - - protected writeString(s: string): void { - const len = Buffer.byteLength(s) - const buf = this.buf - this.writeLong(len) - let pos = this.pos - this.pos += len - if (this.pos > buf.length) { - return - } - if (len > 64) { - // this._writeUtf8(s, len); - this.buf.write(s, this.pos - len, len, 'utf8') - } else { - let i, l, c1, c2 - for (i = 0, l = len; i < l; i++) { - c1 = s.charCodeAt(i) - if (c1 < 0x80) { - buf[pos++] = c1 - } else if (c1 < 0x800) { - buf[pos++] = (c1 >> 6) | 0xc0 - buf[pos++] = (c1 & 0x3f) | 0x80 - } else if ( - (c1 & 0xfc00) === 0xd800 && - ((c2 = s.charCodeAt(i + 1)) & 0xfc00) === 0xdc00 - ) { - c1 = 0x10000 + ((c1 & 0x03ff) << 10) + (c2 & 0x03ff) - i++ - buf[pos++] = (c1 >> 18) | 0xf0 - buf[pos++] = ((c1 >> 12) & 0x3f) | 0x80 - buf[pos++] = ((c1 >> 6) & 0x3f) | 0x80 - buf[pos++] = (c1 & 0x3f) | 0x80 - } else { - buf[pos++] = (c1 >> 12) | 0xe0 - buf[pos++] = ((c1 >> 6) & 0x3f) | 0x80 - buf[pos++] = (c1 & 0x3f) | 0x80 - } - } - } - this.buf = buf - } - - protected readLong(): number { - let n = 0 - let k = 0 - const buf = this.buf - let b, h, f, fk - - do { - b = buf[this.pos++] - h = b & 0x80 - n |= (b & 0x7f) << k - k += 7 - } while (h && k < 28) - - if (h) { - // Switch to float arithmetic, otherwise we might overflow. - f = n - fk = 268435456 // 2 ** 28. - do { - b = buf[this.pos++] - f += (b & 0x7f) * fk - fk *= 128 - } while (b & 0x80) - return (f % 2 ? -(f + 1) : f) / 2 - } - - return (n >> 1) ^ -(n & 1) - } - - protected skipLong(): void { - const buf = this.buf - while (buf[this.pos++] & 0x80) {} - } - - public readTags(): Tag[] { - // var items = this.itemsType; - const val: Tag[] = [] - let n - while ((n = this.readLong())) { - if (n < 0) { - n = -n - this.skipLong() // Skip size. - } - while (n--) { - const name = this.readString() - const value = this.readString() - val.push(/* items._read(tap) */ { name, value }) - } - } - return val - } - - protected readString(): string { - const len = this.readLong() - const pos = this.pos - const buf = this.buf - this.pos += len - if (this.pos > buf.length) { - // return undefined; - throw new Error('TAP Position out of range') - } - return this.buf.slice(pos, pos + len).toString() - } -} - -export function serializeTags(tags: Tag[]): Buffer { - if (tags?.length === 0) { - return Buffer.allocUnsafe(0) - } - const tap = new AVSCTap() - tap.writeTags(tags) - return tap.toBuffer() -} -export function deserializeTags(tagsBuffer: Buffer): Tag[] { - const tap = new AVSCTap(tagsBuffer) - return tap.readTags() -} diff --git a/src/util/arbundles-lite/types.ts b/src/util/arbundles-lite/types.ts deleted file mode 100644 index b1b0be4..0000000 --- a/src/util/arbundles-lite/types.ts +++ /dev/null @@ -1 +0,0 @@ -export type Base64URLString = string diff --git a/src/util/arbundles-lite/utils.ts b/src/util/arbundles-lite/utils.ts deleted file mode 100644 index b9db71f..0000000 --- a/src/util/arbundles-lite/utils.ts +++ /dev/null @@ -1,85 +0,0 @@ -export function longToNByteArray(N: number, long: number): Uint8Array { - const byteArray = new Uint8Array(N) - if (long < 0) - throw new Error('Array is unsigned, cannot represent -ve numbers') - if (long > 2 ** (N * 8) - 1) - throw new Error(`Number ${long} is too large for an array of ${N} bytes`) - for (let index = 0; index < byteArray.length; index++) { - const byte = long & 0xff - byteArray[index] = byte - long = (long - byte) / 256 - } - return byteArray -} - -export function longTo8ByteArray(long: number): Uint8Array { - return longToNByteArray(8, long) -} - -export function shortTo2ByteArray(short: number): Uint8Array { - return longToNByteArray(2, short) -} - -export function longTo16ByteArray(long: number): Uint8Array { - return longToNByteArray(16, long) -} - -export function longTo32ByteArray(long: number): Uint8Array { - return longToNByteArray(32, long) -} - -export function byteArrayToLong(byteArray: Uint8Array): number { - let value = 0 - for (let i = byteArray.length - 1; i >= 0; i--) { - value = value * 256 + byteArray[i] - } - return value -} - -import { createPublicKey } from 'crypto' -import { default as nodeDriver } from 'arweave/node/lib/crypto/node-driver' -import type { JWKInterface } from 'arweave/node/lib/wallet' -export { stringToBuffer, concatBuffers } from 'arweave/node/lib/utils' -export { default as Transaction } from 'arweave/node/lib/transaction' -export { deepHash } from './deepHash' -// export type { CreateTransactionInterface } from 'arweave/node'//"@irys/arweave/common/arweave"; -export { default as Arweave } from 'arweave/node' -import { Tag } from 'arweave/node/lib/transaction' - -export interface CreateTransactionInterface { - format: number - last_tx: string - owner: string - tags: Tag[] - target: string - quantity: string - data: string | Uint8Array | ArrayBuffer - data_size: string - data_root: string - reward: string -} - -// hack as ESM won't unpack .default CJS imports, so we do so dynamically - -const driver: typeof nodeDriver = nodeDriver['default'] - ? nodeDriver['default'] - : nodeDriver -export class CryptoDriver extends driver { - public getPublicKey(jwk: JWKInterface): string { - return createPublicKey({ - key: this.jwkToPem(jwk), - type: 'pkcs1', - format: 'pem' - }) - .export({ - format: 'pem', - type: 'pkcs1' - }) - .toString() - } -} - -let driverInstance: CryptoDriver -export function getCryptoDriver(): CryptoDriver { - return (driverInstance ??= new CryptoDriver()) -} diff --git a/src/util/create-ethereum-data-item-signer.ts b/src/util/create-ethereum-data-item-signer.ts deleted file mode 100644 index 003ac83..0000000 --- a/src/util/create-ethereum-data-item-signer.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createData, Signer } from './arbundles-lite' - -export async function createEthereumDataItemSigner(signer: Signer) { - return ({ - data, - tags, - target, - anchor - }: { - data: string | Uint8Array - tags: any[] - target?: string - anchor?: string - }) => { - const dataItem = createData(data, signer, { tags, target, anchor }) - - return dataItem.sign(signer).then(async () => ({ - id: await dataItem.id, - raw: await dataItem.getRaw() - })) - } -} diff --git a/src/util/send-aos-message.ts b/src/util/send-aos-message.ts deleted file mode 100644 index c0126ad..0000000 --- a/src/util/send-aos-message.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { Logger } from '@nestjs/common' -import { - connect as aoConnect, - createDataItemSigner -} from '@permaweb/aoconnect' - -export const { - message: aoMessage, - result: aoResult, - dryrun: aoDryRun, -} = aoConnect({ CU_URL: process.env.CU_URL }) - -export type SendAosBaseOptions = { - processId: string - data?: string - tags?: { name: string; value: string }[] -} -export type SendAosDryRunOptions = SendAosBaseOptions -export type SendAosMessageOptions = SendAosBaseOptions & { - signer: ReturnType -} - -export type AosSigningFunction = ({ - data, - tags, - target, - anchor -}: { - data: string | Uint8Array - tags: any[] - target?: string - anchor?: string -}) => Promise<{ - id: string - raw: Buffer -}> - -export async function sendAosDryRun( - { processId, data, tags }: SendAosDryRunOptions, - retries = 3 -) { - const logger = new Logger('util/sendAosDryRun') - let attempts = 0 - let lastError: Error | undefined - - while (attempts < retries) { - try { - logger.debug(`Sending AO DryRun to process ${processId}`) - - return { - result: await aoDryRun({ - process: processId, - tags, - data - }) - } - } catch (error) { - logger.error(`Error sending AO DryRun to process ${processId}`, error) - - if (error.message.includes('500')) { - logger.debug( - `Retrying sending AO DryRun to process ${processId}`, - JSON.stringify( - { attempts, retries, error: error.message }, - undefined, - 2 - ) - ) - - // NB: Sleep between each attempt with exponential backoff - await new Promise((resolve) => - setTimeout(resolve, 2 ** attempts * 2000) - ) - - attempts++ - lastError = error - } else { - throw error - } - } - } - - throw lastError -} - -export async function sendAosMessage( - { processId, data, tags, signer }: SendAosMessageOptions, - retries = 3 -) { - const logger = new Logger('util/sendAosMessage') - let attempts = 0 - let lastError: Error | undefined - - while (attempts < retries) { - try { - logger.debug(`Sending AO Message to process ${processId}`) - - const messageId = await aoMessage({ - process: processId, - tags, - data, - signer - }) - - logger.debug( - `Fetching AO Message result ${messageId} from process ${processId}` - ) - const result = await aoResult({ - message: messageId, - process: processId - }) - logger.debug( - `Got AO Message result ${messageId} from process ${processId}` - ) - - return { messageId, result } - } catch (error) { - logger.error(`Error sending AO Message to process ${processId}`, error) - - if (error.message.includes('500')) { - logger.debug( - `Retrying sending AO Message to process ${processId}`, - JSON.stringify( - { attempts, retries, error: error.message }, - undefined, - 2 - ) - ) - - // NB: Sleep between each attempt with exponential backoff - await new Promise((resolve) => - setTimeout(resolve, 2 ** attempts * 2000) - ) - - attempts++ - lastError = error - } else { - throw error - } - } - } - - throw lastError -} From d572c72685dbba7bead5177cc92318cd019b646f Mon Sep 17 00:00:00 2001 From: Jim Toth Date: Tue, 28 Jul 2026 15:10:27 -0400 Subject: [PATCH 2/5] Drop the unused arweave dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declared as a direct dependency but never imported — the Arweave interaction all goes through the bundling service, which used the Turbo SDK. No effect on `npm audit`: arweave stays in the tree transitively via @ardrive/turbo-sdk and @dha-team/arbundles. This is declaration hygiene, so the manifest says what the service actually uses. --- package-lock.json | 1 - package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 596ec84..a424f25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,6 @@ "@nestjs/core": "^11.0.1", "@nestjs/mongoose": "^11.0.3", "@nestjs/platform-express": "^11.0.1", - "arweave": "^1.15.5", "base64url": "^3.0.1", "bignumber.js": "^9.1.2", "bn.js": "^5.2.1", diff --git a/package.json b/package.json index 3fe71fe..1caadb8 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "@nestjs/core": "^11.0.1", "@nestjs/mongoose": "^11.0.3", "@nestjs/platform-express": "^11.0.1", - "arweave": "^1.15.5", "base64url": "^3.0.1", "bignumber.js": "^9.1.2", "bn.js": "^5.2.1", From 3aff22c30739e285fa9c503c6f9bccc27ef6f9c3 Mon Sep 17 00:00:00 2001 From: Jim Toth Date: Tue, 28 Jul 2026 16:22:40 -0400 Subject: [PATCH 3/5] Override elliptic and secp256k1 to their patched versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clears all 3 production criticals. These came from @dha-team/arbundles, which pins the EOL @ethersproject v5 line; arbundles 1.0.4 is already latest and the advisory range is `*`, so there was no upgrade to take — npm's suggested "fix" is a downgrade to 1.0.3. But the advisories are version-exact and both packages already ship fixes: elliptic critical hits <=6.6.0, patched in 6.6.1 secp256k1 high hits exactly 5.0.0, patched in 5.0.1 Both were installed twice — the patched version hoisted at the root, and a vulnerable copy nested under arbundles that its ethersproject chain resolved to. An override collapses them onto the patched ones, so this needs no change to arbundles or to ethers (our own code is already on v6.17). Verified rather than assumed: these are the ECDSA signing primitives, so a clean build proves nothing. The integration specs were run against a real node holding real migrated state, exercising ANS-104 signed writes end to end — operator registry 5/5 (registration credits, operator certificates) and relay rewards 3/3 (settles a round, reads the snapshot back from the settle slot). One low remains in elliptic with range <=6.6.1, i.e. unfixed at latest. --- package-lock.json | 42 ------------------------------------------ package.json | 4 +++- 2 files changed, 3 insertions(+), 43 deletions(-) diff --git a/package-lock.json b/package-lock.json index a424f25..189ace0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -824,27 +824,6 @@ "node": ">=10.0.0" } }, - "node_modules/@dha-team/arbundles/node_modules/secp256k1": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz", - "integrity": "sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "elliptic": "^6.5.4", - "node-addon-api": "^5.0.0", - "node-gyp-build": "^4.2.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@dha-team/arbundles/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/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -1972,27 +1951,6 @@ "hash.js": "1.1.7" } }, - "node_modules/@ethersproject/signing-key/node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", - "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/@ethersproject/signing-key/node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.5", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", - "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", - "license": "MIT" - }, "node_modules/@ethersproject/strings": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", diff --git a/package.json b/package.json index 1caadb8..242592d 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "overrides": { "multer": "^2.2.0", "ws": "$ws", - "js-yaml": "^4.2.0" + "js-yaml": "^4.2.0", + "elliptic": "^6.6.1", + "secp256k1": "^5.0.1" }, "scripts": { "build": "nest build", From f0a0f2205461027517744587fa70c65db5a557fd Mon Sep 17 00:00:00 2001 From: Jim Toth Date: Tue, 28 Jul 2026 17:07:00 -0400 Subject: [PATCH 4/5] Drop the unused geoip-lite dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declared but imported nowhere. GeoIpService does not use it — it fetches /fingerprint-map/ from api-service over HTTP, so the geolocation data comes from there, not from a local database. It was the single largest source of production advisories left in this service. It pulls rimraf 2 -> glob 7 -> minimatch 3 -> brace-expansion 1, and every high in that chain came from it. Its spec baseline is unchanged: 4 failed / 1 passed before and after, the failures being pre-existing and requiring a live api-service at ANYONE_API_URL. Production vulnerabilities: 1 high -> 0. This service has no geo-ip module at all, so the dependency was pure inheritance. --- package-lock.json | 176 +++------------------------------------------- package.json | 1 - 2 files changed, 11 insertions(+), 166 deletions(-) diff --git a/package-lock.json b/package-lock.json index 189ace0..04d7def 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,6 @@ "bn.js": "^5.2.1", "consul": "^2.0.1", "ethers": "^6.13.4", - "geoip-lite": "^1.4.10", "h3-js": "^4.1.0", "keccak": "^3.0.4", "lodash": "^4.17.21", @@ -5160,6 +5159,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -5297,15 +5297,6 @@ "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, - "node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "license": "MIT", - "dependencies": { - "lodash": "^4.17.14" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -5428,6 +5419,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, "node_modules/base-x": { @@ -5702,15 +5694,6 @@ "ieee754": "^1.2.1" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -5827,6 +5810,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -6045,6 +6029,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -6057,6 +6042,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, "license": "MIT" }, "node_modules/color-string": { @@ -6151,6 +6137,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, "license": "MIT" }, "node_modules/concat-stream": { @@ -7232,15 +7219,6 @@ "bser": "2.1.1" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -7563,6 +7541,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -7599,36 +7578,6 @@ "node": ">=6.9.0" } }, - "node_modules/geoip-lite": { - "version": "1.4.10", - "resolved": "https://registry.npmjs.org/geoip-lite/-/geoip-lite-1.4.10.tgz", - "integrity": "sha512-4N69uhpS3KFd97m00wiFEefwa+L+HT5xZbzPhwu+sDawStg6UN/dPwWtUfkQuZkGIY1Cj7wDVp80IsqNtGMi2w==", - "license": "Apache-2.0", - "dependencies": { - "async": "2.1 - 2.6.4", - "chalk": "4.1 - 4.1.2", - "iconv-lite": "0.4.13 - 0.6.3", - "ip-address": "5.8.9 - 5.9.4", - "lazy": "1.0.11", - "rimraf": "2.5.2 - 2.7.1", - "yauzl": "2.9.2 - 2.10.0" - }, - "engines": { - "node": ">=10.3.0" - } - }, - "node_modules/geoip-lite/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -7855,6 +7804,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8076,6 +8026,7 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -8113,20 +8064,6 @@ "url": "https://opencollective.com/ioredis" } }, - "node_modules/ip-address": { - "version": "5.9.4", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-5.9.4.tgz", - "integrity": "sha512-dHkI3/YNJq4b/qQaz+c8LuarD3pY24JqZWfjB8aZx1gtpc2MDILu9L9jpZe1sHpzo/yWFweQVn+U//FhazUxmw==", - "license": "MIT", - "dependencies": { - "jsbn": "1.1.0", - "lodash": "^4.17.15", - "sprintf-js": "1.1.2" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -9076,12 +9013,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" - }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -9206,15 +9137,6 @@ "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", "license": "MIT" }, - "node_modules/lazy": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/lazy/-/lazy-1.0.11.tgz", - "integrity": "sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA==", - "license": "MIT", - "engines": { - "node": ">=0.2.0" - } - }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -10217,6 +10139,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -10279,12 +10202,6 @@ "node": ">=8" } }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" - }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -10718,62 +10635,6 @@ "dev": true, "license": "ISC" }, - "node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -11141,12 +11002,6 @@ "memory-pager": "^1.0.2" } }, - "node_modules/sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", - "license": "BSD-3-Clause" - }, "node_modules/stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", @@ -11382,6 +11237,7 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -12692,16 +12548,6 @@ "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", diff --git a/package.json b/package.json index 242592d..fe6ef5d 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,6 @@ "bn.js": "^5.2.1", "consul": "^2.0.1", "ethers": "^6.13.4", - "geoip-lite": "^1.4.10", "h3-js": "^4.1.0", "keccak": "^3.0.4", "lodash": "^4.17.21", From 5d160b56f994f8bc0e9a53962c8f0c105d475762 Mon Sep 17 00:00:00 2001 From: Jim Toth Date: Tue, 28 Jul 2026 17:55:42 -0400 Subject: [PATCH 5/5] Update mongoose to the patched 8.24.2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a moderate prototype-pollution advisory in mongoose update casting, via `__proto__`-prefixed dotted paths through Schema._getSchema. Affects 8.0.0 - 8.24.0. This service was the only one left exposed, and not for an interesting reason: the declared range `^8.7.2` already allowed the patched version, but its lockfile still pinned 8.24.0 because its `npm audit fix` run was reverted earlier for making the overall count worse. The other three controllers and api-service were already on 8.24.2; operator-checks is on the 7.x line, which the advisory does not cover. No non-breaking fix was skipped here — `npm update mongoose` stays inside the declared range. --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 04d7def..bd434ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9600,9 +9600,9 @@ } }, "node_modules/mongoose": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.24.0.tgz", - "integrity": "sha512-EEZwOibDPZ5uZN3bFapfnRskEbdljAf6sP9ln6u+P4e5IfkOAh6Tqw2g8/Tag++KHOAJ095WXT/c0uqRq4Vckg==", + "version": "8.24.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.24.2.tgz", + "integrity": "sha512-5+H3MSHNJCcr9M+lVplekrZ4/Dyn3N1dOpvgn9gMwvHJhunc4G8SQcBVd/btBQoVdspVNPjx8Pw03YWBv6uTJg==", "license": "MIT", "dependencies": { "bson": "^6.10.4",