diff --git a/.github/workflows/dapp-deploy.yml b/.github/workflows/dapp-deploy.yml index 9e7e9b3..50e0357 100644 --- a/.github/workflows/dapp-deploy.yml +++ b/.github/workflows/dapp-deploy.yml @@ -8,11 +8,7 @@ on: required: true type: choice options: - # dev environments - - bellecour-dev - arbitrum-sepolia-dev - # prod environments (requires a tag starting with dapp-v) - - bellecour-prod - arbitrum-sepolia-prod - arbitrum-prod @@ -24,10 +20,6 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 - # ref should be a tag beginning with dapp-v if not exit error - # use unique clean-tag: - - # else - # use rolling clean-tag: dev - name: Check and extract tag id: tag run: | @@ -71,36 +63,7 @@ jobs: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_PAT }} - sconify: - if: startsWith(github.event.inputs.environment, 'bellecour-') - uses: iExecBlockchainComputing/github-actions-workflows/.github/workflows/sconify.yml@sconify-v2.0.0 - needs: [docker-publish, extract-tag] - with: - image-name: 'iexechub/web3telegram-dapp' - image-tag: ${{ needs.extract-tag.outputs.clean_tag }} - sconify-debug: false - sconify-prod: true - docker-registry: docker.io - sconify-version: ${{ vars.SCONIFY_VERSION }} - binary: /usr/local/bin/node - command: node - host-path: | - /etc/hosts - /etc/resolv.conf - binary-fs: true - fs-dir: /app - heap: 1G - dlopen: 1 - mprotect: 0 - secrets: - docker-username: ${{ secrets.DOCKERHUB_USERNAME }} - docker-password: ${{ secrets.DOCKERHUB_PAT }} - scontain-username: ${{ secrets.SCONTAIN_REGISTRY_USERNAME }} - scontain-password: ${{ secrets.SCONTAIN_REGISTRY_PAT }} - scone-signing-key: ${{ secrets.SCONIFY_SIGNING_PRIVATE_KEY }} - deploy-tdx-dapp: - if: startsWith(github.event.inputs.environment, 'arbitrum-') needs: [extract-tag, docker-publish] runs-on: ubuntu-latest environment: ${{ inputs.environment }} @@ -161,77 +124,3 @@ jobs: cd node_modules/whitelist-smart-contract export ADDRESS_TO_ADD=$(cat ../../deployment-dapp/.app-address) npm run addResourceToWhitelist -- --network ${{ vars.WHITELIST_NETWORK_NAME }} - - deploy-scone-dapp: - if: startsWith(github.event.inputs.environment, 'bellecour-') - needs: [extract-tag, sconify] - runs-on: ubuntu-latest - environment: ${{ inputs.environment }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - cache: 'npm' - - - name: Install dependencies - run: | - npm ci - cd node_modules/whitelist-smart-contract - npm install --save-dev ts-node - cd ../../deployment-dapp - npm ci - - - name: Deploy SCONE dapp contract - env: - WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} - DOCKER_IMAGE_TAG: ${{ needs.sconify.outputs.prod-image-tag }} - CHECKSUM: ${{ needs.sconify.outputs.prod-checksum }} - FINGERPRINT: ${{ needs.sconify.outputs.prod-mrenclave }} - RPC_URL: ${{ secrets.RPC_URL }} - SCONIFY_VERSION: ${{ vars.SCONIFY_VERSION }} - run: | - cd deployment-dapp - npm run deploy-dapp - - - name: Push dapp secret - env: - WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} - TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} - RPC_URL: ${{ secrets.RPC_URL }} - run: | - cd deployment-dapp - npm run push-dapp-secret - - - name: Publish free sell order - env: - WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} - PRICE: ${{ vars.SELL_ORDER_PRICE }} - VOLUME: ${{ vars.SELL_ORDER_VOLUME }} - RPC_URL: ${{ secrets.RPC_URL }} - TEE_FRAMEWORK: ${{ vars.TEE_FRAMEWORK }} - run: | - cd deployment-dapp - npm run publish-sell-order - - - name: Add resource to whitelist - env: - CONTRACT_ADDRESS: ${{ vars.WEB3TELEGRAM_WHITELIST_CONTRACT_ADDRESS }} - PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} - RPC_URL: ${{ secrets.RPC_URL }} - run: | - cd node_modules/whitelist-smart-contract - export ADDRESS_TO_ADD=$(cat ../../deployment-dapp/.app-address) - npm run addResourceToWhitelist -- --network ${{ vars.WHITELIST_NETWORK_NAME }} - - - name: Configure ENS - if: ${{ vars.DAPP_ENS_NAME }} - env: - WALLET_PRIVATE_KEY: ${{ secrets.WEB3TELEGRAM_APP_OWNER_PRIVATEKEY }} - DAPP_ENS_NAME: ${{ vars.DAPP_ENS_NAME }} - run: | - cd deployment-dapp - npm run configure-ens diff --git a/README.md b/README.md index e2b302f..597eced 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; const { PRIVATE_KEY } = process.env; -const web3Provider = getWeb3Provider(PRIVATE_KEY); +const web3Provider = getWeb3Provider(PRIVATE_KEY, 421614); const web3telegram = new IExecWeb3telegram(web3Provider); ``` diff --git a/dapp/package-lock.json b/dapp/package-lock.json index 9e99661..70f9ac3 100644 --- a/dapp/package-lock.json +++ b/dapp/package-lock.json @@ -22,7 +22,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.28.1", "eslint-plugin-sonarjs": "^0.21.0", - "iexec": "^8.24.0", + "iexec": "^9.0.0", "jest": "^29.7.0", "prettier": "^2.8.8" }, @@ -4215,9 +4215,9 @@ "license": "BSD-3-Clause" }, "node_modules/iexec": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/iexec/-/iexec-8.24.0.tgz", - "integrity": "sha512-XMi+kZlRHPB5prubA7PQvhEmKxENN/5P0+gfe96eKKUWZSb3qllzi14btRE/MEmUXwsQok9kpIOq9IajUY8VQQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/iexec/-/iexec-9.0.0.tgz", + "integrity": "sha512-6Rh8GvxBUxuElBFUatn55RG0PdoQBLxYW73hB1LrBA4kycea526qJK5ut7Qi2xF2K5xXXYLwH8QdeioYEC6SuQ==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/dapp/package.json b/dapp/package.json index 5d95353..d108c1e 100644 --- a/dapp/package.json +++ b/dapp/package.json @@ -33,7 +33,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-import": "^2.28.1", "eslint-plugin-sonarjs": "^0.21.0", - "iexec": "^8.24.0", + "iexec": "^9.0.0", "jest": "^29.7.0", "prettier": "^2.8.8" } diff --git a/dapp/tests/e2e/app.test.js b/dapp/tests/e2e/app.test.js index 646fd09..1424c64 100644 --- a/dapp/tests/e2e/app.test.js +++ b/dapp/tests/e2e/app.test.js @@ -38,7 +38,7 @@ describe('sendTelegram', () => { process.env.IEXEC_DATASET_FILENAME = 'data-chatId.zip'; process.env.WEB3TELEGRAM_IPFS_GATEWAY = process.env.WEB3TELEGRAM_IPFS_GATEWAY || - 'https://ipfs-gateway.v8-bellecour.iex.ec'; + 'https://ipfs-gateway.arbitrum-sepolia-testnet.iex.ec'; // developer secret setup process.env.IEXEC_APP_DEVELOPER_SECRET = JSON.stringify({ TELEGRAM_BOT_TOKEN: process.env.TELEGRAM_BOT_TOKEN, diff --git a/dapp/tests/unit/decryptContent.test.js b/dapp/tests/unit/decryptContent.test.js index 47a8f75..383aab6 100644 --- a/dapp/tests/unit/decryptContent.test.js +++ b/dapp/tests/unit/decryptContent.test.js @@ -8,12 +8,13 @@ import { resolveIpfsGatewayUrl, } from '../../src/decryptContent'; -const TEST_IPFS_GATEWAY = 'https://ipfs-gateway.v8-bellecour.iex.ec'; +const TEST_IPFS_GATEWAY = + 'https://ipfs-gateway.arbitrum-sepolia-testnet.iex.ec'; describe('decryptContent', () => { it('should decrypt message correctly', async () => { const iexec = new IExec({ - ethProvider: 'bellecour', + ethProvider: 'arbitrum-sepolia-testnet', }); const encryptionKey = iexec.dataset.generateEncryptionKey(); diff --git a/deployment-dapp/package-lock.json b/deployment-dapp/package-lock.json index 93bad15..a6bd841 100644 --- a/deployment-dapp/package-lock.json +++ b/deployment-dapp/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "iexec": "^8.24.0", + "@iexec/dataprotector": "^2.0.0-beta.27", + "iexec": "^9.0.0", "typescript": "^5.0.4", "yup": "^1.2.0" }, @@ -588,6 +589,61 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@ethersproject/bytes": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/random": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", + "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" + } + }, "node_modules/@graphql-typed-document-node/core": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", @@ -659,6 +715,57 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@iexec/dataprotector": { + "version": "2.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@iexec/dataprotector/-/dataprotector-2.0.0-beta.27.tgz", + "integrity": "sha512-t5+e/XBCq7L7ztMkRb2I5WYqo6pWuXKqMeilQb+SGPPgk7rFTIMhex6d/MJl7peTTAvWKeLU+WNVPY5aXjc+BA==", + "license": "Apache-2.0", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@multiformats/multiaddr": "^12.1.3", + "@typechain/ethers-v6": "^0.5.1", + "@types/bn.js": "^5.1.6", + "borsh": "^2.0.0", + "debug": "^4.3.4", + "ethers": "^6.13.2", + "graphql-request": "^6.0.0", + "iexec": "^9.0.0", + "jszip": "^3.7.1", + "kubo-rpc-client": "^5.4.1", + "magic-bytes.js": "^1.0.15", + "typechain": "^8.3.2", + "yup": "^1.0.2" + } + }, + "node_modules/@iexec/dataprotector/node_modules/@multiformats/multiaddr": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", + "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@multiformats/dns": "^1.0.3", + "abort-error": "^1.0.1", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@iexec/dataprotector/node_modules/graphql-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", + "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "cross-fetch": "^3.1.5" + }, + "peerDependencies": { + "graphql": "14 - 16" + } + }, "node_modules/@inquirer/ansi": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.5.tgz", @@ -1291,6 +1398,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@typechain/ethers-v6": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@typechain/ethers-v6/-/ethers-v6-0.5.1.tgz", + "integrity": "sha512-F+GklO8jBWlsaVV+9oHaPh5NJdd6rAKN4tklGfInX1Q7h0xPgVLP39Jl3eCulPB5qexI71ZFHwbljx4ZXNfouA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.15", + "ts-essentials": "^7.0.1" + }, + "peerDependencies": { + "ethers": "6.x", + "typechain": "^8.3.2", + "typescript": ">=4.7.0" + } + }, "node_modules/@types/bn.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.2.0.tgz", @@ -1323,6 +1445,12 @@ "undici-types": "~7.19.0" } }, + "node_modules/@types/prettier": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", + "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==", + "license": "MIT" + }, "node_modules/@types/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz", @@ -1601,7 +1729,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1630,6 +1757,15 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/array-back": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", + "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", @@ -1792,7 +1928,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/base64-js": { @@ -1830,6 +1965,12 @@ "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", "license": "MIT" }, + "node_modules/borsh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-2.0.0.tgz", + "integrity": "sha512-kc9+BgR3zz9+cjbwM8ODoUB4fs3X3I5A/HtX7LZKxCLaMrEeDFoBpnhZY//DTS1VZBSs6S5v46RZRbZjRFspEg==", + "license": "Apache-2.0" + }, "node_modules/brace-expansion": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz", @@ -1955,7 +2096,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -2014,7 +2154,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -2027,7 +2166,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/colors": { @@ -2039,6 +2177,125 @@ "node": ">=0.1.90" } }, + "node_modules/command-line-args": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", + "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", + "license": "MIT", + "dependencies": { + "array-back": "^3.1.0", + "find-replace": "^3.0.0", + "lodash.camelcase": "^4.3.0", + "typical": "^4.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/command-line-usage": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.3.tgz", + "integrity": "sha512-sH5ZSPr+7UStsloltmDh7Ce5fb8XPlHyoPzTpyyMuYCtervL65+ubVZ6Q61cFtFl62UyJlc8/JwERRbAFPUqgw==", + "license": "MIT", + "dependencies": { + "array-back": "^4.0.2", + "chalk": "^2.4.2", + "table-layout": "^1.0.2", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/command-line-usage/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/command-line-usage/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/command-line-usage/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/command-line-usage/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/command-line-usage/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/command-line-usage/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/commander": { "version": "13.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", @@ -2052,7 +2309,6 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, "license": "MIT" }, "node_modules/confusing-browser-globals": { @@ -2068,6 +2324,15 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3077,6 +3342,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-replace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", + "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", + "license": "MIT", + "dependencies": { + "array-back": "^3.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3150,7 +3427,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, "license": "ISC" }, "node_modules/fsevents": { @@ -3485,7 +3761,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3605,9 +3880,9 @@ "license": "BSD-3-Clause" }, "node_modules/iexec": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/iexec/-/iexec-8.24.0.tgz", - "integrity": "sha512-XMi+kZlRHPB5prubA7PQvhEmKxENN/5P0+gfe96eKKUWZSb3qllzi14btRE/MEmUXwsQok9kpIOq9IajUY8VQQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/iexec/-/iexec-9.0.0.tgz", + "integrity": "sha512-6Rh8GvxBUxuElBFUatn55RG0PdoQBLxYW73hB1LrBA4kycea526qJK5ut7Qi2xF2K5xXXYLwH8QdeioYEC6SuQ==", "license": "Apache-2.0", "dependencies": { "@multiformats/multiaddr": "^13.0.1", @@ -3685,7 +3960,6 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -4351,6 +4625,12 @@ "node": ">= 6" } }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==", + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -4527,6 +4807,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "license": "MIT" + }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4550,6 +4842,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/magic-bytes.js": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.13.0.tgz", + "integrity": "sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==", + "license": "MIT" + }, "node_modules/main-event": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/main-event/-/main-event-1.0.4.tgz", @@ -4637,6 +4935,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4721,6 +5031,26 @@ "semver": "bin/semver.js" } }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-forge": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz", @@ -4847,7 +5177,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -5068,7 +5397,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -5295,6 +5623,15 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/reduce-flatten": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", + "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", @@ -5820,6 +6157,12 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/string-format": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-format/-/string-format-2.0.0.tgz", + "integrity": "sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==", + "license": "WTFPL OR MIT" + }, "node_modules/string-width": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz", @@ -5962,7 +6305,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -5984,6 +6326,39 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/table-layout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.2.tgz", + "integrity": "sha512-qd/R7n5rQTRFi+Zf2sk5XVVd9UQl6ZkduPFC3S7WEGJAmetDTjY3qPN50eSKzwuzEyQKy5TN2TiZdkIjos2L6A==", + "license": "MIT", + "dependencies": { + "array-back": "^4.0.1", + "deep-extend": "~0.6.0", + "typical": "^5.2.0", + "wordwrapjs": "^4.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/table-layout/node_modules/array-back": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.2.tgz", + "integrity": "sha512-NbdMezxqf94cnNfWLL7V/im0Ub+Anbb0IoZhvzie8+4HJ4nMQuzHuy49FkGYCJK2yAloZ3meiB6AVMClbrI1vg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table-layout/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -6015,6 +6390,12 @@ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", "license": "MIT" }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-api-utils": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", @@ -6028,6 +6409,30 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-command-line-args": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/ts-command-line-args/-/ts-command-line-args-2.5.1.tgz", + "integrity": "sha512-H69ZwTw3rFHb5WYpQya40YAX2/w7Ut75uUECbgBIsLmM+BNuYnxsltfyyLMxy6sEeKxgijLTnQtLd0nKd6+IYw==", + "license": "ISC", + "dependencies": { + "chalk": "^4.1.0", + "command-line-args": "^5.1.1", + "command-line-usage": "^6.1.0", + "string-format": "^2.0.0" + }, + "bin": { + "write-markdown": "dist/write-markdown.js" + } + }, + "node_modules/ts-essentials": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-7.0.3.tgz", + "integrity": "sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=3.7.0" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -6093,6 +6498,120 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typechain": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/typechain/-/typechain-8.3.2.tgz", + "integrity": "sha512-x/sQYr5w9K7yv3es7jo4KTX05CLxOf7TRWwoHlrjRh8H82G64g+k7VuWPJlgMo6qrjfCulOdfBjiaDtmhFYD/Q==", + "license": "MIT", + "dependencies": { + "@types/prettier": "^2.1.1", + "debug": "^4.3.1", + "fs-extra": "^7.0.0", + "glob": "7.1.7", + "js-sha3": "^0.8.0", + "lodash": "^4.17.15", + "mkdirp": "^1.0.4", + "prettier": "^2.3.1", + "ts-command-line-args": "^2.2.0", + "ts-essentials": "^7.0.1" + }, + "bin": { + "typechain": "dist/cli/cli.js" + }, + "peerDependencies": { + "typescript": ">=4.3.0" + } + }, + "node_modules/typechain/node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/typechain/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/typechain/node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typechain/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/typechain/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/typechain/node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/typechain/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -6184,6 +6703,15 @@ "node": ">=14.17" } }, + "node_modules/typical": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", + "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/uint8-varint": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.4.tgz", @@ -6319,6 +6847,22 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "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==", + "license": "BSD-2-Clause" + }, + "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==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/wherearewe": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wherearewe/-/wherearewe-2.0.1.tgz", @@ -6454,11 +6998,32 @@ "node": ">=0.10.0" } }, + "node_modules/wordwrapjs": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", + "integrity": "sha512-kKlNACbvHrkpIw6oPeYDSmdCTu2hdMHoyXLTcUKala++lx5Y+wjJ/e474Jqv5abnVmwxw08DiTuHmw69lJGksA==", + "license": "MIT", + "dependencies": { + "reduce-flatten": "^2.0.0", + "typical": "^5.2.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/wordwrapjs/node_modules/typical": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", + "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, "license": "ISC" }, "node_modules/ws": { diff --git a/deployment-dapp/package.json b/deployment-dapp/package.json index 49fc4f1..67ff380 100644 --- a/deployment-dapp/package.json +++ b/deployment-dapp/package.json @@ -18,7 +18,8 @@ "author": "", "license": "ISC", "dependencies": { - "iexec": "^8.24.0", + "@iexec/dataprotector": "^2.0.0-beta.27", + "iexec": "^9.0.0", "typescript": "^5.0.4", "yup": "^1.2.0" }, diff --git a/deployment-dapp/src/deployScript.ts b/deployment-dapp/src/deployScript.ts index 8393281..7104ae1 100644 --- a/deployment-dapp/src/deployScript.ts +++ b/deployment-dapp/src/deployScript.ts @@ -2,15 +2,8 @@ import { deployApp } from './singleFunction/deployApp.js'; import { getIExec, saveAppAddress } from './utils/utils.js'; const main = async () => { - // get env variables from GitHub Actions - const { - RPC_URL, - WALLET_PRIVATE_KEY, - DOCKER_IMAGE_TAG, - CHECKSUM, - FINGERPRINT, - SCONIFY_VERSION, - } = process.env; + const { RPC_URL, WALLET_PRIVATE_KEY, DOCKER_IMAGE_TAG, CHECKSUM } = + process.env; if (!WALLET_PRIVATE_KEY) throw Error(`Missing WALLET_PRIVATE_KEY environment variable`); @@ -25,8 +18,6 @@ const main = async () => { iexec, dockerTag: DOCKER_IMAGE_TAG, checksum: CHECKSUM, - fingerprint: FINGERPRINT, - sconifyVersion: SCONIFY_VERSION, }); await saveAppAddress(address); }; diff --git a/deployment-dapp/src/revokeSellOrderScript.ts b/deployment-dapp/src/revokeSellOrderScript.ts index b3e97c8..123f684 100644 --- a/deployment-dapp/src/revokeSellOrderScript.ts +++ b/deployment-dapp/src/revokeSellOrderScript.ts @@ -17,7 +17,7 @@ const main = async () => { // validate params const orderHash = await orderHashSchema().validate(ORDER_HASH); - //revoke sell order for Tee app (scone) + // revoke sell order for TEE app (TDX) const txHash = await revokeSellOrder(iexec, orderHash); if (!txHash) throw Error(`Failed to revoke app sell order: ${orderHash}`); }; diff --git a/deployment-dapp/src/singleFunction/deployApp.ts b/deployment-dapp/src/singleFunction/deployApp.ts index 7e9e6ae..387f03f 100644 --- a/deployment-dapp/src/singleFunction/deployApp.ts +++ b/deployment-dapp/src/singleFunction/deployApp.ts @@ -12,37 +12,19 @@ export const deployApp = async ({ dockerRepository = DOCKER_IMAGE_REPOSITORY, dockerTag, checksum, - // TODO: to be deleted after migration to TDX - fingerprint, - sconifyVersion, }: { iexec: IExec; dockerNamespace?: string; dockerRepository?: string; dockerTag: string; checksum?: string; - // TODO: to be deleted after migration to TDX - fingerprint?: string; - sconifyVersion?: string; }): Promise => { const name = APP_NAME; const type = APP_TYPE; - let mrenclave; - - // TODO: to be deleted after migration to TDX - if (sconifyVersion) { - console.log( - `Using SCONE framework with SCONIFY version: ${sconifyVersion}` - ); - mrenclave = { - framework: 'SCONE', // workaround framework not auto capitalized - version: `v${sconifyVersion.split('.').slice(0, 2).join('.')}`, // extracts "vX.Y" from "X.Y.Z-vN" format (e.g., "5.9.1-v16" → "v5.9") - entrypoint: 'node --disable-wasm-trap-handler /app/app.js', - heapSize: 1073741824, // 1GB - fingerprint, - }; - } + const mrenclave = { + framework: 'TDX', + }; const app = { owner: await iexec.wallet.getAddress(), @@ -50,7 +32,6 @@ export const deployApp = async ({ type, multiaddr: `${dockerNamespace}/${dockerRepository}:${dockerTag}`, checksum, - // TODO: to be deleted after migration to TDX mrenclave, }; console.log(`Deploying app:\n${JSON.stringify(app, undefined, 2)}`); diff --git a/deployment-dapp/src/singleFunction/resolveName.ts b/deployment-dapp/src/singleFunction/resolveName.ts deleted file mode 100644 index 07404a0..0000000 --- a/deployment-dapp/src/singleFunction/resolveName.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { ENS, IExec } from 'iexec'; - -export const resolveName = async ( - iexec: IExec, - name: ENS -): Promise => { - return iexec.ens.resolveName(name); -}; diff --git a/deployment-dapp/src/utils/utils.ts b/deployment-dapp/src/utils/utils.ts index 6e8e533..14b84bc 100644 --- a/deployment-dapp/src/utils/utils.ts +++ b/deployment-dapp/src/utils/utils.ts @@ -1,12 +1,8 @@ import fs from 'fs/promises'; import { IExec, utils } from 'iexec'; -export const getIExec = ( - privateKey: string, - host: string = 'bellecour' -): IExec => { +export const getIExec = (privateKey: string, host: string): IExec => { const ethProvider = utils.getSignerFromPrivateKey(host, privateKey, { - providers: {}, allowExperimentalNetworks: true, }); return new IExec( diff --git a/examples/node-ts/index.ts b/examples/node-ts/index.ts index 8f5b316..863a504 100644 --- a/examples/node-ts/index.ts +++ b/examples/node-ts/index.ts @@ -2,7 +2,10 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; import { Wallet } from 'ethers'; const test = async () => { - const ethProvider = getWeb3Provider(Wallet.createRandom().privateKey); + const ethProvider = getWeb3Provider( + Wallet.createRandom().privateKey, + 421614 + ); const web3telegram = new IExecWeb3telegram(ethProvider); diff --git a/examples/node/index.js b/examples/node/index.js index 8f5b316..863a504 100644 --- a/examples/node/index.js +++ b/examples/node/index.js @@ -2,7 +2,10 @@ import { IExecWeb3telegram, getWeb3Provider } from '@iexec/web3telegram'; import { Wallet } from 'ethers'; const test = async () => { - const ethProvider = getWeb3Provider(Wallet.createRandom().privateKey); + const ethProvider = getWeb3Provider( + Wallet.createRandom().privateKey, + 421614 + ); const web3telegram = new IExecWeb3telegram(ethProvider); diff --git a/package-lock.json b/package-lock.json index 5c28e18..28d454e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "buffer": "^6.0.3", "ethers": "^6.15.0", "graphql-request": "^6.1.0", - "iexec": "^8.24.0", + "iexec": "^9.0.0", "kubo-rpc-client": "^5.4.1", "yup": "^1.1.1" }, @@ -823,6 +823,63 @@ "yup": "^1.0.2" } }, + "node_modules/@iexec/dataprotector/node_modules/iexec": { + "version": "8.24.0", + "resolved": "https://registry.npmjs.org/iexec/-/iexec-8.24.0.tgz", + "integrity": "sha512-XMi+kZlRHPB5prubA7PQvhEmKxENN/5P0+gfe96eKKUWZSb3qllzi14btRE/MEmUXwsQok9kpIOq9IajUY8VQQ==", + "license": "Apache-2.0", + "dependencies": { + "@multiformats/multiaddr": "^13.0.1", + "@types/bn.js": "^5.2.0", + "bn.js": "^5.2.2", + "buffer": "^6.0.3", + "commander": "^13.1.0", + "debug": "^4.4.3", + "ethers": "^6.13.5", + "fs-extra": "^11.3.0", + "graphql-request": "^7.3.5", + "inquirer": "^13.1.0", + "is-docker": "^3.0.0", + "jszip": "^3.10.1", + "kubo-rpc-client": "^5.3.0", + "multiformats": "^13.4.2", + "node-forge": "^1.3.2", + "ora": "^9.0.0", + "prettyjson": "^1.2.5", + "query-string": "^9.1.1", + "rlc-faucet-contract": "^1.0.10", + "semver": "^7.7.3", + "update-check": "^1.5.4", + "yup": "^1.6.1" + }, + "bin": { + "iexec": "dist/esm/cli/cmd/iexec.js" + } + }, + "node_modules/@iexec/dataprotector/node_modules/iexec/node_modules/@multiformats/multiaddr": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-13.0.1.tgz", + "integrity": "sha512-XToN915cnfr6Lr9EdGWakGJbPT0ghpg/850HvdC+zFX8XvpLZElwa8synCiwa8TuvKNnny6m8j8NVBNCxhIO3g==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@iexec/dataprotector/node_modules/iexec/node_modules/graphql-request": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-7.4.0.tgz", + "integrity": "sha512-xfr+zFb/QYbs4l4ty0dltqiXIp07U6sl+tOKAb0t50/EnQek6CVVBLjETXi+FghElytvgaAWtIOt3EV7zLzIAQ==", + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0" + }, + "peerDependencies": { + "graphql": "14 - 16" + } + }, "node_modules/@inquirer/ansi": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.5.tgz", @@ -5600,9 +5657,9 @@ "license": "BSD-3-Clause" }, "node_modules/iexec": { - "version": "8.24.0", - "resolved": "https://registry.npmjs.org/iexec/-/iexec-8.24.0.tgz", - "integrity": "sha512-XMi+kZlRHPB5prubA7PQvhEmKxENN/5P0+gfe96eKKUWZSb3qllzi14btRE/MEmUXwsQok9kpIOq9IajUY8VQQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/iexec/-/iexec-9.0.0.tgz", + "integrity": "sha512-6Rh8GvxBUxuElBFUatn55RG0PdoQBLxYW73hB1LrBA4kycea526qJK5ut7Qi2xF2K5xXXYLwH8QdeioYEC6SuQ==", "license": "Apache-2.0", "dependencies": { "@multiformats/multiaddr": "^13.0.1", diff --git a/package.json b/package.json index b50f99f..0d2dbe4 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "scripts": { "build": "rm -rf dist && tsc --project tsconfig.build.json", "check-types": "tsc --noEmit", - "test:prepare": "node tests/scripts/prepare-bellecour-fork-for-tests.js && node tests/scripts/prepare-iexec.js", + "test:prepare": "node tests/scripts/prepare-arbitrum-sepolia-fork-for-tests.js", "test": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/**/*.test.ts\" --forceExit -b", "test:coverage": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/**/*.test.ts\" --forceExit --coverage", "test:unit": "NODE_OPTIONS=--experimental-vm-modules jest --testMatch \"**/tests/unit/**/*.test.ts\" -b", @@ -51,7 +51,7 @@ "buffer": "^6.0.3", "ethers": "^6.15.0", "graphql-request": "^6.1.0", - "iexec": "^8.24.0", + "iexec": "^9.0.0", "kubo-rpc-client": "^5.4.1", "yup": "^1.1.1" }, diff --git a/src/config/config.ts b/src/config/config.ts index 4c12def..ae3e465 100644 --- a/src/config/config.ts +++ b/src/config/config.ts @@ -3,8 +3,6 @@ export const MAX_DESIRED_APP_ORDER_PRICE = 0; export const MAX_DESIRED_WORKERPOOL_ORDER_PRICE = 0; export const ANY_DATASET_ADDRESS = 'any'; -export const DEFAULT_CHAIN_ID = 134; - interface ChainConfig { name: string; dappAddress?: string; @@ -17,16 +15,6 @@ interface ChainConfig { } export const CHAIN_CONFIG: Record = { - 134: { - name: 'bellecour', - dappAddress: 'web3telegram.apps.iexec.eth', - prodWorkerpoolAddress: 'prod-v8-bellecour.main.pools.iexec.eth', - dataProtectorSubgraph: - 'https://thegraph.iex.ec/subgraphs/name/bellecour/dataprotector-v2', - ipfsUploadUrl: '/dns4/ipfs-upload.v8-bellecour.iex.ec/https', - ipfsGateway: 'https://ipfs-gateway.v8-bellecour.iex.ec', - whitelistSmartContract: '0x192C6f5AccE52c81Fcc2670f10611a3665AAA98F', - }, 421614: { name: 'arbitrum-sepolia-testnet', dappAddress: undefined, // ENS not supported on this network, address will be resolved from Compass @@ -62,3 +50,27 @@ export const getChainDefaultConfig = ( } return config; }; + +/** + * When `ethProvider` is a string, it may be an RPC URL, a decimal chain id, or an + * iExec chain host name (see each chain's `name` in CHAIN_CONFIG). RPC URLs are not + * resolved here (returns undefined); JsonRpcProvider handles those. + */ +export function tryResolveChainIdFromProviderString( + hint: string +): number | undefined { + const trimmed = hint.trim(); + if (/^https?:\/\//i.test(trimmed)) { + return undefined; + } + if (/^\d+$/.test(trimmed)) { + return Number(trimmed); + } + const lower = trimmed.toLowerCase(); + for (const [id, cfg] of Object.entries(CHAIN_CONFIG)) { + if (cfg.name.toLowerCase() === lower) { + return Number(id); + } + } + return undefined; +} diff --git a/src/utils/getChainId.ts b/src/utils/getChainId.ts index c958eeb..0f7529e 100644 --- a/src/utils/getChainId.ts +++ b/src/utils/getChainId.ts @@ -5,7 +5,7 @@ import { AbstractSigner, Eip1193Provider, } from 'ethers'; -import { DEFAULT_CHAIN_ID } from '../config/config.js'; +import { tryResolveChainIdFromProviderString } from '../config/config.js'; type EthersCompatibleProvider = | string @@ -18,9 +18,10 @@ export async function getChainIdFromProvider( ): Promise { try { if (typeof ethProvider === 'string') { - // Handle network string - if (ethProvider === 'bellecour') return 134; - // TODO add arbitrum & avalanche + const resolved = tryResolveChainIdFromProviderString(ethProvider); + if (resolved !== undefined) { + return resolved; + } const provider = new JsonRpcProvider(ethProvider); const network = await provider.getNetwork(); return Number(network.chainId); @@ -41,6 +42,11 @@ export async function getChainIdFromProvider( } } catch (e) { console.warn('Failed to detect chainId:', e); + throw new Error( + `Failed to detect chainId from ethProvider: ${ + e instanceof Error ? e.message : String(e) + }` + ); } - return DEFAULT_CHAIN_ID; + throw new Error('Unsupported ethProvider for chain ID detection'); } diff --git a/src/utils/getWeb3Provider.ts b/src/utils/getWeb3Provider.ts index d9c6eb7..2f3d1f3 100644 --- a/src/utils/getWeb3Provider.ts +++ b/src/utils/getWeb3Provider.ts @@ -3,11 +3,9 @@ import { Web3SignerProvider } from '../web3telegram/types.js'; export const getWeb3Provider = ( privateKey: string, - options: { allowExperimentalNetworks?: boolean; host?: number | string } = {} -): Web3SignerProvider => { - const chainHost = options?.host ? `${options.host}` : 'bellecour'; - return getSignerFromPrivateKey(chainHost, privateKey, { + host: number | string, + options: { allowExperimentalNetworks?: boolean } = {} +): Web3SignerProvider => + getSignerFromPrivateKey(`${host}`, privateKey, { allowExperimentalNetworks: options?.allowExperimentalNetworks, - providers: {}, }); -}; diff --git a/src/utils/resolveDappAddressFromCompass.ts b/src/utils/resolveDappAddressFromCompass.ts index 6439017..5ca9ec9 100644 --- a/src/utils/resolveDappAddressFromCompass.ts +++ b/src/utils/resolveDappAddressFromCompass.ts @@ -1,10 +1,10 @@ import { CompassCallError } from 'iexec/errors'; -import { AddressOrENS } from '../web3telegram/types.js'; +import { Address } from '../web3telegram/types.js'; export async function resolveDappAddressFromCompass( compassUrl: string, chainId: number -): Promise { +): Promise
{ if (!compassUrl) { return undefined; } diff --git a/src/utils/sendTelegram.models.ts b/src/utils/sendTelegram.models.ts index f478d1b..ba18ef6 100644 --- a/src/utils/sendTelegram.models.ts +++ b/src/utils/sendTelegram.models.ts @@ -1,76 +1,17 @@ -import { Address, BN } from 'iexec'; import { PublishedWorkerpoolorder } from 'iexec/IExecOrderbookModule'; -type VoucherInfo = { - owner: Address; - address: Address; - type: BN; - balance: BN; - expirationTimestamp: BN; - sponsoredApps: Address[]; - sponsoredDatasets: Address[]; - sponsoredWorkerpools: Address[]; - allowanceAmount: BN; - authorizedAccounts: Address[]; -}; - -function bnToNumber(bn: BN) { - return Number(bn.toString()); -} - -export function checkUserVoucher({ - userVoucher, -}: { - userVoucher: VoucherInfo; -}) { - if (bnToNumber(userVoucher.expirationTimestamp) < Date.now() / 1000) { - throw new Error( - 'Oops, it seems your voucher has expired. You might want to ask for a top up. Check on https://builder.iex.ec/' - ); - } - - if (bnToNumber(userVoucher.balance) === 0) { - throw new Error( - 'Oops, it seems your voucher is empty. You might want to ask for a top up. Check on https://builder.iex.ec/' - ); - } -} - export function filterWorkerpoolOrders({ workerpoolOrders, workerpoolMaxPrice, - useVoucher, - userVoucher, }: { workerpoolOrders: PublishedWorkerpoolorder[]; workerpoolMaxPrice: number; - useVoucher: boolean; - userVoucher?: VoucherInfo; }) { if (workerpoolOrders.length === 0) { return null; } - let eligibleWorkerpoolOrders = [...workerpoolOrders]; - let maxVoucherSponsoredAmount = 0; // may be safer to use bigint - - if (useVoucher) { - if (!userVoucher) { - throw new Error( - 'useVoucher === true but userVoucher is undefined? Hum...' - ); - } - // only voucher sponsored workerpoolorders - eligibleWorkerpoolOrders = eligibleWorkerpoolOrders.filter(({ order }) => - userVoucher.sponsoredWorkerpools.includes(order.workerpool) - ); - if (eligibleWorkerpoolOrders.length === 0) { - throw new Error( - 'Found some workerpool orders but none can be sponsored by your voucher.' - ); - } - maxVoucherSponsoredAmount = bnToNumber(userVoucher.balance); - } + const eligibleWorkerpoolOrders = [...workerpoolOrders]; const [cheapestOrder] = eligibleWorkerpoolOrders.sort( (order1, order2) => @@ -79,8 +20,7 @@ export function filterWorkerpoolOrders({ if ( !cheapestOrder || - cheapestOrder.order.workerpoolprice > - workerpoolMaxPrice + maxVoucherSponsoredAmount + cheapestOrder.order.workerpoolprice > workerpoolMaxPrice ) { return null; } diff --git a/src/utils/validators.ts b/src/utils/validators.ts index 964af5c..b448310 100644 --- a/src/utils/validators.ts +++ b/src/utils/validators.ts @@ -18,17 +18,6 @@ export const throwIfMissing = (): never => { const isUndefined = (value: unknown) => value === undefined; const isAddressTest = (value: string) => isAddress(value); -export const isEnsTest = (value: string) => - value.endsWith('.eth') && value.length > 6; - -export const addressOrEnsSchema = () => - string() - .transform((value: string) => value?.toLowerCase() || value) - .test( - 'is-address-or-ens', - '${path} should be an ethereum address or a ENS name', - (value) => isUndefined(value) || isAddressTest(value) || isEnsTest(value) - ); export const addressSchema = () => string() diff --git a/src/web3telegram/IExecWeb3telegram.ts b/src/web3telegram/IExecWeb3telegram.ts index 05d1121..cf10942 100644 --- a/src/web3telegram/IExecWeb3telegram.ts +++ b/src/web3telegram/IExecWeb3telegram.ts @@ -10,7 +10,7 @@ import { Contact, FetchUserContactsParams, SendTelegramParams, - AddressOrENS, + Address, Web3TelegramConfigOptions, Web3SignerProvider, FetchMyContactsParams, @@ -34,8 +34,8 @@ type EthersCompatibleProvider = | string; interface Web3telegramResolvedConfig { - dappAddressOrENS: AddressOrENS; - dappWhitelistAddress: AddressOrENS; + dappAddress: Address; + dappWhitelistAddress: Address; graphQLClient: GraphQLClient; ipfsNode: string; ipfsGateway: string; @@ -45,9 +45,9 @@ interface Web3telegramResolvedConfig { } export class IExecWeb3telegram { - private dappAddressOrENS!: AddressOrENS; + private dappAddress!: Address; - private dappWhitelistAddress!: AddressOrENS; + private dappWhitelistAddress!: Address; private graphQLClient!: GraphQLClient; @@ -68,17 +68,17 @@ export class IExecWeb3telegram { private options: Web3TelegramConfigOptions; constructor( - ethProvider?: EthersCompatibleProvider, + ethProvider: EthersCompatibleProvider, options?: Web3TelegramConfigOptions ) { - this.ethProvider = ethProvider || 'bellecour'; + this.ethProvider = ethProvider; this.options = options || {}; } async init(): Promise { if (!this.initPromise) { this.initPromise = this.resolveConfig().then((config) => { - this.dappAddressOrENS = config.dappAddressOrENS; + this.dappAddress = config.dappAddress; this.dappWhitelistAddress = config.dappWhitelistAddress; this.graphQLClient = config.graphQLClient; this.ipfsNode = config.ipfsNode; @@ -99,7 +99,7 @@ export class IExecWeb3telegram { ...args, iexec: this.iexec, graphQLClient: this.graphQLClient, - dappAddressOrENS: this.dappAddressOrENS, + dappAddress: this.dappAddress, dappWhitelistAddress: this.dappWhitelistAddress, }); } @@ -111,7 +111,7 @@ export class IExecWeb3telegram { ...args, iexec: this.iexec, graphQLClient: this.graphQLClient, - dappAddressOrENS: this.dappAddressOrENS, + dappAddress: this.dappAddress, dappWhitelistAddress: this.dappWhitelistAddress, }); } @@ -121,12 +121,11 @@ export class IExecWeb3telegram { await isValidProvider(this.iexec); return sendTelegram({ ...args, - workerpoolAddressOrEns: - args.workerpoolAddressOrEns || this.defaultWorkerpool, + workerpoolAddress: args.workerpoolAddress || this.defaultWorkerpool, iexec: this.iexec, ipfsNode: this.ipfsNode, ipfsGateway: this.ipfsGateway, - dappAddressOrENS: this.dappAddressOrENS, + dappAddress: this.dappAddress, dappWhitelistAddress: this.dappWhitelistAddress, graphQLClient: this.graphQLClient, }); @@ -139,8 +138,7 @@ export class IExecWeb3telegram { await isValidProvider(this.iexec); return sendTelegramCampaign({ ...args, - workerpoolAddressOrEns: - args.workerpoolAddressOrEns || this.defaultWorkerpool, + workerpoolAddress: args.workerpoolAddress || this.defaultWorkerpool, dataProtector: this.dataProtector, }); } @@ -156,7 +154,7 @@ export class IExecWeb3telegram { dataProtector: this.dataProtector, ipfsNode: this.ipfsNode, ipfsGateway: this.ipfsGateway, - dappAddressOrENS: this.dappAddressOrENS, + dappAddress: this.dappAddress, }); } @@ -187,8 +185,8 @@ export class IExecWeb3telegram { const subgraphUrl = this.options?.dataProtectorSubgraph || chainDefaultConfig?.dataProtectorSubgraph; - const dappAddressOrENS = - this.options?.dappAddressOrENS || + const dappAddress = + this.options?.dappAddress || chainDefaultConfig?.dappAddress || (await resolveDappAddressFromCompass( await iexec.config.resolveCompassURL(), @@ -204,7 +202,7 @@ export class IExecWeb3telegram { const missing = []; if (!subgraphUrl) missing.push('dataProtectorSubgraph'); - if (!dappAddressOrENS) missing.push('dappAddress'); + if (!dappAddress) missing.push('dappAddress'); if (!dappWhitelistAddress) missing.push('whitelistSmartContract'); if (!ipfsGateway) missing.push('ipfsGateway'); if (!defaultWorkerpool) missing.push('prodWorkerpoolAddress'); @@ -236,7 +234,7 @@ export class IExecWeb3telegram { }); return { - dappAddressOrENS, + dappAddress, dappWhitelistAddress: dappWhitelistAddress.toLowerCase(), defaultWorkerpool, graphQLClient, diff --git a/src/web3telegram/fetchMyContacts.ts b/src/web3telegram/fetchMyContacts.ts index 7fcabaa..ffb800d 100644 --- a/src/web3telegram/fetchMyContacts.ts +++ b/src/web3telegram/fetchMyContacts.ts @@ -13,7 +13,7 @@ export type FetchMyContacts = typeof fetchMyContacts; export const fetchMyContacts = async ({ graphQLClient = throwIfMissing(), iexec = throwIfMissing(), - dappAddressOrENS = throwIfMissing(), + dappAddress = throwIfMissing(), dappWhitelistAddress = throwIfMissing(), isUserStrict = false, bulkOnly = false, @@ -30,7 +30,7 @@ export const fetchMyContacts = async ({ return fetchUserContacts({ iexec, graphQLClient, - dappAddressOrENS, + dappAddress, dappWhitelistAddress, userAddress, isUserStrict: vIsUserStrict, diff --git a/src/web3telegram/fetchUserContacts.ts b/src/web3telegram/fetchUserContacts.ts index 8ab7778..84ee67d 100644 --- a/src/web3telegram/fetchUserContacts.ts +++ b/src/web3telegram/fetchUserContacts.ts @@ -4,10 +4,8 @@ import { handleIfProtocolError, WorkflowError } from '../utils/errors.js'; import { autoPaginateRequest } from '../utils/paginate.js'; import { getValidContact } from '../utils/subgraphQuery.js'; import { - addressOrEnsSchema, addressSchema, booleanSchema, - isEnsTest, throwIfMissing, } from '../utils/validators.js'; import { Contact, FetchUserContactsParams, GrantedAccess } from './types.js'; @@ -23,7 +21,7 @@ import { export const fetchUserContacts = async ({ graphQLClient = throwIfMissing(), iexec = throwIfMissing(), - dappAddressOrENS = throwIfMissing(), + dappAddress = throwIfMissing(), dappWhitelistAddress = throwIfMissing(), userAddress, isUserStrict = false, @@ -34,15 +32,15 @@ export const fetchUserContacts = async ({ DappWhitelistAddressConsumer & FetchUserContactsParams): Promise => { try { - const vDappAddressOrENS = addressOrEnsSchema() + const address = addressSchema() .required() - .label('dappAddressOrENS') - .validateSync(dappAddressOrENS); + .label('dappAddress') + .validateSync(dappAddress); const vDappWhitelistAddress = addressSchema() .required() .label('dappWhitelistAddress') .validateSync(dappWhitelistAddress); - const vUserAddress = addressOrEnsSchema() + const vUserAddress = addressSchema() .required() .label('userAddress') .validateSync(userAddress); @@ -55,7 +53,7 @@ export const fetchUserContacts = async ({ fetchAllOrdersByApp({ iexec, userAddress: vUserAddress, - appAddress: vDappAddressOrENS, + appAddress: address, isUserStrict: vIsUserStrict, bulkOnly: vBulkOnly, }), @@ -69,14 +67,9 @@ export const fetchUserContacts = async ({ ]); const orders = dappOrders.concat(whitelistOrders); const myContacts: Omit[] = []; - let web3DappResolvedAddress = vDappAddressOrENS; - if (isEnsTest(vDappAddressOrENS)) { - web3DappResolvedAddress = await iexec.ens.resolveName(vDappAddressOrENS); - } orders.forEach((order) => { if ( - order.order.apprestrict.toLowerCase() === - web3DappResolvedAddress.toLowerCase() || + order.order.apprestrict.toLowerCase() === address.toLowerCase() || order.order.apprestrict.toLowerCase() === vDappWhitelistAddress.toLowerCase() ) { diff --git a/src/web3telegram/internalTypes.ts b/src/web3telegram/internalTypes.ts index 7cd2947..626dfb0 100644 --- a/src/web3telegram/internalTypes.ts +++ b/src/web3telegram/internalTypes.ts @@ -1,5 +1,5 @@ import { IExec } from 'iexec'; -import { AddressOrENS } from './types.js'; +import { Address } from './types.js'; import { GraphQLClient } from 'graphql-request'; import { IExecDataProtectorCore } from '@iexec/dataprotector'; @@ -13,7 +13,7 @@ export type GraphQLResponse = { }; export type DappAddressConsumer = { - dappAddressOrENS: AddressOrENS; + dappAddress: Address; }; export type IpfsNodeConfigConsumer = { diff --git a/src/web3telegram/prepareTelegramCampaign.ts b/src/web3telegram/prepareTelegramCampaign.ts index 7d58e90..6770f88 100644 --- a/src/web3telegram/prepareTelegramCampaign.ts +++ b/src/web3telegram/prepareTelegramCampaign.ts @@ -6,7 +6,7 @@ import { import { handleIfProtocolError, WorkflowError } from '../utils/errors.js'; import * as ipfs from '../utils/ipfs-service.js'; import { - addressOrEnsSchema, + addressSchema, telegramContentSchema, positiveNumberSchema, labelSchema, @@ -30,8 +30,8 @@ export type PrepareTelegramCampaign = typeof prepareTelegramCampaign; export const prepareTelegramCampaign = async ({ iexec = throwIfMissing(), dataProtector = throwIfMissing(), - workerpoolAddressOrEns, - dappAddressOrENS, + workerpoolAddress, + dappAddress, ipfsNode, ipfsGateway, senderName, @@ -48,9 +48,9 @@ export const prepareTelegramCampaign = async ({ DataProtectorConsumer & PrepareTelegramCampaignParams): Promise => { try { - const vWorkerpoolAddressOrEns = addressOrEnsSchema() - .label('WorkerpoolAddressOrEns') - .validateSync(workerpoolAddressOrEns); + const vWorkerpoolAddress = addressSchema() + .label('workerpoolAddress') + .validateSync(workerpoolAddress); const vSenderName = senderNameSchema() .label('senderName') .validateSync(senderName); @@ -59,10 +59,10 @@ export const prepareTelegramCampaign = async ({ .label('telegramContent') .validateSync(telegramContent); const vLabel = labelSchema().label('label').validateSync(label); - const vDappAddressOrENS = addressOrEnsSchema() + const vDappAddress = addressSchema() .required() - .label('dappAddressOrENS') - .validateSync(dappAddressOrENS); + .label('dappAddress') + .validateSync(dappAddress); const vAppMaxPrice = positiveNumberSchema() .label('appMaxPrice') .validateSync(appMaxPrice); @@ -115,10 +115,10 @@ export const prepareTelegramCampaign = async ({ const { bulkRequest: campaignRequest } = await dataProtector.prepareBulkRequest({ - app: vDappAddressOrENS, + app: vDappAddress, appMaxPrice: vAppMaxPrice, workerpoolMaxPrice: vWorkerpoolMaxPrice, - workerpool: vWorkerpoolAddressOrEns, + workerpool: vWorkerpoolAddress, args: vLabel, inputFiles: [], secrets, @@ -132,7 +132,7 @@ export const prepareTelegramCampaign = async ({ throw error; } // Handle protocol errors - this will throw if it's an ApiCallError - // handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true + // handleIfProtocolError transforms ApiCallError into WorkflowError with isProtocolError=true handleIfProtocolError(error); // For all other errors throw new WorkflowError({ diff --git a/src/web3telegram/sendTelegram.ts b/src/web3telegram/sendTelegram.ts index ab1ab7c..5e348e8 100644 --- a/src/web3telegram/sendTelegram.ts +++ b/src/web3telegram/sendTelegram.ts @@ -9,20 +9,15 @@ import { generateSecureUniqueId } from '../utils/generateUniqueId.js'; import * as ipfs from '../utils/ipfs-service.js'; import { checkProtectedDataValidity } from '../utils/subgraphQuery.js'; import { - addressOrEnsSchema, telegramContentSchema, positiveNumberSchema, labelSchema, throwIfMissing, addressSchema, senderNameSchema, - booleanSchema, } from '../utils/validators.js'; import { SendTelegramParams, SendTelegramResponse } from './types.js'; -import { - checkUserVoucher, - filterWorkerpoolOrders, -} from '../utils/sendTelegram.models.js'; +import { filterWorkerpoolOrders } from '../utils/sendTelegram.models.js'; import { DappAddressConsumer, DappWhitelistAddressConsumer, @@ -37,8 +32,8 @@ export type SendTelegram = typeof sendTelegram; export const sendTelegram = async ({ graphQLClient = throwIfMissing(), iexec = throwIfMissing(), - workerpoolAddressOrEns = throwIfMissing(), - dappAddressOrENS, + workerpoolAddress = throwIfMissing(), + dappAddress, dappWhitelistAddress, ipfsNode, ipfsGateway, @@ -49,7 +44,6 @@ export const sendTelegram = async ({ appMaxPrice = MAX_DESIRED_APP_ORDER_PRICE, workerpoolMaxPrice = MAX_DESIRED_WORKERPOOL_ORDER_PRICE, protectedData, - useVoucher = false, }: IExecConsumer & SubgraphConsumer & DappAddressConsumer & @@ -58,7 +52,7 @@ export const sendTelegram = async ({ IpfsGatewayConfigConsumer & SendTelegramParams): Promise => { try { - const vDatasetAddress = addressOrEnsSchema() + const vDatasetAddress = addressSchema() .required() .label('protectedData') .validateSync(protectedData); @@ -70,14 +64,14 @@ export const sendTelegram = async ({ .label('telegramContent') .validateSync(telegramContent); const vLabel = labelSchema().label('label').validateSync(label); - const vWorkerpoolAddressOrEns = addressOrEnsSchema() + const vWorkerpoolAddress = addressSchema() .required() - .label('WorkerpoolAddressOrEns') - .validateSync(workerpoolAddressOrEns); - const vDappAddressOrENS = addressOrEnsSchema() + .label('workerpoolAddress') + .validateSync(workerpoolAddress); + const vDappAddress = addressSchema() .required() - .label('dappAddressOrENS') - .validateSync(dappAddressOrENS); + .label('dappAddress') + .validateSync(dappAddress); const vDappWhitelistAddress = addressSchema() .required() .label('dappWhitelistAddress') @@ -91,9 +85,6 @@ export const sendTelegram = async ({ const vWorkerpoolMaxPrice = positiveNumberSchema() .label('workerpoolMaxPrice') .validateSync(workerpoolMaxPrice); - const vUseVoucher = booleanSchema() - .label('useVoucher') - .validateSync(useVoucher); // Check protected data validity through subgraph const isValidProtectedData = await checkProtectedDataValidity( @@ -107,26 +98,12 @@ export const sendTelegram = async ({ } const requesterAddress = await iexec.wallet.getAddress(); - let userVoucher; - if (vUseVoucher) { - try { - userVoucher = await iexec.voucher.showUserVoucher(requesterAddress); - checkUserVoucher({ userVoucher }); - } catch (err) { - if (err?.message?.startsWith('No Voucher found for address')) { - throw new Error( - 'Oops, it seems your wallet is not associated with any voucher. Check on https://builder.iex.ec/' - ); - } - throw err; - } - } // Fetch app order const apporder = await iexec.orderbook .fetchAppOrderbook({ - app: dappAddressOrENS, + app: vDappAddress, minTag: ['tee'], - workerpool: workerpoolAddressOrEns, + workerpool: vWorkerpoolAddress, }) .then((appOrderbook) => { const desiredPriceAppOrderbook = appOrderbook.orders.filter( @@ -147,7 +124,7 @@ export const sendTelegram = async ({ iexec.orderbook .fetchDatasetOrderbook({ dataset: vDatasetAddress, - app: dappAddressOrENS, + app: vDappAddress, requester: requesterAddress, }) .then((datasetOrderbook) => { @@ -173,23 +150,21 @@ export const sendTelegram = async ({ // Fetch workerpool order for App or AppWhitelist Promise.all([ - // for app iexec.orderbook.fetchWorkerpoolOrderbook({ - workerpool: workerpoolAddressOrEns, - app: vDappAddressOrENS, + workerpool: vWorkerpoolAddress, + app: vDappAddress, dataset: vDatasetAddress, - requester: requesterAddress, // public orders + user specific orders - isRequesterStrict: useVoucher, // If voucher, we only want user specific orders + requester: requesterAddress, + isRequesterStrict: false, minTag: workerpoolMinTag, category: 0, }), - // for app whitelist iexec.orderbook.fetchWorkerpoolOrderbook({ - workerpool: workerpoolAddressOrEns, + workerpool: vWorkerpoolAddress, app: vDappWhitelistAddress, dataset: vDatasetAddress, - requester: requesterAddress, // public orders + user specific orders - isRequesterStrict: useVoucher, // If voucher, we only want user specific orders + requester: requesterAddress, + isRequesterStrict: false, minTag: workerpoolMinTag, category: 0, }), @@ -201,8 +176,6 @@ export const sendTelegram = async ({ ...workerpoolOrderbookForAppWhitelist.orders, ], workerpoolMaxPrice: vWorkerpoolMaxPrice, - useVoucher: vUseVoucher, - userVoucher, }); if (!desiredPriceWorkerpoolOrder) { throw new Error( @@ -258,14 +231,14 @@ export const sendTelegram = async ({ ); const requestorderToSign = await iexec.order.createRequestorder({ - app: vDappAddressOrENS, + app: vDappAddress, category: workerpoolorder.category, dataset: vDatasetAddress, datasetmaxprice: datasetorder.datasetprice, appmaxprice: apporder.appprice, workerpoolmaxprice: workerpoolorder.workerpoolprice, - tag: ['tee'], - workerpool: vWorkerpoolAddressOrEns, + tag: workerpoolMinTag, + workerpool: vWorkerpoolAddress, params: { iexec_secrets: { 1: requesterSecretId, @@ -276,29 +249,19 @@ export const sendTelegram = async ({ const requestorder = await iexec.order.signRequestorder(requestorderToSign); // Match orders and compute task ID - const { dealid: dealId } = await iexec.order.matchOrders( - { - apporder: apporder, - datasetorder: datasetorder, - workerpoolorder: workerpoolorder, - requestorder: requestorder, - }, - { useVoucher: vUseVoucher } - ); + const { dealid: dealId } = await iexec.order.matchOrders({ + apporder: apporder, + datasetorder: datasetorder, + workerpoolorder: workerpoolorder, + requestorder: requestorder, + }); const taskId = await iexec.deal.computeTaskId(dealId, 0); return { - dealId, taskId, + dealId, }; } catch (error) { - // Protocol error detected, re-throwing as-is - if ((error as any)?.isProtocolError === true) { - throw error; - } - // Handle protocol errors - this will throw if it's an ApiCallError - // handleIfProtocolError transforms ApiCallError into a WorkflowError with isProtocolError=true handleIfProtocolError(error); - // For all other errors throw new WorkflowError({ message: 'Failed to sendTelegram', errorCause: error, diff --git a/src/web3telegram/sendTelegramCampaign.ts b/src/web3telegram/sendTelegramCampaign.ts index 14dbae0..5ec81fb 100644 --- a/src/web3telegram/sendTelegramCampaign.ts +++ b/src/web3telegram/sendTelegramCampaign.ts @@ -1,7 +1,7 @@ import { NULL_ADDRESS } from 'iexec/utils'; import { handleIfProtocolError, WorkflowError } from '../utils/errors.js'; import { - addressOrEnsSchema, + addressSchema, throwIfMissing, campaignRequestSchema, } from '../utils/validators.js'; @@ -21,7 +21,7 @@ export type SendTelegramCampaign = typeof sendTelegramCampaign; export const sendTelegramCampaign = async ({ dataProtector = throwIfMissing(), - workerpoolAddressOrEns = throwIfMissing(), + workerpoolAddress = throwIfMissing(), campaignRequest, }: DataProtectorConsumer & SendTelegramCampaignParams): Promise => { @@ -31,18 +31,18 @@ export const sendTelegramCampaign = async ({ .label('campaignRequest') .validateSync(campaignRequest) as CampaignRequest; - const vWorkerpoolAddressOrEns = addressOrEnsSchema() + const vWorkerpoolAddress = addressSchema() .required() - .label('WorkerpoolAddressOrEns') - .validateSync(workerpoolAddressOrEns); + .label('workerpoolAddress') + .validateSync(workerpoolAddress); if ( vCampaignRequest.workerpool !== NULL_ADDRESS && vCampaignRequest.workerpool.toLowerCase() !== - vWorkerpoolAddressOrEns.toLowerCase() + vWorkerpoolAddress.toLowerCase() ) { throw new ValidationError( - "workerpoolAddressOrEns doesn't match campaignRequest workerpool" + "workerpoolAddress doesn't match campaignRequest workerpool" ); } @@ -50,7 +50,7 @@ export const sendTelegramCampaign = async ({ const processBulkRequestResponse: ProcessBulkRequestResponse = await dataProtector.processBulkRequest({ bulkRequest: vCampaignRequest, - workerpool: vWorkerpoolAddressOrEns, + workerpool: vWorkerpoolAddress, }); return processBulkRequestResponse; diff --git a/src/web3telegram/types.ts b/src/web3telegram/types.ts index 39adbfb..6d92f4b 100644 --- a/src/web3telegram/types.ts +++ b/src/web3telegram/types.ts @@ -1,12 +1,8 @@ +import type { AbstractSigner } from 'ethers'; import { BulkRequest } from '@iexec/dataprotector'; -import { EnhancedWallet } from 'iexec'; import { IExecConfigOptions } from 'iexec/IExecConfig'; -export type Web3SignerProvider = EnhancedWallet; - -export type ENS = string; - -export type AddressOrENS = Address | ENS; +export type Web3SignerProvider = AbstractSigner; export type Address = string; @@ -72,11 +68,10 @@ export type SendTelegramParams = { telegramContent: string; protectedData: Address; label?: string; - workerpoolAddressOrEns?: AddressOrENS; + workerpoolAddress?: Address; dataMaxPrice?: number; appMaxPrice?: number; workerpoolMaxPrice?: number; - useVoucher?: boolean; }; export type SendTelegramResponse = { @@ -95,7 +90,7 @@ export type PrepareTelegramCampaignParams = { senderName?: string; telegramContent: string; label?: string; - workerpoolAddressOrEns?: AddressOrENS; + workerpoolAddress?: Address; dataMaxPrice?: number; appMaxPrice?: number; workerpoolMaxPrice?: number; @@ -116,9 +111,9 @@ export type SendTelegramCampaignParams = { */ campaignRequest: CampaignRequest; /** - * Workerpool address or ENS to use for processing + * Workerpool contract address used for processing */ - workerpoolAddressOrEns?: string; + workerpoolAddress?: string; }; export type SendTelegramCampaignResponse = { @@ -134,10 +129,10 @@ export type SendTelegramCampaignResponse = { */ export type Web3TelegramConfigOptions = { /** - * The Ethereum contract address or ENS (Ethereum Name Service) for the telegram sender dapp. + * Ethereum contract address for the telegram sender dapp. * If not provided, the default web3telegram address for the detected chain will be used. */ - dappAddressOrENS?: AddressOrENS; + dappAddress?: Address; /** * The Ethereum contract address for the whitelist. diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml index cfd6117..c341fd4 100644 --- a/tests/docker-compose.yml +++ b/tests/docker-compose.yml @@ -1,255 +1,304 @@ -services: - bellecour-fork: - restart: 'no' - image: ghcr.io/foundry-rs/foundry:v1.0.0 - entrypoint: anvil - command: '--host 0.0.0.0 --port 8545 --block-time 1 --hardfork berlin --fork-url $BELLECOUR_FORK_URL --fork-block-number $BELLECOUR_FORK_BLOCK --chain-id 134 --gas-limit 6700000 --gas-price 0' - expose: - - 8545 - ports: - - 8545:8545 - healthcheck: - # check port 8545 is open without nc - test: (echo >/dev/tcp/$(hostname)/8545) &>/dev/null - interval: 30s - timeout: 5s - retries: 3 - start_period: 90s - - sms: - image: iexechub/iexec-sms:8.7.0 - restart: unless-stopped - environment: - JAVA_TOOL_OPTIONS: '-Xmx256M' - IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS: http://bellecour-fork:8545 - IEXEC_HUB_ADDRESS: '0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f' - IEXEC_SMS_TEE_RUNTIME_FRAMEWORK: scone - IEXEC_SMS_IMAGE_LAS_IMAGE: 'las-image' - IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE: 'pre-compute-image' - IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT: 'pre-compute-fingerprint' - IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE: 'post-compute-image' - IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT: 'post-compute-fingerprint' - ports: - - 13300:13300 - healthcheck: - test: curl -f localhost:13300/actuator/health || exit 1 - depends_on: - bellecour-fork: - condition: service_healthy - - result-proxy: - image: iexechub/iexec-result-proxy:7.1.0 - restart: unless-stopped - environment: - IEXEC_PRIVATE_CHAIN_ADDRESS: http://bellecour-fork:8545 - IEXEC_PUBLIC_CHAIN_ADDRESS: http://bellecour-fork:8545 - IEXEC_HUB_ADDRESS: '0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f' - MONGO_HOST: result-proxy-mongo - MONGO_PORT: 13202 - IEXEC_IPFS_HOST: ipfs - ports: - - 13200:13200 - depends_on: - bellecour-fork: - condition: service_healthy - result-proxy-mongo: - condition: service_started - ipfs: - condition: service_started - - result-proxy-mongo: - restart: unless-stopped - image: library/mongo:4.2 - entrypoint: '/bin/bash' - command: -c "mongod --bind_ip_all --port 13202" - expose: - - 13202 - - ipfs: - restart: unless-stopped - image: ipfs/go-ipfs:v0.9.1 - expose: - - 8080 - - 5001 - ports: - - 8080:8080 - - 5001:5001 - healthcheck: - test: nc -z 0.0.0.0 8080 && nc -z 0.0.0.0 5001 - interval: 10s - timeout: 5s - retries: 3 - start_period: 30s - - market-mongo: - image: mongo:7.0.6 - restart: unless-stopped - expose: - - 27017 - ports: - - 27017:27017 - - market-redis: - image: redis:7.0.7-alpine - restart: unless-stopped - command: redis-server --appendonly yes - expose: - - 6379 - ports: - - 6379:6379 - - market-watcher: - image: iexechub/iexec-market-watcher:7.0.1 - restart: unless-stopped - environment: - CHAIN: BELLECOUR - START_BLOCK: $BELLECOUR_FORK_BLOCK - ETH_WS_HOST: ws://bellecour-fork:8545 - ETH_RPC_HOST: http://bellecour-fork:8545 - MONGO_HOST: market-mongo - REDIS_HOST: market-redis - depends_on: - bellecour-fork: - condition: service_healthy - market-redis: - condition: service_started - market-mongo: - condition: service_started - - market-api: - image: iexechub/iexec-market-api:7.1.1 - restart: unless-stopped - ports: - - 3000:3000 - expose: - - 3000 - environment: - CHAINS: BELLECOUR_FORK - BELLECOUR_FORK_ETH_RPC_HOST: http://bellecour-fork:8545 - BELLECOUR_FORK_CHAIN_ID: 134 - BELLECOUR_FORK_IS_NATIVE: 'true' - BELLECOUR_FORK_IEXEC_ADDRESS: '0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f' - MONGO_HOST: market-mongo - REDIS_HOST: market-redis - RATE_LIMIT_MAX: 10000 - RATE_LIMIT_PERIOD: 60000 - MAX_OPEN_ORDERS_PER_WALLET: 1000 - depends_on: - bellecour-fork: - condition: service_healthy - market-redis: - condition: service_started - market-mongo: - condition: service_started - - graphnode-postgres: - image: postgres:12 - restart: unless-stopped - command: - - 'postgres' - - '-cshared_preload_libraries=pg_stat_statements' - expose: - - 5432 - environment: - POSTGRES_USER: graphnode - POSTGRES_PASSWORD: password - POSTGRES_DB: graphnode-db - POSTGRES_INITDB_ARGS: '-E UTF8 --locale=C' - healthcheck: - test: pg_isready -U graphnode -d graphnode-db - interval: 10s - timeout: 5s - retries: 3 - start_period: 30s - - graphnode: - image: graphprotocol/graph-node:v0.34.1 - restart: unless-stopped - expose: - - 8000 - - 8020 - ports: - # GraphQL HTTP - - 8000:8000 - # GraphQL WS - # - 8001:8001 - # admin RPC - - 8020:8020 - # # metrics - - 8040:8040 - environment: - postgres_host: graphnode-postgres - postgres_port: 5432 - postgres_user: graphnode - postgres_pass: password - postgres_db: graphnode-db - ipfs: ipfs:5001 - ethereum: bellecour:http://bellecour-fork:8545 - GRAPH_ETHEREUM_GENESIS_BLOCK_NUMBER: $BELLECOUR_FORK_BLOCK - depends_on: - bellecour-fork: - condition: service_healthy - graphnode-postgres: - condition: service_healthy - ipfs: - condition: service_started - healthcheck: - test: netcat -w 1 0.0.0.0 8020 - interval: 10s - timeout: 5s - retries: 5 - start_period: 30s - - dataprotector-subgraph-deployer: - image: iexechub/dataprotector-subgraph-deployer:3.0.0 - restart: 'no' - depends_on: - graphnode: - condition: service_healthy - ipfs: - condition: service_started - environment: - ENV: prod - START_BLOCK: $BELLECOUR_FORK_BLOCK - GRAPHNODE_URL: http://graphnode:8020 - IPFS_URL: http://ipfs:5001 - - voucher-subgraph-deployer: - restart: 'no' - # https://github.com/iExecBlockchainComputing/iexec-voucher-subgraph - image: iexechub/voucher-subgraph-deployer:1.0.0 - environment: - RPC_URL: http://bellecour-fork:8545 - GRAPHNODE_URL: http://graphnode:8020 - IPFS_URL: http://ipfs:5001 - VOUCHER_HUB_ADDRESS: '0x3137B6DF4f36D338b82260eDBB2E7bab034AFEda' - VOUCHER_HUB_START_BLOCK: $BELLECOUR_FORK_BLOCK - depends_on: - bellecour-fork: - condition: service_healthy - graphnode: - condition: service_healthy - ipfs: - condition: service_healthy - - stack-ready: - image: bash - command: - - echo "all services ready" - depends_on: - bellecour-fork: - condition: service_healthy - graphnode: - condition: service_healthy - sms: - condition: service_healthy - market-watcher: - condition: service_started - market-api: - condition: service_started - result-proxy: - condition: service_started - dataprotector-subgraph-deployer: - condition: service_completed_successfully - voucher-subgraph-deployer: - condition: service_completed_successfully +services: + arbitrum-sepolia-fork: + restart: 'no' + platform: linux/amd64 + image: ghcr.io/foundry-rs/foundry:v1.0.0 + entrypoint: anvil + command: '--host 0.0.0.0 --port 8545 --block-time 1 --fork-url $ARBITRUM_SEPOLIA_FORK_URL --fork-block-number $ARBITRUM_SEPOLIA_FORK_BLOCK --chain-id 421614' + expose: + - 8545 + ports: + - 8555:8545 + healthcheck: + # check port 8545 is open without nc + test: (echo >/dev/tcp/$(hostname)/8545) &>/dev/null + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + + unknown-chain-fork: + restart: 'no' + platform: linux/amd64 + image: ghcr.io/foundry-rs/foundry:v1.0.0 + entrypoint: anvil + command: '--host 0.0.0.0 --port 8545 --block-time 1 --fork-url $ARBITRUM_SEPOLIA_FORK_URL --fork-block-number $ARBITRUM_SEPOLIA_FORK_BLOCK --chain-id 421615' + expose: + - 8545 + ports: + - 8565:8545 + healthcheck: + # check port 8545 is open without nc + test: (echo >/dev/tcp/$(hostname)/8545) &>/dev/null + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + + service-internal-error: + image: nginx:alpine + platform: linux/amd64 + volumes: + - $PWD/mock/server/http500.nginx.conf:/etc/nginx/conf.d/default.conf:ro + expose: + - 80 + ports: + - 5500:80 + + sms-arbitrum-sepolia: + platform: linux/amd64 + image: iexechub/iexec-sms:8.7.0 + restart: unless-stopped + environment: + JAVA_TOOL_OPTIONS: '-Xmx256M' + IEXEC_SMS_BLOCKCHAIN_NODE_ADDRESS: http://arbitrum-sepolia-fork:8545 + IEXEC_HUB_ADDRESS: '0xB2157BF2fAb286b2A4170E3491Ac39770111Da3E' + IEXEC_SMS_TEE_RUNTIME_FRAMEWORK: scone + IEXEC_SMS_IMAGE_LAS_IMAGE: 'las-image' + IEXEC_TEE_WORKER_PRE_COMPUTE_IMAGE: 'pre-compute-image' + IEXEC_TEE_WORKER_PRE_COMPUTE_FINGERPRINT: 'pre-compute-fingerprint' + IEXEC_TEE_WORKER_POST_COMPUTE_IMAGE: 'post-compute-image' + IEXEC_TEE_WORKER_POST_COMPUTE_FINGERPRINT: 'post-compute-fingerprint' + ports: + - 13350:13300 + healthcheck: + test: curl -f localhost:13300/actuator/health || exit 1 + interval: 10s + timeout: 10s + retries: 10 + start_period: 120s + depends_on: + arbitrum-sepolia-fork: + condition: service_healthy + + result-proxy-arbitrum-sepolia: + platform: linux/amd64 + image: iexechub/iexec-result-proxy:7.1.0 + restart: unless-stopped + environment: + IEXEC_PRIVATE_CHAIN_ADDRESS: http://arbitrum-sepolia-fork:8545 + IEXEC_PUBLIC_CHAIN_ADDRESS: http://arbitrum-sepolia-fork:8545 + IEXEC_HUB_ADDRESS: '0xB2157BF2fAb286b2A4170E3491Ac39770111Da3E' + MONGO_HOST: result-proxy-mongo + MONGO_PORT: 13202 + IEXEC_IPFS_HOST: ipfs + ports: + - 13250:13200 + depends_on: + arbitrum-sepolia-fork: + condition: service_healthy + result-proxy-mongo: + condition: service_started + ipfs: + condition: service_healthy + + result-proxy-mongo: + restart: unless-stopped + image: library/mongo:4.2 + platform: linux/amd64 + entrypoint: '/bin/bash' + command: -c "mongod --bind_ip_all --port 13202" + expose: + - 13202 + ports: + - 13202:13202 + + ipfs: + restart: unless-stopped + image: ipfs/go-ipfs:v0.9.1 + platform: linux/amd64 + expose: + - 8080 + - 5001 + ports: + - 8080:8080 + - 5001:5001 + healthcheck: + test: nc -z 0.0.0.0 8080 && nc -z 0.0.0.0 5001 + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + + market-mongo: + image: mongo:6.0.3 + restart: unless-stopped + platform: linux/amd64 + expose: + - 27017 + ports: + - 27017:27017 + + market-redis: + image: redis:7.0.7-alpine + platform: linux/amd64 + restart: unless-stopped + command: redis-server --appendonly yes + expose: + - 6379 + ports: + - 6379:6379 + healthcheck: + test: nc -z 0.0.0.0 6379 + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + + market-watcher-arbitrum-sepolia: + platform: linux/amd64 + image: iexechub/iexec-market-watcher:7.0.1 + restart: unless-stopped + environment: + CHAIN: ARBITRUM_SEPOLIA + START_BLOCK: $ARBITRUM_SEPOLIA_FORK_BLOCK + CHAIN_ID: 421614 + IEXEC_ADDRESS: '0xB2157BF2fAb286b2A4170E3491Ac39770111Da3E' + IS_NATIVE: 'false' + ETH_WS_HOST: ws://arbitrum-sepolia-fork:8545 + ETH_RPC_HOST: http://arbitrum-sepolia-fork:8545 + MONGO_HOST: market-mongo + REDIS_HOST: market-redis + depends_on: + arbitrum-sepolia-fork: + condition: service_healthy + market-redis: + condition: service_healthy + market-mongo: + condition: service_started + + market-api-arbitrum-sepolia: + platform: linux/amd64 + image: iexechub/iexec-market-api:7.1.2 + restart: unless-stopped + ports: + - 3050:3000 + expose: + - 3000 + environment: + CHAINS: ARBITRUM_SEPOLIA_FORK + ARBITRUM_SEPOLIA_FORK_ETH_RPC_HOST: http://arbitrum-sepolia-fork:8545 + ARBITRUM_SEPOLIA_FORK_CHAIN_ID: 421614 + ARBITRUM_SEPOLIA_FORK_IS_NATIVE: 'false' + ARBITRUM_SEPOLIA_FORK_IEXEC_ADDRESS: '0xB2157BF2fAb286b2A4170E3491Ac39770111Da3E' + MONGO_HOST: market-mongo + REDIS_HOST: market-redis + RATE_LIMIT_MAX: 10000 + RATE_LIMIT_PERIOD: 60000 + MAX_OPEN_ORDERS_PER_WALLET: 1000 + depends_on: + arbitrum-sepolia-fork: + condition: service_healthy + market-redis: + condition: service_healthy + market-mongo: + condition: service_started + + compass-arbitrum-sepolia: + platform: linux/amd64 + image: iexechub/compass:v0.1.1 + restart: unless-stopped + environment: + DATA_FILE_PATH: /app/data.json + volumes: + - $PWD/mock/compass/data.json:/app/data.json:ro + ports: + - 8069:3000 + healthcheck: + test: nc -w 1 0.0.0.0 3000 + + graphnode-postgres: + image: postgres:12 + platform: linux/amd64 + restart: unless-stopped + command: + - 'postgres' + - '-cshared_preload_libraries=pg_stat_statements' + expose: + - 5432 + environment: + POSTGRES_USER: graphnode + POSTGRES_PASSWORD: password + POSTGRES_DB: graphnode-db + POSTGRES_INITDB_ARGS: '-E UTF8 --locale=C' + healthcheck: + test: pg_isready -U graphnode -d graphnode-db + interval: 10s + timeout: 5s + retries: 3 + start_period: 30s + + graphnode: + platform: linux/amd64 + image: graphprotocol/graph-node:v0.34.1 + restart: unless-stopped + expose: + - 8000 + - 8020 + ports: + - 8000:8000 + - 8020:8020 + - 8040:8040 + environment: + postgres_host: graphnode-postgres + postgres_port: 5432 + postgres_user: graphnode + postgres_pass: password + postgres_db: graphnode-db + ipfs: ipfs:5001 + ethereum: 'arbitrum-sepolia:http://arbitrum-sepolia-fork:8545' + GRAPH_ETHEREUM_GENESIS_BLOCK_NUMBER: $ARBITRUM_SEPOLIA_INDEX_BLOCK + depends_on: + arbitrum-sepolia-fork: + condition: service_healthy + graphnode-postgres: + condition: service_healthy + ipfs: + condition: service_started + healthcheck: + test: netcat -w 1 0.0.0.0 8020 + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s + + dataprotector-subgraph-deployer: + platform: linux/amd64 + image: iexechub/dataprotector-subgraph-deployer:3.1.1-main-4df5c2d + restart: 'no' + depends_on: + graphnode: + condition: service_healthy + ipfs: + condition: service_started + environment: + START_BLOCK: $ARBITRUM_SEPOLIA_INDEX_BLOCK + NETWORK_NAME: arbitrum-sepolia + GRAPHNODE_URL: http://graphnode:8020 + IPFS_URL: http://ipfs:5001 + ENV: prod + + stack-ready: + image: bash + platform: linux/amd64 + command: + - echo "all services ready" + depends_on: + arbitrum-sepolia-fork: + condition: service_healthy + sms-arbitrum-sepolia: + condition: service_healthy + market-watcher-arbitrum-sepolia: + condition: service_started + market-api-arbitrum-sepolia: + condition: service_started + result-proxy-arbitrum-sepolia: + condition: service_started + compass-arbitrum-sepolia: + condition: service_healthy + graphnode: + condition: service_healthy + dataprotector-subgraph-deployer: + condition: service_completed_successfully + unknown-chain-fork: + condition: service_healthy diff --git a/tests/e2e/constructor.test.ts b/tests/e2e/constructor.test.ts index bd4f6b0..5ca262f 100644 --- a/tests/e2e/constructor.test.ts +++ b/tests/e2e/constructor.test.ts @@ -7,10 +7,7 @@ import { getTestWeb3SignerProvider, MAX_EXPECTED_WEB2_SERVICES_TIME, } from '../test-utils.js'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; +import { getChainDefaultConfig } from '../../src/config/config.js'; describe('IExecWeb3telegram()', () => { it('instantiates with a valid ethProvider', async () => { @@ -28,7 +25,7 @@ describe('IExecWeb3telegram()', () => { ); await web3telegram.init(); const ipfsGateway = web3telegram['ipfsGateway']; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); + const defaultConfig = getChainDefaultConfig(421614); expect(defaultConfig).not.toBeNull(); expect(ipfsGateway).toStrictEqual(defaultConfig!.ipfsGateway); }); @@ -54,7 +51,7 @@ describe('IExecWeb3telegram()', () => { ); await web3telegram.init(); const graphQLClient = web3telegram['graphQLClient']; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); + const defaultConfig = getChainDefaultConfig(421614); expect(defaultConfig).not.toBeNull(); expect(graphQLClient['url']).toBe(defaultConfig!.dataProtectorSubgraph); }); @@ -77,7 +74,7 @@ describe('IExecWeb3telegram()', () => { const wallet = Wallet.createRandom(); const customSubgraphUrl = 'https://example.com/custom-subgraph'; const customIpfsGateway = 'https://example.com/ipfs_gateway'; - const customDapp = 'web3telegramstg.apps.iexec.eth'; + const customDapp = '0x1111111111111111111111111111111111111111'; const customIpfsNode = 'https://example.com/node'; const smsURL = 'https://custom-sms-url.com'; const iexecGatewayURL = 'https://custom-market-api-url.com'; @@ -93,7 +90,7 @@ describe('IExecWeb3telegram()', () => { ipfsNode: customIpfsNode, ipfsGateway: customIpfsGateway, dataProtectorSubgraph: customSubgraphUrl, - dappAddressOrENS: customDapp, + dappAddress: customDapp, dappWhitelistAddress: customDappWhitelistAddress, } ); @@ -101,14 +98,14 @@ describe('IExecWeb3telegram()', () => { const graphQLClient = web3telegram['graphQLClient']; const ipfsNode = web3telegram['ipfsNode']; const ipfsGateway = web3telegram['ipfsGateway']; - const dappAddressOrENS = web3telegram['dappAddressOrENS']; + const dappAddress = web3telegram['dappAddress']; const iexec = web3telegram['iexec']; const whitelistAddress = web3telegram['dappWhitelistAddress']; expect(graphQLClient['url']).toBe(customSubgraphUrl); expect(ipfsNode).toStrictEqual(customIpfsNode); expect(ipfsGateway).toStrictEqual(customIpfsGateway); - expect(dappAddressOrENS).toStrictEqual(customDapp); + expect(dappAddress).toStrictEqual(customDapp); expect(whitelistAddress).toStrictEqual( customDappWhitelistAddress.toLowerCase() ); @@ -120,7 +117,9 @@ describe('IExecWeb3telegram()', () => { 'When calling a read method should work as expected', async () => { // --- GIVEN - const web3telegram = new IExecWeb3telegram(); + const web3telegram = new IExecWeb3telegram('421614', { + allowExperimentalNetworks: true, + }); const wallet = Wallet.createRandom(); // --- WHEN/THEN @@ -134,10 +133,8 @@ describe('IExecWeb3telegram()', () => { describe.skip('When instantiating SDK with an experimental network', () => { const experimentalNetworkSigner = getWeb3Provider( Wallet.createRandom().privateKey, - { - host: 421614, - allowExperimentalNetworks: true, - } + 421614, + { allowExperimentalNetworks: true } ); describe('Without allowExperimentalNetworks', () => { @@ -175,7 +172,7 @@ describe('IExecWeb3telegram()', () => { expect(web3telegram['ipfsNode']).toBe( arbitrumSepoliaConfig!.ipfsUploadUrl ); - expect(web3telegram['dappAddressOrENS']).toMatch(/^0x[a-fA-F0-9]{40}$/); // resolved from Compass + expect(web3telegram['dappAddress']).toMatch(/^0x[a-fA-F0-9]{40}$/); // resolved from Compass expect(web3telegram['dappWhitelistAddress']).toBe( arbitrumSepoliaConfig!.whitelistSmartContract.toLowerCase() ); @@ -189,17 +186,17 @@ describe('IExecWeb3telegram()', () => { it('should allow custom configuration override for Arbitrum Sepolia', async () => { const customIpfsGateway = 'https://custom-arbitrum-ipfs.com'; - const customDappAddress = 'custom.arbitrum.app.eth'; + const customDappAddress = '0x2222222222222222222222222222222222222222'; const web3telegram = new IExecWeb3telegram(experimentalNetworkSigner, { allowExperimentalNetworks: true, ipfsGateway: customIpfsGateway, - dappAddressOrENS: customDappAddress, + dappAddress: customDappAddress, }); await web3telegram.init(); expect(web3telegram['ipfsGateway']).toBe(customIpfsGateway); - expect(web3telegram['dappAddressOrENS']).toBe(customDappAddress); + expect(web3telegram['dappAddress']).toBe(customDappAddress); const arbitrumSepoliaConfig = getChainDefaultConfig(421614, { allowExperimentalNetworks: true, @@ -230,17 +227,16 @@ describe('IExecWeb3telegram()', () => { expect(chainConfig.dappAddress).toBeUndefined(); // ENS not supported on this network const web3telegram = new IExecWeb3telegram( - getWeb3Provider(Wallet.createRandom().privateKey, { - host: chainId, + getWeb3Provider(Wallet.createRandom().privateKey, chainId, { allowExperimentalNetworks: true, }), { allowExperimentalNetworks: true } ); await web3telegram.init(); - const dappAddressOrENS = web3telegram['dappAddressOrENS']; - expect(typeof dappAddressOrENS).toBe('string'); - expect(dappAddressOrENS).toMatch(/^0x[a-fA-F0-9]{40}$/); + const dappAddress = web3telegram['dappAddress']; + expect(typeof dappAddress).toBe('string'); + expect(dappAddress).toMatch(/^0x[a-fA-F0-9]{40}$/); }); }); }); diff --git a/tests/e2e/fetchMyContacts.test.ts b/tests/e2e/fetchMyContacts.test.ts index 79b33f0..6de397c 100644 --- a/tests/e2e/fetchMyContacts.test.ts +++ b/tests/e2e/fetchMyContacts.test.ts @@ -1,21 +1,20 @@ import { describe, expect, it } from '@jest/globals'; import { IExecDataProtector } from '@iexec/dataprotector'; import { IExecWeb3telegram } from '../../src/index.js'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; -import { getTestConfig, waitSubgraphIndexing } from '../test-utils.js'; -import { HDNodeWallet, Wallet } from 'ethers'; -import { NULL_ADDRESS } from 'iexec/utils'; import { MAX_EXPECTED_BLOCKTIME, MAX_EXPECTED_WEB2_SERVICES_TIME, - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME, + TEST_CHAIN, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, deployRandomDataset, - getTestWeb3SignerProvider, + getTestConfig, getTestIExecOption, + getTestWeb3SignerProvider, + setBalance, + waitSubgraphIndexing, } from '../test-utils.js'; +import { HDNodeWallet, Wallet } from 'ethers'; +import { NULL_ADDRESS } from 'iexec/utils'; import IExec from 'iexec/IExec'; describe('web3telegram.fetchMyContacts()', () => { @@ -23,10 +22,10 @@ describe('web3telegram.fetchMyContacts()', () => { let web3telegram: IExecWeb3telegram; let dataProtector: IExecDataProtector; let protectedData: any; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); beforeAll(async () => { wallet = Wallet.createRandom(); + await setBalance(wallet.address, 10n ** 18n); dataProtector = new IExecDataProtector(...getTestConfig(wallet.privateKey)); web3telegram = new IExecWeb3telegram(...getTestConfig(wallet.privateKey)); protectedData = await dataProtector.core.protectData({ @@ -40,7 +39,7 @@ describe('web3telegram.fetchMyContacts()', () => { 'pass with a granted access for a specific requester', async () => { await dataProtector.core.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedData.address, authorizedUser: wallet.address, }); @@ -65,7 +64,7 @@ describe('web3telegram.fetchMyContacts()', () => { async () => { const grantedAccessForAnyRequester = await dataProtector.core.grantAccess( { - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedData.address, authorizedUser: NULL_ADDRESS, } @@ -105,7 +104,7 @@ describe('web3telegram.fetchMyContacts()', () => { const encryptionKey = await iexec.dataset.generateEncryptionKey(); await iexec.dataset.pushDatasetSecret(dataset.address, encryptionKey); await dataProtector.core.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: dataset.address, authorizedUser: wallet.address, }); @@ -127,7 +126,7 @@ describe('web3telegram.fetchMyContacts()', () => { await waitSubgraphIndexing(); await dataProtector.core.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: notValidProtectedData.address, authorizedUser: wallet.address, }); @@ -164,7 +163,7 @@ describe('web3telegram.fetchMyContacts()', () => { async () => { // Grant access with allowBulk: true await dataProtector.core.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedDataWithBulk.address, authorizedUser: wallet.address, allowBulk: true, @@ -172,7 +171,7 @@ describe('web3telegram.fetchMyContacts()', () => { // Grant access with allowBulk: false (or default) await dataProtector.core.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedDataWithoutBulk.address, authorizedUser: wallet.address, allowBulk: false, @@ -199,7 +198,7 @@ describe('web3telegram.fetchMyContacts()', () => { expect(noBulkContact).toBeUndefined(); }, MAX_EXPECTED_BLOCKTIME + - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME + + TEST_CHAIN.maxExpectedSubgraphIndexingTime + MAX_EXPECTED_WEB2_SERVICES_TIME ); diff --git a/tests/e2e/fetchUserContacts.test.ts b/tests/e2e/fetchUserContacts.test.ts index 99d0657..a2772b0 100644 --- a/tests/e2e/fetchUserContacts.test.ts +++ b/tests/e2e/fetchUserContacts.test.ts @@ -4,16 +4,15 @@ import { } from '@iexec/dataprotector'; import { beforeAll, describe, expect, it } from '@jest/globals'; import { HDNodeWallet, Wallet } from 'ethers'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; +import { getChainDefaultConfig } from '../../src/config/config.js'; import { IExecWeb3telegram, WorkflowError } from '../../src/index.js'; import { MAX_EXPECTED_BLOCKTIME, MAX_EXPECTED_WEB2_SERVICES_TIME, - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME, + TEST_CHAIN, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, getTestConfig, + setBalance, waitSubgraphIndexing, } from '../test-utils.js'; @@ -26,6 +25,7 @@ describe('web3telegram.fetchMyContacts()', () => { beforeAll(async () => { wallet = Wallet.createRandom(); + await setBalance(wallet.address, 10n ** 18n); dataProtector = new IExecDataProtectorCore( ...getTestConfig(wallet.privateKey) ); @@ -66,7 +66,7 @@ describe('web3telegram.fetchMyContacts()', () => { await web3telegram.init(); // eslint-disable-next-line @typescript-eslint/dot-notation - const authorizedApp = web3telegram['dappAddressOrENS']; + const authorizedApp = web3telegram['dappAddress']; await dataProtector.grantAccess({ authorizedApp: authorizedApp, @@ -92,10 +92,10 @@ describe('web3telegram.fetchMyContacts()', () => { 'should return the user contacts for both app and whitelist', async () => { const userWithAccess = Wallet.createRandom().address; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); - expect(defaultConfig).not.toBeNull(); - const authorizedApp = defaultConfig!.dappAddress; - const authorizedWhitelist = defaultConfig!.whitelistSmartContract; + const chainConfig = getChainDefaultConfig(421614); + expect(chainConfig).not.toBeNull(); + const authorizedApp = TEST_WEB3TELEGRAM_DAPP_ADDRESS; + const authorizedWhitelist = chainConfig!.whitelistSmartContract; await dataProtector.grantAccess({ authorizedApp: authorizedApp, @@ -123,15 +123,14 @@ describe('web3telegram.fetchMyContacts()', () => { async () => { const user1 = Wallet.createRandom().address; const user2 = Wallet.createRandom().address; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedData1.address, authorizedUser: user1, }); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedData2.address, authorizedUser: user2, }); @@ -151,9 +150,8 @@ describe('web3telegram.fetchMyContacts()', () => { 'Test that the protected data can be accessed by authorized user', async () => { const userWithAccess = Wallet.createRandom().address; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedData1.address, authorizedUser: userWithAccess, }); @@ -212,14 +210,12 @@ describe('web3telegram.fetchMyContacts()', () => { // Call getTestConfig to get the default configuration const [ethProvider, defaultOptions] = getTestConfig(wallet.privateKey); - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); - expect(defaultConfig).not.toBeNull(); - const authorizedApp = defaultConfig!.dappAddress; + const authorizedApp = TEST_WEB3TELEGRAM_DAPP_ADDRESS; await dataProtector.grantAccess({ authorizedApp: authorizedApp, protectedData: protectedData1.address, - authorizedUser: ethProvider.address, + authorizedUser: await ethProvider.getAddress(), }); const options = { @@ -266,12 +262,8 @@ describe('web3telegram.fetchMyContacts()', () => { it( 'should return only contacts with bulk access when bulkOnly is true', async () => { - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); - expect(defaultConfig).not.toBeNull(); - - // Grant access with allowBulk: true await dataProtector.grantAccess({ - authorizedApp: defaultConfig!.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedDataWithBulk.address, authorizedUser: userWithAccess, allowBulk: true, @@ -279,7 +271,7 @@ describe('web3telegram.fetchMyContacts()', () => { // Grant access with allowBulk: false (or default) await dataProtector.grantAccess({ - authorizedApp: defaultConfig!.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedDataWithoutBulk.address, authorizedUser: userWithAccess, allowBulk: false, @@ -307,7 +299,7 @@ describe('web3telegram.fetchMyContacts()', () => { expect(noBulkContact).toBeUndefined(); }, MAX_EXPECTED_BLOCKTIME + - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME + + TEST_CHAIN.maxExpectedSubgraphIndexingTime + MAX_EXPECTED_WEB2_SERVICES_TIME ); diff --git a/tests/e2e/prepareTelegramCampaign.test.ts b/tests/e2e/prepareTelegramCampaign.test.ts index 499ffd4..9d19236 100644 --- a/tests/e2e/prepareTelegramCampaign.test.ts +++ b/tests/e2e/prepareTelegramCampaign.test.ts @@ -4,19 +4,24 @@ import { } from '@iexec/dataprotector'; import { beforeAll, describe, expect, it } from '@jest/globals'; import { HDNodeWallet } from 'ethers'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; import { Contact, IExecWeb3telegram } from '../../src/index.js'; import { MAX_EXPECTED_BLOCKTIME, MAX_EXPECTED_WEB2_SERVICES_TIME, - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME, + TEST_CHAIN, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, + createAndPublishAppOrders, + createAndPublishWorkerpoolOrder, getRandomWallet, getTestConfig, + getTestIExecOption, + getTestWeb3SignerProvider, + setBalance, + setEthForGas, waitSubgraphIndexing, } from '../test-utils.js'; +import { IExec } from 'iexec'; +import { NULL_ADDRESS } from 'iexec/utils'; describe('web3telegram.prepareTelegramCampaign()', () => { let consumerWallet: HDNodeWallet; @@ -26,17 +31,39 @@ describe('web3telegram.prepareTelegramCampaign()', () => { let validProtectedData1: ProtectedDataWithSecretProps; let validProtectedData2: ProtectedDataWithSecretProps; let validProtectedData3: ProtectedDataWithSecretProps; + const iexecOptions = getTestIExecOption(); const prodWorkerpoolPublicPrice = 1000; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); beforeAll(async () => { - // Create app orders + await createAndPublishWorkerpoolOrder( + TEST_CHAIN.prodWorkerpool, + TEST_CHAIN.prodWorkerpoolOwnerWallet, + NULL_ADDRESS, + 1_000, + prodWorkerpoolPublicPrice + ); + providerWallet = getRandomWallet(); + const resourceProvider = new IExec( + { + ethProvider: getTestWeb3SignerProvider( + TEST_CHAIN.appOwnerWallet.privateKey + ), + }, + iexecOptions + ); + await createAndPublishAppOrders( + resourceProvider, + TEST_WEB3TELEGRAM_DAPP_ADDRESS + ); + dataProtector = new IExecDataProtectorCore( ...getTestConfig(providerWallet.privateKey) ); + await setBalance(providerWallet.address, 10n ** 18n); + // create valid protected data validProtectedData1 = await dataProtector.protectData({ data: { telegram_chatId: '12345' }, @@ -54,28 +81,29 @@ describe('web3telegram.prepareTelegramCampaign()', () => { }); await waitSubgraphIndexing(); - }, 5 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME + 5_000); + }, 5 * (MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME) + TEST_CHAIN.maxExpectedSubgraphIndexingTime + 5_000); beforeEach(async () => { consumerWallet = getRandomWallet(); + await setEthForGas(consumerWallet.address); // Grant access with allowBulk for bulk processing await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData1.address, authorizedUser: consumerWallet.address, allowBulk: true, }); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData2.address, authorizedUser: consumerWallet.address, allowBulk: true, }); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData3.address, authorizedUser: consumerWallet.address, allowBulk: true, @@ -85,7 +113,7 @@ describe('web3telegram.prepareTelegramCampaign()', () => { web3telegram = new IExecWeb3telegram( ...getTestConfig(consumerWallet.privateKey) ); - }, MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_SUBGRAPH_INDEXING_TIME); + }, MAX_EXPECTED_BLOCKTIME + TEST_CHAIN.maxExpectedSubgraphIndexingTime); it( 'should prepare a telegram campaignRequest', diff --git a/tests/e2e/sendTelegram.test.ts b/tests/e2e/sendTelegram.test.ts index 7001667..a05b06c 100644 --- a/tests/e2e/sendTelegram.test.ts +++ b/tests/e2e/sendTelegram.test.ts @@ -3,31 +3,27 @@ import { ProtectedDataWithSecretProps, WorkflowError, } from '@iexec/dataprotector'; -import { beforeAll, describe, expect, it } from '@jest/globals'; +import { beforeAll, beforeEach, describe, expect, it } from '@jest/globals'; import { HDNodeWallet } from 'ethers'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; import { IExecWeb3telegram, WorkflowError as Web3TelegramWorkflowError, } from '../../src/index.js'; import { MAX_EXPECTED_BLOCKTIME, - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME, MAX_EXPECTED_WEB2_SERVICES_TIME, TEST_CHAIN, - addVoucherEligibleAsset, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, createAndPublishAppOrders, createAndPublishWorkerpoolOrder, - createVoucher, - createVoucherType, ensureSufficientStake, + getId, getRandomWallet, getTestConfig, getTestIExecOption, getTestWeb3SignerProvider, + setBalance, + setEthForGas, waitSubgraphIndexing, } from '../test-utils.js'; import { IExec } from 'iexec'; @@ -41,48 +37,27 @@ describe('web3telegram.sendTelegram()', () => { let validProtectedData: ProtectedDataWithSecretProps; let invalidProtectedData: ProtectedDataWithSecretProps; let consumerIExecInstance: IExec; - let prodWorkerpoolAddress: string; - let learnProdWorkerpoolAddress: string; const iexecOptions = getTestIExecOption(); - const prodWorkerpoolPublicPrice = 1000; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); beforeAll(async () => { - // (default) prod workerpool (not free) always available await createAndPublishWorkerpoolOrder( TEST_CHAIN.prodWorkerpool, TEST_CHAIN.prodWorkerpoolOwnerWallet, NULL_ADDRESS, - 1_000, - prodWorkerpoolPublicPrice - ); - // learn prod pool (free) assumed always available - await createAndPublishWorkerpoolOrder( - TEST_CHAIN.learnProdWorkerpool, - TEST_CHAIN.learnProdWorkerpoolOwnerWallet, - NULL_ADDRESS, 0, 10_000 ); - // apporder always available providerWallet = getRandomWallet(); + await setBalance(providerWallet.address, 10n ** 18n); const ethProvider = getTestWeb3SignerProvider( TEST_CHAIN.appOwnerWallet.privateKey ); const resourceProvider = new IExec({ ethProvider }, iexecOptions); await createAndPublishAppOrders( resourceProvider, - defaultConfig!.dappAddress - ); - - learnProdWorkerpoolAddress = await resourceProvider.ens.resolveName( - TEST_CHAIN.learnProdWorkerpool - ); - prodWorkerpoolAddress = await resourceProvider.ens.resolveName( - TEST_CHAIN.prodWorkerpool + TEST_WEB3TELEGRAM_DAPP_ADDRESS ); - //create valid protected data dataProtector = new IExecDataProtectorCore( ...getTestConfig(providerWallet.privateKey) ); @@ -90,7 +65,6 @@ describe('web3telegram.sendTelegram()', () => { data: { telegram_chatId: '12345' }, name: 'test do not use', }); - //create invalid protected data invalidProtectedData = await dataProtector.protectData({ data: { foo: 'bar' }, name: 'test do not use', @@ -99,8 +73,8 @@ describe('web3telegram.sendTelegram()', () => { }, 4 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME + 5_000); beforeEach(async () => { - // use a fresh wallet for calling sendTelegram consumerWallet = getRandomWallet(); + await setEthForGas(consumerWallet.address); const consumerEthProvider = getTestWeb3SignerProvider( consumerWallet.privateKey ); @@ -109,9 +83,9 @@ describe('web3telegram.sendTelegram()', () => { iexecOptions ); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData.address, - authorizedUser: consumerWallet.address, // consumer wallet + authorizedUser: consumerWallet.address, numberOfAccess: 1000, }); web3telegram = new IExecWeb3telegram( @@ -120,21 +94,50 @@ describe('web3telegram.sendTelegram()', () => { }); describe('when using the default (not free) prod workerpool', () => { + let paidWorkerpoolAddress: string; + const prodWorkerpoolPublicPrice = 1000; + + beforeAll(async () => { + // Deploy a fresh workerpool so it has no pre-existing free orders from the fork + await setEthForGas(TEST_CHAIN.prodWorkerpoolOwnerWallet.address); + const workerpoolOwnerEthProvider = getTestWeb3SignerProvider( + TEST_CHAIN.prodWorkerpoolOwnerWallet.privateKey + ); + const workerpoolOwnerIexec = new IExec( + { ethProvider: workerpoolOwnerEthProvider }, + iexecOptions + ); + const { address } = + await workerpoolOwnerIexec.workerpool.deployWorkerpool({ + owner: TEST_CHAIN.prodWorkerpoolOwnerWallet.address, + description: `paid test workerpool ${getId()}`, + }); + paidWorkerpoolAddress = address; + await createAndPublishWorkerpoolOrder( + paidWorkerpoolAddress, + TEST_CHAIN.prodWorkerpoolOwnerWallet, + NULL_ADDRESS, + prodWorkerpoolPublicPrice, + 10 + ); + }, 3 * MAX_EXPECTED_BLOCKTIME); + describe('when using the user does not set the workerpoolMaxPrice', () => { it( 'should throw an error No Workerpool order found for the desired price', async () => { - let error: Error; + let error!: Error; await web3telegram .sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: validProtectedData.address, + workerpoolAddress: paidWorkerpoolAddress, }) .catch((e) => (error = e)); expect(error).toBeDefined(); expect(error.message).toBe('Failed to sendTelegram'); expect(error.cause).toStrictEqual( - Error(`No Workerpool order found for the desired price`) + new Error(`No Workerpool order found for the desired price`) ); }, 2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME @@ -144,18 +147,19 @@ describe('web3telegram.sendTelegram()', () => { it( `should throw an error if the user can't pay with its account`, async () => { - let error: Error; + let error!: Web3TelegramWorkflowError; await web3telegram .sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: validProtectedData.address, + workerpoolAddress: paidWorkerpoolAddress, workerpoolMaxPrice: prodWorkerpoolPublicPrice, }) .catch((e) => (error = e)); expect(error).toBeInstanceOf(Web3TelegramWorkflowError); expect(error.message).toBe('Failed to sendTelegram'); expect(error.cause).toStrictEqual( - Error( + new Error( `Cost per task (${prodWorkerpoolPublicPrice}) is greater than requester account stake (0). Orders can't be matched. If you are the requester, you should deposit to top up your account` ) ); @@ -172,6 +176,7 @@ describe('web3telegram.sendTelegram()', () => { const sendTelegramResponse = await web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: validProtectedData.address, + workerpoolAddress: paidWorkerpoolAddress, workerpoolMaxPrice: prodWorkerpoolPublicPrice, }); expect(sendTelegramResponse).toStrictEqual({ @@ -191,7 +196,7 @@ describe('web3telegram.sendTelegram()', () => { web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: invalidProtectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }) ).rejects.toThrow('Failed to sendTelegram'); @@ -200,7 +205,7 @@ describe('web3telegram.sendTelegram()', () => { await web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: invalidProtectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }); } catch (err) { error = err as Web3TelegramWorkflowError; @@ -218,7 +223,6 @@ describe('web3telegram.sendTelegram()', () => { it( 'should fail if there is no Dataset order found', async () => { - //create valid protected data with blank order to not have: datasetorder is fully consumed error from iexec sdk const protectedData = await dataProtector.protectData({ data: { telegram_chatId: '12345' }, name: 'test do not use', @@ -229,12 +233,12 @@ describe('web3telegram.sendTelegram()', () => { web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: protectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }) ).rejects.toThrow( new WorkflowError({ message: 'Failed to sendTelegram', - errorCause: Error('No Dataset order found for the desired price'), + errorCause: new Error('No Dataset order found for the desired price'), }) ); }, @@ -244,7 +248,6 @@ describe('web3telegram.sendTelegram()', () => { it( 'should throw a protocol error id a service is not available', async () => { - // Call getTestConfig to get the default configuration const [ethProvider, defaultOptions] = getTestConfig( providerWallet.privateKey ); @@ -257,14 +260,13 @@ describe('web3telegram.sendTelegram()', () => { }, }; - // Pass the modified options to IExecWeb3telegram const invalidWeb3telegram = new IExecWeb3telegram(ethProvider, options); let error: Web3TelegramWorkflowError | undefined; try { await invalidWeb3telegram.sendTelegram({ protectedData: validProtectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, telegramContent: 'e2e telegram content for test', }); } catch (err) { @@ -286,7 +288,7 @@ describe('web3telegram.sendTelegram()', () => { const sendTelegramResponse = await web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: validProtectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }); expect(sendTelegramResponse).toStrictEqual({ dealId: expect.any(String), @@ -299,24 +301,22 @@ describe('web3telegram.sendTelegram()', () => { it( 'should successfully send telegram with granted access to whitelist address', async () => { - //create valid protected data const protectedDataForWhitelist = await dataProtector.protectData({ data: { telegram_chatId: '1461320872' }, name: 'test do not use', }); await waitSubgraphIndexing(); - //grant access to whitelist await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: protectedDataForWhitelist.address, - authorizedUser: consumerWallet.address, // consumer wallet + authorizedUser: consumerWallet.address, numberOfAccess: 1000, }); const sendTelegramResponse = await web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: protectedDataForWhitelist.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }); expect('taskId' in sendTelegramResponse).toBe(true); expect(sendTelegramResponse).toStrictEqual({ @@ -327,7 +327,6 @@ describe('web3telegram.sendTelegram()', () => { 2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME ); - // TODO impliment this feature in dapp it( 'should successfully send telegram with content type html', async () => { @@ -335,8 +334,7 @@ describe('web3telegram.sendTelegram()', () => { telegramContent: '

Test html

test paragraph

', protectedData: validProtectedData.address, - // contentType: 'text/html', - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }); expect('taskId' in sendTelegramResponse).toBe(true); expect(sendTelegramResponse).toStrictEqual({ @@ -349,13 +347,12 @@ describe('web3telegram.sendTelegram()', () => { it( 'should successfully send telegram with a valid senderName', - async () => { const sendTelegramResponse = await web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: validProtectedData.address, senderName: 'Product Team', - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }); expect(sendTelegramResponse).toBeDefined(); expect('taskId' in sendTelegramResponse).toBe(true); @@ -370,7 +367,7 @@ describe('web3telegram.sendTelegram()', () => { it( 'should successfully send telegram with message content size < 512 kilo-bytes', async () => { - const desiredSizeInBytes = 500000; // 500 kilo-bytes + const desiredSizeInBytes = 500000; const characterToRepeat = 'A'; const LARGE_CONTENT = characterToRepeat.repeat(desiredSizeInBytes); @@ -378,7 +375,7 @@ describe('web3telegram.sendTelegram()', () => { telegramContent: LARGE_CONTENT, protectedData: validProtectedData.address, senderName: 'Product Team', - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, }); expect(sendTelegramResponse).toStrictEqual({ dealId: expect.any(String), @@ -394,223 +391,14 @@ describe('web3telegram.sendTelegram()', () => { const sendTelegramResponse = await web3telegram.sendTelegram({ telegramContent: 'e2e telegram content for test', protectedData: validProtectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, label: 'ID1234678', }); expect(sendTelegramResponse).toStrictEqual({ dealId: expect.any(String), taskId: expect.any(String), }); - // TODO check label in created deal }, 2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME ); - - describe('when useVoucher:true', () => { - it( - 'should throw error if no voucher available for the requester', - async () => { - let error; - try { - await web3telegram.sendTelegram({ - telegramContent: 'e2e telegram content for test', - protectedData: validProtectedData.address, - workerpoolAddressOrEns: learnProdWorkerpoolAddress, - workerpoolMaxPrice: 1000, - useVoucher: true, - }); - } catch (err) { - error = err; - } - expect(error).toBeDefined(); - expect(error.message).toBe('Failed to sendTelegram'); - expect(error.cause).toStrictEqual( - Error( - 'Oops, it seems your wallet is not associated with any voucher. Check on https://builder.iex.ec/' - ) - ); - }, - 2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME - ); - it( - 'should throw error if workerpool is not sponsored by the voucher', - async () => { - const voucherType = await createVoucherType({ - description: 'test voucher type', - duration: 60 * 60, - }); - await createVoucher({ - owner: consumerWallet.address, - voucherType, - value: 1000, - }); - - let error; - try { - await web3telegram.sendTelegram({ - telegramContent: 'e2e telegram content for test', - protectedData: validProtectedData.address, - // workerpoolAddressOrEns: prodWorkerpoolAddress, // default - workerpoolMaxPrice: 1000, - useVoucher: true, - }); - } catch (err) { - error = err; - } - expect(error).toBeDefined(); - expect(error.message).toBe('Failed to sendTelegram'); - expect(error.cause.message).toBe( - 'Found some workerpool orders but none can be sponsored by your voucher.' - ); - }, - 2 * MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME - ); - describe('when voucher balance covers the full workerpool price', () => { - it( - 'should create a deal for send telegram message', - async () => { - // payable workerpool - const voucherType = await createVoucherType({ - description: 'test voucher type', - duration: 60 * 60, - }); - await addVoucherEligibleAsset(prodWorkerpoolAddress, voucherType); - const voucherValue = 1000; - await createVoucher({ - owner: consumerWallet.address, - voucherType, - value: voucherValue, - }); - await waitSubgraphIndexing(); - - const sendTelegramResponse = await web3telegram.sendTelegram({ - telegramContent: 'e2e telegram content for test', - protectedData: validProtectedData.address, - // workerpoolAddressOrEns: prodWorkerpoolAddress, // default - useVoucher: true, - }); - expect(sendTelegramResponse).toStrictEqual({ - dealId: expect.any(String), - taskId: expect.any(String), - }); - }, - 2 * MAX_EXPECTED_BLOCKTIME + - MAX_EXPECTED_WEB2_SERVICES_TIME + - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME - ); - }); - - describe('when voucher balance does not cover the full workerpool price', () => { - describe('but workerpoolMaxPrice covers the non sponsored amount', () => { - it( - 'should create task if user approves the non sponsored amount', - async () => { - const voucherType = await createVoucherType({ - description: 'test voucher type', - duration: 60 * 60, - }); - await addVoucherEligibleAsset(prodWorkerpoolAddress, voucherType); - - const voucherRemainingValue = 500; - const workerpoolOrderPrice = 600; - const nonSponsoredAmount = - workerpoolOrderPrice - voucherRemainingValue; - - // voucher with balance insufficient to cover workerpool price - const [voucherAddress] = await Promise.all([ - createVoucher({ - owner: consumerWallet.address, - voucherType, - value: voucherRemainingValue, - skipOrders: true, - }), - createAndPublishWorkerpoolOrder( - TEST_CHAIN.prodWorkerpool, - TEST_CHAIN.prodWorkerpoolOwnerWallet, - consumerWallet.address, - workerpoolOrderPrice - ), - ]); - await waitSubgraphIndexing(); - await ensureSufficientStake( - consumerIExecInstance, - nonSponsoredAmount - ); - await consumerIExecInstance.account.approve( - nonSponsoredAmount, - voucherAddress - ); - - const sendTelegramResponse = await web3telegram.sendTelegram({ - telegramContent: 'e2e telegram content for test', - protectedData: validProtectedData.address, - // workerpoolAddressOrEns: prodWorkerpoolAddress, // default - workerpoolMaxPrice: nonSponsoredAmount, - useVoucher: true, - }); - expect(sendTelegramResponse).toStrictEqual({ - dealId: expect.any(String), - taskId: expect.any(String), - }); - }, - 2 * MAX_EXPECTED_BLOCKTIME + - MAX_EXPECTED_WEB2_SERVICES_TIME + - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME - ); - }); - describe('and workerpoolMaxPrice does NOT covers the non sponsored amount', () => { - it( - 'should throws an error No Workerpool order found for the desired price', - async () => { - const voucherType = await createVoucherType({ - description: 'test voucher type', - duration: 60 * 60, - }); - await addVoucherEligibleAsset(prodWorkerpoolAddress, voucherType); - - const voucherRemainingValue = 500; - const workerpoolOrderPrice = 600; - - // voucher with balance insufficient to cover workerpool price - await Promise.all([ - createVoucher({ - owner: consumerWallet.address, - voucherType, - value: voucherRemainingValue, - skipOrders: true, - }), - createAndPublishWorkerpoolOrder( - TEST_CHAIN.prodWorkerpool, - TEST_CHAIN.prodWorkerpoolOwnerWallet, - consumerWallet.address, - workerpoolOrderPrice - ), - ]); - await waitSubgraphIndexing(); - - let error; - try { - await web3telegram.sendTelegram({ - telegramContent: 'e2e telegram content for test', - protectedData: validProtectedData.address, - // workerpoolAddressOrEns: prodWorkerpoolAddress, // default - // workerpoolMaxPrice: 0, // default - useVoucher: true, - }); - } catch (err) { - error = err; - } - expect(error).toBeDefined(); - expect(error.message).toBe('Failed to sendTelegram'); - expect(error.cause.message).toBe( - `No Workerpool order found for the desired price` - ); - }, - 2 * MAX_EXPECTED_BLOCKTIME + - MAX_EXPECTED_WEB2_SERVICES_TIME + - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME - ); - }); - }); - }); }); diff --git a/tests/e2e/sendTelegramCampaign.test.ts b/tests/e2e/sendTelegramCampaign.test.ts index e1fda46..f32af5d 100644 --- a/tests/e2e/sendTelegramCampaign.test.ts +++ b/tests/e2e/sendTelegramCampaign.test.ts @@ -4,16 +4,12 @@ import { } from '@iexec/dataprotector'; import { beforeAll, describe, expect, it } from '@jest/globals'; import { HDNodeWallet } from 'ethers'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; import { Contact, IExecWeb3telegram } from '../../src/index.js'; import { MAX_EXPECTED_BLOCKTIME, MAX_EXPECTED_WEB2_SERVICES_TIME, - MAX_EXPECTED_SUBGRAPH_INDEXING_TIME, TEST_CHAIN, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, createAndPublishAppOrders, createAndPublishWorkerpoolOrder, ensureSufficientStake, @@ -21,6 +17,8 @@ import { getTestConfig, getTestIExecOption, getTestWeb3SignerProvider, + setBalance, + setEthForGas, waitSubgraphIndexing, } from '../test-utils.js'; import { IExec } from 'iexec'; @@ -37,7 +35,6 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { let consumerIExecInstance: IExec; const iexecOptions = getTestIExecOption(); const prodWorkerpoolPublicPrice = 1000; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); beforeAll(async () => { // Create workerpool orders @@ -51,6 +48,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Create app orders providerWallet = getRandomWallet(); + await setBalance(providerWallet.address, 10n ** 18n); const resourceProvider = new IExec( { @@ -62,7 +60,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { ); await createAndPublishAppOrders( resourceProvider, - defaultConfig!.dappAddress + TEST_WEB3TELEGRAM_DAPP_ADDRESS ); dataProtector = new IExecDataProtectorCore( @@ -86,10 +84,11 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { }); await waitSubgraphIndexing(); - }, 5 * (MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME) + MAX_EXPECTED_SUBGRAPH_INDEXING_TIME + 5_000); + }, 5 * (MAX_EXPECTED_BLOCKTIME + MAX_EXPECTED_WEB2_SERVICES_TIME) + TEST_CHAIN.maxExpectedSubgraphIndexingTime + 5_000); beforeEach(async () => { consumerWallet = getRandomWallet(); + await setEthForGas(consumerWallet.address); const consumerEthProvider = getTestWeb3SignerProvider( consumerWallet.privateKey ); @@ -100,21 +99,21 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Grant access with allowBulk for bulk processing await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData1.address, authorizedUser: consumerWallet.address, allowBulk: true, }); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData2.address, authorizedUser: consumerWallet.address, allowBulk: true, }); await dataProtector.grantAccess({ - authorizedApp: defaultConfig.dappAddress, + authorizedApp: TEST_WEB3TELEGRAM_DAPP_ADDRESS, protectedData: validProtectedData3.address, authorizedUser: consumerWallet.address, allowBulk: true, @@ -149,7 +148,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { maxProtectedDataPerTask: 3, appMaxPrice: 1000, workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, senderName: 'Bulk Test Sender', }); const campaignRequest = prepareResult.campaignRequest; @@ -158,7 +157,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Use the workerpool from campaignRequest (already resolved to address) const result = await web3telegram.sendTelegramCampaign({ campaignRequest, - workerpoolAddressOrEns: campaignRequest.workerpool, + workerpoolAddress: campaignRequest.workerpool, }); // Verify the result @@ -200,7 +199,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { maxProtectedDataPerTask: 1, appMaxPrice: 1000, workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, senderName: 'Single Contact Test', }); const campaignRequest = prepareResult.campaignRequest; @@ -209,7 +208,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Use the workerpool from campaignRequest (already resolved to address) const result = await web3telegram.sendTelegramCampaign({ campaignRequest, - workerpoolAddressOrEns: campaignRequest.workerpool, + workerpoolAddress: campaignRequest.workerpool, }); // Verify the result @@ -248,7 +247,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { maxProtectedDataPerTask: 1, // Force one protected data per task appMaxPrice: 1000, workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, senderName: 'Max Data Test', label: 'MAXDATA', }); @@ -258,7 +257,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Use the workerpool from campaignRequest (already resolved to address) const result = await web3telegram.sendTelegramCampaign({ campaignRequest, - workerpoolAddressOrEns: campaignRequest.workerpool, + workerpoolAddress: campaignRequest.workerpool, }); // Verify the result @@ -295,7 +294,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { maxProtectedDataPerTask: 3, appMaxPrice: 1000, workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, senderName: 'CustomSender', label: 'CUSTOM123', }); @@ -305,7 +304,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { // Use the workerpool from campaignRequest (already resolved to address) const result = await web3telegram.sendTelegramCampaign({ campaignRequest, - workerpoolAddressOrEns: campaignRequest.workerpool, + workerpoolAddress: campaignRequest.workerpool, }); // Verify the result @@ -319,7 +318,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { ); it( - 'should throw error when workerpoolAddressOrEns does not match campaignRequest.workerpool', + 'should throw error when workerpoolAddress does not match campaignRequest.workerpool', async () => { // Fetch contacts with allowBulk access const contacts: Contact[] = await web3telegram.fetchMyContacts({ @@ -335,7 +334,7 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { maxProtectedDataPerTask: 3, appMaxPrice: 1000, workerpoolMaxPrice: 1000, - workerpoolAddressOrEns: TEST_CHAIN.prodWorkerpool, + workerpoolAddress: TEST_CHAIN.prodWorkerpool, senderName: 'Mismatch Test', }); const campaignRequest = prepareResult.campaignRequest; @@ -346,14 +345,14 @@ describe('web3telegram.sendTelegramCampaign() - Bulk Processing', () => { await expect( web3telegram.sendTelegramCampaign({ campaignRequest, - workerpoolAddressOrEns: differentWorkerpool, + workerpoolAddress: differentWorkerpool, }) ).rejects.toMatchObject({ message: 'Failed to sendTelegramCampaign', cause: expect.objectContaining({ name: 'ValidationError', message: - "workerpoolAddressOrEns doesn't match campaignRequest workerpool", + "workerpoolAddress doesn't match campaignRequest workerpool", }), }); }, diff --git a/tests/mock/compass/data.json b/tests/mock/compass/data.json new file mode 100644 index 0000000..a0f427d --- /dev/null +++ b/tests/mock/compass/data.json @@ -0,0 +1,24 @@ +[ + { + "chainId": "421614", + "description": "arbitrum-sepolia-fork", + "iapps": [ + { + "key": "web3telegram-tdx", + "address": "0x7f67e78a4b0A98c50333B8b72851952c396601a1" + } + ], + "workerpools": [ + { + "name": "unreachable-workerpool", + "apiUrl": "https://unreachable-workerpool.iex.ec", + "address": "0xB967057a21dc6A66A29721d96b8Aa7454B7c383F" + }, + { + "name": "workerpool-http-500", + "apiUrl": "http://localhost:5500", + "address": "0x2956f0cb779904795a5f30d3b3ea88b714c3123f" + } + ] + } +] diff --git a/tests/mock/server/http500.nginx.conf b/tests/mock/server/http500.nginx.conf new file mode 100644 index 0000000..54751ad --- /dev/null +++ b/tests/mock/server/http500.nginx.conf @@ -0,0 +1,6 @@ +server { + listen 80; + location / { + return 500; + } +} diff --git a/tests/scripts/prepare-arbitrum-sepolia-fork-for-tests.js b/tests/scripts/prepare-arbitrum-sepolia-fork-for-tests.js new file mode 100644 index 0000000..87b81e3 --- /dev/null +++ b/tests/scripts/prepare-arbitrum-sepolia-fork-for-tests.js @@ -0,0 +1,212 @@ +import { + Contract, + JsonRpcProvider, + JsonRpcSigner, + Wallet, + formatEther, + toBeHex, +} from 'ethers'; + +/** Must match tests/test-utils.ts prodWorkerpoolOwnerWallet / appOwnerWallet private keys. */ +const PROD_WORKERPOOL_OWNER_PK = + '0x6a12f56d7686e85ab0f46eb3c19cb0c75bfabf8fb04e595654fc93ad652fa7bc'; +const APP_OWNER_PK = + '0xa911b93e50f57c156da0b8bff2277d241bcdb9345221a3e246a99c6e7cedcde5'; + +const PROD_WORKERPOOL_OWNER_WALLET = new Wallet( + PROD_WORKERPOOL_OWNER_PK +).address; +const APP_OWNER_WALLET = new Wallet(APP_OWNER_PK).address; +const TARGET_POCO_ADMIN_WALLET = '0x7bd4783FDCAD405A28052a0d1f11236A741da593'; +const PROD_WORKERPOOL = '0x2956f0cb779904795a5f30d3b3ea88b714c3123f'; +const WEB3_TELEGRAM_DAPP_ADDRESS = '0x7f67e78a4b0A98c50333B8b72851952c396601a1'; +const IEXEC_HUB_ADDRESS = '0xB2157BF2fAb286b2A4170E3491Ac39770111Da3E'; + +const rpcURL = 'http://localhost:8555'; + +const provider = new JsonRpcProvider(rpcURL, undefined, { + pollingInterval: 1000, +}); + +const setBalance = async (address, weiAmount) => { + await fetch(rpcURL, { + method: 'POST', + body: JSON.stringify({ + method: 'anvil_setBalance', + params: [address, toBeHex(weiAmount)], + id: 1, + jsonrpc: '2.0', + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + const balance = await provider.getBalance(address); + console.log(`${address} wallet balance is now ${formatEther(balance)} ETH`); +}; + +const impersonate = async (address) => { + await fetch(rpcURL, { + method: 'POST', + body: JSON.stringify({ + method: 'anvil_impersonateAccount', + params: [address], + id: 1, + jsonrpc: '2.0', + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + console.log(`impersonating ${address}`); +}; + +const stopImpersonate = async (address) => { + await fetch(rpcURL, { + method: 'POST', + body: JSON.stringify({ + method: 'anvil_stopImpersonatingAccount', + params: [address], + id: 1, + jsonrpc: '2.0', + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + console.log(`stop impersonating ${address}`); +}; + +const getIExecHubOwnership = async (hubAddress, targetOwner) => { + const iexecContract = new Contract( + hubAddress, + [ + { + inputs: [], + name: 'owner', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { internalType: 'address', name: 'newOwner', type: 'address' }, + ], + name: 'transferOwnership', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + ], + provider + ); + const iexecOwner = await iexecContract.owner(); + await setBalance(iexecOwner, 1n * 10n ** 18n); + await impersonate(iexecOwner); + await iexecContract + .connect(new JsonRpcSigner(provider, iexecOwner)) + .transferOwnership(targetOwner) + .then((tx) => tx.wait()); + await stopImpersonate(iexecOwner); + + const newOwner = await iexecContract.owner(); + console.log(`IExecHub proxy at ${hubAddress} is now owned by ${newOwner}`); +}; + +const getIExecResourceOwnership = async (resourceAddress, targetOwner) => { + const RESOURCE_ABI = [ + { + inputs: [], + name: 'owner', + outputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [], + name: 'registry', + outputs: [ + { + internalType: 'contract IRegistry', + name: '', + type: 'address', + }, + ], + stateMutability: 'view', + type: 'function', + }, + ]; + const RESOURCE_REGISTRY_ABI = [ + { + inputs: [ + { + internalType: 'address', + name: 'from', + type: 'address', + }, + { + internalType: 'address', + name: 'to', + type: 'address', + }, + { + internalType: 'uint256', + name: 'tokenId', + type: 'uint256', + }, + ], + name: 'safeTransferFrom', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, + ]; + + const resourceContract = new Contract( + resourceAddress, + RESOURCE_ABI, + provider + ); + + const resourceOwner = await resourceContract.owner(); + const resourceRegistryAddress = await resourceContract.registry(); + const resourceRegistryContract = new Contract( + resourceRegistryAddress, + RESOURCE_REGISTRY_ABI, + provider + ); + + await impersonate(resourceOwner); + await resourceRegistryContract + .connect(new JsonRpcSigner(provider, resourceOwner)) + .safeTransferFrom(resourceOwner, targetOwner, resourceAddress) + .then((tx) => tx.wait()); + await stopImpersonate(resourceOwner); + + const newOwner = await resourceContract.owner(); + console.log(`resource ${resourceAddress} is now owned by ${newOwner}`); +}; + +const main = async () => { + console.log(`preparing arbitrum-sepolia-fork at ${rpcURL}`); + + await setBalance(TARGET_POCO_ADMIN_WALLET, 1000000n * 10n ** 18n); + await getIExecHubOwnership(IEXEC_HUB_ADDRESS, TARGET_POCO_ADMIN_WALLET); + + await getIExecResourceOwnership( + PROD_WORKERPOOL, + PROD_WORKERPOOL_OWNER_WALLET + ); + await getIExecResourceOwnership(WEB3_TELEGRAM_DAPP_ADDRESS, APP_OWNER_WALLET); + + await setBalance(PROD_WORKERPOOL_OWNER_WALLET, 100n * 10n ** 18n); + await setBalance(APP_OWNER_WALLET, 100n * 10n ** 18n); +}; + +main(); diff --git a/tests/scripts/prepare-bellecour-fork-for-tests.js b/tests/scripts/prepare-bellecour-fork-for-tests.js deleted file mode 100644 index 95801d9..0000000 --- a/tests/scripts/prepare-bellecour-fork-for-tests.js +++ /dev/null @@ -1,297 +0,0 @@ -import { - Contract, - EnsPlugin, - JsonRpcProvider, - JsonRpcSigner, - Network, - formatEther, - keccak256, - toBeHex, -} from 'ethers'; - -const VOUCHER_HUB_ADDRESS = '0x3137B6DF4f36D338b82260eDBB2E7bab034AFEda'; -const TARGET_VOUCHER_MANAGER_WALLET = - '0x44cA21A3c4efE9B1A0268e2e9B2547E7d9C8f19C'; // Should be same wallet as TEST_CHAIN.voucherManagerWallet -const LEARN_WORKERPOOL_OWNER_WALLET = - '0x02D0e61355e963210d0DE382e6BA09781181bB94'; -const PROD_WORKERPOOL_OWNER_WALLET = - '0x1Ff6AfF580e8Ca738F76485E0914C2aCaDa7B462'; -const APP_OWNER_WALLET = '0x626D65C778fB98f813C25F84249E3012B80e8d91'; -const LEARN_WORKERPOOL_ENS = 'prod-v8-learn.main.pools.iexec.eth'; -const PROD_WORKERPOOL_ENS = 'prod-v8-bellecour.main.pools.iexec.eth'; -// TODO change to prod ens when it's available -const WEB3_TELEGRAM_DAPP_ADDRESS_ENS = 'web3telegram.apps.iexec.eth'; - -const rpcURL = 'http://localhost:8545'; - -const provider = new JsonRpcProvider( - rpcURL, - new Network('bellecour-fork', 134).attachPlugin( - new EnsPlugin('0x5f5B93fca68c9C79318d1F3868A354EE67D8c006', 134) - ), - { - pollingInterval: 1000, // speed up tests - } -); - -const LEARN_WORKERPOOL = await provider.resolveName(LEARN_WORKERPOOL_ENS); -const PROD_WORKERPOOL = await provider.resolveName(PROD_WORKERPOOL_ENS); -const WEB3_TELEGRAM_DAPP_ADDRESS = await provider.resolveName( - WEB3_TELEGRAM_DAPP_ADDRESS_ENS -); - -const setBalance = async (address, weiAmount) => { - await fetch(rpcURL, { - method: 'POST', - body: JSON.stringify({ - method: 'anvil_setBalance', - params: [address, toBeHex(weiAmount)], - id: 1, - jsonrpc: '2.0', - }), - headers: { - 'Content-Type': 'application/json', - }, - }); - const balance = await provider.getBalance(address); - console.log(`${address} wallet balance is now ${formatEther(balance)} RLC`); -}; - -const impersonate = async (address) => { - await fetch(rpcURL, { - method: 'POST', - body: JSON.stringify({ - method: 'anvil_impersonateAccount', - params: [address], - id: 1, - jsonrpc: '2.0', - }), - headers: { - 'Content-Type': 'application/json', - }, - }); - console.log(`impersonating ${address}`); -}; - -const stopImpersonate = async (address) => { - await fetch(rpcURL, { - method: 'POST', - body: JSON.stringify({ - method: 'anvil_stopImpersonatingAccount', - params: [address], - id: 1, - jsonrpc: '2.0', - }), - headers: { - 'Content-Type': 'application/json', - }, - }); - console.log(`stop impersonating ${address}`); -}; - -const getVoucherManagementRoles = async (targetManager) => { - const voucherHubContract = new Contract( - VOUCHER_HUB_ADDRESS, - [ - { - inputs: [], - name: 'defaultAdmin', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'grantRole', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'bytes32', - name: 'role', - type: 'bytes32', - }, - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'hasRole', - outputs: [ - { - internalType: 'bool', - name: '', - type: 'bool', - }, - ], - stateMutability: 'view', - type: 'function', - }, - ], - provider - ); - - const defaultAdmin = await voucherHubContract.defaultAdmin(); - - console.log('VoucherHub defaultAdmin:', defaultAdmin); - - await impersonate(defaultAdmin); - - const MINTER_ROLE = keccak256(Buffer.from('MINTER_ROLE')); - - const MANAGER_ROLE = keccak256(Buffer.from('MANAGER_ROLE')); - - await voucherHubContract - .connect(new JsonRpcSigner(provider, defaultAdmin)) - .grantRole(MINTER_ROLE, targetManager, { gasPrice: 0 }) - .then((tx) => tx.wait()); - - await voucherHubContract - .connect(new JsonRpcSigner(provider, defaultAdmin)) - .grantRole(MANAGER_ROLE, targetManager, { - gasPrice: 0, - }) - .then((tx) => tx.wait()); - - await stopImpersonate(defaultAdmin); - - console.log( - `${targetManager} has role MINTER_ROLE: ${await voucherHubContract.hasRole( - MINTER_ROLE, - targetManager - )}` - ); - - console.log( - `${targetManager} has role MANAGER_ROLE: ${await voucherHubContract.hasRole( - MANAGER_ROLE, - targetManager - )}` - ); -}; - -const getIExecResourceOwnership = async (resourceAddress, targetOwner) => { - const RESOURCE_ABI = [ - { - inputs: [], - name: 'owner', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - { - inputs: [], - name: 'registry', - outputs: [ - { - internalType: 'contract IRegistry', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - ]; - const RESOURCE_REGISTRY_ABI = [ - { - inputs: [ - { - internalType: 'address', - name: 'from', - type: 'address', - }, - { - internalType: 'address', - name: 'to', - type: 'address', - }, - { - internalType: 'uint256', - name: 'tokenId', - type: 'uint256', - }, - ], - name: 'safeTransferFrom', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - ]; - - const resourceContract = new Contract( - resourceAddress, - RESOURCE_ABI, - provider - ); - - const resourceOwner = await resourceContract.owner(); - const resourceRegistryAddress = await resourceContract.registry(); - const resourceRegistryContract = new Contract( - resourceRegistryAddress, - RESOURCE_REGISTRY_ABI, - provider - ); - - await impersonate(resourceOwner); - await resourceRegistryContract - .connect(new JsonRpcSigner(provider, resourceOwner)) - .safeTransferFrom(resourceOwner, targetOwner, resourceAddress, { - gasPrice: 0, - }) - .then((tx) => tx.wait()); - await stopImpersonate(resourceOwner); - - const newOwner = await resourceContract.owner(); - console.log(`resource ${resourceAddress} is now owned by ${newOwner}`); -}; - -const main = async () => { - console.log(`preparing bellecour-fork at ${rpcURL}`); - - // prepare Voucher - await setBalance(TARGET_VOUCHER_MANAGER_WALLET, 1000000n * 10n ** 18n); - await getVoucherManagementRoles(TARGET_VOUCHER_MANAGER_WALLET); - - // prepare workerpools - await getIExecResourceOwnership( - LEARN_WORKERPOOL, - LEARN_WORKERPOOL_OWNER_WALLET - ); - await getIExecResourceOwnership( - PROD_WORKERPOOL, - PROD_WORKERPOOL_OWNER_WALLET - ); - - // prepare web3telegram app for tests - await getIExecResourceOwnership(WEB3_TELEGRAM_DAPP_ADDRESS, APP_OWNER_WALLET); -}; - -main(); diff --git a/tests/scripts/prepare-iexec.js b/tests/scripts/prepare-iexec.js deleted file mode 100644 index c2dd4ff..0000000 --- a/tests/scripts/prepare-iexec.js +++ /dev/null @@ -1,24 +0,0 @@ -import { readFile, writeFile } from 'fs/promises'; -import { resolve } from 'path'; - -const disableCheckImplementedOnChain = async () => { - const configModulePath = resolve( - 'node_modules/iexec/dist/esm/common/utils/config.js' - ); - const configModule = await readFile(configModulePath, 'utf8'); - const OG_CODE_SNIPPET = - 'export const checkImplementedOnChain = (chainId, featureName) => {'; - const REPLACEMENT_CODE_SNIPPET = - 'export const checkImplementedOnChain = (chainId, featureName) => { return;'; - - if (!configModule.includes(REPLACEMENT_CODE_SNIPPET)) { - console.log('disabling checkImplementedOnChain implementation...'); - const patchedConfigModule = configModule.replace( - OG_CODE_SNIPPET, - REPLACEMENT_CODE_SNIPPET - ); - await writeFile(configModulePath, patchedConfigModule, 'utf8'); - } -}; - -disableCheckImplementedOnChain(); diff --git a/tests/scripts/prepare-test-env.js b/tests/scripts/prepare-test-env.js index 7cdb445..eafd471 100644 --- a/tests/scripts/prepare-test-env.js +++ b/tests/scripts/prepare-test-env.js @@ -1,33 +1,44 @@ import { writeFileSync } from 'fs'; -const forkUrl = 'https://bellecour.iex.ec'; +const arbitrumSepoliaForkUrl = + process.env.ARBITRUM_SEPOLIA_FORK_URL || + 'https://sepolia-rollup.arbitrum.io/rpc'; -fetch(forkUrl, { +const forkBlockNumber = await fetch(arbitrumSepoliaForkUrl, { method: 'POST', body: JSON.stringify({ - jsonrpc: 2.0, + jsonrpc: '2.0', method: 'eth_blockNumber', params: [], id: 1, }), + headers: { + 'Content-Type': 'application/json', + }, }) .then((res) => res.json()) .then((jsonRes) => { - const forkBlockNumber = parseInt(jsonRes.result.substring(2), 16); + console.log( + `Current block number of ${arbitrumSepoliaForkUrl} is ${JSON.stringify(jsonRes)}` + ); + return parseInt(jsonRes.result.substring(2), 16); + }) + .catch((e) => { + throw Error( + `Failed to get current block number from ${arbitrumSepoliaForkUrl}: ${e}` + ); + }); - console.log('Creating .env file for docker-compose test-stack'); - writeFileSync( - '.env', - `############ THIS FILE IS GENERATED ############ +console.log('Creating .env file for docker-compose test-stack'); +writeFileSync( + '.env', + `############ THIS FILE IS GENERATED ############ # run "node prepare-test-env.js" to regenerate # ################################################ -# blockchain node to use as the reference for the local fork -BELLECOUR_FORK_URL=${forkUrl} +ARBITRUM_SEPOLIA_FORK_URL=${arbitrumSepoliaForkUrl} # block number to fork from -BELLECOUR_FORK_BLOCK=${forkBlockNumber}` - ); - }) - .catch((e) => { - throw Error(`Failed to get current block number from ${forkUrl}: ${e}`); - }); +ARBITRUM_SEPOLIA_FORK_BLOCK=${forkBlockNumber} +# block number to index from (should be fork block + 1 to skip all existing ArbitrumInternalTxType which is not supported by a graphnode connected to anvil) +ARBITRUM_SEPOLIA_INDEX_BLOCK=${forkBlockNumber + 1}` +); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index c6d0806..f06e0d8 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,50 +1,119 @@ -import { Wallet, JsonRpcProvider, ethers, Contract } from 'ethers'; +import { + Wallet, + JsonRpcProvider, + ethers, + Contract, + keccak256, + AbiCoder, + toBeHex, +} from 'ethers'; import { type Web3TelegramConfigOptions, type Web3SignerProvider, } from '../src/web3telegram/types.js'; import { IExec, utils } from 'iexec'; import { randomInt } from 'crypto'; -import { getSignerFromPrivateKey } from 'iexec/utils'; + +/** Production web3telegram TDX app on Arbitrum Sepolia (fork inherits deployment). */ +export const TEST_WEB3TELEGRAM_DAPP_ADDRESS = + '0x7f67e78a4b0A98c50333B8b72851952c396601a1'; export const TEST_CHAIN = { ipfsGateway: 'http://127.0.0.1:8080', ipfsNode: 'http://127.0.0.1:5001', - rpcURL: 'http://localhost:8545', - chainId: '134', - smsURL: 'http://127.0.0.1:13300', - smsDebugURL: 'http://127.0.0.1:13301', - resultProxyURL: 'http://127.0.0.1:13200', - iexecGatewayURL: 'http://127.0.0.1:3000', - voucherHubAddress: '0x3137B6DF4f36D338b82260eDBB2E7bab034AFEda', - voucherManagerWallet: new Wallet( - '0x2c906d4022cace2b3ee6c8b596564c26c4dcadddf1e949b769bcb0ad75c40c33' - ), - voucherSubgraphURL: - 'http://127.0.0.1:8000/subgraphs/name/bellecour/iexec-voucher', - learnProdWorkerpool: 'prod-v8-learn.main.pools.iexec.eth', - learnProdWorkerpoolOwnerWallet: new Wallet( - '0x800e01919eadf36f110f733decb1cc0f82e7941a748e89d7a3f76157f6654bb3' - ), - prodWorkerpool: 'prod-v8-bellecour.main.pools.iexec.eth', + rpcURL: 'http://localhost:8555', + chainId: '421614', + smsURL: 'http://127.0.0.1:13350', + smsDebugURL: 'http://127.0.0.1:13351', + resultProxyURL: 'http://127.0.0.1:13250', + iexecGatewayURL: 'http://127.0.0.1:3050', + compassURL: 'http://127.0.0.1:8069', + prodWorkerpool: '0x2956f0cb779904795a5f30d3b3ea88b714c3123f', prodWorkerpoolOwnerWallet: new Wallet( '0x6a12f56d7686e85ab0f46eb3c19cb0c75bfabf8fb04e595654fc93ad652fa7bc' ), appOwnerWallet: new Wallet( '0xa911b93e50f57c156da0b8bff2277d241bcdb9345221a3e246a99c6e7cedcde5' ), - provider: new JsonRpcProvider('http://localhost:8545', undefined, { - pollingInterval: 1000, // speed up tests + provider: new JsonRpcProvider('http://localhost:8555', 421614, { + pollingInterval: 1000, }), - hubAddress: '0x3eca1B216A7DF1C7689aEb259fFB83ADFB894E7f', + hubAddress: '0xB2157BF2fAb286b2A4170E3491Ac39770111Da3E', + isNative: false, + subgraphUrl: + 'http://127.0.0.1:8000/subgraphs/name/arbitrum-sepolia/dataprotector-v2', + maxExpectedSubgraphIndexingTime: 5_000, + /** + * [rlc-multichain](https://github.com/iExecBlockchainComputing/rlc-multichain/tree/v0.1.0) is an openzeppelin ERC20Upgradeable contract + * + * ERC20Upgradeable contract use a specific storage slot, which is: + * ``` + * // keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ERC20")) - 1)) & ~bytes32(uint256(0xff)) + * bytes32 private constant ERC20StorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00; + * ``` + * sources: https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v5.3.0/contracts/token/ERC20/ERC20Upgradeable.sol#L43-L44 + */ + erc20BalanceSlot: + '0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00' as const, }; export const sleep = (ms: number) => new Promise((res) => setTimeout(res, ms)); -export const MAX_EXPECTED_SUBGRAPH_INDEXING_TIME = 5_000; +export const waitSubgraphIndexing = async ( + timeoutMs = 60_000 +): Promise => { + const provider = new JsonRpcProvider(TEST_CHAIN.rpcURL); + const targetBlock = await provider.getBlockNumber(); + + const deadline = Date.now() + timeoutMs; + while (Date.now() < deadline) { + try { + const res = await fetch(TEST_CHAIN.subgraphUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ query: '{ _meta { block { number } } }' }), + }); + const json = await res.json(); + const indexedBlock: number = json?.data?._meta?.block?.number ?? 0; + if (indexedBlock >= targetBlock) return; + } catch { + // subgraph not ready yet, keep polling + } + await sleep(1_000); + } + throw new Error( + `waitSubgraphIndexing: subgraph did not index block ${targetBlock} within ${timeoutMs}ms` + ); +}; + +const anvilSetBalance = async (address: string, targetWeiBalance: bigint) => { + await fetch(TEST_CHAIN.rpcURL, { + method: 'POST', + body: JSON.stringify({ + method: 'anvil_setBalance', + params: [address, toBeHex(targetWeiBalance)], + id: 1, + jsonrpc: '2.0', + }), + headers: { + 'Content-Type': 'application/json', + }, + }); +}; + +export const setBalance = async ( + address: string, + targetWeiBalance: ethers.BigNumberish +) => { + await anvilSetBalance(address, BigInt(`${targetWeiBalance}`)); +}; -export const waitSubgraphIndexing = () => - sleep(MAX_EXPECTED_SUBGRAPH_INDEXING_TIME); +export const setEthForGas = async ( + address: string, + wei: bigint = 10n ** 18n +) => { + await setBalance(address, wei); +}; export const getRequiredFieldMessage = (field: string = 'this') => `${field} is a required field`; @@ -59,12 +128,6 @@ export const MAX_EXPECTED_WEB2_SERVICES_TIME = 80_000; export const MARKET_API_CALL_TIMEOUT = 2_000; -export const timeouts = { - // utils - createVoucherType: MAX_EXPECTED_BLOCKTIME * 2, - createVoucher: MAX_EXPECTED_BLOCKTIME * 4 + MARKET_API_CALL_TIMEOUT * 2, -}; - export const getTestWeb3SignerProvider = ( privateKey: string = Wallet.createRandom().privateKey ): Web3SignerProvider => @@ -72,29 +135,83 @@ export const getTestWeb3SignerProvider = ( export const getTestRpcProvider = () => new JsonRpcProvider(TEST_CHAIN.rpcURL); +const anvilSetNRlcTokenBalance = async ( + address: string, + targetNRlcBalance: ethers.BigNumberish +) => { + const hubContract = new Contract( + TEST_CHAIN.hubAddress, + [ + { + inputs: [], + name: 'token', + outputs: [{ internalType: 'address', name: '', type: 'address' }], + stateMutability: 'view', + type: 'function', + }, + ], + TEST_CHAIN.provider + ); + const rlcAddress = await hubContract.token(); + + const balanceSlot = keccak256( + AbiCoder.defaultAbiCoder().encode( + ['address', 'uint256'], + [address, TEST_CHAIN.erc20BalanceSlot] + ) + ); + + await fetch(TEST_CHAIN.rpcURL, { + method: 'POST', + body: JSON.stringify({ + method: 'anvil_setStorageAt', + params: [ + rlcAddress, + balanceSlot, + toBeHex(BigInt(`${targetNRlcBalance}`), 32), + ], + id: 1, + jsonrpc: '2.0', + }), + headers: { + 'Content-Type': 'application/json', + }, + }); +}; + +export const setNRlcBalance = async ( + address: string, + nRlcTargetBalance: ethers.BigNumberish +) => { + if (TEST_CHAIN.isNative) { + const weiAmount = BigInt(`${nRlcTargetBalance}`) * 10n ** 9n; + await anvilSetBalance(address, weiAmount); + return; + } + await anvilSetNRlcTokenBalance(address, nRlcTargetBalance); +}; + export const getTestIExecOption = () => ({ smsURL: TEST_CHAIN.smsURL, smsDebugURL: TEST_CHAIN.smsDebugURL, resultProxyURL: TEST_CHAIN.resultProxyURL, iexecGatewayURL: TEST_CHAIN.iexecGatewayURL, - voucherHubAddress: TEST_CHAIN.voucherHubAddress, - voucherSubgraphURL: TEST_CHAIN.voucherSubgraphURL, ipfsGatewayURL: TEST_CHAIN.ipfsGateway, ipfsNodeURL: TEST_CHAIN.ipfsNode, + compassURL: TEST_CHAIN.compassURL, + hubAddress: TEST_CHAIN.hubAddress, }); export const getTestConfig = ( - privateKey?: string + privateKey: string ): [Web3SignerProvider, Web3TelegramConfigOptions] => { - const ethProvider = privateKey - ? getTestWeb3SignerProvider(privateKey) - : undefined; + const ethProvider = getTestWeb3SignerProvider(privateKey); const options = { + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, iexecOptions: getTestIExecOption(), ipfsGateway: 'http://127.0.0.1:8080', ipfsNode: 'http://127.0.0.1:5001', - dataProtectorSubgraph: - 'http://127.0.0.1:8000/subgraphs/name/DataProtector-v2', + dataProtectorSubgraph: TEST_CHAIN.subgraphUrl, }; return [ethProvider, options]; }; @@ -133,21 +250,12 @@ export const getRandomTxHash = () => { export const createAndPublishAppOrders = async ( resourceProvider, - appAddressOrEns + appAddress: string ) => { - // Resolve ENS name to address if needed - let appAddress = appAddressOrEns; - if (appAddressOrEns && appAddressOrEns.includes('.eth')) { - appAddress = await resourceProvider.ens.resolveName(appAddressOrEns); - if (!appAddress) { - throw new Error(`Failed to resolve ENS name: ${appAddressOrEns}`); - } - } - await resourceProvider.order .createApporder({ app: appAddress, - tag: ['tee', 'scone'], + tag: ['tee', 'tdx'], volume: 100, appprice: 0, }) @@ -155,98 +263,6 @@ export const createAndPublishAppOrders = async ( .then(resourceProvider.order.publishApporder); }; -export const setBalance = async ( - address: string, - targetWeiBalance: ethers.BigNumberish -) => { - await fetch(TEST_CHAIN.rpcURL, { - method: 'POST', - body: JSON.stringify({ - method: 'anvil_setBalance', - params: [address, ethers.toBeHex(targetWeiBalance)], - id: 1, - jsonrpc: '2.0', - }), - headers: { - 'Content-Type': 'application/json', - }, - }); -}; - -export const setNRlcBalance = async ( - address: string, - nRlcTargetBalance: ethers.BigNumberish -) => { - const weiAmount = BigInt(`${nRlcTargetBalance}`) * 10n ** 9n; // 1 nRLC is 10^9 wei - await setBalance(address, weiAmount); -}; - -export const createVoucherType = async ({ - description = 'test', - duration = 1000, -} = {}) => { - const VOUCHER_HUB_ABI = [ - { - inputs: [ - { - internalType: 'string', - name: 'description', - type: 'string', - }, - { - internalType: 'uint256', - name: 'duration', - type: 'uint256', - }, - ], - name: 'createVoucherType', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: 'uint256', - name: 'id', - type: 'uint256', - }, - { - indexed: false, - internalType: 'string', - name: 'description', - type: 'string', - }, - { - indexed: false, - internalType: 'uint256', - name: 'duration', - type: 'uint256', - }, - ], - name: 'VoucherTypeCreated', - type: 'event', - }, - ]; - const voucherHubContract = new Contract( - TEST_CHAIN.voucherHubAddress, - VOUCHER_HUB_ABI, - TEST_CHAIN.provider - ) as any; - const signer = TEST_CHAIN.voucherManagerWallet.connect(TEST_CHAIN.provider); - const createVoucherTypeTxHash = await voucherHubContract - .connect(signer) - .createVoucherType(description, duration); - const txReceipt = await createVoucherTypeTxHash.wait(); - const { id } = getEventFromLogs('VoucherTypeCreated', txReceipt.logs, { - strict: true, - }).args; - - return id as bigint; -}; - export const ensureSufficientStake = async ( iexec: IExec, requiredStake: ethers.BigNumberish @@ -282,199 +298,14 @@ export const createAndPublishWorkerpoolOrder = async ( requesterrestrict, volume, workerpoolprice, - tag: ['tee', 'scone'], + tag: ['tee', 'tdx'], }); await iexec.order .signWorkerpoolorder(workerpoolorder) .then((o) => iexec.order.publishWorkerpoolorder(o)); } catch (error) { - // In test environment, workerpools might not exist, so we skip the order creation console.warn( `Skipping workerpool order creation for ${workerpool}: ${error.message}` ); } }; - -export const WORKERPOOL_ORDER_PER_VOUCHER = 1000; - -export const createVoucher = async ({ - owner, - voucherType, - value, - skipOrders = false, -}: { - owner: string; - voucherType: ethers.BigNumberish; - value: ethers.BigNumberish; - skipOrders?: boolean; -}) => { - const VOUCHER_HUB_ABI = [ - { - inputs: [ - { - internalType: 'address', - name: 'owner', - type: 'address', - }, - { - internalType: 'uint256', - name: 'voucherType', - type: 'uint256', - }, - { - internalType: 'uint256', - name: 'value', - type: 'uint256', - }, - ], - name: 'createVoucher', - outputs: [ - { - internalType: 'address', - name: 'voucherAddress', - type: 'address', - }, - ], - stateMutability: 'nonpayable', - type: 'function', - }, - { - inputs: [ - { - internalType: 'address', - name: 'account', - type: 'address', - }, - ], - name: 'getVoucher', - outputs: [ - { - internalType: 'address', - name: '', - type: 'address', - }, - ], - stateMutability: 'view', - type: 'function', - }, - ]; - - const iexec = new IExec( - { - ethProvider: getSignerFromPrivateKey( - TEST_CHAIN.rpcURL, - TEST_CHAIN.voucherManagerWallet.privateKey - ), - }, - { hubAddress: TEST_CHAIN.hubAddress } - ); - - // ensure RLC balance - await setNRlcBalance(await iexec.wallet.getAddress(), value); - - // deposit RLC to voucherHub - const contractClient = await iexec.config.resolveContractsClient(); - const iexecContract = contractClient.getIExecContract(); - - try { - await iexecContract.depositFor(TEST_CHAIN.voucherHubAddress, { - value: BigInt(value) * 10n ** 9n, - gasPrice: 0, - }); - } catch (error) { - console.error('Error depositing RLC:', error); - throw error; - } - - const voucherHubContract = new Contract( - TEST_CHAIN.voucherHubAddress, - VOUCHER_HUB_ABI, - TEST_CHAIN.provider - ) as any; - - const signer = TEST_CHAIN.voucherManagerWallet.connect(TEST_CHAIN.provider); - - try { - const createVoucherTxHash = await voucherHubContract - .connect(signer) - .createVoucher(owner, voucherType, value); - - await createVoucherTxHash.wait(); - } catch (error) { - console.error('Error creating voucher:', error); - throw error; - } - - if (!skipOrders) { - try { - const workerpoolprice = Math.floor( - Number(value) / WORKERPOOL_ORDER_PER_VOUCHER - ); - await createAndPublishWorkerpoolOrder( - TEST_CHAIN.prodWorkerpool, - TEST_CHAIN.prodWorkerpoolOwnerWallet, - owner, - workerpoolprice, - WORKERPOOL_ORDER_PER_VOUCHER - ); - } catch (error) { - // In test environment, workerpool orders might fail, but we don't want to fail the voucher creation - console.warn('Error publishing workerpoolorder:', error.message); - } - } - - try { - return voucherHubContract.getVoucher(owner); - } catch (error) { - console.error('Error getting voucher:', error); - throw error; - } -}; - -export const addVoucherEligibleAsset = async (assetAddress, voucherTypeId) => { - const voucherHubContract = new Contract(TEST_CHAIN.voucherHubAddress, [ - { - inputs: [ - { - internalType: 'uint256', - name: 'voucherTypeId', - type: 'uint256', - }, - { - internalType: 'address', - name: 'asset', - type: 'address', - }, - ], - name: 'addEligibleAsset', - outputs: [], - stateMutability: 'nonpayable', - type: 'function', - }, - ]) as any; - - const signer = TEST_CHAIN.voucherManagerWallet.connect(TEST_CHAIN.provider); - - const retryableAddEligibleAsset = async (tryCount = 1) => { - try { - const tx = await voucherHubContract - .connect(signer) - .addEligibleAsset(voucherTypeId, assetAddress); - await tx.wait(); - } catch (error) { - console.warn( - `Error adding eligible asset to voucher (try count ${tryCount}):`, - error - ); - if (tryCount < 3) { - await sleep(3000 * tryCount); - await retryableAddEligibleAsset(tryCount + 1); - } else { - throw new Error( - `Failed to add eligible asset to voucher after ${tryCount} attempts` - ); - } - } - }; - await retryableAddEligibleAsset(); -}; diff --git a/tests/unit/constructor.test.ts b/tests/unit/constructor.test.ts index 4d939ca..69ef598 100644 --- a/tests/unit/constructor.test.ts +++ b/tests/unit/constructor.test.ts @@ -3,10 +3,10 @@ import { IExecWeb3telegram } from '../../src/index.js'; describe('When instantiating SDK without a signer', () => { describe('When calling a write method', () => { it('should throw an error for unauthorized method', async () => { - // --- GIVEN - const web3telegram = new IExecWeb3telegram(); + const web3telegram = new IExecWeb3telegram('421614', { + allowExperimentalNetworks: true, + }); - // --- WHEN/THEN await expect(web3telegram.fetchMyContacts()).rejects.toThrow( 'Unauthorized method. Please log in with your wallet, you must set a valid provider with a signer.' ); diff --git a/tests/unit/fetchMyContacts.test.ts b/tests/unit/fetchMyContacts.test.ts index 3fa88ca..ec48b74 100644 --- a/tests/unit/fetchMyContacts.test.ts +++ b/tests/unit/fetchMyContacts.test.ts @@ -1,11 +1,11 @@ import { describe, expect, it, jest } from '@jest/globals'; import { Address } from 'iexec'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; +import { getChainDefaultConfig } from '../../src/config/config.js'; import { type FetchMyContacts } from '../../src/web3telegram/fetchMyContacts.js'; -import { getRandomAddress } from '../test-utils.js'; +import { + getRandomAddress, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, +} from '../test-utils.js'; jest.unstable_mockModule('../../src/utils/subgraphQuery.js', () => ({ getValidContact: jest.fn(), @@ -14,7 +14,7 @@ jest.unstable_mockModule('../../src/utils/subgraphQuery.js', () => ({ describe('fetchMyContacts', () => { let testedModule: any; let fetchMyContacts: FetchMyContacts; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); + const defaultConfig = getChainDefaultConfig(421614); beforeAll(async () => { // import tested module after all mocked modules @@ -36,7 +36,7 @@ describe('fetchMyContacts', () => { }, orderHash: '0x396392835c2cbe933023dd28a3d6eedceb21c52b1dba199835a6f24cc75e7685', - chainId: 134, + chainId: 421614, publicationTimestamp: '2023-06-15T16:39:22.713Z', signer: '0xD52C27CC2c7D3fb5BA4440ffa825c12EA5658D60', status: 'open', @@ -64,11 +64,6 @@ describe('fetchMyContacts', () => { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: mockFetchDatasetOrderbook, }, @@ -79,13 +74,13 @@ describe('fetchMyContacts', () => { iexec: iexec, // @ts-expect-error No need for graphQLClient here graphQLClient: {}, - dappAddressOrENS: defaultConfig.dappAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, }); const userAddress = (await iexec.wallet.getAddress()).toLowerCase(); expect(iexec.orderbook.fetchDatasetOrderbook).toHaveBeenNthCalledWith(1, { dataset: 'any', - app: defaultConfig.dappAddress.toLowerCase(), + app: TEST_WEB3TELEGRAM_DAPP_ADDRESS.toLowerCase(), requester: userAddress, isAppStrict: true, isRequesterStrict: false, @@ -125,11 +120,6 @@ describe('fetchMyContacts', () => { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: mockFetchDatasetOrderbook, }, @@ -140,14 +130,14 @@ describe('fetchMyContacts', () => { iexec: iexec, // @ts-expect-error No need for graphQLClient here graphQLClient: {}, - dappAddressOrENS: defaultConfig.dappAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, isUserStrict: true, }); const userAddress = (await iexec.wallet.getAddress()).toLowerCase(); expect(iexec.orderbook.fetchDatasetOrderbook).toHaveBeenNthCalledWith(1, { dataset: 'any', - app: defaultConfig.dappAddress.toLowerCase(), + app: TEST_WEB3TELEGRAM_DAPP_ADDRESS.toLowerCase(), requester: userAddress, isAppStrict: true, isRequesterStrict: true, @@ -199,11 +189,6 @@ describe('fetchMyContacts', () => { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: mockFetchDatasetOrderbook, }, @@ -215,7 +200,7 @@ describe('fetchMyContacts', () => { iexec: iexec, // @ts-expect-error No need for graphQLClient here graphQLClient: {}, - dappAddressOrENS: defaultConfig.dappAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, }); @@ -247,11 +232,6 @@ describe('fetchMyContacts', () => { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: mockFetchDatasetOrderbook, }, @@ -262,14 +242,14 @@ describe('fetchMyContacts', () => { iexec: iexec, // @ts-expect-error No need for graphQLClient here graphQLClient: {}, - dappAddressOrENS: defaultConfig.dappAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, bulkOnly: true, }); const userAddress = (await iexec.wallet.getAddress()).toLowerCase(); expect(iexec.orderbook.fetchDatasetOrderbook).toHaveBeenNthCalledWith(1, { dataset: 'any', - app: defaultConfig.dappAddress.toLowerCase(), + app: TEST_WEB3TELEGRAM_DAPP_ADDRESS.toLowerCase(), requester: userAddress, isAppStrict: true, isRequesterStrict: false, @@ -309,11 +289,6 @@ describe('fetchMyContacts', () => { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: mockFetchDatasetOrderbook, }, @@ -324,14 +299,14 @@ describe('fetchMyContacts', () => { iexec: iexec, // @ts-expect-error No need for graphQLClient here graphQLClient: {}, - dappAddressOrENS: defaultConfig.dappAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, bulkOnly: false, }); const userAddress = (await iexec.wallet.getAddress()).toLowerCase(); expect(iexec.orderbook.fetchDatasetOrderbook).toHaveBeenNthCalledWith(1, { dataset: 'any', - app: defaultConfig.dappAddress.toLowerCase(), + app: TEST_WEB3TELEGRAM_DAPP_ADDRESS.toLowerCase(), requester: userAddress, isAppStrict: true, isRequesterStrict: false, @@ -371,11 +346,6 @@ describe('fetchMyContacts', () => { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: mockFetchDatasetOrderbook, }, @@ -386,7 +356,7 @@ describe('fetchMyContacts', () => { iexec: iexec, // @ts-expect-error No need for graphQLClient here graphQLClient: {}, - dappAddressOrENS: defaultConfig.dappAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, isUserStrict: true, bulkOnly: true, @@ -394,7 +364,7 @@ describe('fetchMyContacts', () => { const userAddress = (await iexec.wallet.getAddress()).toLowerCase(); expect(iexec.orderbook.fetchDatasetOrderbook).toHaveBeenNthCalledWith(1, { dataset: 'any', - app: defaultConfig.dappAddress.toLowerCase(), + app: TEST_WEB3TELEGRAM_DAPP_ADDRESS.toLowerCase(), requester: userAddress, isAppStrict: true, isRequesterStrict: true, diff --git a/tests/unit/sendTelegram.models.test.ts b/tests/unit/sendTelegram.models.test.ts index 5e17e04..37f8bec 100644 --- a/tests/unit/sendTelegram.models.test.ts +++ b/tests/unit/sendTelegram.models.test.ts @@ -1,260 +1,101 @@ -import { Address, BN } from 'iexec'; import { PublishedWorkerpoolorder } from 'iexec/IExecOrderbookModule'; -// import { VoucherInfo } from 'iexec/IExecVoucherModule'; - import { getRandomAddress } from '../test-utils.js'; -import { - checkUserVoucher, - filterWorkerpoolOrders, -} from '../../src/utils/sendTelegram.models.js'; - -// To import from 'iexec' once exported -type VoucherInfo = { - owner: Address; - address: Address; - type: BN; - balance: BN; - expirationTimestamp: BN; - sponsoredApps: Address[]; - sponsoredDatasets: Address[]; - sponsoredWorkerpools: Address[]; - allowanceAmount: BN; - authorizedAccounts: Address[]; -}; +import { filterWorkerpoolOrders } from '../../src/utils/sendTelegram.models.js'; describe('sendTelegram.models', () => { - describe('checkUserVoucher', () => { - describe('When voucher is expired', () => { - it('should throw an Error with the correct message', async () => { - // --- GIVEN - const userVoucher = { - expirationTimestamp: Date.now() / 1000 - 60, // Expired 1min ago - } as unknown as VoucherInfo; - - expect(() => - checkUserVoucher({ - userVoucher, - }) - ).toThrow( - new Error( - 'Oops, it seems your voucher has expired. You might want to ask for a top up. Check on https://builder.iex.ec/' - ) - ); - }); - }); - - describe('When voucher has a balance equals to 0', () => { - it('should throw an Error with the correct message', async () => { - // --- GIVEN - const userVoucher = { - expirationTimestamp: Date.now() / 1000 + 3600, // Will expire in 1h - balance: 0, - } as unknown as VoucherInfo; - - expect(() => - checkUserVoucher({ - userVoucher, - }) - ).toThrow( - new Error( - 'Oops, it seems your voucher is empty. You might want to ask for a top up. Check on https://builder.iex.ec/' - ) - ); - }); - }); - }); - describe('filterWorkerpoolOrders()', () => { describe('When workerpool orders is an empty array', () => { it('should answer with null', () => { - // --- GIVEN const workerpoolOrders = []; - // --- WHEN const foundOrder = filterWorkerpoolOrders({ workerpoolOrders, workerpoolMaxPrice: 0, - useVoucher: false, - userVoucher: undefined, }); - // --- THEN expect(foundOrder).toBeNull(); }); }); - describe('useVoucher === false', () => { - describe('When all orders are too expensive', () => { - it('should answer with null', () => { - // --- GIVEN - const workerpoolOrders = [ - { - order: { - workerpoolprice: 1, - }, + describe('When all orders are too expensive', () => { + it('should answer with null', () => { + const workerpoolOrders = [ + { + order: { + workerpoolprice: 1, }, - { - order: { - workerpoolprice: 2, - }, + }, + { + order: { + workerpoolprice: 2, }, - ] as PublishedWorkerpoolorder[]; + }, + ] as PublishedWorkerpoolorder[]; - // --- WHEN - const foundOrder = filterWorkerpoolOrders({ - workerpoolOrders, - workerpoolMaxPrice: 0, // <-- I want a free workerpool order - useVoucher: false, - userVoucher: undefined, - }); - - // --- THEN - expect(foundOrder).toBeNull(); + const foundOrder = filterWorkerpoolOrders({ + workerpoolOrders, + workerpoolMaxPrice: 0, }); - }); - describe('When one order is cheap enough', () => { - it('should answer with it', () => { - // --- GIVEN - const workerpoolOrders = [ - { - order: { - workerpoolprice: 1, - }, - }, - { - order: { - workerpoolprice: 2, - }, - }, - ] as PublishedWorkerpoolorder[]; - - // --- WHEN - const foundOrder = filterWorkerpoolOrders({ - workerpoolOrders, - workerpoolMaxPrice: 1, - useVoucher: false, - }); - - // --- THEN - expect(foundOrder).toBeTruthy(); - expect(foundOrder.workerpoolprice).toBe(1); - }); + expect(foundOrder).toBeNull(); }); }); - describe('useVoucher === true', () => { - describe('When there are workerpool orders but workerpool is NOT included in the voucher sponsored workerpools', () => { - it('should answer with null', () => { - // --- GIVEN - const userVoucher = { - balance: 4, // Technically it should be a BN - sponsoredWorkerpools: [getRandomAddress()], - } as unknown as VoucherInfo; - const workerpoolOrders = [ - { - order: { - workerpoolprice: 3, - workerpool: getRandomAddress(), - }, + describe('When one order is cheap enough', () => { + it('should answer with it', () => { + const workerpoolOrders = [ + { + order: { + workerpoolprice: 1, }, - { - order: { - workerpoolprice: 1, - workerpool: getRandomAddress(), - }, + }, + { + order: { + workerpoolprice: 2, }, - ] as PublishedWorkerpoolorder[]; + }, + ] as PublishedWorkerpoolorder[]; - expect(() => - filterWorkerpoolOrders({ - workerpoolOrders, - workerpoolMaxPrice: 0, - useVoucher: true, - userVoucher, - }) - ).toThrow( - new Error( - 'Found some workerpool orders but none can be sponsored by your voucher.' - ) - ); + const foundOrder = filterWorkerpoolOrders({ + workerpoolOrders, + workerpoolMaxPrice: 1, }); + + expect(foundOrder).toBeTruthy(); + expect(foundOrder!.workerpoolprice).toBe(1); }); + }); - describe('When voucher balance is greater than asked maxPrice', () => { - it('should answer with the cheapest sponsored order', () => { - // --- GIVEN - const userVoucher = { - balance: 4, // Technically it should be a BN - sponsoredWorkerpools: [ - '0x3779Da315D935D3E3957561667236BF6859C1b0E', - ], - } as unknown as VoucherInfo; - const workerpoolOrders = [ - { - order: { - workerpoolprice: 3, - workerpool: '0x3779Da315D935D3E3957561667236BF6859C1b0E', - }, + describe('When multiple sponsored pools exist', () => { + it('should pick the cheapest eligible order', () => { + const workerpoolOrders = [ + { + order: { + workerpoolprice: 3, + workerpool: '0x3779Da315D935D3E3957561667236BF6859C1b0E', }, - { - order: { - workerpoolprice: 1, - workerpool: '0x3779Da315D935D3E3957561667236BF6859C1b0E', - }, + }, + { + order: { + workerpoolprice: 1, + workerpool: '0x3779Da315D935D3E3957561667236BF6859C1b0E', }, - { - order: { - workerpoolprice: 0, - workerpool: getRandomAddress(), - }, + }, + { + order: { + workerpoolprice: 0, + workerpool: getRandomAddress(), }, - ] as PublishedWorkerpoolorder[]; + }, + ] as PublishedWorkerpoolorder[]; - // --- WHEN - const foundOrder = filterWorkerpoolOrders({ - workerpoolOrders, - workerpoolMaxPrice: 0, - useVoucher: true, - userVoucher, - }); - - // --- THEN - expect(foundOrder).toBeTruthy(); - expect(foundOrder.workerpoolprice).toBe(1); + const foundOrder = filterWorkerpoolOrders({ + workerpoolOrders, + workerpoolMaxPrice: 2, }); - }); - describe('When voucher balance is not enough but user wants to pay the rest (workerpoolMaxPrice)', () => { - it('should answer with the cheapest order', () => { - // --- GIVEN - const userVoucher = { - balance: 2, // Technically it should be a BN - sponsoredWorkerpools: [ - '0x3779Da315D935D3E3957561667236BF6859C1b0E', - ], - } as unknown as VoucherInfo; - const workerpoolOrders = [ - { - order: { - workerpoolprice: 3, - workerpool: '0x3779Da315D935D3E3957561667236BF6859C1b0E', - }, - }, - ] as PublishedWorkerpoolorder[]; - - // --- WHEN - const foundOrder = filterWorkerpoolOrders({ - workerpoolOrders, - workerpoolMaxPrice: 1, - useVoucher: true, - userVoucher, - }); - - // --- THEN - expect(foundOrder).toBeTruthy(); - expect(foundOrder.workerpoolprice).toBe(3); - }); + expect(foundOrder).toBeTruthy(); + expect(foundOrder!.workerpoolprice).toBe(0); }); }); }); diff --git a/tests/unit/sendTelegram.test.ts b/tests/unit/sendTelegram.test.ts index c12f62f..aab5cfd 100644 --- a/tests/unit/sendTelegram.test.ts +++ b/tests/unit/sendTelegram.test.ts @@ -1,10 +1,10 @@ import { expect, it, jest } from '@jest/globals'; import { type SendTelegram } from '../../src/web3telegram/sendTelegram.js'; -import { getRandomAddress } from '../test-utils.js'; import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; + getRandomAddress, + TEST_WEB3TELEGRAM_DAPP_ADDRESS, +} from '../test-utils.js'; +import { getChainDefaultConfig } from '../../src/config/config.js'; import { mockAllForSendTelegram } from '../utils/mockAllForSendTelegram.js'; jest.unstable_mockModule('../../src/utils/subgraphQuery.js', () => ({ @@ -21,7 +21,7 @@ jest.unstable_mockModule('../../src/utils/ipfs-service.js', () => ({ describe('sendTelegram', () => { let testedModule: any; let sendTelegram: SendTelegram; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); + const defaultConfig = getChainDefaultConfig(421614); beforeAll(async () => { // import tested module after all mocked modules @@ -43,8 +43,8 @@ describe('sendTelegram', () => { sendTelegram({ graphQLClient: { request: jest.fn() } as any, iexec: mockAllForSendTelegram() as any, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, - dappAddressOrENS: defaultConfig.dappAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, ipfsNode: defaultConfig.ipfsUploadUrl, ipfsGateway: defaultConfig.ipfsGateway, @@ -76,8 +76,8 @@ describe('sendTelegram', () => { sendTelegram({ graphQLClient: { request: jest.fn() } as any, iexec: mockAllForSendTelegram() as any, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, - dappAddressOrENS: defaultConfig.dappAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, ipfsNode: defaultConfig.ipfsUploadUrl, ipfsGateway: defaultConfig.ipfsGateway, @@ -109,8 +109,8 @@ describe('sendTelegram', () => { sendTelegram({ graphQLClient: { request: jest.fn() } as any, iexec: mockAllForSendTelegram() as any, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, - dappAddressOrENS: defaultConfig.dappAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, ipfsNode: defaultConfig.ipfsUploadUrl, ipfsGateway: defaultConfig.ipfsGateway, @@ -141,8 +141,8 @@ describe('sendTelegram', () => { sendTelegram({ graphQLClient: { request: jest.fn() } as any, iexec: mockAllForSendTelegram() as any, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, - dappAddressOrENS: defaultConfig.dappAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, ipfsNode: defaultConfig.ipfsUploadUrl, ipfsGateway: defaultConfig.ipfsGateway, @@ -175,8 +175,8 @@ describe('sendTelegram', () => { sendTelegram({ graphQLClient: { request: jest.fn() } as any, iexec: mockAllForSendTelegram() as any, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, - dappAddressOrENS: defaultConfig.dappAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, ipfsNode: defaultConfig.ipfsUploadUrl, ipfsGateway: defaultConfig.ipfsGateway, @@ -214,8 +214,8 @@ describe('sendTelegram', () => { await sendTelegram({ graphQLClient: { request: jest.fn() } as any, iexec, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, - dappAddressOrENS: defaultConfig.dappAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, + dappAddress: TEST_WEB3TELEGRAM_DAPP_ADDRESS, dappWhitelistAddress: defaultConfig.whitelistSmartContract, ipfsNode: defaultConfig.ipfsUploadUrl, ipfsGateway: defaultConfig.ipfsGateway, @@ -229,7 +229,7 @@ describe('sendTelegram', () => { 1, { workerpool: defaultConfig.prodWorkerpoolAddress, - app: defaultConfig.dappAddress.toLowerCase(), + app: TEST_WEB3TELEGRAM_DAPP_ADDRESS.toLowerCase(), dataset: protectedData, requester: userAddress, isRequesterStrict: false, diff --git a/tests/unit/sendTelegramCampaign.test.ts b/tests/unit/sendTelegramCampaign.test.ts index 8362b5e..caea349 100644 --- a/tests/unit/sendTelegramCampaign.test.ts +++ b/tests/unit/sendTelegramCampaign.test.ts @@ -1,16 +1,13 @@ import { expect, it, jest, describe, beforeAll } from '@jest/globals'; import { type SendTelegramCampaign } from '../../src/web3telegram/sendTelegramCampaign.js'; import { getRandomAddress } from '../test-utils.js'; -import { - DEFAULT_CHAIN_ID, - getChainDefaultConfig, -} from '../../src/config/config.js'; +import { getChainDefaultConfig } from '../../src/config/config.js'; import { BulkRequest } from '@iexec/dataprotector'; describe('sendTelegramCampaign', () => { let testedModule: any; let sendTelegramCampaign: SendTelegramCampaign; - const defaultConfig = getChainDefaultConfig(DEFAULT_CHAIN_ID); + const defaultConfig = getChainDefaultConfig(421614); beforeAll(async () => { // import tested module after all mocked modules @@ -58,7 +55,7 @@ describe('sendTelegramCampaign', () => { // --- WHEN const result = await sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, }); @@ -113,7 +110,7 @@ describe('sendTelegramCampaign', () => { // --- WHEN const result = await sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, }); @@ -163,7 +160,7 @@ describe('sendTelegramCampaign', () => { // --- WHEN await sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, }); @@ -185,7 +182,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, // campaignRequest is not provided } as any) ).rejects.toThrow(); @@ -194,7 +191,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, } as any) ).rejects.toMatchObject({ message: expect.stringMatching( @@ -237,7 +234,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, }) ).rejects.toMatchObject({ @@ -245,7 +242,7 @@ describe('sendTelegramCampaign', () => { }); }); - it('should throw error when workerpoolAddressOrEns is not provided', async () => { + it('should throw error when workerpoolAddress is not provided', async () => { // --- GIVEN const mockCampaignRequest: BulkRequest = { app: '0x0000000000000000000000000000000000000000', @@ -275,7 +272,7 @@ describe('sendTelegramCampaign', () => { sendTelegramCampaign({ dataProtector: mockDataprotector, campaignRequest: mockCampaignRequest, - // workerpoolAddressOrEns is not provided + // workerpoolAddress is not provided } as any) ).rejects.toMatchObject({ message: expect.stringMatching( @@ -311,7 +308,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ // dataProtector is not provided - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, } as any) ).rejects.toMatchObject({ @@ -321,7 +318,7 @@ describe('sendTelegramCampaign', () => { }); }); - it('should throw error when workerpoolAddressOrEns is invalid', async () => { + it('should throw error when workerpoolAddress is invalid', async () => { // --- GIVEN const mockCampaignRequest: BulkRequest = { app: '0x0000000000000000000000000000000000000000', @@ -350,7 +347,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: 'invalid-address', + workerpoolAddress: 'invalid-address', campaignRequest: mockCampaignRequest, }) ).rejects.toMatchObject({ @@ -373,7 +370,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: null as any, // Invalid campaignRequest }) ).rejects.toMatchObject({ @@ -420,7 +417,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, }) ).rejects.toBe(protocolError); @@ -458,7 +455,7 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: defaultConfig.prodWorkerpoolAddress, + workerpoolAddress: defaultConfig.prodWorkerpoolAddress, campaignRequest: mockCampaignRequest, }) ).rejects.toMatchObject({ @@ -466,7 +463,7 @@ describe('sendTelegramCampaign', () => { }); }); - it('should throw error when workerpoolAddressOrEns does not match campaignRequest.workerpool', async () => { + it('should throw error when workerpoolAddress does not match campaignRequest.workerpool', async () => { // --- GIVEN const mockCampaignRequest: BulkRequest = { app: '0x0000000000000000000000000000000000000000', @@ -497,15 +494,14 @@ describe('sendTelegramCampaign', () => { await expect( sendTelegramCampaign({ dataProtector: mockDataprotector, - workerpoolAddressOrEns: differentWorkerpool, + workerpoolAddress: differentWorkerpool, campaignRequest: mockCampaignRequest, }) ).rejects.toMatchObject({ message: 'Failed to sendTelegramCampaign', cause: expect.objectContaining({ name: 'ValidationError', - message: - "workerpoolAddressOrEns doesn't match campaignRequest workerpool", + message: "workerpoolAddress doesn't match campaignRequest workerpool", }), }); diff --git a/tests/unit/utils/filterWorkerpoolOrders.test.ts b/tests/unit/utils/filterWorkerpoolOrders.test.ts index 5e55001..dc7aa48 100644 --- a/tests/unit/utils/filterWorkerpoolOrders.test.ts +++ b/tests/unit/utils/filterWorkerpoolOrders.test.ts @@ -7,7 +7,6 @@ describe('filterWorkerpoolOrders', () => { filterWorkerpoolOrders({ workerpoolOrders: [], workerpoolMaxPrice: 100, - useVoucher: false, }) ).toBeNull(); }); @@ -41,7 +40,6 @@ describe('filterWorkerpoolOrders', () => { filterWorkerpoolOrders({ workerpoolOrders: orders, workerpoolMaxPrice: 100, - useVoucher: false, }) ).toEqual(orders[0].order); }); @@ -75,7 +73,6 @@ describe('filterWorkerpoolOrders', () => { filterWorkerpoolOrders({ workerpoolOrders: orders, workerpoolMaxPrice: 100, - useVoucher: false, }) ).toBeNull(); }); @@ -151,7 +148,6 @@ describe('filterWorkerpoolOrders', () => { filterWorkerpoolOrders({ workerpoolOrders: orders, workerpoolMaxPrice: 100, - useVoucher: false, }) ).toEqual(orders[1].order); // the cheapest }); @@ -227,7 +223,6 @@ describe('filterWorkerpoolOrders', () => { filterWorkerpoolOrders({ workerpoolOrders: orders, workerpoolMaxPrice: 100, - useVoucher: false, }) ).toBeNull(); }); @@ -303,7 +298,6 @@ describe('filterWorkerpoolOrders', () => { filterWorkerpoolOrders({ workerpoolOrders: orders, workerpoolMaxPrice: 100, - useVoucher: false, }) ).toEqual(orders[1].order); }); diff --git a/tests/unit/utils/validators.test.ts b/tests/unit/utils/validators.test.ts index a78d9a5..2eff8f4 100644 --- a/tests/unit/utils/validators.test.ts +++ b/tests/unit/utils/validators.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from '@jest/globals'; import { ValidationError } from 'yup'; import { - addressOrEnsSchema, + addressSchema, senderNameSchema, telegramContentSchema, labelSchema, @@ -11,50 +11,41 @@ import { getRandomAddress, getRequiredFieldMessage } from '../../test-utils.js'; const CANNOT_BE_NULL_ERROR = new ValidationError('this cannot be null'); const IS_REQUIRED_ERROR = new ValidationError(getRequiredFieldMessage()); -describe('addressOrEnsSchema()', () => { +describe('addressSchema()', () => { describe('validateSync()', () => { const address = getRandomAddress(); const EXPECTED_ERROR = new ValidationError( - 'this should be an ethereum address or a ENS name' + 'this should be an ethereum address' ); it('transforms to lowercase', () => { - const res = addressOrEnsSchema().validateSync(address); + const res = addressSchema().validateSync(address); expect(res).toBe(address.toLowerCase()); }); it('accepts undefined (is not required by default)', () => { - const res = addressOrEnsSchema().validateSync(undefined); + const res = addressSchema().validateSync(undefined); expect(res).toBeUndefined(); }); it('accepts case insensitive ethereum address', () => { - expect(addressOrEnsSchema().validateSync(address)).toBeDefined(); - expect( - addressOrEnsSchema().validateSync(address.toUpperCase()) - ).toBeDefined(); - expect( - addressOrEnsSchema().validateSync(address.toLowerCase()) - ).toBeDefined(); + expect(addressSchema().validateSync(address)).toBeDefined(); + expect(addressSchema().validateSync(address.toUpperCase())).toBeDefined(); + expect(addressSchema().validateSync(address.toLowerCase())).toBeDefined(); }); - it('accepts string ending with ".eth"', () => { - expect(addressOrEnsSchema().validateSync('FOO.eth')).toBe('foo.eth'); + it('does not accept string ending with ".eth"', () => { + expect(() => addressSchema().validateSync('FOO.eth')).toThrow( + EXPECTED_ERROR + ); }); it('does not accept null', () => { - expect(() => addressOrEnsSchema().validateSync(null)).toThrow( + expect(() => addressSchema().validateSync(null)).toThrow( CANNOT_BE_NULL_ERROR ); }); it('does not accept empty string', () => { - expect(() => addressOrEnsSchema().validateSync('')).toThrow( - EXPECTED_ERROR - ); + expect(() => addressSchema().validateSync('')).toThrow(EXPECTED_ERROR); }); it('does not accept non address string', () => { - expect(() => addressOrEnsSchema().validateSync('test')).toThrow( - EXPECTED_ERROR - ); - }); - it('does not accept ENS name with label < 3 char', () => { - expect(() => addressOrEnsSchema().validateSync('ab.eth')).toThrow( + expect(() => addressSchema().validateSync('test')).toThrow( EXPECTED_ERROR ); }); @@ -63,7 +54,7 @@ describe('addressOrEnsSchema()', () => { describe('validateSync()', () => { it('does not accept undefined', () => { expect(() => - addressOrEnsSchema().required().validateSync(undefined) + addressSchema().required().validateSync(undefined) ).toThrow(IS_REQUIRED_ERROR); }); }); diff --git a/tests/utils/mockAllForSendTelegram.ts b/tests/utils/mockAllForSendTelegram.ts index 5fa86a6..8ba7559 100644 --- a/tests/utils/mockAllForSendTelegram.ts +++ b/tests/utils/mockAllForSendTelegram.ts @@ -11,11 +11,6 @@ export function mockAllForSendTelegram() { .fn<() => Promise
>() .mockResolvedValue(getRandomAddress()), }, - ens: { - resolveName: jest - .fn<() => Promise
>() - .mockResolvedValue(getRandomAddress()), - }, orderbook: { fetchDatasetOrderbook: jest .fn<() => Promise<{ orders: any[] }>>()