diff --git a/.eslintignore b/.eslintignore index 1a3c85b4..e7a3ae4f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -6,3 +6,5 @@ docs dist test-extension/simple-browser-extension test-extension/dapp-vite +unit-tests/code-snippets +test-extension \ No newline at end of file diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 2159ae3a..eb3d7c12 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,3 +1,10 @@ module.exports = { - extends: ['@massalabs'], + extends: ['@massalabs', 'prettier'], + rules: { + 'tsdoc/syntax': 'warn', + 'max-len': ['error', 200], + camelcase: 'off', + '@typescript-eslint/no-unused-vars': 'error', + 'no-console': 'warn', + }, }; diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..fa9699b8 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "semi": true, + "trailingComma": "all", + "singleQuote": true, + "printWidth": 80, + "tabWidth": 2 +} diff --git a/package-lock.json b/package-lock.json index f8b9a56d..9fc79607 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,8 +10,7 @@ "license": "(MIT AND Apache-2.0)", "dependencies": { "@hicaru/bearby.js": "^0.5.5", - "@massalabs/massa-web3": "^3.0.2", - "@massalabs/web3-utils": "^1.4.7", + "@massalabs/web3-utils": "^1.4.8", "axios": "^0.26.1", "bignumber.js": "^9.1.1", "bs58check": "^3.0.1", @@ -24,7 +23,6 @@ "devDependencies": { "@babel/preset-env": "^7.22.14", "@massalabs/eslint-config": "^0.0.9", - "@massalabs/prettier-config-as": "^0.0.2", "@playwright/test": "^1.32.3", "@types/bn.js": "^5.1.1", "@types/chai": "^4.3.4", @@ -35,6 +33,7 @@ "babel-jest": "^29.6.4", "chai": "^4.3.7", "chalk": "^4.1.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-jsdoc": "^41.1.1", "express": "^4.18.2", "fs-extra": "^11.1.1", @@ -2743,6 +2742,18 @@ "node": "^14 || ^16 || ^17 || ^18 || ^19" } }, + "node_modules/@massalabs/eslint-config/node_modules/eslint-config-prettier": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", + "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/@massalabs/eslint-config/node_modules/eslint-plugin-jsdoc": { "version": "39.9.1", "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.9.1.tgz", @@ -2773,75 +2784,12 @@ "node": ">=12.0.0" } }, - "node_modules/@massalabs/massa-web3": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@massalabs/massa-web3/-/massa-web3-3.0.2.tgz", - "integrity": "sha512-XdCqq5b6fOFahkXDG1F9vX9+fmBYdQbz5K8JqomD1NFAh7Q9CNA1IG6dlUAnN6GNGkdCJ6XiPsRxUCZfwkejyg==", - "dependencies": { - "@massalabs/wallet-provider": "^1.5.1", - "@massalabs/web3-utils": "^1.4.7", - "@noble/ed25519": "^1.7.3", - "@noble/hashes": "^1.2.0", - "@types/ws": "^8.5.4", - "@web3pack/base58-check": "^1.0.3", - "axios": "^0.26.1", - "bignumber.js": "^9.1.1", - "bip39": "^3.0.4", - "bs58check": "^3.0.1", - "buffer": "^6.0.3", - "crypto-js": "^4.1.1", - "dotenv": "^16.0.3", - "js-base64": "^3.7.5", - "string_decoder": "^1.3.0", - "tslib": "^2.5.2", - "util": "^0.12.5", - "varint": "^6.0.0" - }, - "optionalDependencies": { - "bufferutil": "^4.0.7", - "utf-8-validate": "^6.0.2" - } - }, - "node_modules/@massalabs/massa-web3/node_modules/js-base64": { - "version": "3.7.5", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.5.tgz", - "integrity": "sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA==" - }, - "node_modules/@massalabs/prettier-config-as": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@massalabs/prettier-config-as/-/prettier-config-as-0.0.2.tgz", - "integrity": "sha512-4ZLQByir4Pvr6AzWTrMjPkwHqB7FqtuTYQHPrcbW4CDHlSYZgvzVZqEV+klk8ZVI1POygvJ/y3H8cp19ZueBZg==", - "dev": true, - "dependencies": { - "assemblyscript-prettier": "^1.0.6" - } - }, - "node_modules/@massalabs/wallet-provider": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@massalabs/wallet-provider/-/wallet-provider-1.5.1.tgz", - "integrity": "sha512-Q/50oKteRXkVCtFMXDolkhhqzY/qFGE7UU60JdDyvl6k0QHam0AkSz550+q2IPqHpIv4MtKNMWFmdzhzrDKTZw==", - "dependencies": { - "@hicaru/bearby.js": "^0.5.0", - "@massalabs/web3-utils": "^1.4.1", - "axios": "^0.26.1", - "bignumber.js": "^9.1.1", - "bs58check": "^3.0.1", - "buffer": "^6.0.3", - "npm-run-all": "^4.1.5", - "rimraf": "^5.0.5", - "uid": "^2.0.1", - "varint": "^6.0.0" - }, - "optionalDependencies": { - "bufferutil": "^4.0.7", - "utf-8-validate": "^6.0.2" - } - }, "node_modules/@massalabs/web3-utils": { - "version": "1.4.7", - "resolved": "https://registry.npmjs.org/@massalabs/web3-utils/-/web3-utils-1.4.7.tgz", - "integrity": "sha512-nD7yf5P8ldg2wdyAKFI8sz3XEUTklz29dXcOjZdXn4fKzrHF4mqvq2OUZ+uR31OziZboKxTGK5r8AxcZTKL5Zg==", + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@massalabs/web3-utils/-/web3-utils-1.4.8.tgz", + "integrity": "sha512-mMmH/hnDLSe55O6YITMuOe/k8ju6i6n4/yOinXO717OMiYFthp+WYoHk9IbSiAuCyFTCimROhjvgiGcaqfdVYw==", "dependencies": { + "bignumber.js": "^9.1.2", "buffer": "^6.0.3", "events": "^3.3.0", "string_decoder": "^1.3.0" @@ -2878,17 +2826,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@noble/ed25519": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/@noble/ed25519/-/ed25519-1.7.3.tgz", - "integrity": "sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] - }, "node_modules/@noble/hashes": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", @@ -3237,7 +3174,8 @@ "node_modules/@types/node": { "version": "18.17.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.1.tgz", - "integrity": "sha512-xlR1jahfizdplZYRU59JlUx9uzF1ARa8jbhM11ccpCJya8kvos5jwdm2ZAgxSCwOl0fq21svP18EVwPBXMQudw==" + "integrity": "sha512-xlR1jahfizdplZYRU59JlUx9uzF1ARa8jbhM11ccpCJya8kvos5jwdm2ZAgxSCwOl0fq21svP18EVwPBXMQudw==", + "dev": true }, "node_modules/@types/prettier": { "version": "2.7.3", @@ -3278,14 +3216,6 @@ "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==", "dev": true }, - "node_modules/@types/ws": { - "version": "8.5.10", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", - "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", @@ -3489,21 +3419,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@web3pack/base-x": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@web3pack/base-x/-/base-x-1.0.2.tgz", - "integrity": "sha512-P3XgVnEQ1QFyUTmHzT1sXNprLyxE1aG8WAnk5/Fj+3j4AmsK4dRfMdV3t/aIdYP3i1KvjPRkQJhFXGpxUc+M8A==" - }, - "node_modules/@web3pack/base58-check": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@web3pack/base58-check/-/base58-check-1.0.3.tgz", - "integrity": "sha512-+s4HKOnJbIkj45jhGfSxgWkKsjBENuNbfqASPTLPy/yjGGv/jGCxzFCl0fb4gudV3x0gS50gLpJsC8qQ6cV1gw==", - "dependencies": { - "@web3pack/base-x": "^1.0.1", - "buffer": "^6.0.3", - "hash.js": "^1.1.7" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -4020,61 +3935,6 @@ "node": ">=0.10.0" } }, - "node_modules/assemblyscript": { - "version": "0.27.9", - "resolved": "https://registry.npmjs.org/assemblyscript/-/assemblyscript-0.27.9.tgz", - "integrity": "sha512-cFE/AMjVtBQ2iKFZPu/a3Z/KJzGex61C+X+y3GuLJ8Hr9Zdf46sy/JlIl6ikothQd2umM9CQDAD/uAPAEHL+oA==", - "dev": true, - "peer": true, - "dependencies": { - "binaryen": "112.0.0-nightly.20230411", - "long": "^5.2.1" - }, - "bin": { - "asc": "bin/asc.js", - "asinit": "bin/asinit.js" - }, - "engines": { - "node": ">=16", - "npm": ">=7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/assemblyscript" - } - }, - "node_modules/assemblyscript-prettier": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/assemblyscript-prettier/-/assemblyscript-prettier-1.0.7.tgz", - "integrity": "sha512-SAyX9HNTgM4evkyrGyh/gZ61CSh0kG3hJPdlF1oWJ8R7rLHoJJVKjiw3SJjzLyhk1a+PCykAApUBxjpf+ES3uQ==", - "dev": true, - "dependencies": { - "chalk": "^5.0.1", - "cli-progress": "^3.11.2", - "commander": "^9.4.0", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0" - }, - "bin": { - "as-prettier": "index.mjs" - }, - "peerDependencies": { - "assemblyscript": ">=0.20.0", - "prettier": "^2.7.1" - } - }, - "node_modules/assemblyscript-prettier/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", - "dev": true, - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -4349,9 +4209,9 @@ "dev": true }, "node_modules/bignumber.js": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.1.tgz", - "integrity": "sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", "engines": { "node": "*" } @@ -4365,25 +4225,6 @@ "node": ">=8" } }, - "node_modules/binaryen": { - "version": "112.0.0-nightly.20230411", - "resolved": "https://registry.npmjs.org/binaryen/-/binaryen-112.0.0-nightly.20230411.tgz", - "integrity": "sha512-4V9r9x9fjAVFZdR2yvBFc3BEJJIBYvd2X8X8k0zAuJsao2gl9wNHDmpQ30QsLo6hgkRfRImkCbCjhXW3RDOYXQ==", - "dev": true, - "peer": true, - "bin": { - "wasm-opt": "bin/wasm-opt", - "wasm2js": "bin/wasm2js" - } - }, - "node_modules/bip39": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", - "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", - "dependencies": { - "@noble/hashes": "^1.2.0" - } - }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -4868,18 +4709,6 @@ "node": ">=4" } }, - "node_modules/cli-progress": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", - "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", - "dev": true, - "dependencies": { - "string-width": "^4.2.3" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/cli-truncate": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", @@ -5043,15 +4872,6 @@ "node": ">= 0.8" } }, - "node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, "node_modules/comment-parser": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", @@ -5224,11 +5044,6 @@ "node": ">= 8" } }, - "node_modules/crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" - }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -5537,17 +5352,6 @@ "node": ">=12" } }, - "node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" - } - }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -5916,9 +5720,9 @@ } }, "node_modules/eslint-config-prettier": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.9.0.tgz", - "integrity": "sha512-+sbni7NfVXnOpnRadUA8S28AUlsZt9GjgFvABIRL9Hkn8KqNzOp+7Lw4QWtrwn20KzU3wqu1QoOj2m+7rKRqkA==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -7012,15 +6816,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasown": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", @@ -7295,7 +7090,8 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true }, "node_modules/inquirer": { "version": "7.3.3", @@ -7416,21 +7212,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-array-buffer": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", @@ -7586,20 +7367,6 @@ "node": ">=6" } }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -9383,13 +9150,6 @@ "node": ">=0.8.0" } }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "dev": true, - "peer": true - }, "node_modules/loupe": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", @@ -9594,11 +9354,6 @@ "node": ">=6" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -13605,7 +13360,8 @@ "node_modules/tslib": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==" + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true }, "node_modules/tslint": { "version": "6.1.3", @@ -14243,18 +13999,6 @@ "node": ">=6.14.2" } }, - "node_modules/util": { - "version": "0.12.5", - "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", - "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", - "dependencies": { - "inherits": "^2.0.3", - "is-arguments": "^1.0.4", - "is-generator-function": "^1.0.7", - "is-typed-array": "^1.1.3", - "which-typed-array": "^1.1.2" - } - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", diff --git a/package.json b/package.json index 1f0a3034..17d193d8 100644 --- a/package.json +++ b/package.json @@ -53,8 +53,7 @@ ], "dependencies": { "@hicaru/bearby.js": "^0.5.5", - "@massalabs/massa-web3": "^3.0.2", - "@massalabs/web3-utils": "^1.4.7", + "@massalabs/web3-utils": "^1.4.8", "axios": "^0.26.1", "bignumber.js": "^9.1.1", "bs58check": "^3.0.1", @@ -67,7 +66,6 @@ "devDependencies": { "@babel/preset-env": "^7.22.14", "@massalabs/eslint-config": "^0.0.9", - "@massalabs/prettier-config-as": "^0.0.2", "@playwright/test": "^1.32.3", "@types/bn.js": "^5.1.1", "@types/chai": "^4.3.4", @@ -78,6 +76,7 @@ "babel-jest": "^29.6.4", "chai": "^4.3.7", "chalk": "^4.1.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-jsdoc": "^41.1.1", "express": "^4.18.2", "fs-extra": "^11.1.1", @@ -101,7 +100,6 @@ "bufferutil": "^4.0.7", "utf-8-validate": "^6.0.2" }, - "prettier": "@massalabs/prettier-config-as", "_moduleAliases": { "@massalabs/wallet-provider": "./dist/index.js" } diff --git a/src/bearbyWallet/BearbyAccount.ts b/src/bearbyWallet/BearbyAccount.ts index fa25768a..07c087f9 100644 --- a/src/bearbyWallet/BearbyAccount.ts +++ b/src/bearbyWallet/BearbyAccount.ts @@ -1,30 +1,20 @@ import { Args, + CHAIN_ID_RPC_URL_MAP, IContractReadOperationData, IContractReadOperationResponse, + MAX_GAS_CALL, } from '@massalabs/web3-utils'; import { ITransactionDetails } from '..'; import { IAccountBalanceResponse, IAccountDetails } from '../account'; import { IAccount } from '../account/IAccount'; import { web3 } from '@hicaru/bearby.js'; -import { - postRequest, - JsonRpcResponseData, -} from '../massaStation/RequestHandler'; +import { postRequest } from '../massaStation/RequestHandler'; import { BalanceResponse } from './BalanceResponse'; -import { NodeStatus } from './NodeStatus'; -import { JSON_RPC_REQUEST_METHOD } from './jsonRpcMethods'; -import axios, { AxiosRequestHeaders, AxiosResponse } from 'axios'; import { IAccountSignOutput } from '../account/AccountSign'; /** * The maximum allowed gas for a read operation */ -const MAX_READ_BLOCK_GAS = BigInt(4_294_967_295); - -/** - * The RPC we are using to query the node - */ -export const PUBLIC_NODE_RPC = 'https://buildnet.massa.net/api/v2'; export enum OperationsType { Payment, @@ -45,17 +35,10 @@ export enum OperationTypeId { CallSC = 4, } -const requestHeaders = { - Accept: - 'application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Content-Type': 'application/json', -} as AxiosRequestHeaders; - export class BearbyAccount implements IAccount { private _providerName: string; private _address: string; private _name: string; - private _nodeUrl = PUBLIC_NODE_RPC; public constructor({ address, name }: IAccountDetails, providerName: string) { this._address = address; @@ -75,7 +58,6 @@ export class BearbyAccount implements IAccount { return this._providerName; } - // TODO: Should be removed from account interface as it more a provider method public async connect() { try { await web3.wallet.connect(); @@ -84,8 +66,8 @@ export class BearbyAccount implements IAccount { } } - // needs testing public async balance(): Promise { + // TODO: check if we need to connect every time await this.connect(); // Not available on bearby. we have to manually call the api const body = { @@ -95,14 +77,15 @@ export class BearbyAccount implements IAccount { id: 0, }; - const addressInfos = await postRequest( - PUBLIC_NODE_RPC, - body, - ); + // get node url: This is a temporary solution. We should get the balance from the provider + const nodeUrl = await getNodesUrl(); + + const addressInfos = await postRequest(nodeUrl, body); if (addressInfos.isError || addressInfos.error) { throw addressInfos.error.message; } + return { finalBalance: addressInfos.result.result[0].final_balance, candidateBalance: addressInfos.result.result[0].candidate_balance, @@ -129,11 +112,7 @@ export class BearbyAccount implements IAccount { }; } - // need testing - public async buyRolls( - amount: bigint, - fee: bigint, - ): Promise { + public async buyRolls(amount: bigint): Promise { await this.connect(); const operationId = await web3.massa.buyRolls(amount.toString()); @@ -142,11 +121,7 @@ export class BearbyAccount implements IAccount { } as ITransactionDetails; } - // need testing - public async sellRolls( - amount: bigint, - fee: bigint, - ): Promise { + public async sellRolls(amount: bigint): Promise { await this.connect(); const operationId = await web3.massa.sellRolls(amount.toString()); @@ -158,7 +133,6 @@ export class BearbyAccount implements IAccount { public async sendTransaction( amount: bigint, recipientAddress: string, - fee: bigint, ): Promise { await this.connect(); @@ -167,9 +141,7 @@ export class BearbyAccount implements IAccount { recipientAddress, ); - return { - operationId, - } as ITransactionDetails; + return { operationId }; } public async callSC( @@ -182,6 +154,7 @@ export class BearbyAccount implements IAccount { nonPersistentExecution = false, ): Promise { await this.connect(); + if (nonPersistentExecution) { return this.nonPersistentCallSC( contractAddress, @@ -212,101 +185,6 @@ export class BearbyAccount implements IAccount { return { operationId }; } - /** - * Retrieves the node's status. - * - * @remarks - * The returned information includes: - * - Whether the node is reachable - * - The number of connected peers - * - The node's version - * - The node's configuration parameters - * - * @returns A promise that resolves to the node's status information. - */ - public async getNodeStatus(): Promise { - const jsonRpcRequestMethod = JSON_RPC_REQUEST_METHOD.GET_STATUS; - return await this.sendJsonRPCRequest(jsonRpcRequestMethod, []); - } - - /** - * Sends a post JSON rpc request to the node. - * - * @param resource - The rpc method to call. - * @param params - The parameters to pass to the rpc method. - * - * @throws An error if the rpc method returns an error. - * - * @returns A promise that resolves as the result of the rpc method. - */ - protected async sendJsonRPCRequest( - resource: JSON_RPC_REQUEST_METHOD, - params: object, - ): Promise { - let resp: JsonRpcResponseData = null; - resp = await this.promisifyJsonRpcCall(resource, params); - - // in case of rpc error, rethrow the error. - if (resp.isError || resp.error) { - throw resp.error; - } - - return resp.result; - } - - /** - * Converts a json rpc call to a promise that resolves as a JsonRpcResponseData - * - * @privateRemarks - * If there is an error while sending the request, the function catches the error, the isError - * property is set to true, the result property set to null, and the error property set to a - * new Error object with a message indicating that there was an error. - * - * @param resource - The rpc method to call. - * @param params - The parameters to pass to the rpc method. - * - * @returns A promise that resolves as a JsonRpcResponseData. - */ - private async promisifyJsonRpcCall( - resource: JSON_RPC_REQUEST_METHOD, - params: object, - ): Promise> { - let resp: AxiosResponse> = null; - - const body = { - jsonrpc: '2.0', - method: resource, - params: params, - id: 0, - }; - - try { - resp = await axios.post(this._nodeUrl, body, { headers: requestHeaders }); - } catch (ex) { - return { - isError: true, - result: null, - error: new Error('JSON.parse error: ' + String(ex)), - } as JsonRpcResponseData; - } - - const responseData: JsonRpcResponseData = resp.data; - - if (responseData.error) { - return { - isError: true, - result: null, - error: new Error(responseData.error.message), - } as JsonRpcResponseData; - } - - return { - isError: false, - result: responseData.result as T, - error: null, - } as JsonRpcResponseData; - } - public async nonPersistentCallSC( contractAddress: string, functionName: string, @@ -315,14 +193,12 @@ export class BearbyAccount implements IAccount { fee: bigint, maxGas: bigint, ): Promise { - // not clean but bearby doesn't allow us to get its node urls - const node = PUBLIC_NODE_RPC; // Gas amount check - if (maxGas > MAX_READ_BLOCK_GAS) { + if (maxGas > MAX_GAS_CALL) { throw new Error( ` The gas submitted ${maxGas.toString()} exceeds the max. allowed block gas of - ${MAX_READ_BLOCK_GAS.toString()} + ${MAX_GAS_CALL.toString()} `, ); } @@ -354,9 +230,10 @@ export class BearbyAccount implements IAccount { ]; // returns operation ids let jsonRpcCallResult: Array = []; + const nodeUrl = await getNodesUrl(); try { let resp = await postRequest>( - node, + nodeUrl, body, ); if (resp.isError || resp.error) { @@ -382,3 +259,9 @@ export class BearbyAccount implements IAccount { }; } } + +// TODO: Should be removed from account when bearby.js is updated +async function getNodesUrl(): Promise { + const info = (await web3.massa.getNodesStatus()) as any; + return CHAIN_ID_RPC_URL_MAP[info.result.chain_id]; +} diff --git a/src/bearbyWallet/BearbyConnect.ts b/src/bearbyWallet/BearbyConnect.ts index f1c4b821..85a44efb 100644 --- a/src/bearbyWallet/BearbyConnect.ts +++ b/src/bearbyWallet/BearbyConnect.ts @@ -14,5 +14,4 @@ export async function connectBearby(): Promise { export async function disconnectBearby(): Promise { await web3.wallet.disconnect(); - console.log('Bearby disconnected'); } diff --git a/src/bearbyWallet/BearbyProvider.ts b/src/bearbyWallet/BearbyProvider.ts index e99fa49b..a1cafc3a 100644 --- a/src/bearbyWallet/BearbyProvider.ts +++ b/src/bearbyWallet/BearbyProvider.ts @@ -1,4 +1,8 @@ -import { web3 } from '@hicaru/bearby.js'; +import { + JsonRPCResponse, + JsonRPCResponseNodeStatus, + web3, +} from '@hicaru/bearby.js'; import { IAccount, IAccountDetails } from '../account'; import { IAccountDeletionResponse, @@ -6,19 +10,10 @@ import { IProvider, } from '../provider'; import { BearbyAccount } from './BearbyAccount'; +import { CHAIN_ID_RPC_URL_MAP } from '@massalabs/web3-utils'; export class BearbyProvider implements IProvider { - private providerName: string; - - /** - * Provider constructor - * - * @param providerName - The name of the provider. - * @returns An instance of the Provider class. - */ - public constructor(providerName: string) { - this.providerName = providerName; - } + private providerName = 'BEARBY'; public name(): string { return this.providerName; @@ -34,33 +29,43 @@ export class BearbyProvider implements IProvider { address: await web3.wallet.account.base58, name: 'BEARBY', }; + return [new BearbyAccount(account, this.providerName)]; } - public async importAccount( - publicKey: string, - privateKey: string, - ): Promise { + public async importAccount(): Promise { throw new Error('Method not implemented.'); } - public async deleteAccount( - address: string, - ): Promise { + public async deleteAccount(): Promise { throw new Error('Method not implemented.'); } public async getNodesUrls(): Promise { - return ['https://buildnet.massa.net/api/v2']; + const chainId = await this.getChainId(); + // TODO: Check why we need to put in an array + return [CHAIN_ID_RPC_URL_MAP[chainId.toString()]]; + } + + public async getChainId(): Promise { + // TODO: remove any when bearby.js is updated https://github.com/bearby-wallet/bearby-web3/issues/10 + const info = (await web3.massa.getNodesStatus()) as any; + return BigInt(info.result.chain_id); } public async getNetwork(): Promise { const network = await web3.wallet.network; - return network.net; } - public async generateNewAccount(name: string): Promise { + // TODO: Harmonize the response with other providers + public async getNodeStatus(): Promise< + JsonRPCResponse + > { + return web3.massa.getNodesStatus(); + } + + public async generateNewAccount(): Promise { throw new Error('Method not implemented.'); } diff --git a/src/connector/Connector.ts b/src/connector/Connector.ts index 06424b89..5b804379 100644 --- a/src/connector/Connector.ts +++ b/src/connector/Connector.ts @@ -22,12 +22,6 @@ import { IAccountSignRequest, IAccountSignResponse, } from '..'; -import { - ON_MASSA_STATION_DISCOVERED, - ON_MASSA_STATION_DISCONNECTED, - MassaStationDiscovery, -} from '../massaStation/MassaStationDiscovery'; -import { MASSA_STATION_PROVIDER_NAME } from '../massaStation/MassaStationProvider'; import { IAccount } from '../account/IAccount'; import { PluginInfo } from '../massaStation/types'; @@ -68,7 +62,6 @@ export type AllowedResponses = class Connector { private registeredProviders: Record = {}; private pendingRequests: Map; - private massaStationListener: MassaStationDiscovery; private providersInfo: Record = {}; @@ -87,8 +80,6 @@ class Connector { public constructor() { if (typeof document !== 'undefined') { this.pendingRequests = new Map(); - this.massaStationListener = new MassaStationDiscovery(); - this.initMassaStationListener(); this.register(); // start listening to messages from content script @@ -136,30 +127,6 @@ class Connector { } } - private initMassaStationListener() { - this.massaStationListener.on( - ON_MASSA_STATION_DISCOVERED, - (walletModule: PluginInfo) => { - this.registeredProviders[ - MASSA_STATION_PROVIDER_NAME - ] = `${MASSA_WINDOW_OBJECT}_${MASSA_STATION_PROVIDER_NAME}`; - - this.providersInfo[MASSA_STATION_PROVIDER_NAME] = walletModule; - }, - ); - this.massaStationListener.on(ON_MASSA_STATION_DISCONNECTED, () => { - delete this.registeredProviders[MASSA_STATION_PROVIDER_NAME]; - }); - } - - public async startMassaStationDiscovery() { - try { - await this.massaStationListener.startListening(); - } catch (e) { - console.log('get MassaStation provider error: ', e); - } - } - /** * This method sends a message from the webpage script to the content script. * diff --git a/src/index.ts b/src/index.ts index 289ff54b..49dfae86 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,23 +13,13 @@ if (typeof window !== 'undefined') { window.Buffer = Buffer; } -import { MASSA_WINDOW_OBJECT, connector } from './connector/Connector'; -import { IProvider } from './provider/IProvider'; -import { Provider } from './provider/Provider'; -import { - MASSA_STATION_PROVIDER_NAME, - MassaStationProvider, -} from './massaStation/MassaStationProvider'; -import { detectBearby } from './bearbyWallet/BearbyConnect'; -import { BearbyProvider } from './bearbyWallet/BearbyProvider'; -import { wait } from './utils/time'; - export enum AvailableCommands { ProviderListAccounts = 'LIST_ACCOUNTS', ProviderDeleteAccount = 'DELETE_ACCOUNT', ProviderImportAccount = 'IMPORT_ACCOUNT', ProviderGetNodesUrls = 'GET_NODES_URLS', ProviderGetNetwork = 'GET_NETWORK', + ProviderGetChainId = 'GET_CHAIN_ID', AccountBalance = 'ACCOUNT_BALANCE', AccountSign = 'ACCOUNT_SIGN', ProviderGenerateNewAccount = 'GENERATE_NEW_ACCOUNT', @@ -43,86 +33,6 @@ export interface ITransactionDetails { operationId: string; } -/** - * Get the list of providers that are available to interact with. - * - * @param retry - If true, will retry to get the list of providers if none are available. - * @param pollInterval - The timeout in milliseconds to wait between retries. default is 2000ms. - * @param timeout - The timeout in milliseconds to wait before giving up. default is 3000ms. - * - * @returns An array of providers. - */ -export async function providers( - retry = true, - timeout = 3000, - pollInterval = 500, -): Promise { - const startTime = Date.now(); - - await connector.startMassaStationDiscovery(); - - let bearby: BearbyProvider | undefined; - if (await detectBearby()) { - bearby = new BearbyProvider('BEARBY'); - } - - while (Date.now() - startTime < timeout) { - const providerInstances: IProvider[] = getProviderInstances(); - - if (bearby) providerInstances.push(bearby); - - if (!retry || providerInstances.length > 0) { - return providerInstances; - } - - await wait(pollInterval); - } - - return []; -} - -function getProviderInstances() { - const availableProviders = Object.keys(connector.getWalletProviders()); - - const providerInstances: IProvider[] = availableProviders.map( - (providerName) => { - if (providerName === MASSA_STATION_PROVIDER_NAME) { - return new MassaStationProvider( - connector.getProviderInfo(providerName), - ); - } else { - return new Provider(providerName); - } - }, - ); - return providerInstances; -} - -/** - * Manually register a provider to interact with. - * - * @param name - The name of the provider. - * @param id - The id of the HTML element that is used to communicate with the provider. - */ -export function registerProvider(name: string, id = MASSA_WINDOW_OBJECT): void { - if (typeof document !== 'undefined') { - const registerEvent = new CustomEvent('register', { - detail: { providerName: name }, - }); - const element = document?.getElementById(id); - if (element) { - element.dispatchEvent(registerEvent); - } - } -} - -export async function getProviderByName( - providerName: string, -): Promise { - const providersList = await providers(); - return providersList.find((p) => p.name() === providerName); -} - export { AllowedRequests, AllowedResponses } from './connector'; export { @@ -153,4 +63,6 @@ export { IMassaStationWallet } from './massaStation/MassaStationProvider'; export { MassaStationAccount } from './massaStation/MassaStationAccount'; +export { providers, ProvidersListener } from './providersManager'; + export { connectBearby, disconnectBearby } from './bearbyWallet/BearbyConnect'; diff --git a/src/massaStation/MassaStationAccount.ts b/src/massaStation/MassaStationAccount.ts index fde999ba..9fa9223c 100644 --- a/src/massaStation/MassaStationAccount.ts +++ b/src/massaStation/MassaStationAccount.ts @@ -27,16 +27,6 @@ import { ExecuteFunctionBody } from './types'; */ const MAX_READ_BLOCK_GAS = BigInt(4_294_967_295); -/** - * This interface represents the payload returned by making a call to MassaStation's sign - * operation `/signOperation` url. - */ -interface ISignOperation { - operation: string; - batch?: boolean; - correlationId?: string; -} - /** * This interface represents the the individual wallet's final and pending balances returned by MassaStation */ diff --git a/src/massaStation/MassaStationDiscovery.ts b/src/massaStation/MassaStationDiscovery.ts index b709c7ff..92b4de08 100644 --- a/src/massaStation/MassaStationDiscovery.ts +++ b/src/massaStation/MassaStationDiscovery.ts @@ -1,15 +1,3 @@ -/** - * This file defines a TypeScript class named MassaStationDiscovery. - * The class is being used to recursively search for a connection to MassaStation's server - * and if so report this via emitting messages. - * - * @remarks - * - If you are only looking to use our library, the connector MassaStationDiscovery will not be useful to you. - * - If you want to work on this repo, you will probably be interested in this object - * - */ - -import { EventEmitter } from 'events'; import { getRequest } from './RequestHandler'; import { PluginManagerBody } from './types'; @@ -19,71 +7,24 @@ import { PluginManagerBody } from './types'; export const MASSA_STATION_DISCOVERY_URL = 'https://station.massa/plugin-manager'; -/** - * A message emitted on successful MassaStation discovery - */ -export const ON_MASSA_STATION_DISCOVERED = 'ON_MASSA_STATION_DISCOVERED'; - -/** - * A message emitted on MassaStation disconnect - */ -export const ON_MASSA_STATION_DISCONNECTED = 'ON_MASSA_STATION_DISCONNECTED'; - const MS_WALLET_PLUGIN_NAME = 'Massa Wallet'; const MS_WALLET_PLUGIN_AUTHOR = 'Massa Labs'; -/** - * This file defines a TypeScript class named MassaStation. - * The class is being used to recursively ping MassaStation's server - * and if a response is received emit a message so MassaStation can be enlisted as - * a wallet provider in the `Connector` class. - */ -export class MassaStationDiscovery extends EventEmitter { - private isDiscovered = false; +// timeout +const TIMEOUT = 2000; - /** - * MassaStation constructor - * - * @remarks - * - It creates a timeout using the given `pollIntervalMillis` argument on every trigger of which - * the MassaStation pinging is triggered and if a successful response is fetched, - * a message `ON_MASSA_STATION_DISCOVERED` is emitted that MassaStation has been discovered - * as a wallet provider upon which the `Connector` class will enlist MassaStation as a wallet provider - * - If once found, but then disconnected the following message `ON_MASSA_STATION_DISCONNECTED` is being emitted - * so that the `Connector` class delists MassaStation as a wallet provider - * - * @returns An instance of the MassaStation class. - * - */ - public constructor() { - super(); +export async function isMassaStationInstalled(): Promise { + const response = await getRequest( + MASSA_STATION_DISCOVERY_URL, + TIMEOUT, + ); - this.startListening = this.startListening.bind(this); + if (response.isError) { + return false; } - /** - * A method to start listening for a connection to MassaStation's server. - * - * @returns void - */ - public async startListening(): Promise { - const resp = await getRequest( - MASSA_STATION_DISCOVERY_URL, - 2000, - ); + const isMassaStation = (module) => + module.name === MS_WALLET_PLUGIN_NAME && + module.author === MS_WALLET_PLUGIN_AUTHOR; - if (!resp.isError) { - const walletModule = resp.result.find( - (module) => - module.name === MS_WALLET_PLUGIN_NAME && - module.author === MS_WALLET_PLUGIN_AUTHOR, - ); - if (walletModule) { - this.isDiscovered = true; - this.emit(ON_MASSA_STATION_DISCOVERED, walletModule); - } - } else if (this.isDiscovered) { - this.isDiscovered = false; - this.emit(ON_MASSA_STATION_DISCONNECTED); - } - } + return !!response.result.find(isMassaStation); } diff --git a/src/massaStation/MassaStationProvider.ts b/src/massaStation/MassaStationProvider.ts index d309d2d4..2061e625 100644 --- a/src/massaStation/MassaStationProvider.ts +++ b/src/massaStation/MassaStationProvider.ts @@ -18,7 +18,7 @@ import { import { MassaStationAccount } from './MassaStationAccount'; import { IAccount } from '../account/IAccount'; import { IAccountDetails } from '../account'; -import { PluginInfo, getNetworkInfoBody } from './types'; +import { getNetworkInfoBody } from './types'; import EventEmitter from 'events'; /** @@ -77,14 +77,6 @@ export class MassaStationProvider implements IProvider { private massaStationEventsListener = new EventEmitter(); private currentNetwork: INetwork; - /** - * Provider constructor - * - * @param providerName - The name of the provider. - * @returns An instance of the Provider class. - */ - public constructor(private infos: PluginInfo) {} - /** * This method returns the name of the provider. * @returns The name of the provider. @@ -284,6 +276,29 @@ export class MassaStationProvider implements IProvider { } } + /** + * Returns the chain id of the network MassaStation is connected to. + * + * @throws an error if the call fails. + * + * @returns a Promise that resolves to a chain id. + */ + public async getChainId(): Promise { + try { + const nodesResponse = await getRequest( + `${MASSA_STATION_URL}massa/node`, + ); + if (nodesResponse.isError || nodesResponse.error) { + throw nodesResponse.error.message; + } + const nodes = nodesResponse.result as { chainId: number }; + return BigInt(nodes.chainId); + } catch (ex) { + console.error(`MassaStation nodes retrieval error`, ex); + throw ex; + } + } + /** * This method sends an http call to the MassaStation server to create a new random account. * @@ -314,9 +329,7 @@ export class MassaStationProvider implements IProvider { } } - public listenAccountChanges( - callback: (address: string) => void, - ): { unsubscribe: () => void } | undefined { + public listenAccountChanges(): { unsubscribe: () => void } | undefined { throw new Error( 'listenAccountChanges is not yet implemented for the current provider.', ); diff --git a/src/provider/IProvider.ts b/src/provider/IProvider.ts index b3970f1b..6e58fae1 100644 --- a/src/provider/IProvider.ts +++ b/src/provider/IProvider.ts @@ -24,6 +24,7 @@ export interface IProvider { deleteAccount(address: string): Promise; getNodesUrls(): Promise; getNetwork(): Promise; + getChainId(): Promise; generateNewAccount(name: string): Promise; connect(): Promise; disconnect(): Promise; diff --git a/src/provider/Provider.ts b/src/provider/Provider.ts index 660e61ab..fed817b6 100644 --- a/src/provider/Provider.ts +++ b/src/provider/Provider.ts @@ -170,6 +170,31 @@ export class Provider implements IProvider { }); } + /** + * Returns the chain id of the network the provider is connected to. + * + * @returns a Promise that resolves to the chain id (bigint). + */ + public async getChainId(): Promise { + return new Promise((resolve, reject) => { + connector.sendMessageToContentScript( + this.providerName, + AvailableCommands.ProviderGetChainId, + {}, + (result, err) => { + if (err) return reject(err); + else if (typeof result !== 'number') { + return reject( + new Error(`Expected a number but got ${typeof result} instead`), + ); + } else { + return resolve(BigInt(result)); + } + }, + ); + }); + } + /** * This method generates a new account by a given name and adds it to the wallet. * @@ -191,17 +216,13 @@ export class Provider implements IProvider { }); } - public listenAccountChanges( - callback: (address: string) => void, - ): { unsubscribe: () => void } | undefined { + public listenAccountChanges(): { unsubscribe: () => void } | undefined { throw new Error( 'listenAccountChanges is not yet implemented for the current provider.', ); } - public listenNetworkChanges( - callback: (network: string) => void, - ): { unsubscribe: () => void } | undefined { + public listenNetworkChanges(): { unsubscribe: () => void } | undefined { throw new Error( 'listenNetworkChanges is not yet implemented for the current provider.', ); diff --git a/src/providersManager/ProvidersListener.ts b/src/providersManager/ProvidersListener.ts new file mode 100644 index 00000000..0eed712e --- /dev/null +++ b/src/providersManager/ProvidersListener.ts @@ -0,0 +1,65 @@ +import { IProvider } from '../provider/IProvider'; +import { providers } from './providers'; + +export class ProvidersListener { + private intervalDelay: number; + private intervalId: NodeJS.Timeout | null; + private currentProviders: IProvider[] = []; + + constructor(intervalDelay = 1000) { + this.intervalDelay = intervalDelay; + } + + private async checkForChanges( + callback: (providers: IProvider[]) => void, + ): Promise { + try { + const newProviders = await providers(); + if (this.hasProvidersChanged(newProviders)) { + this.currentProviders = newProviders; + callback(newProviders); + } + } catch (error) { + console.error('Error checking provider changes:', error); + } + } + + private hasProvidersChanged(newProviders: IProvider[]): boolean { + const newProviderNameSet = new Set(newProviders.map((p) => p.name)); + const currentProviderNameSet = new Set( + this.currentProviders.map((p) => p.name), + ); + + if (newProviderNameSet.size !== currentProviderNameSet.size) { + return true; + } + + for (let providerName of newProviderNameSet) { + if (!currentProviderNameSet.has(providerName)) { + return true; + } + } + + return false; + } + + public async subscribe( + callback: (providers: IProvider[]) => void, + ): Promise<{ unsubscribe: () => void }> { + this.currentProviders = await providers(); + callback(this.currentProviders); + + this.intervalId = setInterval( + () => this.checkForChanges(callback), + this.intervalDelay, + ); + + return { + unsubscribe: () => { + if (this.intervalId) { + clearInterval(this.intervalId); + } + }, + }; + } +} diff --git a/src/providersManager/index.ts b/src/providersManager/index.ts new file mode 100644 index 00000000..9eeef35e --- /dev/null +++ b/src/providersManager/index.ts @@ -0,0 +1,2 @@ +export * from './providers'; +export * from './ProvidersListener'; diff --git a/src/providersManager/providerList.ts b/src/providersManager/providerList.ts new file mode 100644 index 00000000..337276b7 --- /dev/null +++ b/src/providersManager/providerList.ts @@ -0,0 +1,27 @@ +import { web3 } from '@hicaru/bearby.js'; +import { BearbyProvider } from '../bearbyWallet/BearbyProvider'; +import { isMassaStationInstalled } from '../massaStation/MassaStationDiscovery'; +import { MassaStationProvider } from '../massaStation/MassaStationProvider'; +import { IProvider } from '../provider/IProvider'; + +export type ProviderList = { + name: string; + checkInstalled: () => Promise; + createInstance: () => IProvider; + isInstalled: boolean; +}; + +export const providerList: ProviderList[] = [ + { + name: 'BEARBY', + checkInstalled: async () => web3.wallet.installed, + createInstance: () => new BearbyProvider(), + isInstalled: false, + }, + { + name: 'MASSA_STATION', + checkInstalled: isMassaStationInstalled, + createInstance: () => new MassaStationProvider(), + isInstalled: false, + }, +]; diff --git a/src/providersManager/providers.ts b/src/providersManager/providers.ts new file mode 100644 index 00000000..707197b3 --- /dev/null +++ b/src/providersManager/providers.ts @@ -0,0 +1,33 @@ +import { Provider } from '../provider/Provider'; +import { connector } from '../connector/Connector'; +import { providerList } from './providerList'; +import { IProvider } from 'src/provider/IProvider'; + +export async function providers(): Promise { + const providerInstances: IProvider[] = []; + + for (const provider of providerList) { + try { + if (await provider.checkInstalled()) { + providerInstances.push(provider.createInstance()); + } + } catch (error) { + console.error(`Error initializing provider ${provider.name}:`, error); + } + } + + providerInstances.push(...addCustomProvider(connector)); + + return providerInstances; +} + +// Custom providers are community provided providers that are not part of the official list. +// But they must implement the wallet provider massa standard. +function addCustomProvider(connector: any): IProvider[] { + const providerInstances: IProvider[] = []; + const availableProviders = Object.keys(connector.getWalletProviders()); + availableProviders.forEach((providerName) => { + providerInstances.push(new Provider(providerName)); + }); + return providerInstances; +} diff --git a/src/utils/time.ts b/src/utils/time.ts index c814e423..0571409e 100644 --- a/src/utils/time.ts +++ b/src/utils/time.ts @@ -102,7 +102,7 @@ export class Interval { * @returns void */ export const wait = async (timeMilli: number): Promise => { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { const timeout = new Timeout(timeMilli, () => { timeout.clear(); return resolve(); diff --git a/test-extension/dapp-vite/main.js b/test-extension/dapp-vite/main.js index abd18f46..744d22e6 100644 --- a/test-extension/dapp-vite/main.js +++ b/test-extension/dapp-vite/main.js @@ -1,10 +1,6 @@ import { providers } from '@massalabs/wallet-provider'; import { Args } from '@massalabs/web3-utils'; (async () => { - console.log(await providers()); - - const delay = (ms) => new Promise((res) => setTimeout(res, ms)); - console.log('[DAPP_HTML] Hello from Dapp! '); let providerList = await providers();