diff --git a/m1/infrastructure/README.md b/m1/infrastructure/README.md new file mode 100644 index 00000000..0ee44f7a --- /dev/null +++ b/m1/infrastructure/README.md @@ -0,0 +1,20 @@ + +### Move Subnet Infrastructure +```bash +├── bridge-faucet +├── evm-rpc +├── explorer +└── subnet-proxy +``` +The Move Subnet infrastructure consists of the following components: + +- **Bridge Faucet**: A web project that provides a user interface for operations between Move-VM and Move-EVM. + +- **EVM-RPC**: A service that offers RPC capabilities for the Move Subnet. It can be used by projects in the EVM ecosystem, such as Metamask, ethers, and others. + +- **Explorer**: An explorer specifically designed for the Move Subnet, allowing users to explore and navigate through its functionalities. + +- **Subnet Proxy**: This component acts as a converter, transforming the Move Subnet's JSON-RPC service into a RESTful API format using the Aptos SDK. This enables developers to interact with the Move Subnet using RESTful endpoints. + + + diff --git a/m1/infrastructure/evm-rpc/.env.example b/m1/infrastructure/evm-rpc/.env.example new file mode 100644 index 00000000..84cca5b7 --- /dev/null +++ b/m1/infrastructure/evm-rpc/.env.example @@ -0,0 +1,3 @@ +EVM_SENDER =0xf238ff22567c56bdaa18105f229ac0dacc2d9f73dfc5bf08a2a2a4a0fac4d221 +FAUCET_SENDER =0xf238ff22567c56bdaa18105f229ac0dacc2d9f73dfc5bf08a2a2a4a0fac4d221 +NODE_URL=https://devnet.m1.movementlabs.xyz/v1 diff --git a/m1/infrastructure/evm-rpc/.gitignore b/m1/infrastructure/evm-rpc/.gitignore new file mode 100644 index 00000000..86162dd4 --- /dev/null +++ b/m1/infrastructure/evm-rpc/.gitignore @@ -0,0 +1,7 @@ +node_modules +.env +dist +app.cjs +move/build +.vscode +db \ No newline at end of file diff --git a/m1/infrastructure/evm-rpc/.prettierrc b/m1/infrastructure/evm-rpc/.prettierrc new file mode 100644 index 00000000..2d9dd752 --- /dev/null +++ b/m1/infrastructure/evm-rpc/.prettierrc @@ -0,0 +1,9 @@ +{ + "tabWidth": 4, + "semi": true, + "singleQuote": true, + "endOfLine": "lf", + "bracketSpacing": true, + "arrowParens": "avoid", + "printWidth": 110 +} diff --git a/m1/infrastructure/evm-rpc/README.md b/m1/infrastructure/evm-rpc/README.md new file mode 100644 index 00000000..bf597a51 --- /dev/null +++ b/m1/infrastructure/evm-rpc/README.md @@ -0,0 +1,81 @@ +# Project Tutorial: Implementing EVM Runtime on MOVE + +This project demonstrates how to: + +- Call with [EVM runtime](https://github.com/movemntdev/movement-v2/blob/main/aptos-move/framework/aptos-framework/sources/evm/evm.move) on Movement Subnet. +- Implement partial Ethereum RPC methods to interact with Solidity contracts using MetaMask and Remix. +- Deploy Solidity contracts using Remix. +- Perform contract read and write operations. + + +### Implemented RPC Methods + +The following RPC methods have been implemented to ensure interaction with Solidity contracts using MetaMask and Remix: + +- `eth_chainId`: Get the chain ID, currently fixed at 336. +- `net_version`: Get the version number. +- `eth_gasPrice`: Get the current gas price. +- `eth_blockNumber`: Get the latest block number. Updated every 2 seconds. +- `eth_sendRawTransaction`: Send signed raw transaction data. This checks the correctness of the signature. +- `eth_call`: Invoke methods of smart contracts. +- `eth_getTransactionCount`: Get the transaction count for a specific address. +- `eth_getTransactionByHash`: Get transaction information based on the transaction hash. +- `eth_getTransactionReceipt`: Get the transaction receipt based on the transaction hash. +- `eth_estimateGas`: Estimate the gas consumption for a transaction. For successful transactions, if the gas is less than 21,000, it will return 21,000, but the actual consumed gas will be used when sending the transaction. +- `eth_getBlockByNumber`: Get block information based on the block number. +- `eth_getBlockByHash`: Get block information based on the block hash. Currently returns empty. +- `eth_getBalance`: Get the balance of a specific address +- `eth_getCode`: Get the code of a specific contract address. +- `eth_getStorageAt`: Get the storage at a specific position in a specific address +- `eth_getLogs`: Returns an array of all logs matching a given filter object. +- `web3_clientVersion`: Returns the current client version. + + +### Start Your EVM RPC + +> If you don't want to start the EVM RPC yourself, you can found the link at `https://github.com/movemntdev/movement-v2` + +- Set environment variables +```bash +mv .env.example .env +``` + +- `NODE_URL`: The subnet restful endpoint provided by the movement subnet` + +- `EVM_SENDER`: The private key of a account to send EVM transactions to the Move. Please ensure that the account has enough MOVE native token to pay for the gas fee.(At least 10) + +- `FAUCET_SENDER`: The private key of a account to send bridge move native token to evm native token. Please ensure that the account has enough MOVE native token to pay for the gas fee and bridge token.(At least 10) + + +Then, run the following command to start the server: + +``` +npn run start + +# This will start a server on port 3044 +``` + + +### Add RPC to MetaMask + +1. Open MetaMask ![png](static/d17J7RxpqC.png) +2. Go to settings ![png](static/KhoOwatzms.png) +3. Go to network settings ![png](static/d5L1LFOLZR.png) +4. Add a network ![png](static/nwzl29YTEb.png) +5. Add network information (if it's local development, replace RPC with http://127.0.0.1:3044/v1) ![png](static/chrome_xvlAxtXOYq.png) + +### Connect MetaMask to Remix and Interact with Contracts + +1. Open [Remix IDE](http://remix.ethereum.org/), and open the built-in _Storage_ contract ![png](static/chrome_ci8sbs7hKq.png) +2. Compile the contract ![png](static/chrome_YU6sTLmcb3.png) +3. Deploy the contract (make sure to select the network environment provided by MetaMask). After successful deployment, the contract address will appear in the bottom left corner for interaction.![png](static/chrome_WIbIq1LHp5.png) + +4. Interact with the contract![png](static/chrome_pYLDdKbT6Z.png) + +### Possible Issues + +- If you are using MetaMask to send transactions and a transaction fails, please follow these steps to clear the transaction history and retry. This is because the nonce does not change when an EVM transaction fails, and MetaMask will increment by default instead of fetching the latest nonce. + - Go to Settings + - Navigate to Advanced + - Click on Clear Activity Tab Data + - Confirm by clicking Clear diff --git a/m1/infrastructure/evm-rpc/abi/bridge.json b/m1/infrastructure/evm-rpc/abi/bridge.json new file mode 100644 index 00000000..a402cb5a --- /dev/null +++ b/m1/infrastructure/evm-rpc/abi/bridge.json @@ -0,0 +1,20 @@ +[ + { + "inputs": [ + { + "internalType": "bytes", + "name": "to", + "type": "bytes" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] diff --git a/m1/infrastructure/evm-rpc/package-lock.json b/m1/infrastructure/evm-rpc/package-lock.json new file mode 100644 index 00000000..3d93a57f --- /dev/null +++ b/m1/infrastructure/evm-rpc/package-lock.json @@ -0,0 +1,2645 @@ +{ + "name": "move-evm-rpc", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "move-evm-rpc", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@ethereumjs/common": "^4.1.0", + "@ethereumjs/tx": "^5.1.0", + "@iarna/toml": "^2.2.5", + "aptos": "^1.20.0", + "async-lock": "^1.4.0", + "bignumber.js": "^9.1.2", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "ethers": "^6.7.1", + "express": "^4.18.2", + "json-rpc-2.0": "^1.7.0", + "node-fetch": "^3.3.2", + "sequelize": "^6.35.2", + "sqlite3": "^5.1.6" + }, + "devDependencies": { + "prettier": "^3.1.1" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.9.2.tgz", + "integrity": "sha512-0h+FrQDqe2Wn+IIGFkTCd4aAwTJ+7834Ek1COohCyV26AXhwQ7WQaz+4F/nLOeVl/3BtWHOHLPsq46V8YB46Eg==" + }, + "node_modules/@aptos-labs/aptos-client": { + "version": "0.0.2", + "resolved": "https://registry.npmmirror.com/@aptos-labs/aptos-client/-/aptos-client-0.0.2.tgz", + "integrity": "sha512-FgKZb5zDPz8MmAcVxXzYhxP6OkzuIPoDRJp48YJ8+vrZ9EOZ35HaWGN2M3u+GPdnFE9mODFqkxw3azh3kHGZjQ==", + "dependencies": { + "axios": "0.27.2", + "got": "^11.0.0" + }, + "engines": { + "node": ">=15.10.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/@ethereumjs/common/-/common-4.1.0.tgz", + "integrity": "sha512-XWdQvUjlQHVwh4uGEPFKHpsic69GOsMXEhlHrggS5ju/+2zAmmlz6B25TkCCymeElC9DUp13tH5Tc25Iuvtlcg==", + "dependencies": { + "@ethereumjs/util": "^9.0.1", + "crc": "^4.3.2" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/@ethereumjs/rlp/-/rlp-5.0.1.tgz", + "integrity": "sha512-Ab/Hfzz+T9Zl+65Nkg+9xAmwKPLicsnQ4NW49pgvJp9ovefuic95cgOS9CbPc9izIEgsqm1UitV0uNveCvud9w==", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/@ethereumjs/tx/-/tx-5.1.0.tgz", + "integrity": "sha512-VUhw2+4yXArJZRWhPjmZFrN4WUjUo0qUZUszVpW2KzsGlqCFf67kwJcH9Rca5eS0CRHjr2qHJLpvYOjNuaXVdA==", + "dependencies": { + "@ethereumjs/common": "^4.1.0", + "@ethereumjs/rlp": "^5.0.1", + "@ethereumjs/util": "^9.0.1", + "ethereum-cryptography": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@ethereumjs/util": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/@ethereumjs/util/-/util-9.0.1.tgz", + "integrity": "sha512-NdFFEzCc3H1sYkNnnySwLg6owdQMhjUc2jfuDyx8Xv162WSluCnnSKouKOSG3njGNEyy2I9NmF8zTRDwuqpZWA==", + "dependencies": { + "@ethereumjs/rlp": "^5.0.1", + "ethereum-cryptography": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "c-kzg": "^2.1.2" + }, + "peerDependenciesMeta": { + "c-kzg": { + "optional": true + } + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "optional": true + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmmirror.com/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==" + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@noble/curves": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@noble/curves/-/curves-1.1.0.tgz", + "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "dependencies": { + "@noble/hashes": "1.3.1" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.3.1.tgz", + "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "engines": { + "node": ">= 16" + } + }, + "node_modules/@noble/secp256k1": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@noble/secp256k1/-/secp256k1-1.7.1.tgz", + "integrity": "sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@scure/base": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@scure/base/-/base-1.1.3.tgz", + "integrity": "sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==" + }, + "node_modules/@scure/bip32": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/@scure/bip32/-/bip32-1.3.1.tgz", + "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "dependencies": { + "@noble/curves": "~1.1.0", + "@noble/hashes": "~1.3.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/@scure/bip39/-/bip39-1.2.1.tgz", + "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "dependencies": { + "@noble/hashes": "~1.3.0", + "@scure/base": "~1.1.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmmirror.com/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.2", + "resolved": "https://registry.npmmirror.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.2.tgz", + "integrity": "sha512-FD+nQWA2zJjh4L9+pFXqWOi0Hs1ryBCfI+985NjluQ1p8EYtoLvjLOKidXBtZ4/IcxDX4o8/E8qDS3540tNliw==" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmmirror.com/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "18.15.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.13.tgz", + "integrity": "sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==" + }, + "node_modules/@types/responselike": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.0.tgz", + "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/validator": { + "version": "13.11.7", + "resolved": "https://registry.npmmirror.com/@types/validator/-/validator-13.11.7.tgz", + "integrity": "sha512-q0JomTsJ2I5Mv7dhHhQLGjMvX0JJm5dyZ1DXQySIUzU1UlwzB8bt+R6+LODUbz0UDIOvEzGc28tk27gBJw2N8Q==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-4.0.0-beta.5.tgz", + "integrity": "sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==" + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + }, + "node_modules/aptos": { + "version": "1.20.0", + "resolved": "https://registry.npmmirror.com/aptos/-/aptos-1.20.0.tgz", + "integrity": "sha512-driZt7qEr4ndKqqVHMyuFsQAHy4gJ4HPQttgVIpeDfnOIEnIV7A2jyJ9EYO2A+MayuyxXB+7yCNXT4HyBFJdpA==", + "dependencies": { + "@aptos-labs/aptos-client": "^0.0.2", + "@noble/hashes": "1.1.3", + "@scure/bip39": "1.1.0", + "eventemitter3": "^5.0.1", + "form-data": "4.0.0", + "tweetnacl": "1.0.3" + }, + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/aptos/node_modules/@noble/hashes": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@noble/hashes/-/hashes-1.1.3.tgz", + "integrity": "sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==" + }, + "node_modules/aptos/node_modules/@scure/bip39": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@scure/bip39/-/bip39-1.1.0.tgz", + "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "dependencies": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/async-lock": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/async-lock/-/async-lock-1.4.0.tgz", + "integrity": "sha512-coglx5yIWuetakm3/1dsX9hxCNox22h7+V80RQOu2XUUMidtArxKoZoOtHUPuR84SycKTXzgGzAUR5hJxujyJQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "optional": true, + "peer": true + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmmirror.com/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "optional": true, + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmmirror.com/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/crc": { + "version": "4.3.2", + "resolved": "https://registry.npmmirror.com/crc/-/crc-4.3.2.tgz", + "integrity": "sha512-uGDHf4KLLh2zsHa8D8hIQ1H/HtFQhyHrc0uhHBcoKGol/Xnb+MPYfUMw7cvON6ze/GUESTudKayDcJC5HnJv1A==", + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "buffer": ">=6.0.3" + }, + "peerDependenciesMeta": { + "buffer": { + "optional": true + } + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/dottie": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/dottie/-/dottie-2.0.6.tgz", + "integrity": "sha512-iGCHkfUc5kFekGiqhe8B/mdaurD+lakO9txNnTvKtA6PISrw86LgqHvRzWYPyoE2Ph5aMIrCw9/uko6XHTKCwA==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmmirror.com/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "optional": true + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ethereum-cryptography": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", + "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", + "dependencies": { + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/ethers": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.7.1.tgz", + "integrity": "sha512-qX5kxIFMfg1i+epfgb0xF4WM7IqapIIu50pOJ17aebkxxa4BacW5jFrQRmCJpDEg2ZK2oNtR5QjrQ1WDBF29dA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@adraffy/ens-normalize": "1.9.2", + "@noble/hashes": "1.1.2", + "@noble/secp256k1": "1.7.1", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.2.tgz", + "integrity": "sha512-KYRCASVTv6aeUi1tsF8/vpyR7zpfs3FUzy2Jqm+MU+LmUKhQ0y2FpfwqkCcxSg2ua4GALJd8k2R76WxwZGbQpA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmmirror.com/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "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": "*" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmmirror.com/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "optional": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "optional": true, + "peer": true + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "optional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "optional": true + }, + "node_modules/inflection": { + "version": "1.13.4", + "resolved": "https://registry.npmmirror.com/inflection/-/inflection-1.13.4.tgz", + "integrity": "sha512-6I/HUDeYFfuNCVS3td055BaXBwKYuzw7K3ExVMStBowKo9oOAMJIXIHvdyR3iboTCp1b+1i5DSkIZTcwIktuDw==", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "optional": true + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "optional": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "optional": true + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-rpc-2.0": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/json-rpc-2.0/-/json-rpc-2.0-1.7.0.tgz", + "integrity": "sha512-asnLgC1qD5ytP+fvBP8uL0rvj+l8P6iYICbzZ8dVxCpESffVjzA7KkYkbKCIbavs7cllwH1ZUaNtJwphdeRqpg==" + }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmmirror.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmmirror.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmmirror.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmmirror.com/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmmirror.com/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmmirror.com/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", + "optional": true, + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmmirror.com/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmmirror.com/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/pg-connection-string": { + "version": "2.6.2", + "resolved": "https://registry.npmmirror.com/pg-connection-string/-/pg-connection-string-2.6.2.tgz", + "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" + }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/retry-as-promised": { + "version": "7.0.4", + "resolved": "https://registry.npmmirror.com/retry-as-promised/-/retry-as-promised-7.0.4.tgz", + "integrity": "sha512-XgmCoxKWkDofwH8WddD0w85ZfqYz+ZHlr5yo+3YUCfycWawU56T5ckWXsScsj5B8tqUcIG67DxXByo3VUgiAdA==" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmmirror.com/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/sequelize": { + "version": "6.35.2", + "resolved": "https://registry.npmmirror.com/sequelize/-/sequelize-6.35.2.tgz", + "integrity": "sha512-EdzLaw2kK4/aOnWQ7ed/qh3B6/g+1DvmeXr66RwbcqSm/+QRS9X0LDI5INBibsy4eNJHWIRPo3+QK0zL+IPBHg==", + "dependencies": { + "@types/debug": "^4.1.8", + "@types/validator": "^13.7.17", + "debug": "^4.3.4", + "dottie": "^2.0.6", + "inflection": "^1.13.4", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.43", + "pg-connection-string": "^2.6.1", + "retry-as-promised": "^7.0.4", + "semver": "^7.5.4", + "sequelize-pool": "^7.1.0", + "toposort-class": "^1.0.1", + "uuid": "^8.3.2", + "validator": "^13.9.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "ibm_db": { + "optional": true + }, + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "oracledb": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "snowflake-sdk": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-pool": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/sequelize-pool/-/sequelize-pool-7.1.0.tgz", + "integrity": "sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/sequelize/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/sequelize/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "optional": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmmirror.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "optional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "optional": true + }, + "node_modules/sqlite3": { + "version": "5.1.6", + "resolved": "https://registry.npmmirror.com/sqlite3/-/sqlite3-5.1.6.tgz", + "integrity": "sha512-olYkWoKFVNSSSQNvxVUfjiVbz3YtBwTJj+mfV5zpHmqW3sELx2Cf4QCdirMelhM5Zh+KDVaKgQHqCxrqiWHybw==", + "hasInstallScript": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "node-addon-api": "^4.2.0", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validator": { + "version": "13.11.0", + "resolved": "https://registry.npmmirror.com/validator/-/validator-13.11.0.tgz", + "integrity": "sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmmirror.com/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/ws": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } +} diff --git a/m1/infrastructure/evm-rpc/package.json b/m1/infrastructure/evm-rpc/package.json new file mode 100644 index 00000000..b9876084 --- /dev/null +++ b/m1/infrastructure/evm-rpc/package.json @@ -0,0 +1,33 @@ +{ + "name": "move-evm-rpc", + "version": "1.0.0", + "description": "", + "main": "index.js", + "type": "module", + "scripts": { + "start": "node src/app.js", + "format": "prettier --write src/**/*.js " + }, + "keywords": [], + "author": "shaokun", + "license": "ISC", + "dependencies": { + "@ethereumjs/common": "^4.1.0", + "@ethereumjs/tx": "^5.1.0", + "@iarna/toml": "^2.2.5", + "aptos": "^1.20.0", + "async-lock": "^1.4.0", + "bignumber.js": "^9.1.2", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "ethers": "^6.7.1", + "express": "^4.18.2", + "json-rpc-2.0": "^1.7.0", + "node-fetch": "^3.3.2", + "sequelize": "^6.35.2", + "sqlite3": "^5.1.6" + }, + "devDependencies": { + "prettier": "^3.1.1" + } +} diff --git a/m1/infrastructure/evm-rpc/src/app.js b/m1/infrastructure/evm-rpc/src/app.js new file mode 100644 index 00000000..15939cf8 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/app.js @@ -0,0 +1,81 @@ +import 'dotenv/config'; +import express from 'express'; +import cors from 'cors'; +import JsonRpc from 'json-rpc-2.0'; +import { rpc } from './rpc.js'; +import { SERVER_PORT } from './const.js'; +import { ethers } from 'ethers'; +import { faucet } from './bridge.js'; +import { getMoveHash } from './db.js'; +const { JSONRPCServer, createJSONRPCErrorResponse } = JsonRpc; +const app = express(); +app.use(cors()); +app.use(express.json({ limit: '10mb' })); + +const server = new JSONRPCServer(); +for (const [key, value] of Object.entries(rpc)) { + server.addMethod(key, value); +} +// error handler +server.applyMiddleware(async function (next, request, serverParams) { + try { + return await next(request, serverParams); + } catch (error) { + const message = typeof error === 'string' ? error : error?.message || 'Internal error'; + const err = createJSONRPCErrorResponse(request.id, error?.code || -32000, message, { + message, + }); + return err; + } +}); +app.get('/v1/eth_faucet', async function (req, res, next) { + const address = req.query.address; + if (!ethers.isAddress(address)) { + res.status(400).json({ + error: 'invalid address', + }); + return; + } + try { + let hash = await faucet(address); + res.json({ + data: hash, + }); + } catch (error) { + res.status(400).json({ + error: 'please try again after 10 minutes', + }); + } +}); + +app.get('/v1/move_hash', async function (req, res, next) { + const hash = req.query?.hash?.toLowerCase() ?? '0x1'; + const move_hash = await getMoveHash(hash); + res.status(200).json({ + data: move_hash, + }); +}); + +app.use('/v1', async function (req, res, next) { + const context = { ip: req.ip }; + console.log('>>> %s %s', context.ip, req.body.method); + let str_req = `<<< ${JSON.stringify(req.body)}`; + server.receive(req.body).then(jsonRPCResponse => { + if (jsonRPCResponse.error) { + console.error(str_req, jsonRPCResponse); + } else { + console.log(str_req, jsonRPCResponse); + } + if (Array.isArray(req.body) && req.body.length === 1) { + res.json([jsonRPCResponse]); + } else { + res.json(jsonRPCResponse); + } + }); +}); + +app.set('trust proxy', true); +app.listen(SERVER_PORT, () => { + console.log('server start at http://127.0.0.1:' + SERVER_PORT); +}); +import('./task.js'); diff --git a/m1/infrastructure/evm-rpc/src/bridge.js b/m1/infrastructure/evm-rpc/src/bridge.js new file mode 100644 index 00000000..429a4939 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/bridge.js @@ -0,0 +1,629 @@ +import { HexString } from 'aptos'; +import { Op } from 'sequelize'; +import { + EVM_CONTRACT, + SENDER_ACCOUNT, + SENDER_ADDRESS, + client, + ZERO_HASH, + LOG_BLOOM, + FAUCET_SENDER_ADDRESS, + FAUCET_SENDER_ACCOUNT, +} from './const.js'; +import { parseRawTx, sleep, toHex, toNumber } from './helper.js'; +import { TxEvents, getMoveHash, saveMoveEvmTxHash, saveTx } from './db.js'; +import { ZeroAddress, ethers, isHexString, toBeHex, keccak256 } from 'ethers'; +import BigNumber from 'bignumber.js'; +import Lock from 'async-lock'; +const LOCKER_MAX_PENDING = 20; +const locker = new Lock({ + maxExecutionTime: 30 * 1000, +}); + +const LOCKER_KEY_SEND_TX = 'sendTx'; +let lastBlockTime = Date.now(); +let lastBlock = '0x1'; +await getBlock(); + +export async function faucet(addr) { + const payload = { + function: `${EVM_CONTRACT}::evm::deposit`, + type_arguments: [], + arguments: [toBuffer(addr), toBuffer(toBeHex((1e18).toString()))], + }; + const txnRequest = await client.generateTransaction(FAUCET_SENDER_ADDRESS, payload); + const signedTxn = await client.signTransaction(FAUCET_SENDER_ACCOUNT, txnRequest); + const transactionRes = await client.submitTransaction(signedTxn); + await client.waitForTransaction(transactionRes.hash); + return transactionRes.hash; +} + +export async function eth_feeHistory() { + const block = await getBlock(); + const baseFeePerGas = toHex(1500 * 10 ** 9); + return { + oldestBlock: toHex(toNumber(block) - 4), + reward: [ + ['0x5f5e100', '0xd3cdba48'], + ['0x5f5e100', '0xb146453a'], + ['0xb8c63f00', '0xb8c63f00'], + ['0x5f5e100', '0x77359400'], + ], + baseFeePerGas: Array.from({ length: 4 }, () => baseFeePerGas), + gasUsedRatio: [0.5329073333333333, 0.3723229, 0.9996228333333333, 0.5487537333333333], + }; +} + +/** + * Get the latest block. If the last block was fetched less than 2 seconds ago, return the cached block. + * Otherwise, fetch the latest block from the client and update the cache. + * @returns {Promise} - A promise that resolves to the latest block + */ +export async function getBlock() { + if (Date.now() - lastBlockTime >= 2000) { + let info = await client.getLedgerInfo(); + lastBlockTime = Date.now(); + lastBlock = toHex(info.block_height); + return lastBlock; + } + return lastBlock; +} +/** + * Get a block by its number. If the block number is "latest", fetch the latest block from the client. + * @param {string|number} block - The block number or "latest" + * @returns {Promise} - A promise that resolves to the block object with the following properties: + * - difficulty: string - The difficulty level of the block + * - extraData: string - Extra data related to the block + * - gasLimit: string - The maximum gas that transactions in the block are allowed to consume + * - gasUsed: string - The total gas that transactions in the block have consumed + * - hash: string - The hash of the block + * - logsBloom: string - The bloom filter for the logs in the block + * - miner: string - The address of the miner who mined the block + * - mixHash: string - A hash that, combined with the nonce, proves that the block has gone through enough computation + * - nonce: string - A random value that, combined with the mixHash, proves that the block has gone through enough computation + * - number: string - The number of the block in the blockchain + * - parentHash: string - The hash of the parent block + * - receiptsRoot: string - The root of the receipts trie of the block + * - sha3Uncles: string - The SHA3 hash of the uncles data in the block + * - size: string - The size of the block in bytes + * - stateRoot: string - The root of the final state trie of the block + * - timestamp: string - The timestamp when the block was mined + * - totalDifficulty: string - The total difficulty of the chain up to this block + * - transactions: Array - The transactions included in the block + * - transactionsRoot: string - The root of the transactions trie of the block + * - uncles: Array - The uncle blocks of the block + */ +export async function getBlockByNumber(block) { + if (block === 'latest') { + let info = await client.getLedgerInfo(); + block = info.block_height; + } + block = BigNumber(block).toNumber(); + let info = await client.getBlockByHeight(block, true); + let parentHash = ZERO_HASH; + if (block > 2) { + let info = await client.getBlockByHeight(block - 1); + parentHash = info.block_hash; + } + let transactions = info.transactions || []; + let evm_tx = []; + transactions.forEach(it => { + if (it.type === 'user_transaction' && it.payload.function.startsWith('0x1::evm::send_tx')) { + evm_tx.push(parseMoveTxPayload(it).hash); + } + }); + const genHash = c => { + const seed = info.block_hash; + let hash = seed; + while (c > 0) { + c--; + hash = keccak256(hash); + } + return hash; + }; + + return { + baseFeePerGas: '0xc', // eip1559 + difficulty: '0x0', + extraData: genHash(1), + gasLimit: toHex(30_000_000), + gasUsed: '0x0000000000000000', + hash: info.block_hash, + logsBloom: LOG_BLOOM, + miner: ZeroAddress, + mixHash: genHash(2), + nonce: '0x0000000000000000', + number: toHex(block), + parentHash: parentHash, + receiptsRoot: genHash(3), + sha3Uncles: genHash(4), + size: toHex(1000000), + stateRoot: genHash(5), + timestamp: toHex(Math.trunc(info.block_timestamp / 1e6)), + totalDifficulty: '0x0000000000000000', + transactions: evm_tx, + transactionsRoot: genHash(6), + uncles: [], + }; +} + +export async function getBlockByHash(hash) { + return {}; +} +/** + * Get the code at a specific address. + * @param {string} addr - The address to get the code from. + * @returns {Promise} - A promise that resolves to the code at the given address. + */ +export async function getCode(addr) { + let result = await getAccountInfo(addr); + return result.code; +} + +export async function getStorageAt(addr, pos) { + let res = '0x'; + let payload = { + function: EVM_CONTRACT + `::evm::get_storage_at`, + type_arguments: [], + arguments: [addr, toHex(pos)], + }; + try { + let result = await client.view(payload); + res = result[0]; + } catch (error) { + console.log('getStorageAt error', error); + } + return res; +} + +// Forge will send multiple transactions at the same time +// and the order of nonces is not necessarily in ascending order, +// so we need to sort them again. +async function checkAddressNonce(info) { + const startTs = Date.now(); + while (1) { + try { + const accInfo = await Promise.race([ + getAccountInfo(info.from), + new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), 10000)), + ]); + if (parseInt(accInfo.nonce) === parseInt(info.nonce)) { + return true; + } + } catch (error) { + continue; + } + if (Date.now() - startTs > 30 * 1000) { + throw 'Timeout to Discard. Please send tx follow address nonce order'; + } + await sleep(0.5); + } +} + +// Because only successful transactions in Move EVM will update the nonce, +// we don't need to check the nonce here. +// We can directly read it from the blockchain instead of relying on user input. +export async function sendRawTx(tx) { + const info = parseRawTx(tx); + console.log('raw tx info', info); + // let v = info.v; + // if (v === 27 || v === 28) { + // throw 'only replay-protected (EIP-155) transactions allowed over RPC'; + // } + // if (v !== 707 && v !== 708) { + // throw 'chain id error'; + // } + checkTxQueue(); + // this guarantee the nonce order for same from address + await checkAddressNonce(info); + // this guarantee the the sender address is order + return locker.acquire(LOCKER_KEY_SEND_TX, async function (done) { + let fee = '0x01'; + let gasPrice = toNumber(BigNumber(info.gasPrice).div(1e10).decimalPlaces(0)); + // we don't need too large gasPrice for send tx + // now it enough to finish this tx + // now it will cost the sender gas , so set it a limit + if (gasPrice > 300) gasPrice = 300; + if (gasPrice < 100) gasPrice = 100; + const payload = { + function: `${EVM_CONTRACT}::evm::send_tx`, + type_arguments: [], + arguments: [ + toBuffer(info.from), // // useless will remove at next version + toBuffer(tx), + toBuffer(fee), + 1, // useless will remove at next version + ], + }; + let gasInfo; + try { + const txnRequest = await client.generateTransaction(SENDER_ADDRESS, payload); + let res = await client.simulateTransaction(SENDER_ACCOUNT, txnRequest, { + estimatePrioritizedGasUnitPrice: true, + }); + gasInfo = { + success: res[0].success, + gas_used: res[0].gas_used, + error: res[0].vm_status, + }; + } catch (error) { + gasInfo = { + success: false, + gas_used: 0, + error: error.message || 'sendTx error', + }; + } + if (!gasInfo.success) return done(gasInfo.error); + fee = toBeHex(BigNumber(gasPrice).times(gasInfo.gas_used).decimalPlaces(0).toFixed(0)); + console.log('nonce %s,fee:%s', info.nonce, fee); + payload.arguments[2] = toBuffer(fee); + sendTx(payload, true, { + gas_unit_price: gasPrice, + }) + .then(hash => { + saveTx(tx, hash, JSON.stringify(info)); + saveMoveEvmTxHash(hash, info.hash).then(() => { + done(null, info.hash); + }); + }) + .catch(err => { + done(err.message || 'sendTx error'); + }); + }); +} + +export function callContract(from, contract, calldata) { + from = from || ZeroAddress; + return view(from, contract, calldata); +} +/** + * Estimate the gas needed for a transaction. + * @param {Object} info - The transaction information, including from, to, data, and value. + * @returns {Promise} - A promise that resolves to an object containing: + * - success: boolean - Whether the gas estimation was successful + * - gas_used: number - The amount of gas used + * - show_gas: number - The amount of gas to show, + */ +export async function estimateGas(info) { + if (!info.data) info.data = '0x'; + const payload = { + function: `${EVM_CONTRACT}::evm::estimate_tx_gas`, + type_arguments: [], + arguments: [ + // The arguments for the function. + toBuffer(info.from), // The sender's address. + toBuffer(info.to || ZeroAddress), // The receiver's address, or the zero address if no receiver is specified. + toBuffer(info.data === '0x' ? '0x' : toBeHex(info.data)), // The data to send, or '0x' if no data is specified. + toBuffer(toBeHex(info.value || '0x0')), // The value to send, or '0x0' if no value is specified. + 1, // The last argument is always 1. + ], + }; // Set a default `error_gas` value to `1e6` (1,000,000). This value is used if the gas estimation fails. + const error_gas = 1e6; + let res; + try { + const txnRequest = await client.generateTransaction(SENDER_ADDRESS, payload); + res = await client.simulateTransaction(SENDER_ACCOUNT, txnRequest, { + estimatePrioritizedGasUnitPrice: true, + }); + if (res[0].success) { + res[0].show_gas = res[0].gas_used; // Set `show_gas` to the gas used by the transaction. + if (res[0].gas_used < 21000) { + // If the gas used is less than 21,000 (the minimum gas required for a transaction in Ethereum)... + res[0].show_gas = 21000; // Set `show_gas` to 21,000. + } + } else { + res[0].show_gas = error_gas; + res[0].gas_used = error_gas; + res[0].error = res[0].vm_status; + } + } catch (error) { + res = [ + { + success: false, + gas_used: error_gas, + show_gas: error_gas, + error: error.message || 'estimate gas error', + }, + ]; + } + const ret = { + success: res[0].success, + gas_used: res[0].gas_used, + show_gas: res[0].show_gas, + error: res[0].error, + }; + return ret; +} +export async function getGasPrice() { + const info = await client.estimateGasPrice(); + // for the move is 8 and eth is 18 + // enlarge this gas price to fit eth decimals + return toHex(BigNumber(info.prioritized_gas_estimate).times(1e10)); +} +/** + * Get a transaction by its hash. + * @param {string} tx - The hash of the transaction. + * @returns {Promise} - A promise that resolves to an object containing: + * - blockHash: string - The hash of the block containing the transaction + * - blockNumber: string - The number of the block containing the transaction + * - from: string - The address from which the transaction was sent + * - gas: string - The amount of gas used by the transaction + * - gasPrice: string - The price of gas in the transaction + * - hash: string - The hash of the transaction + * - input: string - The input data of the transaction + * - nonce: string - The nonce of the transaction + * - to: string - The address to which the transaction was sent + * - transactionIndex: string - The index of the transaction in the block + * - value: string - The value transferred in the transaction + * - v: string - The v value of the transaction's signature + * - r: string - The r value of the transaction's signature + * - s: string - The s value of the transaction's signature + */ +export async function getTransactionByHash(evm_hash) { + let tx = await getMoveHash(evm_hash); + let info = await client.getTransactionByHash(tx); + let block = await client.getBlockByVersion(info.version); + const { to, from, data, nonce, value, v, r, s, hash, type } = parseMoveTxPayload(info); + return { + blockHash: ZERO_HASH, + blockNumber: toHex(block.block_height), + from: from, + gas: toHex(info.gas_used), + gasPrice: toHex(+info.gas_unit_price * 1e10), + maxFeePerGas: toHex(info.max_fee_per_gas), + maxPriorityFeePerGas: toHex(info.max_priority_fee_per_gas), + hash: hash, + input: data, + type, + nonce: toHex(nonce), + to: to, + transactionIndex: '0x0', + value: toHex(value), + v: toHex(v), + r: r, + s: s, + }; +} + +export async function getTransactionReceipt(evm_hash) { + let tx = await getMoveHash(evm_hash); + let info = await client.getTransactionByHash(tx); + let block = await client.getBlockByVersion(info.version); + const { to, from, type } = parseMoveTxPayload(info); + let contractAddress = await getDeployedContract(info); + const logs = parseLogs(info, block.block_height, block.block_hash, evm_hash); + let recept = { + blockHash: block.block_hash, + blockNumber: toHex(block.block_height), + contractAddress, + cumulativeGasUsed: toHex(info.gas_used), + effectiveGasPrice: toHex(info.gas_unit_price * 1e10), + from: from, + gasUsed: toHex(info.gas_used), + logs: logs, + to: Boolean(contractAddress) ? null : to, + logsBloom: LOG_BLOOM, + status: info.success ? '0x1' : '0x0', + transactionHash: evm_hash, + transactionIndex: '0x0', + type, + }; + return recept; +} +/** + * Retrieves the nonce for a given sender. + * @param {string} sender - The sender's address. + * @returns {Promise} The nonce in hexadecimal format. + * @throws Will throw an error if the account information cannot be retrieved. + */ +export async function getNonce(sender) { + let info = await getAccountInfo(sender); + return toHex(info.nonce); +} + +/** + * Retrieves the balance for a given sender. + * @param {string} sender - The sender's address. + * @returns {Promise} The balance in hexadecimal format. + * @throws Will throw an error if the account information cannot be retrieved. + */ +export async function getBalance(sender) { + let info = await getAccountInfo(sender); + return toHex(info.balance); +} + +const CACHE_ETH_ADDRESS_TO_MOVE = {}; + +/** + * Retrieves account information for a given Ethereum address. + * @param {string} acc - The Ethereum address. + * @returns {Promise} An object containing the account's balance, nonce, and code. + * @throws Will not throw an error if the Ethereum address has not been deposited from Move. + */ +async function getAccountInfo(acc) { + const ret = { + balance: '0x0', + nonce: 0, + code: '0x', + }; + acc = acc.toLowerCase(); + try { + let moveAddress = CACHE_ETH_ADDRESS_TO_MOVE[acc]; + if (!moveAddress) { + let payload = { + function: `${EVM_CONTRACT}::evm::get_move_address`, + type_arguments: [], + arguments: [acc], + }; + let result = await client.view(payload); + moveAddress = result[0]; + CACHE_ETH_ADDRESS_TO_MOVE[acc] = moveAddress; + } + const resource = await client.getAccountResource(moveAddress, `${EVM_CONTRACT}::evm::Account`); + ret.balance = resource.data.balance; + ret.nonce = +resource.data.nonce; + ret.code = resource.data.code; + } catch (error) { + // if this eth address not deposit from move ,it will error + } + + return ret; +} + +async function sendTx(payload, wait = false, option = {}) { + try { + const txnRequest = await client.generateTransaction(SENDER_ADDRESS, payload, { + ...option, + max_gas_amount: 2 * 1e6, + expiration_timestamp_secs: Math.trunc(Date.now() / 1000) + 10, + }); + const signedTxn = await client.signTransaction(SENDER_ACCOUNT, txnRequest); + const transactionRes = await client.submitTransaction(signedTxn); + console.log('sendTx', transactionRes.hash); + if (wait) await client.waitForTransaction(transactionRes.hash); + return transactionRes.hash; + } catch (error) { + throw new Error(error.message || 'sendTx error '); + } +} +/** + * Retrieves the address of the deployed contract. + * @param {Object} info - The transaction information. + * @returns {Promise} The address of the deployed contract, or null if the transaction was not successful or did not deploy a contract. + */ +async function getDeployedContract(info) { + if (!info.success) return null; + const { nonce, to, from } = parseMoveTxPayload(info); + if (to === ZeroAddress) { + return ethers.getCreateAddress({ from: from, nonce }).toLowerCase(); + } + return null; +} + +async function view(from, contract, calldata) { + let payload = { + function: EVM_CONTRACT + `::evm::query`, + type_arguments: [], + arguments: [from, contract, calldata], + }; + try { + let result = await client.view(payload); + return result[0]; + } catch (error) { + throw error.message; + } +} + +function toBuffer(hex) { + return new HexString(hex).toUint8Array(); +} + +function parseMoveTxPayload(info) { + const args = info.payload.arguments; + const tx = parseRawTx(args[1]); + return { + value: tx.value, + from: tx.from, + to: tx.to, + type: tx.type, + nonce: tx.nonce, + data: tx.data, + fee: args[2], + r: tx.r, + s: tx.s, + v: tx.v, + hash: tx.hash, + limit: tx.limit, + gasPrice: tx.gasPrice, + }; +} + +function move2ethAddress(addr) { + addr = addr.toLowerCase(); + return '0x' + addr.slice(-40); +} + +export async function getLogs(obj) { + const nowBlock = await getBlock(); + const fromBlock = isHexString(obj.fromBlock) ? toNumber(obj.fromBlock) : toNumber(nowBlock); + const toBlock = isHexString(obj.toBlock) ? toNumber(obj.toBlock) : toNumber(nowBlock); + const address = Array.isArray(obj.address) ? obj.address : [obj.address]; + const topics = obj.topics; + const topicsWhere = {}; + if (topics && topics.length > 0 && topics.length <= 4) { + for (let i = 0; i < topics.length; i++) { + const item = Array.isArray(topics[i]) ? topics[i] : [topics[i]]; + topicsWhere[`topic${i}`] = { + [Op.in]: item, + }; + } + } + const ret = await TxEvents.findAll({ + attributes: [ + 'address', + 'topics', + 'data', + 'blockNumber', + 'transactionHash', + 'transactionIndex', + 'blockHash', + 'logIndex', + ], + where: { + blockNumber: { + [Op.gte]: fromBlock, + [Op.lte]: toBlock, + }, + address: { + [Op.in]: address, + }, + ...topicsWhere, + }, + limit: 10000, + }); + return ret.map(it => { + it = it.dataValues; + return { + ...it, + topics: JSON.parse(it.topics), + blockNumber: toHex(it.blockNumber), + removed: false, + }; + }); +} + +function parseLogs(info, blockNumber, blockHash, evm_hash) { + let logs = []; + let events = info.events || []; + let evmLogs = [1, 2, 3, 4].map(it => `${EVM_CONTRACT}::evm::Log${it}Event`); + events = events.filter(it => evmLogs.includes(it.type)); + for (let i = 0; i < events.length; i++) { + const event = events[i]; + let topics = []; + if (event.data.topic0) topics.push(event.data.topic0); + if (event.data.topic1) topics.push(event.data.topic1); + if (event.data.topic2) topics.push(event.data.topic2); + if (event.data.topic3) topics.push(event.data.topic3); + logs.push({ + address: move2ethAddress(event.data.contract), + topics, + data: event.data.data, + blockNumber: toHex(blockNumber), + transactionHash: evm_hash, + transactionIndex: toHex(event.sequence_number), + blockHash: blockHash, + logIndex: toHex(i), + removed: false, + }); + } + return logs; +} + +function checkTxQueue() { + if ( + locker['queues'][LOCKER_KEY_SEND_TX] && + locker['queues'][LOCKER_KEY_SEND_TX].length > LOCKER_MAX_PENDING + ) { + throw new Error('system busy'); + } +} diff --git a/m1/infrastructure/evm-rpc/src/const.js b/m1/infrastructure/evm-rpc/src/const.js new file mode 100644 index 00000000..c25eb819 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/const.js @@ -0,0 +1,57 @@ +import { AptosClient, AptosAccount } from 'aptos'; + +export const SERVER_PORT = process.env.SERVER_PORT || 3044; + +/** + * NODE_URL is the URL of the node, fetched from environment variables + */ +export const NODE_URL = process.env.NODE_URL; + +/** + * EVM_SENDER is the sender's address, fetched from environment variables + */ +const EVM_SENDER = process.env.EVM_SENDER; +const FAUCET_SENDER = process.env.FAUCET_SENDER; + +/** + * EVM_CONTRACT is the contract address + */ +export const EVM_CONTRACT = '0x1'; + +/** + * CHAIN_ID is the ID of the chain + */ +export const CHAIN_ID = 336; + +/** + * ZERO_HASH is a constant representing a hash of all zeros + */ +export const ZERO_HASH = '0x' + '0'.repeat(64); + +/** + * LOG_BLOOM is a constant representing a bloom filter of all zeros + */ +export const LOG_BLOOM = '0x' + '0'.repeat(512); + +/** + * SENDER_ACCOUNT is the sender's account, created from the sender's private key + */ +export const SENDER_ACCOUNT = AptosAccount.fromAptosAccountObject({ + privateKeyHex: EVM_SENDER, +}); + +/** + * SENDER_ADDRESS is the sender's address, fetched from the sender's account + */ +export const SENDER_ADDRESS = SENDER_ACCOUNT.address().hexString; + +/** + * client is an instance of AptosClient, initialized with the node URL + */ +export const client = new AptosClient(NODE_URL); + +export const FAUCET_SENDER_ACCOUNT = AptosAccount.fromAptosAccountObject({ + privateKeyHex: FAUCET_SENDER, +}); + +export const FAUCET_SENDER_ADDRESS = FAUCET_SENDER_ACCOUNT.address().hexString; diff --git a/m1/infrastructure/evm-rpc/src/db.js b/m1/infrastructure/evm-rpc/src/db.js new file mode 100644 index 00000000..8556ff12 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/db.js @@ -0,0 +1,177 @@ +// User.js + +import { DataTypes, Sequelize } from 'sequelize'; + +const sequelize = new Sequelize('database', null, null, { + dialect: 'sqlite', + storage: './db/database.db', + logging: false, +}); + +export const RawTx = sequelize.define('RawTx', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true, + }, + tx: { + type: DataTypes.TEXT, + allowNull: false, + }, + hash: { + type: DataTypes.STRING, + allowNull: false, + }, + info: { + type: DataTypes.JSON, + allowNull: false, + }, +}); +await RawTx.sync(); +export function saveTx(tx, hash, info) { + RawTx.create({ + tx, + hash, + info, + }).catch(err => { + // ignore + }); +} + +const MoveEvmTxHash = sequelize.define( + 'MoveEvmTxHash', + { + id: { + type: DataTypes.INTEGER.UNSIGNED, + primaryKey: true, + autoIncrement: true, + }, + move_hash: { + type: DataTypes.STRING, + allowNull: false, + }, + evm_hash: { + type: DataTypes.STRING, + allowNull: false, + }, + }, + { + indexes: [ + { + fields: ['move_hash'], + }, + { + fields: ['evm_hash'], + }, + ], + }, +); +await MoveEvmTxHash.sync(); + +export async function saveMoveEvmTxHash(move_hash, evm_hash) { + return MoveEvmTxHash.create({ + move_hash, + evm_hash, + }).catch(err => { + // ignore + }); +} + +export async function getMoveHash(evm_hash) { + let move_hash = await MoveEvmTxHash.findOne({ + where: { + evm_hash, + }, + order: [['id', 'desc']], + }).then(res => res?.move_hash ?? null); + return move_hash || evm_hash; +} + +export const TxEvents = sequelize.define( + 'TxEvents', + { + id: { + type: DataTypes.INTEGER.UNSIGNED, + primaryKey: true, + autoIncrement: true, + }, + logIndex: { + type: DataTypes.STRING, + allowNull: false, + }, + blockNumber: { + type: DataTypes.INTEGER.UNSIGNED, + allowNull: false, + }, + blockHash: { + type: DataTypes.STRING(66), + allowNull: false, + }, + transactionHash: { + type: DataTypes.STRING(66), + allowNull: false, + }, + transactionIndex: { + type: DataTypes.STRING, + allowNull: false, + }, + address: { + type: DataTypes.STRING(42), + allowNull: false, + }, + data: { + type: DataTypes.TEXT('long'), + allowNull: false, + }, + topic0: { + type: DataTypes.STRING(66), + allowNull: false, + }, + topic1: { + type: DataTypes.STRING(66), + allowNull: false, + }, + topic2: { + type: DataTypes.STRING(66), + allowNull: false, + }, + topic3: { + type: DataTypes.STRING(66), + allowNull: false, + }, + topics: { + type: DataTypes.TEXT('long'), + allowNull: false, + comment: 'topic json array', + }, + }, + { + indexes: [ + { + fields: ['blockNumber', 'address', 'topic0'], + fields: ['blockNumber', 'address', 'topic0', 'topic1'], + fields: ['blockNumber', 'address', 'topic0', 'topic1', 'topic2'], + fields: ['blockNumber', 'address', 'topic0', 'topic1', 'topic2', 'topic3'], + }, + ], + }, +); +await TxEvents.sync(); + +export const GLobalState = sequelize.define('GLobalState', { + id: { + type: DataTypes.INTEGER.UNSIGNED, + primaryKey: true, + autoIncrement: true, + }, + key: { + type: DataTypes.STRING, + allowNull: false, + unique: true, + }, + value: { + type: DataTypes.TEXT, + allowNull: false, + }, +}); +await GLobalState.sync(); diff --git a/m1/infrastructure/evm-rpc/src/helper.js b/m1/infrastructure/evm-rpc/src/helper.js new file mode 100644 index 00000000..31d4a7c7 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/helper.js @@ -0,0 +1,65 @@ +import { ZeroAddress, Transaction } from 'ethers'; +import { BigNumber } from 'bignumber.js'; +import { randomBytes } from 'node:crypto'; +import { TransactionFactory } from '@ethereumjs/tx'; +export function parseRawTx(tx) { + const tx_ = Transaction.from(tx); + const txJson = tx_.toJSON(); + const tx2 = TransactionFactory.fromSerializedData(Buffer.from(tx.slice(2), 'hex')); + const from = tx_.from.toLowerCase(); + let gasPrice = toHex(1500 * 10 ** 9); + if (txJson.type === 2) { + gasPrice = toHex(txJson.maxFeePerGas); + } else if (txJson.type === 0) { + gasPrice = toHex(txJson.gasPrice); + } + return { + hash: tx_.hash, + nonce: txJson.nonce, + from: from, + type: toHex(txJson.type || 0), + messageHash: tx_.unsignedHash, + gasPrice: gasPrice, + limit: toHex(txJson.gasLimit), + to: txJson.to?.toLowerCase() || ZeroAddress, + value: toHex(txJson.value), + data: txJson.data || '0x', + v: +tx2.v?.toString() ?? 27, + r: (tx2.r && toHex(tx2.r)) || '0x', + s: (tx2.s && toHex(tx2.s)) || '0x', + chainId: +txJson.chainId, + }; +} + +export function toHex(number) { + let ret = BigNumber(number).toString(16); + return '0x' + ret; +} + +export function toNumber(number) { + return BigNumber(number).toNumber(); +} + +export function toNumberStr(number) { + return BigNumber(number).decimalPlaces(0).toFixed(); +} + +export function toU256Hex(a, includePrefix = true) { + let it = toHex(a).slice(2).padStart(64, '0'); + if (includePrefix) return '0x' + it; + return it; +} + +export function sleep(s) { + return new Promise(r => { + setTimeout(r, s * 1000); + }); +} + +export function randomHex(bytes = 32) { + return '0x' + Buffer.from(randomBytes(bytes)).toString('hex'); +} + +let x = + '0x02f8d58201500486015d3ef7980086015d3ef79800825208946a9a394cb23b2c5b2e4290f75f80a8e049f3347e80b864c47f00270000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000668656c6c6f320000000000000000000000000000000000000000000000000000c001a038787b861c38d1ff1efaa187cba5f4939228d103e732eae0173d7078389e0af9a079d70b4d9453f35688d3930bbfd87827a274eec1a7ffd8034898d5a600c14811'; +parseRawTx(x); diff --git a/m1/infrastructure/evm-rpc/src/provider.js b/m1/infrastructure/evm-rpc/src/provider.js new file mode 100644 index 00000000..500f9691 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/provider.js @@ -0,0 +1,16 @@ +import { URL } from './const'; +import { fetch } from 'node-fetch'; +export function request(method, ...params) { + const rpcData = { + jsonrpc: '2.0', + method: method, + params: [...params], + id: 1, + }; + const body = JSON.stringify(rpcData); + return fetch(URL, { + method: 'POST', + body, + headers: { 'Content-Type': 'application/json' }, + }).then(response => response.json()); +} diff --git a/m1/infrastructure/evm-rpc/src/rate.js b/m1/infrastructure/evm-rpc/src/rate.js new file mode 100644 index 00000000..9698ef99 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/rate.js @@ -0,0 +1,14 @@ +let request = new Map(); + +export function canRequest(ip) { + let callTime = request.get(ip); + if (!callTime) { + request.set(ip, Date.now()); + return true; + } + if (Date.now() - callTime < 10 * 1000) { + return false; + } + request.set(ip, Date.now()); + return true; +} diff --git a/m1/infrastructure/evm-rpc/src/rpc.js b/m1/infrastructure/evm-rpc/src/rpc.js new file mode 100644 index 00000000..2cc2789a --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/rpc.js @@ -0,0 +1,187 @@ +import { toHex } from './helper.js'; +import { CHAIN_ID } from './const.js'; +import { + callContract, + estimateGas, + getBalance, + getBlock, + getBlockByHash, + getBlockByNumber, + getCode, + getGasPrice, + getNonce, + getStorageAt, + getTransactionByHash, + getTransactionReceipt, + sendRawTx, + faucet, + getLogs, + eth_feeHistory, +} from './bridge.js'; +import JsonRpc from 'json-rpc-2.0'; +const { JSONRPCErrorException } = JsonRpc; +export const rpc = { + eth_feeHistory: async function (args) { + return eth_feeHistory(); + }, + eth_getLogs: async function (args) { + return getLogs(args[0]); + }, + web3_clientVersion: async function () { + return 'Geth/v1.11.6-omnibus-f83e1598/linux-.mdx64/go1.20.3'; + }, + /** + * Returns the chain ID in hexadecimal format. + * @returns {Promise} The chain ID. + */ + eth_chainId: async function () { + return toHex(CHAIN_ID); + }, + + /** + * Returns the version number in hexadecimal format. + * @returns {Promise} The version number. + */ + net_version: async function () { + return toHex(CHAIN_ID); + }, + + /** + * Retrieves the current gas price. + * @returns {Promise} The current gas price. + */ + eth_gasPrice: async function () { + return getGasPrice(); + }, + + /** + * Retrieves the latest block number. + * @returns {Promise} The latest block number. + */ + eth_blockNumber: async function () { + return getBlock(); + }, + + /** + * Sends a signed raw transaction. + * @param {Array} args - The arguments array, where the first element is the signed transaction data. + * @returns {Promise} The transaction hash. + * @throws Will throw an error if the transaction fails. + */ + eth_sendRawTransaction: async function (args) { + try { + return await sendRawTx(args[0]); + } catch (error) { + if (typeof error === 'string') { + throw new JSONRPCErrorException(error, -32000); + } + throw new JSONRPCErrorException(error.message || 'execution reverted', -32000); + } + }, + + /** + * Invokes a method of a smart contract. + * @param {Array} args - The arguments array, where the first element is an object containing the 'from', 'to', and 'data' properties. + * @returns {Promise} The result of the contract method invocation. + * @throws Will throw an error if the contract method invocation fails. + */ + eth_call: async function (args) { + let { to, data: data_, from } = args[0]; + if (args[0].gasPrice) return {}; + try { + return await callContract(from, to, data_); + } catch (error) { + throw new JSONRPCErrorException('execution reverted', -32000); + } + }, + + /** + * Get the transaction count for a given address + * @param {Array} args - The arguments array, where args[0] is the address + * @returns {Promise} - A promise that resolves to the transaction count + */ + eth_getTransactionCount: async function (args) { + return getNonce(args[0]); + }, + + /** + * Get a transaction by its hash + * @param {Array} args - The arguments array, where args[0] is the transaction hash + * @returns {Promise} - A promise that resolves to the transaction object + */ + eth_getTransactionByHash: async function (args) { + return getTransactionByHash(args[0]); + }, + + /** + * Get the receipt of a transaction by its hash + * @param {Array} args - The arguments array, where args[0] is the transaction hash + * @returns {Promise} - A promise that resolves to the transaction receipt object + */ + eth_getTransactionReceipt: async function (args) { + return getTransactionReceipt(args[0]); + }, + + /** + * Estimate the gas required to execute a transaction + * @param {Array} args - The arguments array, where args[0] is the transaction object + * @returns {Promise} - A promise that resolves to the estimated gas + */ + eth_estimateGas: async function (args) { + let res = await estimateGas(args[0]); + if (!res.success) { + throw new JSONRPCErrorException(res.error, -32000); + } + return toHex(res.show_gas); + }, + + /** + * Get a block by its number + * @param {Array} args - The arguments array, where args[0] is the block number + * @returns {Promise} - A promise that resolves to the block object + */ + eth_getBlockByNumber: async function (args) { + return getBlockByNumber(args[0]); + }, + + /** + * Get a block by its hash + * @param {Array} args - The arguments array, where args[0] is the block hash + * @returns {Promise} - A promise that resolves to the block object + */ + eth_getBlockByHash: async function (args) { + return getBlockByHash(args[0]); + }, + + /** + * Get the balance of an address + * @param {Array} args - The arguments array, where args[0] is the address + * @param {Object} ctx - The context object + * @returns {Promise} - A promise that resolves to the balance + */ + eth_getBalance: async function (args) { + return getBalance(args[0]); + }, + + /** + * Get the code at a specific address + * @param {Array} args - The arguments array, where args[0] is the address + * @returns {Promise} - A promise that resolves to the code + */ + eth_getCode: async function (args) { + return getCode(args[0]); + }, + + /** + * Get the storage at a specific position in a specific address + * @param {Array} args - The arguments array, where args[0] is the address and args[1] is the storage position + * @returns {Promise} - A promise that resolves to the storage value + */ + eth_getStorageAt: async function (args) { + return getStorageAt(args[0], args[1]); + }, + + eth_faucet: async function (args) { + return faucet(args[0]); + }, +}; diff --git a/m1/infrastructure/evm-rpc/src/task.js b/m1/infrastructure/evm-rpc/src/task.js new file mode 100644 index 00000000..5acd1221 --- /dev/null +++ b/m1/infrastructure/evm-rpc/src/task.js @@ -0,0 +1,92 @@ +import { getTransactionReceipt } from './bridge.js'; +import { GLobalState, RawTx, TxEvents } from './db.js'; +import { sleep } from './helper.js'; +import { Op } from 'sequelize'; +async function saveEvents(tx) { + const receipt = await getTransactionReceipt(tx); + let logs = receipt.logs; + if (logs.length > 0) { + logs = logs.map(log => { + const { + address, + topics, + data, + blockNumber, + transactionHash, + transactionIndex, + blockHash, + logIndex, + } = log; + return { + logIndex, + blockNumber: parseInt(blockNumber.slice(2), 16), + blockHash, + transactionHash, + transactionIndex, + address, + data: data || '0x', + topics: JSON.stringify(topics), + topic0: topics[0] || '', + topic1: topics[1] || '', + topic2: topics[2] || '', + topic3: topics[3] || '', + }; + }); + await TxEvents.bulkCreate(logs); + } +} +let latest_sync_event_tx_id = -1; +async function syncTxEvents() { + const KEY = 'latestSyncEventTx'; + if (latest_sync_event_tx_id === -1) { + const latestTx = await GLobalState.findOne({ + where: { + key: KEY, + }, + }); + if (!latestTx) { + await GLobalState.create({ + key: KEY, + value: '0', + }); + return; + } + latest_sync_event_tx_id = parseInt(latestTx.value); + } + const nextTx = await RawTx.findOne({ + attributes: ['id', 'hash'], + where: { + id: { + [Op.gt]: latest_sync_event_tx_id, + }, + }, + }); + if (nextTx) { + await saveEvents(nextTx.hash); + await GLobalState.update( + { + value: nextTx.id, + }, + { + where: { + key: KEY, + }, + }, + ); + latest_sync_event_tx_id = parseInt(nextTx.id); + } else { + await sleep(1); + } +} +async function startSyncEventsTask() { + while (true) { + try { + await syncTxEvents(); + } catch (e) { + console.log(e); + } + await sleep(0.1); + } +} + +startSyncEventsTask(); diff --git a/m1/infrastructure/evm-rpc/static/KhoOwatzms.png b/m1/infrastructure/evm-rpc/static/KhoOwatzms.png new file mode 100644 index 00000000..afc242fe Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/KhoOwatzms.png differ diff --git a/m1/infrastructure/evm-rpc/static/chrome_WIbIq1LHp5.png b/m1/infrastructure/evm-rpc/static/chrome_WIbIq1LHp5.png new file mode 100644 index 00000000..ec1b4f03 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/chrome_WIbIq1LHp5.png differ diff --git a/m1/infrastructure/evm-rpc/static/chrome_YU6sTLmcb3.png b/m1/infrastructure/evm-rpc/static/chrome_YU6sTLmcb3.png new file mode 100644 index 00000000..1bf9e0e0 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/chrome_YU6sTLmcb3.png differ diff --git a/m1/infrastructure/evm-rpc/static/chrome_ci8sbs7hKq.png b/m1/infrastructure/evm-rpc/static/chrome_ci8sbs7hKq.png new file mode 100644 index 00000000..f65415f0 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/chrome_ci8sbs7hKq.png differ diff --git a/m1/infrastructure/evm-rpc/static/chrome_pYLDdKbT6Z.png b/m1/infrastructure/evm-rpc/static/chrome_pYLDdKbT6Z.png new file mode 100644 index 00000000..6512e14e Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/chrome_pYLDdKbT6Z.png differ diff --git a/m1/infrastructure/evm-rpc/static/chrome_xvlAxtXOYq.png b/m1/infrastructure/evm-rpc/static/chrome_xvlAxtXOYq.png new file mode 100644 index 00000000..93230af9 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/chrome_xvlAxtXOYq.png differ diff --git a/m1/infrastructure/evm-rpc/static/d17J7RxpqC.png b/m1/infrastructure/evm-rpc/static/d17J7RxpqC.png new file mode 100644 index 00000000..df11db25 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/d17J7RxpqC.png differ diff --git a/m1/infrastructure/evm-rpc/static/d5L1LFOLZR.png b/m1/infrastructure/evm-rpc/static/d5L1LFOLZR.png new file mode 100644 index 00000000..295cf4a5 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/d5L1LFOLZR.png differ diff --git a/m1/infrastructure/evm-rpc/static/nwzl29YTEb.png b/m1/infrastructure/evm-rpc/static/nwzl29YTEb.png new file mode 100644 index 00000000..269f31d1 Binary files /dev/null and b/m1/infrastructure/evm-rpc/static/nwzl29YTEb.png differ diff --git a/m1/infrastructure/subnet-proxy/.gitignore b/m1/infrastructure/subnet-proxy/.gitignore new file mode 100644 index 00000000..b512c09d --- /dev/null +++ b/m1/infrastructure/subnet-proxy/.gitignore @@ -0,0 +1 @@ +node_modules \ No newline at end of file diff --git a/m1/infrastructure/subnet-proxy/.prettierrc b/m1/infrastructure/subnet-proxy/.prettierrc new file mode 100644 index 00000000..2d9dd752 --- /dev/null +++ b/m1/infrastructure/subnet-proxy/.prettierrc @@ -0,0 +1,9 @@ +{ + "tabWidth": 4, + "semi": true, + "singleQuote": true, + "endOfLine": "lf", + "bracketSpacing": true, + "arrowParens": "avoid", + "printWidth": 110 +} diff --git a/m1/infrastructure/subnet-proxy/package-lock.json b/m1/infrastructure/subnet-proxy/package-lock.json new file mode 100644 index 00000000..21a0d59d --- /dev/null +++ b/m1/infrastructure/subnet-proxy/package-lock.json @@ -0,0 +1,1465 @@ +{ + "name": "subnet-request-proxy", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "subnet-request-proxy", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "aptos": "^1.7.2", + "body-parser": "^1.20.2", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "express-async-errors": "^3.1.1", + "express-rate-limit": "^6.7.0", + "lodash": "^4.17.21", + "node-fetch": "^2.6.9", + "prettier": "^3.1.1" + } + }, + "node_modules/@noble/hashes": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.3.tgz", + "integrity": "sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@scure/bip39": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", + "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aptos": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/aptos/-/aptos-1.7.2.tgz", + "integrity": "sha512-unM7bPbu3UGoVB/EhTvA+QDo8nqb6pDfqttsKwC7nYavQnl4t5dxCoFfIFcbijBtSOTfo4is5ldi4Uz4cY9ESA==", + "dependencies": { + "@noble/hashes": "1.1.3", + "@scure/bip39": "1.1.0", + "axios": "0.27.2", + "form-data": "4.0.0", + "tweetnacl": "1.0.3" + }, + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-async-errors": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz", + "integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==", + "peerDependencies": { + "express": "^4.16.2" + } + }, + "node_modules/express-rate-limit": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz", + "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==", + "engines": { + "node": ">= 12.9.0" + }, + "peerDependencies": { + "express": "^4 || ^5" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "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==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + }, + "dependencies": { + "@noble/hashes": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.3.tgz", + "integrity": "sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==" + }, + "@scure/base": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", + "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==" + }, + "@scure/bip39": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", + "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "requires": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "aptos": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/aptos/-/aptos-1.7.2.tgz", + "integrity": "sha512-unM7bPbu3UGoVB/EhTvA+QDo8nqb6pDfqttsKwC7nYavQnl4t5dxCoFfIFcbijBtSOTfo4is5ldi4Uz4cY9ESA==", + "requires": { + "@noble/hashes": "1.1.3", + "@scure/bip39": "1.1.0", + "axios": "0.27.2", + "form-data": "4.0.0", + "tweetnacl": "1.0.3" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + } + } + }, + "express-async-errors": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/express-async-errors/-/express-async-errors-3.1.1.tgz", + "integrity": "sha512-h6aK1da4tpqWSbyCa3FxB/V6Ehd4EEB15zyQq9qe75OZBp0krinNKuH4rAY+S/U/2I36vdLAUFSjQJ+TFmODng==", + "requires": {} + }, + "express-rate-limit": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-6.7.0.tgz", + "integrity": "sha512-vhwIdRoqcYB/72TK3tRZI+0ttS8Ytrk24GfmsxDXK9o9IhHNO5bXRiXQSExPQ4GbaE5tvIS7j1SGrxsuWs+sGA==", + "requires": {} + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "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==", + "requires": { + "mime-db": "1.52.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==" + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + } + } +} diff --git a/m1/infrastructure/subnet-proxy/package.json b/m1/infrastructure/subnet-proxy/package.json new file mode 100644 index 00000000..f8c03b88 --- /dev/null +++ b/m1/infrastructure/subnet-proxy/package.json @@ -0,0 +1,25 @@ +{ + "name": "subnet-request-proxy", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node src/app.js", + "format": "prettier --write src/**/*.js " + }, + "keywords": [], + "author": "shaokun", + "license": "ISC", + "dependencies": { + "aptos": "^1.7.2", + "body-parser": "^1.20.2", + "cors": "^2.8.5", + "dotenv": "^16.3.1", + "express": "^4.18.2", + "express-async-errors": "^3.1.1", + "express-rate-limit": "^6.7.0", + "lodash": "^4.17.21", + "node-fetch": "^2.6.9", + "prettier": "^3.1.1" + } +} diff --git a/m1/infrastructure/subnet-proxy/readme.md b/m1/infrastructure/subnet-proxy/readme.md new file mode 100644 index 00000000..783d33fc --- /dev/null +++ b/m1/infrastructure/subnet-proxy/readme.md @@ -0,0 +1,29 @@ + +## Introduction +This repository contains the code for the Movement Subnet JSON-RPC middleware. The purpose of this middleware is to ensure compatibility with the Aptos SDK. + +## Prerequisites +Before starting, ensure that you have the following dependencies installed: +- Node.js(^18.0) +## Installation +1. Clone the repository to your local machine. +2. Navigate to the project directory. +3. Open the `.env` file and replace the `url` with the RPC endpoint for the desired subnet. You can find the RPC endpoint at [movement-v2](https://github.com/movemntdev/movement-v2). +4. Save the `.env` file. +5. Run the following command to install the required dependencies: +```bash +npm i +``` + +## Usage +To start the middleware, run the following command: +```bash +npm start +``` + +## Test +```javascript +const aptos = require("aptos"); +const NODE_URL = "https://127.0.0.1:3001/v1"; +const client = new aptos.AptosClient(NODE_URL); +``` \ No newline at end of file diff --git a/m1/infrastructure/subnet-proxy/src/app.js b/m1/infrastructure/subnet-proxy/src/app.js new file mode 100644 index 00000000..321e9561 --- /dev/null +++ b/m1/infrastructure/subnet-proxy/src/app.js @@ -0,0 +1,391 @@ +require('dotenv').config(); +require('express-async-errors'); +const express = require('express'); +const bodyParser = require('body-parser'); +const rateLimit = require('express-rate-limit'); +const cors = require('cors'); +const { request } = require('./provider'); +const { sleep } = require('./utils'); +const { PORT } = require('./const'); +const app = express(); +// app.use( +// cors({ +// origin: true, +// methods: ['GET', 'POST'], +// allowedHeaders: ['Content-Type', 'Authorization', 'x-aptos-client'], +// credentials: true, +// }), +// ); +app.use( + cors({ + credentials: true, + origin: function (origin, callback) { + callback(null, true); + }, + }), +); +const limit = { + limit: '10000kb', +}; +app.use(express.json(limit)); +app.use(express.urlencoded({ extended: true, ...limit })); +app.use( + bodyParser.raw({ + type: 'application/x.aptos.signed_transaction+bcs', + ...limit, + }), +); +app.set('trust proxy', 1); +const router = express.Router(); + +function parsePage(req) { + const data = req.query; + const option = {}; + if (data.limit) option.limit = parseInt(data.limit); + if (data.start) option.start = data.start; + return option; +} + +function setHeader(header, res) { + if (!header) return; + if (Object.keys(header).length < 7) return; + res.setHeader('X-APTOS-BLOCK-HEIGHT', header.block_height); + res.setHeader('X-APTOS-CHAIN-ID', header.chain_id); + res.setHeader('X-APTOS-EPOCH', header.epoch); + res.setHeader('X-APTOS-LEDGER-OLDEST-VERSION', header.ledger_oldest_version); + res.setHeader('X-APTOS-LEDGER-TIMESTAMPUSEC', header.ledger_timestamp_usec); + res.setHeader('X-APTOS-LEDGER-VERSION', header.ledger_version); + res.setHeader('X-APTOS-OLDEST-BLOCK-HEIGHT', header.oldest_block_height); + if (header.cursor) { + res.setHeader('X-APTOS-CURSOR', header.cursor); + } +} + +router.get('/transactions', async (req, res) => { + const option = { ...parsePage(req), is_bcs_format: req.is_bcs_format }; + const result = await request('getTransactions', option); + res.sendData(result); +}); + +router.post('/transactions', async (req, res) => { + const body = Buffer.from(req.body).toString('hex'); + let option = { data: body, is_bcs_format: req.is_bcs_format }; + const result = await request('submitTransaction', option); + res.sendData(result); +}); + +router.post('/transactions/batch', async (req, res) => { + const body = Buffer.from(req.body).toString('hex'); + let option = { data: body, is_bcs_format: req.is_bcs_format }; + const result = await request('submitTransactionBatch', option); + res.sendData(result); +}); + +router.get('/transactions/by_hash/:txn_hash', async (req, res) => { + let txn_hash = req.params.txn_hash; + if (txn_hash.startsWith('0x')) txn_hash = txn_hash.slice(2); + let option = { + data: txn_hash, + is_bcs_format: req.is_bcs_format, + }; + const result = await request('getTransactionByHash', option); + res.sendData(result); +}); + +router.get('/transactions/by_version/:txn_version', async (req, res) => { + let txn_version = req.params.txn_version; + let option = { + version: txn_version, + is_bcs_format: req.is_bcs_format, + }; + const result = await request('getTransactionByVersion', option); + res.sendData(result); +}); + +router.get('/accounts/:address/transactions', async (req, res) => { + const address = req.params.address; + const page = parsePage(req); + let option = { + data: address, + ...page, + is_bcs_format: req.is_bcs_format, + }; + + const result = await request('getAccountsTransactions', option); + res.sendData(result); +}); + +router.post('/transactions/simulate', async (req, res) => { + const body = Buffer.from(req.body).toString('hex'); + let option = { data: body, is_bcs_format: req.is_bcs_format }; + const result = await request('simulateTransaction', option); + res.sendData(result); +}); + +router.get('/estimate_gas_price', async (req, res) => { + const result = await request('estimateGasPrice'); + res.sendData(result); +}); + +router.get('/accounts/:address', async (req, res) => { + let option = { + is_bcs_format: req.is_bcs_format, + }; + option.data = req.params.address; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getAccount', option); + res.sendData(result); +}); + +router.get('/accounts/:address/resources', async (req, res) => { + const page = parsePage(req); + let option = { + ...page, + is_bcs_format: req.is_bcs_format, + }; + option.data = req.params.address; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getAccountResources', option); + res.sendData(result); +}); + +router.get('/accounts/:address/modules', async (req, res) => { + const page = parsePage(req); + let option = { + ...page, + is_bcs_format: req.is_bcs_format, + }; + option.data = req.params.address; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getAccountModules', option); + res.sendData(result); +}); + +router.get('/accounts/:address/resource/:resource_type', async (req, res) => { + const address = req.params.address; + let resource_type = req.params.resource_type; + if (resource_type === '0x1::coin::CoinStore<0x1::aptos_coin::MVMTCoin>') { + resource_type = '0x1::coin::CoinStore<0x1::aptos_coin::AptosCoin>'; + } + if (resource_type === '0x1::coin::CoinInfo<0x1::aptos_coin::MVMTCoin>') { + resource_type = '0x1::coin::CoinInfo<0x1::aptos_coin::AptosCoin>'; + } + let option = { + account: address, + resource: resource_type, + is_bcs_format: req.is_bcs_format, + }; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getAccountResourcesState', option); + res.sendData(result); +}); + +router.get('/accounts/:address/module/:module_name', async (req, res) => { + const address = req.params.address; + const module_name = req.params.module_name; + let option = { + account: address, + resource: module_name, + is_bcs_format: req.is_bcs_format, + }; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getAccountModulesState', option); + res.sendData(result); +}); + +router.get('/blocks/by_height/:height', async (req, res) => { + const height = req.params.height; + const option = { with_transactions: false, is_bcs_format: req.is_bcs_format }; + const query = req.query; + if (query.with_transactions?.toString() === 'true') { + option.with_transactions = true; + } + + option.height_or_version = parseInt(height); + const result = await request('getBlockByHeight', option); + res.sendData(result); +}); + +router.get('/blocks/by_version/:version', async (req, res) => { + const version = req.params.version; + const option = { + with_transactions: false, + is_bcs_format: req.is_bcs_format, + }; + if (req.query.with_transactions?.toString() === 'true') { + option.with_transactions = true; + } + option.height_or_version = parseInt(version); + const result = await request('getBlockByVersion', option); + res.sendData(result); +}); + +router.post('/view', async (req, res) => { + const body = req.body; + let option = { + data: JSON.stringify(body), + is_bcs_format: req.is_bcs_format, + }; + const result = await request('viewFunction', option); + res.sendData(result); +}); + +router.post('/tables/:table_handle/item', async (req, res) => { + const body = req.body; + const table_handle = req.params.table_handle; + let option = { + query: table_handle, + body: JSON.stringify(body), + is_bcs_format: req.is_bcs_format, + }; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getTableItem', option); + res.sendData(result); +}); + +router.post('/tables/:table_handle/raw_item', async (req, res) => { + const body = req.body; + const table_handle = req.params.table_handle; + let option = { + query: table_handle, + body: JSON.stringify(body), + is_bcs_format: req.is_bcs_format, + }; + if (req.query.ledger_version) option.ledger_version = '' + req.query.ledger_version; + const result = await request('getRawTableItem', option); + res.sendData(result); +}); + +router.get('/accounts/:address/events/:creation_number', async (req, res) => { + const page = parsePage(req); + const address = req.params.address; + const creation_number = req.params.creation_number; + let option = { + ...page, + address, + creation_number, + is_bcs_format: req.is_bcs_format, + }; + const result = await request('getEventsByCreationNumber', option); + res.sendData(result); +}); + +router.get('/accounts/:address/events/:event_handle/:field_name', async (req, res) => { + const page = parsePage(req); + const address = req.params.address; + const event_handle = req.params.event_handle; + const field_name = req.params.field_name; + let option = { + ...page, + address, + event_handle, + field_name, + is_bcs_format: req.is_bcs_format, + }; + const result = await request('getEventsByEventHandle', option); + res.sendData(result); +}); + +router.get('/', async (req, res) => { + const result = await request('getLedgerInfo'); + res.sendData(result); +}); + +router.get('/-/healthy', async (req, res) => { + res.json({ message: 'success' }); +}); + +// check the account is exist +async function checkAccount(option) { + let tryCount = 0; + while (tryCount < 10) { + let account_result = await request('getAccount', option); + if (account_result.error) { + if (tryCount === 0) { + await request('createAccount', option); + await sleep(1); + } + } else { + break; + } + tryCount++; + } +} + +async function handleMint(req, res) { + const address = req.query.address; + const option = { + data: address, + }; + await checkAccount(option); + let faucet_res = await request('faucet', option); + await sleep(1); + faucet_res.data = [faucet_res.data.hash]; + res.sendData(faucet_res); +} + +router.get('/mint', handleMint); +router.post('/mint', handleMint); +router.get('/faucet', handleMint); +router.post('/faucet', handleMint); + +const limiter = rateLimit({ + windowMs: 5 * 60 * 1000, // 5 minutes + max: 1000, // Limit each IP to 1000 requests per `window` (here, per 15 minutes) + standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers + legacyHeaders: false, // Disable the `X-RateLimit-*` headers +}); + +const bcs_formatter = (req, res, next) => { + let is_bcs_format = false; + let accepts = req.headers['accept']; + let bcs = 'application/x-bcs'; + if (accepts) { + accepts = accepts.split(','); + if (accepts.includes(bcs)) { + is_bcs_format = true; + } + } + req.is_bcs_format = is_bcs_format; + res.sendData = data => { + setHeader(data.header, res); + if (data.error) { + res.status(data.error.code || 404).json(data.error); + } else { + if (is_bcs_format) { + res.setHeader('Content-Type', bcs); + const buffer = Buffer.from(data.data, 'hex'); + res.status(200).send(buffer); + } else { + res.status(200).json(data.data); + } + } + }; + next(); +}; + +// for aptos cli request faucet +app.post('/mint', async function (req, res) { + const address = req.query.auth_key; + const option = { + data: address, + }; + await checkAccount(option); + const result = await request('faucetWithCli', { ...option, is_bcs_format: true }); + await sleep(1); + res.send(result.data); +}); + +app.use('/v1', bcs_formatter, router); + +app.use((err, req, res, next) => { + console.error('--------err---------', err); + res.status(404); + res.json({ + error_code: 'account_not_found', + message: 'Internal Server Error', + }); +}); +app.listen(PORT, () => { + console.log(` app listening on port ${PORT}`); +}); diff --git a/m1/infrastructure/subnet-proxy/src/const.js b/m1/infrastructure/subnet-proxy/src/const.js new file mode 100644 index 00000000..851ec7ad --- /dev/null +++ b/m1/infrastructure/subnet-proxy/src/const.js @@ -0,0 +1,8 @@ +const BASE_URL = process.env.BASE_URL; +const SUBNET_ID = process.env.SUBNET_ID; +const URL = `${BASE_URL}/ext/bc/${SUBNET_ID}/rpc`; +const PORT = process.env.PORT || 3001; +module.exports = { + URL, + PORT, +}; diff --git a/m1/infrastructure/subnet-proxy/src/provider.js b/m1/infrastructure/subnet-proxy/src/provider.js new file mode 100644 index 00000000..606d8935 --- /dev/null +++ b/m1/infrastructure/subnet-proxy/src/provider.js @@ -0,0 +1,83 @@ +const fetch = require('node-fetch'); +const { URL } = require('./const'); +const _ = require('lodash'); +let counter = 1; + +function parseRustString(rustString) { + let fields = ['message', 'error_code', 'vm_error_code']; + const codes = { + BadRequest: 400, + Forbidden: 403, + NotFound: 404, + Gone: 410, + Internal: 500, + ServiceUnavailable: 503, + }; + let result = {}; + let match = rustString.match(/(.*?)\(/)[1]; + result['code'] = codes[match] || 404; + for (let field of fields) { + let regex = new RegExp(field + ': (.*?)[,}]'); + let match = rustString.match(regex); + result[field] = match ? match[1].trim() : null; + } + let someValues = rustString.match(/Some\((.*?)\)/g); + if (someValues) { + const headers = someValues.map(value => { + return Number(value.replace('Some(', '').replace(')', '')); + }); + result['header'] = { + chain_id: headers[0], + ledger_version: headers[1], + ledger_oldest_version: headers[2], + ledger_timestamp_usec: headers[3], + epoch: headers[4], + block_height: headers[5], + oldest_block_height: headers[6], + cursor: headers[7] || null, + }; + } + result['error_code'] = _.snakeCase(result['error_code']); + result['vm_error_code'] = result['vm_error_code'] === 'None' ? null : result['vm_error_code']; + return result; +} + +function request(method, params) { + counter++; + const rpcData = { + jsonrpc: '2.0', + method: method, + params: !!params ? [params] : [], + id: counter, + }; + let body = JSON.stringify(rpcData); + console.log('-------rpcData-----', body); + return fetch(URL, { + method: 'POST', + body, + headers: { 'Content-Type': 'application/json' }, + }) + .then(response => response.json()) + .then(res => { + // console.log('---rpc----res-----', body, res); + let result = res.result; + let data = result.data || '{}'; + let error = result.error; + if (error) { + error = parseRustString(error); + result.header = error.header && JSON.stringify(error.header); + delete error.header; + } else { + if (!params?.is_bcs_format) { + data = JSON.parse(result.data); + } + } + let ret = { + data, + header: result.header && JSON.parse(result.header), + error: error, + }; + return ret; + }); +} +module.exports = { request }; diff --git a/m1/infrastructure/subnet-proxy/src/utils.js b/m1/infrastructure/subnet-proxy/src/utils.js new file mode 100644 index 00000000..91248ef8 --- /dev/null +++ b/m1/infrastructure/subnet-proxy/src/utils.js @@ -0,0 +1,21 @@ +const { HexString, TxnBuilderTypes } = require('aptos'); + +function getAddress(pubKey) { + pubKey = pubKey.replace('0x', ''); + let key = HexString.ensure(pubKey).toUint8Array(); + + pubKey = new TxnBuilderTypes.Ed25519PublicKey(key); + + const authKey = TxnBuilderTypes.AuthenticationKey.fromEd25519PublicKey(pubKey); + let keys = authKey.derivedAddress(); + return keys.hexString.slice(2); +} + +function sleep(s) { + return new Promise(r => setTimeout(r, s * 1000)); +} + +module.exports = { + sleep, + getAddress, +}; diff --git a/movement-sdk/Cargo.lock b/movement-sdk/Cargo.lock index 5f16cbb2..6344aaef 100644 --- a/movement-sdk/Cargo.lock +++ b/movement-sdk/Cargo.lock @@ -8895,6 +8895,7 @@ dependencies = [ "semver", "serde 1.0.195", "serde_json", + "services", "sui", "tempfile", "tokio", diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/localnet.rs b/movement-sdk/artifacts/src/known_artifacts/m1/localnet.rs index 01429ad2..898a93cf 100644 --- a/movement-sdk/artifacts/src/known_artifacts/m1/localnet.rs +++ b/movement-sdk/artifacts/src/known_artifacts/m1/localnet.rs @@ -33,8 +33,8 @@ impl ConstructorOperations for Constructor { ].into_iter().collect()) } - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() + fn from_config(version : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { + Self::default_with_version(version) } } diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/m1_with_submodules.rs b/movement-sdk/artifacts/src/known_artifacts/m1/m1_with_submodules.rs index d3f0f2a5..a6be29ed 100644 --- a/movement-sdk/artifacts/src/known_artifacts/m1/m1_with_submodules.rs +++ b/movement-sdk/artifacts/src/known_artifacts/m1/m1_with_submodules.rs @@ -33,7 +33,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } @@ -82,32 +82,5 @@ pub mod test { } - #[derive(Debug, Clone)] - pub struct Fake; - - impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "avalanche".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - - } - } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/mod.rs b/movement-sdk/artifacts/src/known_artifacts/m1/mod.rs index 881c2473..e2041fb1 100644 --- a/movement-sdk/artifacts/src/known_artifacts/m1/mod.rs +++ b/movement-sdk/artifacts/src/known_artifacts/m1/mod.rs @@ -2,4 +2,6 @@ pub mod m1_with_submodules; pub mod subnet; pub mod testnet_id; pub mod testnet; -pub mod localnet; \ No newline at end of file +pub mod localnet; +pub mod testnet_cid; +pub mod testnet_vmid; \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/subnet.rs b/movement-sdk/artifacts/src/known_artifacts/m1/subnet.rs index 066abfb2..57f65a39 100644 --- a/movement-sdk/artifacts/src/known_artifacts/m1/subnet.rs +++ b/movement-sdk/artifacts/src/known_artifacts/m1/subnet.rs @@ -65,7 +65,7 @@ impl ConstructorOperations for Constructor { let movement = Self::build(); #[cfg(target_os = "windows")] - let movement = Artifact::unsupported(); + let movement = Artifact::unsupported("subnet".to_string()); movement @@ -76,7 +76,7 @@ impl ConstructorOperations for Constructor { .with_version(version.clone()) } - fn from_config(config : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, config : &Self::Config) -> Self::Artifact { if config.build { Self::build() @@ -137,32 +137,5 @@ pub mod test { } - #[derive(Debug, Clone)] - pub struct Fake; - - impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "avalanche".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - - } - } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/testnet.rs b/movement-sdk/artifacts/src/known_artifacts/m1/testnet.rs index faae173b..4dfd0754 100644 --- a/movement-sdk/artifacts/src/known_artifacts/m1/testnet.rs +++ b/movement-sdk/artifacts/src/known_artifacts/m1/testnet.rs @@ -4,6 +4,8 @@ use util::{ util::util::version }; use super::{ + testnet_vmid, + testnet_cid, testnet_id, subnet, super::third_party::avalanche::{ @@ -32,27 +34,31 @@ impl ConstructorOperations for Constructor { fn default_with_version(version : &util::util::util::Version) -> Self::Artifact { // source should have the same version - let avalanche = avalanche::Constructor::default_with_version(version); - let avalanchego = avalanchego::Constructor::default_with_version(version); + let avalanche = avalanche::Constructor::default(); + let avalanchego = avalanchego::Constructor::default(); let subnet = subnet::Constructor::default_with_version(version); let testnet_id = testnet_id::Constructor::default_with_version(version); + let testnet_cid = testnet_cid::Constructor::default_with_version(version); + let testnet_vmid = testnet_vmid::Constructor::default_with_version(version); Artifact::self_contained_script( "testnet".to_string(), r#" echo $MOVEMENT_DIR - cp $MOVEMENT_DIR/bin/subnet $MOVEMENT_DIR/bin/$(cat $MOVEMENT_DIR/rsc/testnet-id) + cp $MOVEMENT_DIR/bin/subnet $MOVEMENT_DIR/bin/$(cat $MOVEMENT_DIR/rsc/testnet-vmid) "#.to_string(), ).with_dependencies(vec![ avalanche.into(), avalanchego.into(), testnet_id.into(), + testnet_cid.into(), + testnet_vmid.into(), subnet.into(), ].into_iter().collect()) } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/testnet_cid.rs b/movement-sdk/artifacts/src/known_artifacts/m1/testnet_cid.rs new file mode 100644 index 00000000..c07efb45 --- /dev/null +++ b/movement-sdk/artifacts/src/known_artifacts/m1/testnet_cid.rs @@ -0,0 +1,78 @@ +use util::{ + release::Release, + artifact::Artifact, + util::util::patterns::constructor::ConstructorOperations +}; + +#[derive(Debug, Clone)] +pub struct Config; + +#[derive(Debug, Clone)] +pub struct Constructor; + +impl ConstructorOperations for Constructor { + + type Artifact = Artifact; + type Config = Config; + + fn default() -> Self::Artifact { + + Artifact::resource_release( + "testnet-cid".to_string(), + Release::github_release( + "movemntdev".to_string(), + "M1".to_string(), + "testnet-cid".to_string(), + "".to_string() + ) + ) + + } + + fn default_with_version(version : &util::util::util::Version) -> Self::Artifact { + Self::default().with_version(version.clone()) + } + + fn from_config(version : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { + Self::default_with_version(version) + } + +} + +#[cfg(test)] +pub mod test { + + use super::*; + use util::movement_dir::MovementDir; + + #[tokio::test] + async fn test_testnet_cid_with_submodules() -> Result<(), anyhow::Error> { + + let temp_home = tempfile::tempdir()?; + + // Add any other essential system paths. This example includes /usr/bin and /bin. + test_helpers::clean_path(vec![ + "/usr/bin".to_string(), "/bin".to_string(), + ])?; + std::env::set_var("HOME", temp_home.path()); + + // Perform test actions here + let dir = temp_home.path().to_path_buf(); + let movement_dir = MovementDir::new(&dir); + let artifact = Constructor::default(); + + test_helpers::clean_path(vec![ + "/usr/bin".to_string(), "/bin".to_string(), + ])?; + artifact.install(&movement_dir).await?; + assert!(tokio::fs::try_exists( + dir.join("rsc").join("testnet-cid") + ).await?); + + Ok(()) + + } + + + +} \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/testnet_id.rs b/movement-sdk/artifacts/src/known_artifacts/m1/testnet_id.rs index cae7b7ed..3ae83cb4 100644 --- a/movement-sdk/artifacts/src/known_artifacts/m1/testnet_id.rs +++ b/movement-sdk/artifacts/src/known_artifacts/m1/testnet_id.rs @@ -33,8 +33,8 @@ impl ConstructorOperations for Constructor { Self::default().with_version(version.clone()) } - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() + fn from_config(version : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { + Self::default_with_version(version) } } @@ -45,7 +45,6 @@ pub mod test { use super::*; use util::movement_dir::MovementDir; - #[cfg(target_os = "macos")] #[tokio::test] async fn test_testnet_id_with_submodules() -> Result<(), anyhow::Error> { diff --git a/movement-sdk/artifacts/src/known_artifacts/m1/testnet_vmid.rs b/movement-sdk/artifacts/src/known_artifacts/m1/testnet_vmid.rs new file mode 100644 index 00000000..d14f08db --- /dev/null +++ b/movement-sdk/artifacts/src/known_artifacts/m1/testnet_vmid.rs @@ -0,0 +1,78 @@ +use util::{ + release::Release, + artifact::Artifact, + util::util::patterns::constructor::ConstructorOperations +}; + +#[derive(Debug, Clone)] +pub struct Config; + +#[derive(Debug, Clone)] +pub struct Constructor; + +impl ConstructorOperations for Constructor { + + type Artifact = Artifact; + type Config = Config; + + fn default() -> Self::Artifact { + + Artifact::resource_release( + "testnet-vmid".to_string(), + Release::github_release( + "movemntdev".to_string(), + "M1".to_string(), + "testnet-vmid".to_string(), + "".to_string() + ) + ) + + } + + fn default_with_version(version : &util::util::util::Version) -> Self::Artifact { + Self::default().with_version(version.clone()) + } + + fn from_config(version : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { + Self::default_with_version(version) + } + +} + +#[cfg(test)] +pub mod test { + + use super::*; + use util::movement_dir::MovementDir; + + #[tokio::test] + async fn test_testnet_vmid_with_submodules() -> Result<(), anyhow::Error> { + + let temp_home = tempfile::tempdir()?; + + // Add any other essential system paths. This example includes /usr/bin and /bin. + test_helpers::clean_path(vec![ + "/usr/bin".to_string(), "/bin".to_string(), + ])?; + std::env::set_var("HOME", temp_home.path()); + + // Perform test actions here + let dir = temp_home.path().to_path_buf(); + let movement_dir = MovementDir::new(&dir); + let artifact = Constructor::default(); + + test_helpers::clean_path(vec![ + "/usr/bin".to_string(), "/bin".to_string(), + ])?; + artifact.install(&movement_dir).await?; + assert!(tokio::fs::try_exists( + dir.join("rsc").join("testnet-vmid") + ).await?); + + Ok(()) + + } + + + +} \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/movement/movement.rs b/movement-sdk/artifacts/src/known_artifacts/movement/movement.rs index 9290aaf8..ebabe32d 100644 --- a/movement-sdk/artifacts/src/known_artifacts/movement/movement.rs +++ b/movement-sdk/artifacts/src/known_artifacts/movement/movement.rs @@ -66,7 +66,7 @@ impl ConstructorOperations for Constructor { let movement = Self::build(); #[cfg(target_os = "windows")] - let movement = Artifact::unsupported(); + let movement = Artifact::unsupported("movement".to_string()); movement @@ -77,7 +77,7 @@ impl ConstructorOperations for Constructor { .with_version(version.clone()) } - fn from_config(config : &Self::Config) -> Self::Artifact { + fn from_config(version : &util::util::util::Version, config : &Self::Config) -> Self::Artifact { if config.build { Self::build() @@ -132,32 +132,4 @@ pub mod test { } - #[derive(Debug, Clone)] - pub struct Fake; - - impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "avalanche".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - - } - - } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanche.rs b/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanche.rs index 25987546..9122a9eb 100644 --- a/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanche.rs +++ b/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanche.rs @@ -43,7 +43,7 @@ impl ConstructorOperations for Constructor { ); #[cfg(target_os = "windows")] - let avalanche = Artifact::unsupported(); + let avalanche = Artifact::unsupported("avalanche".to_string()); avalanche } @@ -52,7 +52,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } @@ -160,7 +160,7 @@ pub mod test { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } diff --git a/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanchego.rs b/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanchego.rs index 54f5f133..9a33772f 100644 --- a/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanchego.rs +++ b/movement-sdk/artifacts/src/known_artifacts/third_party/avalanche/avalanchego.rs @@ -48,7 +48,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } @@ -77,31 +77,4 @@ pub mod test { } - #[derive(Debug, Clone)] - pub struct Fake; - - impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "cargo".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - - } - } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/third_party/cargo/cargo.rs b/movement-sdk/artifacts/src/known_artifacts/third_party/cargo/cargo.rs index 336fb525..d8df615d 100644 --- a/movement-sdk/artifacts/src/known_artifacts/third_party/cargo/cargo.rs +++ b/movement-sdk/artifacts/src/known_artifacts/third_party/cargo/cargo.rs @@ -29,7 +29,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } @@ -73,65 +73,4 @@ pub mod test { } - #[tokio::test] - async fn test_fake_should_not_work() -> Result<(), anyhow::Error> { - - let temp_home = tempfile::tempdir()?; - let temp_cargo_bin = temp_home.path().join(".cargo/bin").to_str().unwrap().to_owned(); - - // - test_helpers::clean_path(vec![ - "/usr/bin".to_string(), "/bin".to_string(), temp_cargo_bin - ])?; - std::env::set_var("HOME", temp_home.path()); - std::env::set_var("CARGO_HOME", temp_home.path().join(".cargo")); - std::env::set_var("RUSTUP_HOME", temp_home.path().join(".rustup")); - - - // Perform test actions here - let dir = temp_home.path().to_path_buf(); - let movement_dir = MovementDir::new(&dir); - let artifact = Fake::default(); - - artifact.install(&movement_dir).await?; - - let exists = match std::process::Command::new("cargo").arg("--version").output() { - Ok(output) => output.status.success(), - Err(_) => false, - }; - - assert!(!exists); - - Ok(()) - - } - - #[derive(Debug, Clone)] - pub struct Fake; - - impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "cargo".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - - } - - } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/third_party/sys/brew.rs b/movement-sdk/artifacts/src/known_artifacts/third_party/sys/brew.rs index 281c677b..55d81546 100644 --- a/movement-sdk/artifacts/src/known_artifacts/third_party/sys/brew.rs +++ b/movement-sdk/artifacts/src/known_artifacts/third_party/sys/brew.rs @@ -36,7 +36,7 @@ impl ConstructorOperations for Constructor { ); #[cfg(target_os = "windows")] - let avalanche = Artifact::unsupported(); + let avalanche = Artifact::unsupported("brew".to_string()); avalanche } @@ -45,7 +45,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } @@ -93,65 +93,5 @@ pub mod test { } - #[tokio::test] - async fn test_fake_should_not_work() -> Result<(), anyhow::Error> { - - let temp_home = tempfile::tempdir()?; - let temp_avalanche_bin = temp_home.path().join(".avalanche/bin").to_str().unwrap().to_owned(); - - // - test_helpers::clean_path(vec![ - "/usr/bin".to_string(), "/bin".to_string(), temp_avalanche_bin - ])?; - std::env::set_var("HOME", temp_home.path()); - std::env::set_var("avalanche_HOME", temp_home.path().join(".avalanche")); - std::env::set_var("RUSTUP_HOME", temp_home.path().join(".rustup")); - - // Perform test actions here - let dir = temp_home.path().to_path_buf(); - let movement_dir = MovementDir::new(&dir); - let artifact = Fake::default(); - - artifact.install(&movement_dir).await?; - - let exists = match std::process::Command::new("avalanche").arg("--version").output() { - Ok(output) => output.status.success(), - Err(_) => false, - }; - - assert!(!exists); - - Ok(()) - - } - - #[derive(Debug, Clone)] - pub struct Fake; - - impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "avalanche".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - - } - - } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/third_party/sys/curl.rs b/movement-sdk/artifacts/src/known_artifacts/third_party/sys/curl.rs index d7ca4127..7227bab8 100644 --- a/movement-sdk/artifacts/src/known_artifacts/third_party/sys/curl.rs +++ b/movement-sdk/artifacts/src/known_artifacts/third_party/sys/curl.rs @@ -25,34 +25,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - -} - -#[derive(Debug, Clone)] -pub struct Fake; - -impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "curl".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } @@ -87,40 +60,5 @@ pub mod test { } - #[cfg(not(target_os = "macos"))] - #[tokio::test] - async fn test_fake_should_not_work() -> Result<(), anyhow::Error> { - - let temp_home = tempfile::tempdir()?; - - let system_paths = vec!["/usr/bin", "/bin"]; - let new_path = system_paths.into_iter().map(String::from) - .collect::>() - .join(":"); - - // Override environment variables - std::env::set_var("HOME", temp_home.path()); - std::env::set_var("CARGO_HOME", temp_home.path().join(".cargo")); - std::env::set_var("RUSTUP_HOME", temp_home.path().join(".rustup")); - std::env::set_var("PATH", new_path); - - - // Perform test actions here - let dir = temp_home.path().to_path_buf(); - let movement_dir = MovementDir::new(&dir); - let artifact = Fake::default(); - - artifact.install(&movement_dir).await?; - - let exists = match std::process::Command::new("curl").arg("--version").output() { - Ok(output) => output.status.success(), - Err(_) => false, - }; - - assert!(!exists); - - Ok(()) - - } } \ No newline at end of file diff --git a/movement-sdk/artifacts/src/known_artifacts/third_party/sys/git.rs b/movement-sdk/artifacts/src/known_artifacts/third_party/sys/git.rs index dc7345ee..06ed82d9 100644 --- a/movement-sdk/artifacts/src/known_artifacts/third_party/sys/git.rs +++ b/movement-sdk/artifacts/src/known_artifacts/third_party/sys/git.rs @@ -19,7 +19,7 @@ impl ConstructorOperations for Constructor { #[cfg(target_os = "macos")] let git = Artifact::noop("git".to_string()); // Should already be installed on macOS - #[cfg(target_os = "ubuntu")] + #[cfg(not(target_os = "macos"))] let git = Artifact::self_contained_script( "git".to_string(), r#" @@ -29,8 +29,7 @@ impl ConstructorOperations for Constructor { "#.to_string(), ); - #[cfg(not(any(target_os = "macos", target_os = "ubuntu")))] - let git = Artifact::unsupported(); + // todo: update for windows git @@ -40,34 +39,7 @@ impl ConstructorOperations for Constructor { Self::default() } - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() - } - -} - -#[derive(Debug, Clone)] -pub struct Fake; - -impl ConstructorOperations for Fake { - - type Artifact = Artifact; - type Config = Config; - - fn default() -> Self::Artifact { - Artifact::self_contained_script( - "git".to_string(), - r#" - echo fake - "#.to_string(), - ) - } - - fn default_with_version(_ : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { + fn from_config(_ : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { Self::default() } diff --git a/movement-sdk/clis/movement/Cargo.toml b/movement-sdk/clis/movement/Cargo.toml index e9a96091..fa6bd1ae 100644 --- a/movement-sdk/clis/movement/Cargo.toml +++ b/movement-sdk/clis/movement/Cargo.toml @@ -17,6 +17,7 @@ serde_json = { workspace = true } const-str = { workspace = true } util = { workspace = true } artifacts = { workspace = true } +services = { workspace = true } # aptos and sui only if features are enabled diff --git a/movement-sdk/clis/movement/src/aptos/README.md b/movement-sdk/clis/movement/src/aptos/README.md deleted file mode 100644 index 8d90ce31..00000000 --- a/movement-sdk/clis/movement/src/aptos/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# `aptos` -The `aptos` subcommand roughly subsumes the Aptos CLI. \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/aptos/aptos.rs b/movement-sdk/clis/movement/src/aptos/aptos.rs deleted file mode 100644 index f0b09280..00000000 --- a/movement-sdk/clis/movement/src/aptos/aptos.rs +++ /dev/null @@ -1,17 +0,0 @@ -use clap::Parser; -use aptos::Tool; -use clap::Subcommand; -use std::fmt::{self, Debug, Formatter}; -use crate::common::cli::Command; - -#[derive(Subcommand)] -pub enum Aptos { - #[clap(subcommand)] - Tool(Tool) -} - -impl Debug for Aptos { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "Aptos") - } -} \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/aptos/mod.rs b/movement-sdk/clis/movement/src/aptos/mod.rs deleted file mode 100644 index 7422e029..00000000 --- a/movement-sdk/clis/movement/src/aptos/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod aptos; -pub use self::aptos::Aptos; \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/ctl/ctl.rs b/movement-sdk/clis/movement/src/ctl/ctl.rs index 6cdfc319..f9801a9a 100644 --- a/movement-sdk/clis/movement/src/ctl/ctl.rs +++ b/movement-sdk/clis/movement/src/ctl/ctl.rs @@ -1,10 +1,10 @@ -use async_trait::async_trait; use clap::Subcommand; use super::{ start::Start, status::Status, stop::Stop, }; +use util::cli::Command; #[derive(Subcommand, Debug)] #[clap( @@ -18,4 +18,24 @@ pub enum Ctl { Status(Status), #[clap(subcommand)] Stop(Stop), -} \ No newline at end of file +} + +#[async_trait::async_trait] +impl Command for Ctl { + + async fn get_name(&self) -> String { + "ctl".to_string() + } + + async fn execute(self) -> Result { + + match self { + Ctl::Start(start) => start.execute().await?, + _ => unimplemented!() + }; + + Ok("SUCCESS".to_string()) + } + +} + diff --git a/movement-sdk/clis/movement/src/ctl/start/m1/indexer.rs b/movement-sdk/clis/movement/src/ctl/start/m1/indexer.rs new file mode 100644 index 00000000..e69de29b diff --git a/movement-sdk/clis/movement/src/ctl/start/m1/m1.rs b/movement-sdk/clis/movement/src/ctl/start/m1/m1.rs new file mode 100644 index 00000000..8491e392 --- /dev/null +++ b/movement-sdk/clis/movement/src/ctl/start/m1/m1.rs @@ -0,0 +1,30 @@ +use clap::Subcommand; +use util::cli::Command; +use super::testnet::Testnet; + +#[derive(Subcommand, Debug)] +#[clap( + rename_all = "kebab-case", + about = "Start an M1 service" +)] +pub enum M1 { + Testnet(Testnet) +} + +#[async_trait::async_trait] +impl Command for M1 { + + async fn get_name(&self) -> String { + "start".to_string() + } + + async fn execute(self) -> Result { + + match self { + M1::Testnet(testnet) => testnet.execute().await? + }; + + Ok("SUCCESS".to_string()) + } + +} \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/ctl/start/m1/mod.rs b/movement-sdk/clis/movement/src/ctl/start/m1/mod.rs new file mode 100644 index 00000000..ca94c7e5 --- /dev/null +++ b/movement-sdk/clis/movement/src/ctl/start/m1/mod.rs @@ -0,0 +1,5 @@ +pub mod proxy; +pub mod testnet; +pub mod indexer; +pub mod m1; +pub use m1::*; \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/ctl/start/m1/proxy.rs b/movement-sdk/clis/movement/src/ctl/start/m1/proxy.rs new file mode 100644 index 00000000..e69de29b diff --git a/movement-sdk/clis/movement/src/ctl/start/m1/testnet.rs b/movement-sdk/clis/movement/src/ctl/start/m1/testnet.rs new file mode 100644 index 00000000..97fc83c7 --- /dev/null +++ b/movement-sdk/clis/movement/src/ctl/start/m1/testnet.rs @@ -0,0 +1,53 @@ +use services::m1::testnet; +use async_trait::async_trait; +use clap::Parser; +use util::{cli::Command, util::util::constructor::ConstructorOperations}; +use crate::manage::{ + InstallationArgs, + VersionArgs +}; +use util::util::util::Version; +use util::service::ServiceOperations; +use util::movement_dir::MovementDir; + +#[derive(Debug, Parser, Clone)] +pub struct Testnet { + + #[clap(flatten)] + pub version_args : VersionArgs, + + #[clap(flatten)] + pub installation_args : InstallationArgs + +} + +impl Into for Testnet { + fn into(self) -> testnet::Config { + testnet::Config + } +} + + +#[async_trait] +impl Command for Testnet { + + async fn get_name(&self) -> String { + "testnet".to_string() + } + + async fn execute(self) -> Result { + + let movement_dir = MovementDir::default(); + + // todo: handle config and version + let config : testnet::Config = self.clone().into(); + let version : Version = self.version_args.try_into()?; + + let service = testnet::Constructor::default(); + + service.start(&movement_dir).await?; + + Ok("SUCCESS".to_string()) + } + +} \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/ctl/start/mod.rs b/movement-sdk/clis/movement/src/ctl/start/mod.rs index eb594da6..82e2ff5c 100644 --- a/movement-sdk/clis/movement/src/ctl/start/mod.rs +++ b/movement-sdk/clis/movement/src/ctl/start/mod.rs @@ -1,2 +1,3 @@ pub mod start; -pub use start::Start; \ No newline at end of file +pub use start::Start; +pub mod m1; \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/ctl/start/start.rs b/movement-sdk/clis/movement/src/ctl/start/start.rs index 1b02d17d..14871a00 100644 --- a/movement-sdk/clis/movement/src/ctl/start/start.rs +++ b/movement-sdk/clis/movement/src/ctl/start/start.rs @@ -1,5 +1,6 @@ -use async_trait::async_trait; use clap::Subcommand; +use util::cli::Command; +use super::m1::M1; #[derive(Subcommand, Debug)] #[clap( @@ -7,5 +8,24 @@ use clap::Subcommand; about = "Start a Movement service" )] pub enum Start { - + #[clap(subcommand)] + M1(M1) +} + +#[async_trait::async_trait] +impl Command for Start { + + async fn get_name(&self) -> String { + "start".to_string() + } + + async fn execute(self) -> Result { + + match self { + Start::M1(m1) => m1.execute().await? + }; + + Ok("SUCCESS".to_string()) + } + } \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/lib.rs b/movement-sdk/clis/movement/src/lib.rs index db78fe06..5c530672 100644 --- a/movement-sdk/clis/movement/src/lib.rs +++ b/movement-sdk/clis/movement/src/lib.rs @@ -49,7 +49,7 @@ impl Command for MovementCommand { Ok("SUCCESS".to_string()) }, MovementCommand::Ctl(ctl) => { - // ctl.execute().await?; + ctl.execute().await?; Ok("SUCCESS".to_string()) }, #[cfg(feature = "aptos")] diff --git a/movement-sdk/clis/movement/src/manage/install/m1/localnet.rs b/movement-sdk/clis/movement/src/manage/install/m1/localnet.rs index b1fc4ee7..809984a7 100644 --- a/movement-sdk/clis/movement/src/manage/install/m1/localnet.rs +++ b/movement-sdk/clis/movement/src/manage/install/m1/localnet.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use clap::Parser; use util::{cli::Command, util::util::constructor::ConstructorOperations}; use artifacts::known_artifacts::{ - install_default, + install, m1::m1_with_submodules }; use crate::manage::{ @@ -10,6 +10,7 @@ use crate::manage::{ VersionArgs }; use util::util::util::Version; +use util::movement_dir::MovementDir; #[derive(Debug, Parser, Clone)] @@ -39,14 +40,19 @@ impl Command for Localnet { async fn execute(self) -> Result { + let movement_dir = MovementDir::default(); let config : m1_with_submodules::Config = self.clone().into(); let version : Version = self.version_args.try_into()?; let artifact = m1_with_submodules::Constructor::from_config( + &version, &config - ).with_version(version); + ); - install_default(vec![artifact.into()]).await?; + install( + movement_dir, + vec![artifact.into()] + ).await?; Ok("SUCCESS".to_string()) } diff --git a/movement-sdk/clis/movement/src/manage/install/m1/testnet.rs b/movement-sdk/clis/movement/src/manage/install/m1/testnet.rs index cc916ac8..e69363da 100644 --- a/movement-sdk/clis/movement/src/manage/install/m1/testnet.rs +++ b/movement-sdk/clis/movement/src/manage/install/m1/testnet.rs @@ -1,15 +1,17 @@ +use artifacts::known_artifacts::movement; use async_trait::async_trait; use clap::Parser; use util::{cli::Command, util::util::constructor::ConstructorOperations}; use artifacts::known_artifacts::{ m1::testnet, - install_default + install }; use crate::manage::{ InstallationArgs, VersionArgs }; use util::util::util::Version; +use util::movement_dir::MovementDir; #[derive(Debug, Parser, Clone)] pub struct Testnet { @@ -38,14 +40,19 @@ impl Command for Testnet { async fn execute(self) -> Result { + let movement_dir = MovementDir::default(); let config : testnet::Config = self.clone().into(); let version : Version = self.version_args.try_into()?; let artifact = testnet::Constructor::from_config( + &version, &config - ).with_version(version); + ); - install_default(vec![artifact.into()]).await?; + install( + movement_dir, + vec![artifact.into()] + ).await?; Ok("SUCCESS".to_string()) } diff --git a/movement-sdk/clis/movement/src/sui/README.md b/movement-sdk/clis/movement/src/sui/README.md deleted file mode 100644 index 87a2203c..00000000 --- a/movement-sdk/clis/movement/src/sui/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# `sui` -The `sui` subcommand roughly subsumes the Sui CLI. \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/sui/mod.rs b/movement-sdk/clis/movement/src/sui/mod.rs deleted file mode 100644 index b165ffa0..00000000 --- a/movement-sdk/clis/movement/src/sui/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod sui; -pub use self::sui::Sui; \ No newline at end of file diff --git a/movement-sdk/clis/movement/src/sui/sui.rs b/movement-sdk/clis/movement/src/sui/sui.rs deleted file mode 100644 index a4cdccaa..00000000 --- a/movement-sdk/clis/movement/src/sui/sui.rs +++ /dev/null @@ -1,54 +0,0 @@ -pub use clap::Parser; -use sui::sui_commands::SuiCommand; -use clap::{FromArgMatches, ArgMatches, Subcommand}; -use std::fmt::{self, Debug, Formatter}; -use crate::common::cli::Command; - - - -#[derive(Subcommand)] -pub struct Sui { - #[clap(subcommand)] - command: SuiCommand -} - -impl Debug for Sui { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "Sui") - } -} - -#[async_trait::async_trait] -impl Command for Sui { - - async fn get_name(&self) -> String { - "sui".to_string() - } - - async fn execute(self) -> Result { - #[cfg(windows)] - colored::control::set_virtual_terminal(true).unwrap(); - - let args = Args::parse(); - let _guard = match args.command { - SuiCommand::Console { .. } - | SuiCommand::Client { .. } - | SuiCommand::KeyTool { .. } - | SuiCommand::Move { .. } => telemetry_subscribers::TelemetryConfig::new() - .with_log_level("error") - .with_env() - .init(), - _ => telemetry_subscribers::TelemetryConfig::new() - .with_env() - .init(), - }; - - debug!("Sui CLI version: {VERSION}"); - - exit_main!(args.command.execute().await); - - Ok("SUCCESS".to_string()) - - } - -} \ No newline at end of file diff --git a/movement-sdk/services/src/m1/testnet.rs b/movement-sdk/services/src/m1/testnet.rs index 967617ad..142d1f48 100644 --- a/movement-sdk/services/src/m1/testnet.rs +++ b/movement-sdk/services/src/m1/testnet.rs @@ -1,7 +1,9 @@ use util::{ service::Service, - util::util::patterns::constructor::ConstructorOperations + util::util::patterns::constructor::ConstructorOperations, + util::util::version }; +use artifacts::known_artifacts::m1::testnet; #[derive(Debug, Clone)] pub struct Config; @@ -16,23 +18,30 @@ impl ConstructorOperations for Constructor { fn default() -> Self::Artifact { + Self::default_with_version(&version::Version::Latest) + + } + + fn default_with_version(version : &util::util::util::Version) -> Self::Artifact { + Service::foreground( "testnet".to_string(), r#" + set -e echo $MOVEMENT_DIR - $MOVEMENT_DIR/bin/avalanchego --fuji --track-subnets= + $MOVEMENT_DIR/bin/avalanchego --network-id=fuji --track-subnets=$(cat $MOVEMENT_DIR/rsc/testnet-vmid) "#.to_string(), - vec![] + vec![ + testnet::Constructor::default_with_version( + version + ).into() + ] ) } - fn default_with_version(version : &util::util::util::Version) -> Self::Artifact { - Self::default() - } - - fn from_config(_ : &Self::Config) -> Self::Artifact { - Self::default() + fn from_config(version : &util::util::util::Version, _ : &Self::Config) -> Self::Artifact { + Self::default_with_version(version) } } diff --git a/movement-sdk/util/util/src/util/util/patterns.rs b/movement-sdk/util/util/src/util/util/patterns.rs index 08a0c499..31aecbbc 100644 --- a/movement-sdk/util/util/src/util/util/patterns.rs +++ b/movement-sdk/util/util/src/util/util/patterns.rs @@ -21,10 +21,10 @@ pub mod constructor { T::default() } - fn from_config(config : &Self::Config) -> Self::Artifact; + fn from_config(version : &Version, config : &Self::Config) -> Self::Artifact; - fn sub_from_config(config : &Self::Config) -> Self::Artifact where T : ConstructorOperations { - T::from_config(config) + fn sub_from_config(version : &Version, config : &Self::Config) -> Self::Artifact where T : ConstructorOperations { + T::from_config(version, config) } }