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..bd434ac 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,14 +18,11 @@ "@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", "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", @@ -189,6 +188,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 +781,48 @@ "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/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -940,91 +992,1173 @@ "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, + "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/@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": { + "@ethersproject/logger": "^5.8.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": { + "@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/@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": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, + "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": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@ethersproject/logger": "^5.8.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/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", - "engines": { - "node": ">= 4" + "dependencies": { + "@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/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", + "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", "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 +3650,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 +3684,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 +3708,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 +5015,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", @@ -3923,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" @@ -4022,6 +5259,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", @@ -4047,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", @@ -4178,8 +5419,18 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, "license": "MIT" }, + "node_modules/base-x": { + "version": "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 +5470,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 +5641,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,20 +5688,12 @@ } ], "license": "MIT", + "optional": true, "dependencies": { "base64-js": "^1.3.1", "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", @@ -4552,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", @@ -4770,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" @@ -4782,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": { @@ -4866,7 +6127,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" @@ -4876,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": { @@ -4968,9 +6230,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 +7108,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", @@ -5943,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", @@ -6274,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": { @@ -6310,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", @@ -6566,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" @@ -6620,6 +7859,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 +7928,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", @@ -6789,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", @@ -6826,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", @@ -6950,6 +8174,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 +8963,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", @@ -7762,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", @@ -7781,6 +9026,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", @@ -7882,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", @@ -8052,6 +9298,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 +9414,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 +9451,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 +9543,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", @@ -8362,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", @@ -8505,6 +9743,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 +9937,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", @@ -8882,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" @@ -8944,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", @@ -9127,6 +10379,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 +10450,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 +10574,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", @@ -9372,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", @@ -9541,6 +10748,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", @@ -9789,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", @@ -9843,6 +11050,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", @@ -10020,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" @@ -10291,6 +11509,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 +11570,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 +11849,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 +11981,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 +12086,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 +12158,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 +12492,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", @@ -11275,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", @@ -11320,15 +12583,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..fe6ef5d 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", @@ -29,6 +31,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,14 +40,11 @@ "@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", "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", 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 -}