diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index b938e02f..5c315135 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -28,18 +28,7 @@ jobs: with: node-version: ${{ matrix.node-version }} - ## Try getting the node modules from cache, if failed npm ci - - uses: actions/cache@v2 - id: cache-npm - with: - path: node_modules - key: ${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node-${{ matrix.node-version }}-${{ env.cache-name }}- - ${{ runner.OS }}-node-${{ matrix.node-version }}- - - name: Install npm deps - if: steps.cache-npm.outputs.cache-hit != 'true' run: npm ci - name: Commit linting diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index dfcdb9f8..f66e586a 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -25,21 +25,8 @@ jobs: with: node-version: ${{ matrix.node-version }} - ## Try getting the node modules from cache, if failed npm ci - - uses: actions/cache@v2 - id: cache-npm - with: - path: node_modules - key: ${{ runner.os }}-node-${{ matrix.node }}-${{ hashFiles('**/package-lock.json') }} - restore-keys: | - ${{ runner.OS }}-node-${{ matrix.node-version }}-${{ env.cache-name }}- - ${{ runner.OS }}-node-${{ matrix.node-version }}- - - name: Install npm deps - if: steps.cache-npm.outputs.cache-hit != 'true' run: npm ci - name: Run tests run: npm run test - - diff --git a/package-lock.json b/package-lock.json index 7c64f63c..af1390a0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,19 @@ { - "name": "@ethersphere/bee-dashboard", - "version": "0.31.0", + "name": "@upcoming/bee-dashboard", + "version": "0.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "@ethersphere/bee-dashboard", - "version": "0.31.0", + "name": "@upcoming/bee-dashboard", + "version": "0.3.0", "license": "BSD-3-Clause", "dependencies": { - "@ethersphere/bee-js": "^8.3.1", - "@ethersphere/swarm-cid": "^0.1.0", "@fairdatasociety/fdp-storage": "^0.19.0", "@material-ui/core": "4.12.3", "@material-ui/icons": "4.11.2", "@material-ui/lab": "4.0.0-alpha.57", + "@upcoming/bee-js": "^0.16.0", "axios": "^0.28.1", "bignumber.js": "^9.1.2", "buffer": "^6.0.3", @@ -26,7 +25,6 @@ "formik": "2.2.9", "formik-material-ui": "3.0.1", "jszip": "^3.10.1", - "mantaray-js": "^1.0.3", "material-ui-dropzone": "3.5.0", "notistack": "^3.0.1", "opener": "1.5.2", @@ -2437,45 +2435,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@ethersphere/bee-js": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-8.3.1.tgz", - "integrity": "sha512-HIyEzYQmDynFoD0+yXMtNkSBTwdRIKZZs1cZ6H85BAI1eKEXt2dGy+t/IzsUAa5oLq1K7uyoaawaaLZMJqlfrQ==", - "license": "BSD-3-Clause", - "dependencies": { - "axios": "^0.28.1", - "cafe-utility": "^23.10.0", - "elliptic": "^6.5.4", - "isomorphic-ws": "^4.0.1", - "js-sha3": "^0.8.0", - "semver": "^7.3.5", - "ws": "^8.7.0" - }, - "engines": { - "bee": "2.2.0-06a0aca7", - "beeApiVersion": "7.1.0" - } - }, - "node_modules/@ethersphere/bee-js/node_modules/ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@ethersphere/swarm-cid": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@ethersphere/swarm-cid/-/swarm-cid-0.1.0.tgz", @@ -5492,6 +5451,44 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@upcoming/bee-js": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@upcoming/bee-js/-/bee-js-0.16.0.tgz", + "integrity": "sha512-9bxls0mgg7z3U/3MXX2uApj/zWgIOlt0gmngDasdnubQV3zgRg1oF0gHXbU+oEo7wnjxCfk7LeZQxHfSFEcrkg==", + "license": "BSD-3-Clause", + "dependencies": { + "axios": "^0.28.1", + "cafe-utility": "^27.14.0", + "isomorphic-ws": "^4.0.1", + "semver": "^7.3.5", + "ws": "^8.7.0" + }, + "engines": { + "bee": "2.4.0-390a402e", + "beeApiVersion": "7.2.0" + } + }, + "node_modules/@upcoming/bee-js/node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/@vue/compiler-core": { "version": "3.2.21", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.21.tgz", @@ -7041,9 +7038,9 @@ } }, "node_modules/cafe-utility": { - "version": "23.12.0", - "resolved": "https://registry.npmjs.org/cafe-utility/-/cafe-utility-23.12.0.tgz", - "integrity": "sha512-B8MHryv6dDTw8GRfJxHLy4zzhewEEYulPAXiSRqkNCeqXFoQAk8THhlU00Yk7dvc8bppnHoS7FaQ468dfGfe6A==", + "version": "27.14.0", + "resolved": "https://registry.npmjs.org/cafe-utility/-/cafe-utility-27.14.0.tgz", + "integrity": "sha512-NIaYYP5Mr8khnG/Dp/qWdeyKLwj8c8nu5JqMCLApNND9EFsZTXkmtbII4DaZjIiR2yPaQtfj/xvMb9BvC4ZgKQ==", "license": "MIT" }, "node_modules/call-bind": { @@ -8732,11 +8729,6 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, - "node_modules/dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" - }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -10929,17 +10921,6 @@ "node": ">=8.0.0" } }, - "node_modules/get-random-values": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-random-values/-/get-random-values-1.2.2.tgz", - "integrity": "sha512-lMyPjQyl0cNNdDf2oR+IQ/fM3itDvpoHy45Ymo2r0L1EjazeSl13SfbKZs7KtZ/3MDCeueiaJiuOEfKqRTsSgA==", - "dependencies": { - "global": "^4.4.0" - }, - "engines": { - "node": "10 || 12 || >=14" - } - }, "node_modules/get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -11006,15 +10987,6 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "node_modules/global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "dependencies": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -13962,15 +13934,6 @@ "tmpl": "1.0.5" } }, - "node_modules/mantaray-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mantaray-js/-/mantaray-js-1.0.3.tgz", - "integrity": "sha512-ZMQCbrwuFOArtdYKvNd/oS/AnqhvCbldm+UCWQ+HH3Osna1SYBPZcnZpFhSwoNheamNBkhuAoOl9gI8saVRZqg==", - "dependencies": { - "get-random-values": "^1.2.2", - "js-sha3": "^0.8.0" - } - }, "node_modules/material-ui-dropzone": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/material-ui-dropzone/-/material-ui-dropzone-3.5.0.tgz", @@ -14129,14 +14092,6 @@ "node": ">=6" } }, - "node_modules/min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "dependencies": { - "dom-walk": "^0.1.0" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -16446,14 +16401,6 @@ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", "integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==" }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -22375,28 +22322,6 @@ } } }, - "@ethersphere/bee-js": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-8.3.1.tgz", - "integrity": "sha512-HIyEzYQmDynFoD0+yXMtNkSBTwdRIKZZs1cZ6H85BAI1eKEXt2dGy+t/IzsUAa5oLq1K7uyoaawaaLZMJqlfrQ==", - "requires": { - "axios": "^0.28.1", - "cafe-utility": "^23.10.0", - "elliptic": "^6.5.4", - "isomorphic-ws": "^4.0.1", - "js-sha3": "^0.8.0", - "semver": "^7.3.5", - "ws": "^8.7.0" - }, - "dependencies": { - "ws": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", - "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "requires": {} - } - } - }, "@ethersphere/swarm-cid": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/@ethersphere/swarm-cid/-/swarm-cid-0.1.0.tgz", @@ -24503,6 +24428,26 @@ } } }, + "@upcoming/bee-js": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@upcoming/bee-js/-/bee-js-0.16.0.tgz", + "integrity": "sha512-9bxls0mgg7z3U/3MXX2uApj/zWgIOlt0gmngDasdnubQV3zgRg1oF0gHXbU+oEo7wnjxCfk7LeZQxHfSFEcrkg==", + "requires": { + "axios": "^0.28.1", + "cafe-utility": "^27.14.0", + "isomorphic-ws": "^4.0.1", + "semver": "^7.3.5", + "ws": "^8.7.0" + }, + "dependencies": { + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "requires": {} + } + } + }, "@vue/compiler-core": { "version": "3.2.21", "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.21.tgz", @@ -25732,9 +25677,9 @@ "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" }, "cafe-utility": { - "version": "23.12.0", - "resolved": "https://registry.npmjs.org/cafe-utility/-/cafe-utility-23.12.0.tgz", - "integrity": "sha512-B8MHryv6dDTw8GRfJxHLy4zzhewEEYulPAXiSRqkNCeqXFoQAk8THhlU00Yk7dvc8bppnHoS7FaQ468dfGfe6A==" + "version": "27.14.0", + "resolved": "https://registry.npmjs.org/cafe-utility/-/cafe-utility-27.14.0.tgz", + "integrity": "sha512-NIaYYP5Mr8khnG/Dp/qWdeyKLwj8c8nu5JqMCLApNND9EFsZTXkmtbII4DaZjIiR2yPaQtfj/xvMb9BvC4ZgKQ==" }, "call-bind": { "version": "1.0.2", @@ -27040,11 +26985,6 @@ "entities": "^2.0.0" } }, - "dom-walk": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", - "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" - }, "domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -28675,14 +28615,6 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, - "get-random-values": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-random-values/-/get-random-values-1.2.2.tgz", - "integrity": "sha512-lMyPjQyl0cNNdDf2oR+IQ/fM3itDvpoHy45Ymo2r0L1EjazeSl13SfbKZs7KtZ/3MDCeueiaJiuOEfKqRTsSgA==", - "requires": { - "global": "^4.4.0" - } - }, "get-stream": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", @@ -28728,15 +28660,6 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "global": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", - "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", - "requires": { - "min-document": "^2.19.0", - "process": "^0.11.10" - } - }, "global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -30977,15 +30900,6 @@ "tmpl": "1.0.5" } }, - "mantaray-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/mantaray-js/-/mantaray-js-1.0.3.tgz", - "integrity": "sha512-ZMQCbrwuFOArtdYKvNd/oS/AnqhvCbldm+UCWQ+HH3Osna1SYBPZcnZpFhSwoNheamNBkhuAoOl9gI8saVRZqg==", - "requires": { - "get-random-values": "^1.2.2", - "js-sha3": "^0.8.0" - } - }, "material-ui-dropzone": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/material-ui-dropzone/-/material-ui-dropzone-3.5.0.tgz", @@ -31100,14 +31014,6 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, - "min-document": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", - "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", - "requires": { - "dom-walk": "^0.1.0" - } - }, "min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -32663,11 +32569,6 @@ "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.25.0.tgz", "integrity": "sha512-WCjJHl1KEWbnkQom1+SzftbtXMKQoezOCYs5rECqMN+jP+apI7ftoflyqigqzopSO3hMhTEb0mFClA8lkolgEg==" }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", diff --git a/package.json b/package.json index 8e3dfe3d..a7ff42a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "@ethersphere/bee-dashboard", - "version": "0.31.0", + "name": "@upcoming/bee-dashboard", + "version": "0.3.0", "description": "An app which helps users to setup their Bee node and do actions like cash out cheques", "keywords": [ "bee", @@ -26,12 +26,11 @@ "url": "https://github.com/ethersphere/bee-dashboard.git" }, "dependencies": { - "@ethersphere/bee-js": "^8.3.1", - "@ethersphere/swarm-cid": "^0.1.0", "@fairdatasociety/fdp-storage": "^0.19.0", "@material-ui/core": "4.12.3", "@material-ui/icons": "4.11.2", "@material-ui/lab": "4.0.0-alpha.57", + "@upcoming/bee-js": "^0.16.0", "axios": "^0.28.1", "bignumber.js": "^9.1.2", "buffer": "^6.0.3", @@ -43,7 +42,6 @@ "formik": "2.2.9", "formik-material-ui": "3.0.1", "jszip": "^3.10.1", - "mantaray-js": "^1.0.3", "material-ui-dropzone": "3.5.0", "notistack": "^3.0.1", "opener": "1.5.2", diff --git a/src/App.tsx b/src/App.tsx index 41125eec..ad3541d4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,6 @@ import { Provider as PlatformProvider } from './providers/Platform' import { Provider as SettingsProvider } from './providers/Settings' import { Provider as StampsProvider } from './providers/Stamps' import { Provider as TopUpProvider } from './providers/TopUp' -import { Provider as BalanceProvider } from './providers/WalletBalance' import BaseRouter from './routes' import { theme } from './theme' @@ -45,26 +44,24 @@ const App = ({ > - - - - - - - - <> - - - - - - - - - - - - + + + + + + + <> + + + + + + + + + + + diff --git a/src/components/CashoutModal.tsx b/src/components/CashoutModal.tsx index 28eaaf18..582f97ff 100644 --- a/src/components/CashoutModal.tsx +++ b/src/components/CashoutModal.tsx @@ -9,7 +9,6 @@ import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' import Zap from 'remixicon-react/FlashlightLineIcon' import { Context as SettingsContext } from '../providers/Settings' -import EthereumAddress from './EthereumAddress' interface Props { peerId: string @@ -37,13 +36,9 @@ export default function CheckoutModal({ peerId, uncashedAmount }: Props): ReactE .cashoutLastCheque(peerId) .then(res => { setOpen(false) - enqueueSnackbar( - - Successfully cashed out cheque. Transaction - - , - { variant: 'success' }, - ) + enqueueSnackbar(Successfully cashed out cheque. Transaction {res.toHex()}, { + variant: 'success', + }) }) .catch((e: Error) => { console.error(e) // eslint-disable-line diff --git a/src/components/ChainSync.tsx b/src/components/ChainSync.tsx index 62f44e7a..d97eadf6 100644 --- a/src/components/ChainSync.tsx +++ b/src/components/ChainSync.tsx @@ -1,4 +1,4 @@ -import { ChainState } from '@ethersphere/bee-js' +import { ChainState } from '@upcoming/bee-js' import { useContext, useEffect, useState } from 'react' import { Context } from '../providers/Settings' import ExpandableListItem from './ExpandableListItem' diff --git a/src/components/EthereumAddress.tsx b/src/components/EthereumAddress.tsx index 43f73aed..c79390ef 100644 --- a/src/components/EthereumAddress.tsx +++ b/src/components/EthereumAddress.tsx @@ -1,5 +1,5 @@ -import { Utils } from '@ethersphere/bee-js' import { Typography } from '@material-ui/core/' +import { EthAddress } from '@upcoming/bee-js' import { ReactElement } from 'react' import Identicon from 'react-identicons' import { BLOCKCHAIN_EXPLORER_URL } from '../constants' @@ -8,7 +8,7 @@ import { Flex } from './Flex' import QRCodeModal from './QRCodeModal' interface Props { - address: string | undefined + address: EthAddress | undefined hideBlockie?: boolean transaction?: boolean truncate?: boolean @@ -21,7 +21,7 @@ export default function EthereumAddress(props: Props): ReactElement { {props.hideBlockie ? null : (
- +
)}
@@ -45,8 +45,8 @@ export default function EthereumAddress(props: Props): ReactElement { {props.address}
- - + +
) : ( '-' diff --git a/src/components/Map.tsx b/src/components/Map.tsx index 43f23231..d6b6dcc6 100644 --- a/src/components/Map.tsx +++ b/src/components/Map.tsx @@ -1,4 +1,4 @@ -import type { Peer } from '@ethersphere/bee-js' +import type { Peer } from '@upcoming/bee-js' import DottedMap, { DottedMapWithoutCountriesLib } from 'dotted-map/without-countries' import { CSSProperties, ReactElement, useContext, useEffect, useState } from 'react' import mapData from '../assets/data/map-data.json' diff --git a/src/components/SideBar.tsx b/src/components/SideBar.tsx index 7b41529c..e3b2f4a3 100644 --- a/src/components/SideBar.tsx +++ b/src/components/SideBar.tsx @@ -1,6 +1,6 @@ -import { BeeModes } from '@ethersphere/bee-js' import { Box, Divider, Drawer, Grid, List, Link as MUILink, Typography } from '@material-ui/core' import { Theme, createStyles, makeStyles } from '@material-ui/core/styles' +import { BeeModes } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import { Link } from 'react-router-dom' import FilesIcon from 'remixicon-react/ArrowUpDownLineIcon' diff --git a/src/components/StampExtensionModal.tsx b/src/components/StampExtensionModal.tsx index c71d83db..8a7fe98f 100644 --- a/src/components/StampExtensionModal.tsx +++ b/src/components/StampExtensionModal.tsx @@ -1,4 +1,3 @@ -import { Bee } from '@ethersphere/bee-js' import { Box } from '@material-ui/core' import Button from '@material-ui/core/Button' import Dialog from '@material-ui/core/Dialog' @@ -6,6 +5,7 @@ import DialogActions from '@material-ui/core/DialogActions' import DialogContent from '@material-ui/core/DialogContent' import DialogTitle from '@material-ui/core/DialogTitle' import Input from '@material-ui/core/Input' +import { BatchId, Bee } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, ReactNode, useState } from 'react' @@ -13,14 +13,14 @@ interface Props { type: 'Topup' | 'Dilute' icon: ReactNode bee: Bee - stamp: string + stamp: BatchId } export default function StampExtensionModal({ type, icon, bee, stamp }: Props): ReactElement { const [open, setOpen] = useState(false) const [amount, setAmount] = useState('') const { enqueueSnackbar } = useSnackbar() - const label = `${type} ${stamp.substring(0, 8)}` + const label = `${type} ${stamp.toHex().substring(0, 8)}` const handleClickOpen = (e: React.MouseEvent) => { setOpen(true) diff --git a/src/components/TopologyStats.tsx b/src/components/TopologyStats.tsx index 5fe14f1d..11e2c5d5 100644 --- a/src/components/TopologyStats.tsx +++ b/src/components/TopologyStats.tsx @@ -1,4 +1,4 @@ -import type { Topology } from '@ethersphere/bee-js' +import type { Topology } from '@upcoming/bee-js' import type { ReactElement } from 'react' import { pickThreshold, ThresholdValues } from '../utils/threshold' import ExpandableListItem from './ExpandableListItem' diff --git a/src/components/WithdrawDepositModal.tsx b/src/components/WithdrawDepositModal.tsx index 2401a875..2a49d557 100644 --- a/src/components/WithdrawDepositModal.tsx +++ b/src/components/WithdrawDepositModal.tsx @@ -1,24 +1,23 @@ -import { ReactElement, ReactNode, useState } from 'react' import Button from '@material-ui/core/Button' -import Input from '@material-ui/core/Input' import Dialog from '@material-ui/core/Dialog' import DialogActions from '@material-ui/core/DialogActions' import DialogContent from '@material-ui/core/DialogContent' import DialogContentText from '@material-ui/core/DialogContentText' import DialogTitle from '@material-ui/core/DialogTitle' import FormHelperText from '@material-ui/core/FormHelperText' -import { Token } from '../models/Token' -import type { BigNumber } from 'bignumber.js' +import Input from '@material-ui/core/Input' +import { BZZ, TransactionId } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' +import { ReactElement, ReactNode, useState } from 'react' interface Props { successMessage: string errorMessage: string dialogMessage: string label: string - max?: BigNumber - min?: BigNumber - action: (amount: bigint) => Promise + max?: BZZ + min?: BZZ + action: (amount: BZZ) => Promise icon?: ReactNode } @@ -34,7 +33,7 @@ export default function WithdrawDepositModal({ }: Props): ReactElement { const [open, setOpen] = useState(false) const [amount, setAmount] = useState('') - const [amountToken, setAmountToken] = useState(null) + const [amountToken, setAmountToken] = useState(null) const [amountError, setAmountError] = useState(null) const { enqueueSnackbar } = useSnackbar() @@ -51,7 +50,7 @@ export default function WithdrawDepositModal({ if (amountToken === null) return try { - const transactionHash = await action(amountToken.toBigInt as bigint) + const transactionHash = await action(amountToken) setOpen(false) enqueueSnackbar(`${successMessage} Transaction ${transactionHash}`, { variant: 'success' }) } catch (e) { @@ -65,12 +64,12 @@ export default function WithdrawDepositModal({ setAmount(value) setAmountError(null) try { - const t = Token.fromDecimal(value) + const t = BZZ.fromDecimalString(value) setAmountToken(t) - if (min && t.toDecimal.isLessThan(min)) setAmountError(new Error(`Needs to be more than ${min}`)) + if (min && t.lt(min)) setAmountError(new Error(`Needs to be more than ${min.toSignificantDigits(4)}`)) - if (max && t.toDecimal.isGreaterThan(max)) setAmountError(new Error(`Needs to be less than ${max}`)) + if (max && t.gt(max)) setAmountError(new Error(`Needs to be less than ${max.toSignificantDigits(4)}`)) } catch (e) { setAmountError(e as Error) } diff --git a/src/containers/DepositModal.tsx b/src/containers/DepositModal.tsx index 31ba6b06..93a617b3 100644 --- a/src/containers/DepositModal.tsx +++ b/src/containers/DepositModal.tsx @@ -1,4 +1,4 @@ -import { BigNumber } from 'bignumber.js' +import { BZZ } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import Download from 'remixicon-react/DownloadLineIcon' import WithdrawDepositModal from '../components/WithdrawDepositModal' @@ -16,13 +16,13 @@ export default function DepositModal(): ReactElement { dialogMessage="Amount of xBZZ to deposit to the checkbook, from your node." label="Deposit" icon={} - min={new BigNumber(0)} - action={async (amount: bigint) => { + min={BZZ.fromPLUR('1')} + action={async (amount: BZZ) => { if (!beeApi) { throw new Error('Bee URL is not valid') } - const transactionHash = await beeApi.depositTokens(amount.toString()) + const transactionHash = await beeApi.depositTokens(amount) refresh() return transactionHash diff --git a/src/containers/StakeModal.tsx b/src/containers/StakeModal.tsx index 6af30520..2a7725b0 100644 --- a/src/containers/StakeModal.tsx +++ b/src/containers/StakeModal.tsx @@ -1,4 +1,4 @@ -import { BigNumber } from 'bignumber.js' +import { BZZ } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import Download from 'remixicon-react/DownloadLineIcon' import WithdrawDepositModal from '../components/WithdrawDepositModal' @@ -21,8 +21,8 @@ export default function StakeModal({ onStarted, onFinished }: Props): ReactEleme dialogMessage="Specify the amount of xBZZ you would like to stake. Your first stake must be at least 10 xBZZ. This will lock your tokens." label="Stake" icon={} - min={new BigNumber(0)} - action={async (amount: bigint) => { + min={BZZ.fromPLUR('1')} + action={async (amount: BZZ) => { if (!beeApi) { throw new Error('Bee URL is not valid') } @@ -30,13 +30,13 @@ export default function StakeModal({ onStarted, onFinished }: Props): ReactEleme onStarted() try { - await beeApi.depositStake(amount.toString()) + const transactionHash = await beeApi.depositStake(amount) + + return transactionHash } finally { refresh() onFinished() } - - return 'unknown' }} /> ) diff --git a/src/containers/WithdrawModal.tsx b/src/containers/WithdrawModal.tsx index 94ed0c08..30eb5529 100644 --- a/src/containers/WithdrawModal.tsx +++ b/src/containers/WithdrawModal.tsx @@ -1,4 +1,4 @@ -import { BigNumber } from 'bignumber.js' +import { BZZ } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import Upload from 'remixicon-react/UploadLineIcon' import WithdrawDepositModal from '../components/WithdrawDepositModal' @@ -16,13 +16,13 @@ export default function WithdrawModal(): ReactElement { dialogMessage="Amount of xBZZ to withdraw from the checkbook to your node." label="Withdraw" icon={} - min={new BigNumber(0)} - action={async (amount: bigint) => { + min={BZZ.fromPLUR('1')} + action={async (amount: BZZ) => { if (!beeApi) { throw new Error('Bee URL is not valid') } - const transactionHash = await beeApi.withdrawTokens(amount.toString()) + const transactionHash = await beeApi.withdrawTokens(amount) refresh() return transactionHash diff --git a/src/hooks/accounting.ts b/src/hooks/accounting.ts index c379621b..d005ebcf 100644 --- a/src/hooks/accounting.ts +++ b/src/hooks/accounting.ts @@ -1,22 +1,20 @@ -import { Bee, LastCashoutActionResponse } from '@ethersphere/bee-js' +import { AllSettlements, Bee, BZZ, LastCashoutActionResponse, PeerBalance, Settlements } from '@upcoming/bee-js' import { useEffect, useState } from 'react' -import { Token } from '../models/Token' -import { Balance, Settlement, Settlements } from '../types' import { makeRetriablePromise, unwrapPromiseSettlements } from '../utils' interface UseAccountingHook { isLoadingUncashed: boolean - totalUncashed: Token + totalUncashed: BZZ accounting: Accounting[] | null } export interface Accounting { peer: string - uncashedAmount: Token - balance: Token - received: Token - sent: Token - total: Token + uncashedAmount: BZZ + balance: BZZ + received: BZZ + sent: BZZ + total: BZZ } /** @@ -29,8 +27,8 @@ export interface Accounting { * @returns */ function mergeAccounting( - balances: Balance[] | null, - settlements?: Settlement[], + balances: PeerBalance[] | null, + settlements?: Settlements[], uncashedAmounts?: LastCashoutActionResponse[], ): Accounting[] | null { // Settlements or balances are still loading or there is an error -> return null @@ -44,9 +42,9 @@ function mergeAccounting( (accounting[peer] = { peer, balance, - sent: new Token('0'), - received: new Token('0'), - uncashedAmount: new Token('0'), + sent: BZZ.fromPLUR('0'), + received: BZZ.fromPLUR('0'), + uncashedAmount: BZZ.fromPLUR('0'), total: balance, }), ) @@ -57,7 +55,7 @@ function mergeAccounting( ...accounting[peer], sent, received, - total: new Token(accounting[peer].balance.toBigNumber.plus(received.toBigNumber).minus(sent.toBigNumber)), + total: accounting[peer].balance.plus(received).minus(sent), }), ) @@ -65,14 +63,16 @@ function mergeAccounting( if (!uncashedAmounts) return Object.values(accounting).sort((a, b) => (a.peer < b.peer ? -1 : 1)) uncashedAmounts?.forEach(({ peer, uncashedAmount }) => { - accounting[peer].uncashedAmount = new Token(uncashedAmount) + accounting[peer].uncashedAmount = uncashedAmount }) // Return sorted by the uncashed amount first and then by the peer id return Object.values(accounting).sort((a, b) => { - const diff = b.uncashedAmount.toBigNumber.minus(a.uncashedAmount.toBigNumber).toNumber() + const diff = Number(b.uncashedAmount.minus(a.uncashedAmount)) - if (diff !== 0) return diff + if (diff !== 0) { + return diff + } return a.peer < b.peer ? -1 : 1 }) @@ -80,8 +80,8 @@ function mergeAccounting( export const useAccounting = ( beeApi: Bee | null, - settlements: Settlements | null, - balances: Balance[] | null, + settlements: AllSettlements | null, + balances: PeerBalance[] | null, ): UseAccountingHook => { const [isLoadingUncashed, setIsloadingUncashed] = useState(false) const [uncashedAmounts, setUncashedAmounts] = useState(undefined) @@ -92,7 +92,7 @@ export const useAccounting = ( setIsloadingUncashed(true) const promises = settlements.settlements - .filter(({ received }) => received.toBigNumber.gt('0')) + .filter(({ received }) => received.gt(BZZ.fromPLUR('0'))) .map(({ peer }) => makeRetriablePromise(() => beeApi.getLastCashoutAction(peer))) Promise.allSettled(promises).then(settlements => { @@ -104,10 +104,8 @@ export const useAccounting = ( const accounting = mergeAccounting(balances, settlements?.settlements, uncashedAmounts) - let totalUncashed: Token = new Token('0') - accounting?.forEach( - ({ uncashedAmount }) => (totalUncashed = new Token(totalUncashed.toBigNumber.plus(uncashedAmount.toBigNumber))), - ) + let totalUncashed = BZZ.fromPLUR('0') + accounting?.forEach(({ uncashedAmount }) => (totalUncashed = totalUncashed.plus(uncashedAmount))) return { isLoadingUncashed, diff --git a/src/models/BzzToken.ts b/src/models/BzzToken.ts deleted file mode 100644 index 2249480b..00000000 --- a/src/models/BzzToken.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BigNumber } from 'bignumber.js' -import { Token } from './Token' - -export const BZZ_DECIMAL_PLACES = 16 - -export class BzzToken extends Token { - constructor(value: BigNumber | string | bigint) { - super(value, BZZ_DECIMAL_PLACES) - } - - static fromDecimal(value: BigNumber | string | bigint): BzzToken { - return Token.fromDecimal(value, BZZ_DECIMAL_PLACES) - } -} diff --git a/src/models/DaiToken.ts b/src/models/DaiToken.ts deleted file mode 100644 index 65fb7854..00000000 --- a/src/models/DaiToken.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { BigNumber } from 'bignumber.js' -import { Token } from './Token' - -const DAI_DECIMAL_PLACES = 18 - -export class DaiToken extends Token { - constructor(value: BigNumber | string | bigint) { - super(value, DAI_DECIMAL_PLACES) - } - - static fromDecimal(value: BigNumber | string | bigint): DaiToken { - return Token.fromDecimal(value, DAI_DECIMAL_PLACES) - } -} diff --git a/src/models/Token.test.ts b/src/models/Token.test.ts deleted file mode 100644 index 55abe413..00000000 --- a/src/models/Token.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import BigNumber from 'bignumber.js' -import { Token } from './Token' - -describe('models/Token', () => { - describe('Token.fromDecimal', () => { - const values = [ - { bzz: '0', baseUnits: '0' }, - { bzz: '0.1', baseUnits: BigInt('1000000000000000') }, - { bzz: '9.9', baseUnits: BigInt('99000000000000000') }, - ] - - // Test with default 16 decimal places - values.forEach(({ bzz, baseUnits }) => { - test(`converting ${bzz} => ${baseUnits}`, () => { - expect(Token.fromDecimal(bzz).toBigNumber.eq(baseUnits.toString())).toBe(true) - }) - }) - - // Test with 0 decimal places - values.forEach(({ baseUnits }) => { - test(`converting ${baseUnits} => ${baseUnits} with 0 decimals`, () => { - expect(Token.fromDecimal(baseUnits, 0).toBigNumber.eq(baseUnits.toString())).toBe(true) - }) - }) - }) - - describe('new Token', () => { - const cs = ['0', '1234567890', '99000000000000000'] - const correctValues = [...cs, ...cs.map(BigInt), ...cs.map(v => new BigNumber(v))] - - correctValues.forEach(v => { - test(`New Token ${v} of type ${typeof v}`, () => { - const t = new Token(v) - - expect(t.toBigNumber.eq(v.toString())).toBe(true) - }) - }) - }) -}) diff --git a/src/models/Token.ts b/src/models/Token.ts deleted file mode 100644 index 48806c8e..00000000 --- a/src/models/Token.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { BigNumber } from 'bignumber.js' -import { isInteger, makeBigNumber } from '../utils' - -const POSSIBLE_DECIMALS = [18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0] -type digits = typeof POSSIBLE_DECIMALS[number] - -const BZZ_DECIMALS = 16 - -export class Token { - private amount: BigNumber // Represented in the base units, so it is always an integer value - private readonly decimals: digits - - constructor(amount: BigNumber | string | bigint, decimals: digits = BZZ_DECIMALS) { - const a = makeBigNumber(amount) - - if (!isInteger(a) || !POSSIBLE_DECIMALS.includes(decimals)) { - throw new TypeError(`Not a valid token values: ${amount} ${decimals}`) - } - - this.amount = a - this.decimals = decimals - } - - /** - * Construct new Token from a digit representation - * - * @param amount Amount of a token in the digits (1 token = 10^decimals) - * @param decimals Number of decimals for the token (must be integer) - * - * @throws {TypeError} If the decimals is not an integer or the amount after conversion is not an integer - * - * @returns new Token - */ - static fromDecimal(amount: BigNumber | string | bigint, decimals: digits = BZZ_DECIMALS): Token | never { - const a = makeBigNumber(amount) - - // No need to do any validation here, it is done when the new token is created - const t = a.multipliedBy(new BigNumber(10).pow(decimals)) - - return new Token(t, decimals) - } - - get toBigInt(): bigint { - return BigInt(this.amount.toFixed(0)) - } - - get toString(): string { - return this.amount.toFixed(0) - } - - get toBigNumber(): BigNumber { - return new BigNumber(this.amount) - } - - get toDecimal(): BigNumber { - return this.amount.dividedBy(new BigNumber(10).pow(this.decimals)) - } - - toFixedDecimal(digits = 7): string { - return this.toDecimal.toFixed(digits) - } - - toSignificantDigits(digits = 4): string { - const asString = this.toDecimal.toFixed(this.decimals) - - let indexOfSignificantDigit = -1 - let reachedDecimalPoint = false - - for (let i = 0; i < asString.length; i++) { - const char = asString[i] - - if (char === '.') { - reachedDecimalPoint = true - indexOfSignificantDigit = i + 1 - } else if (reachedDecimalPoint && char !== '0') { - indexOfSignificantDigit = i - break - } - } - - return asString.slice(0, indexOfSignificantDigit + digits) - } - - minusBaseUnits(amount: string | BigNumber | bigint): Token { - const baseUnits = makeBigNumber(amount) - - return new Token( - this.toBigNumber.minus(baseUnits.multipliedBy(new BigNumber(10).pow(this.decimals))), - this.decimals, - ) - } - - plusBaseUnits(amount: string | BigNumber | bigint): Token { - const baseUnits = makeBigNumber(amount) - - return new Token(this.toBigNumber.plus(baseUnits.multipliedBy(new BigNumber(10).pow(this.decimals))), this.decimals) - } -} diff --git a/src/pages/account/AccountNavigation.tsx b/src/pages/account/AccountNavigation.tsx index e7394b94..b06761b3 100644 --- a/src/pages/account/AccountNavigation.tsx +++ b/src/pages/account/AccountNavigation.tsx @@ -1,5 +1,5 @@ -import { BeeModes } from '@ethersphere/bee-js' import { createStyles, makeStyles, Tab, Tabs, Theme } from '@material-ui/core' +import { BeeModes } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import { useNavigate } from 'react-router-dom' import { Context } from '../../providers/Bee' diff --git a/src/pages/account/chequebook/AccountChequebook.tsx b/src/pages/account/chequebook/AccountChequebook.tsx index 740adac8..151ab9dc 100644 --- a/src/pages/account/chequebook/AccountChequebook.tsx +++ b/src/pages/account/chequebook/AccountChequebook.tsx @@ -1,4 +1,3 @@ -import { Utils } from '@ethersphere/bee-js' import { Box } from '@material-ui/core' import { ReactElement, useContext } from 'react' import ExpandableList from '../../../components/ExpandableList' @@ -35,20 +34,20 @@ export function AccountChequebook(): ReactElement { @@ -60,7 +59,7 @@ export function AccountChequebook(): ReactElement { - + {x.feedHash && } diff --git a/src/pages/account/staking/AccountStaking.tsx b/src/pages/account/staking/AccountStaking.tsx index 451c9494..45c0c227 100644 --- a/src/pages/account/staking/AccountStaking.tsx +++ b/src/pages/account/staking/AccountStaking.tsx @@ -5,16 +5,14 @@ import ExpandableListItemActions from '../../../components/ExpandableListItemAct import { Loading } from '../../../components/Loading' import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard' import StakeModal from '../../../containers/StakeModal' -import { CheckState, Context as BeeContext } from '../../../providers/Bee' -import { Context as BalanceContext } from '../../../providers/WalletBalance' +import { Context as BeeContext, CheckState } from '../../../providers/Bee' import { AccountNavigation } from '../AccountNavigation' import { Header } from '../Header' export function AccountStaking(): ReactElement { const [loading, setLoading] = useState(false) - const { status, stake } = useContext(BeeContext) - const { balance } = useContext(BalanceContext) + const { status, stake, walletBalance } = useContext(BeeContext) if (status.all === CheckState.ERROR) return @@ -31,15 +29,15 @@ export function AccountStaking(): ReactElement {
- {loading || stake?.toDecimal === undefined ? ( + {loading || !stake ? ( ) : ( - - {balance?.bzz ? ( + + {walletBalance?.bzzBalance ? ( ) : null} diff --git a/src/pages/account/wallet/AccountWallet.tsx b/src/pages/account/wallet/AccountWallet.tsx index 62af0fc7..d504741c 100644 --- a/src/pages/account/wallet/AccountWallet.tsx +++ b/src/pages/account/wallet/AccountWallet.tsx @@ -1,5 +1,5 @@ -import { BeeModes, Utils } from '@ethersphere/bee-js' import { Box, Grid, Typography } from '@material-ui/core' +import { BeeModes } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import { useNavigate } from 'react-router' import Download from 'remixicon-react/DownloadLineIcon' @@ -13,15 +13,13 @@ import { SwarmButton } from '../../../components/SwarmButton' import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard' import { Context as BeeContext, CheckState } from '../../../providers/Bee' import { Context as SettingsContext } from '../../../providers/Settings' -import { Context as BalanceProvider } from '../../../providers/WalletBalance' import { ROUTES } from '../../../routes' import { AccountNavigation } from '../AccountNavigation' import { Header } from '../Header' export function AccountWallet(): ReactElement { - const { nodeAddresses, nodeInfo, status } = useContext(BeeContext) + const { nodeAddresses, nodeInfo, status, walletBalance } = useContext(BeeContext) const { isDesktop } = useContext(SettingsContext) - const { balance } = useContext(BalanceProvider) const navigate = useNavigate() @@ -53,20 +51,22 @@ export function AccountWallet(): ReactElement { )} - {balance && nodeAddresses ? ( + {walletBalance && nodeAddresses ? ( <> - + - + - + ) : ( diff --git a/src/pages/accounting/PeerBalances.tsx b/src/pages/accounting/PeerBalances.tsx index 130d011b..f281fba2 100644 --- a/src/pages/accounting/PeerBalances.tsx +++ b/src/pages/accounting/PeerBalances.tsx @@ -1,3 +1,4 @@ +import { BZZ } from '@upcoming/bee-js' import type { ReactElement } from 'react' import CashoutModal from '../../components/CashoutModal' import ExpandableList from '../../components/ExpandableList' @@ -5,44 +6,43 @@ import ExpandableListItem from '../../components/ExpandableListItem' import ExpandableListItemActions from '../../components/ExpandableListItemActions' import ExpandableListItemKey from '../../components/ExpandableListItemKey' import { Accounting } from '../../hooks/accounting' -import type { Token } from '../../models/Token' interface Props { isLoadingUncashed: boolean - totalUncashed: Token + totalUncashed: BZZ accounting: Accounting[] | null } export default function PeerBalances({ accounting, isLoadingUncashed, totalUncashed }: Props): ReactElement | null { - const uncashedPeers = accounting?.filter(({ uncashedAmount }) => uncashedAmount.toBigNumber.isGreaterThan('0')) || [] + const uncashedPeers = accounting?.filter(({ uncashedAmount }) => uncashedAmount.gt(BZZ.fromPLUR('0'))) || [] return ( - + {uncashedPeers.map(({ peer, balance, received, sent, uncashedAmount, total }) => ( - + - + - {uncashedAmount.toBigNumber.isGreaterThan('0') && ( + {uncashedAmount.gt(BZZ.fromPLUR('0')) && ( - + )} diff --git a/src/pages/fdp/index.tsx b/src/pages/fdp/index.tsx index c388ddc2..15ae2b4d 100644 --- a/src/pages/fdp/index.tsx +++ b/src/pages/fdp/index.tsx @@ -1,14 +1,13 @@ -import { Bee } from '@ethersphere/bee-js' import { FdpStorage } from '@fairdatasociety/fdp-storage' import { Pod } from '@fairdatasociety/fdp-storage/dist/pod/types' import { CircularProgress, Typography } from '@material-ui/core' +import { Bee, MantarayNode } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, useEffect, useState } from 'react' import ImportIcon from 'remixicon-react/AddBoxLineIcon' import PlusCircle from 'remixicon-react/AddCircleLineIcon' import { SwarmButton } from '../../components/SwarmButton' import { joinUrl } from '../../react-fs/Utility' -import { ManifestJs } from '../../utils/manifest' import { FdpLogin } from './FdpLogin' import { FdpPods } from './FdpPods' import { Horizontal } from './Horizontal' @@ -25,7 +24,9 @@ async function makeFdp(): Promise { return null } - return new FdpStorage('http://localhost:1633', highestCapacityBatch.batchID, { + // TODO: FDS has bad types + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return new FdpStorage('http://localhost:1633', highestCapacityBatch.batchID.toHex() as any, { ensOptions: { rpcUrl: sepolia, contractAddresses: { @@ -120,11 +121,16 @@ export default function FDP(): ReactElement { } setCreatingPod(true) const bee = new Bee('http://localhost:1633') - const manifestJs = new ManifestJs(bee) - const entries = await manifestJs.getHashes(importHash) + const manifest = await MantarayNode.unmarshal(bee, importHash) + await manifest.loadRecursively(bee) + const nodes = manifest.collect() await fdp.personalStorage.create(name) - for (const [path, hash] of Object.entries(entries)) { - await fdp.file.uploadData(name, joinUrl('/', path), await bee.downloadData(hash)) + for (const node of nodes) { + await fdp.file.uploadData( + name, + joinUrl('/', node.fullPathString), + (await bee.downloadData(node.targetAddress)).toUint8Array(), + ) } const pods = await fdp.personalStorage.list() setPods(pods.pods) diff --git a/src/pages/feeds/CreateNewFeed.tsx b/src/pages/feeds/CreateNewFeed.tsx index fb81db2c..3196fff4 100644 --- a/src/pages/feeds/CreateNewFeed.tsx +++ b/src/pages/feeds/CreateNewFeed.tsx @@ -1,4 +1,5 @@ import { Box, Grid, Typography } from '@material-ui/core' +import { NULL_TOPIC } from '@upcoming/bee-js' import { Form, Formik } from 'formik' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' @@ -108,7 +109,7 @@ export default function CreateNewFeed(): ReactElement { {values.type === 'V3' && } - + diff --git a/src/pages/feeds/UpdateFeed.tsx b/src/pages/feeds/UpdateFeed.tsx index bf108e53..bfc33306 100644 --- a/src/pages/feeds/UpdateFeed.tsx +++ b/src/pages/feeds/UpdateFeed.tsx @@ -122,7 +122,7 @@ export default function UpdateFeed(): ReactElement { {stamps ? ( ({ value: x.batchID, label: x.batchID.slice(0, 8) }))} + options={stamps.map(x => ({ value: x.batchID.toHex(), label: x.batchID.toHex().slice(0, 8) }))} onChange={onStampChange} label="Stamp" /> diff --git a/src/pages/feeds/index.tsx b/src/pages/feeds/index.tsx index a8dada40..389a08f9 100644 --- a/src/pages/feeds/index.tsx +++ b/src/pages/feeds/index.tsx @@ -1,18 +1,19 @@ import { Box, Typography } from '@material-ui/core' +import { NULL_TOPIC } from '@upcoming/bee-js' import { ReactElement, useContext, useState } from 'react' -import Download from 'remixicon-react/DownloadLineIcon' +import { useNavigate } from 'react-router' import PlusSquare from 'remixicon-react/AddBoxLineIcon' -import Info from 'remixicon-react/InformationLineIcon' import Trash from 'remixicon-react/DeleteBin7LineIcon' -import { useNavigate } from 'react-router' +import Download from 'remixicon-react/DownloadLineIcon' +import Info from 'remixicon-react/InformationLineIcon' import ExpandableList from '../../components/ExpandableList' import ExpandableListItem from '../../components/ExpandableListItem' import ExpandableListItemActions from '../../components/ExpandableListItemActions' import ExpandableListItemKey from '../../components/ExpandableListItemKey' import { SwarmButton } from '../../components/SwarmButton' import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard' -import { CheckState, Context as BeeContext } from '../../providers/Bee' -import { Context as IdentityContext, Identity } from '../../providers/Feeds' +import { Context as BeeContext, CheckState } from '../../providers/Bee' +import { Identity, Context as IdentityContext } from '../../providers/Feeds' import { ROUTES } from '../../routes' import { formatEnum } from '../../utils' import { persistIdentitiesWithoutUpdate } from '../../utils/identity' @@ -97,7 +98,7 @@ export default function Feeds(): ReactElement { - + {x.feedHash && } diff --git a/src/pages/files/AssetSummary.tsx b/src/pages/files/AssetSummary.tsx index 54249905..9a980c4a 100644 --- a/src/pages/files/AssetSummary.tsx +++ b/src/pages/files/AssetSummary.tsx @@ -1,5 +1,5 @@ -import { Utils } from '@ethersphere/bee-js' import { Box } from '@material-ui/core' +import { Reference } from '@upcoming/bee-js' import { ReactElement } from 'react' import { DocumentationText } from '../../components/DocumentationText' import ExpandableListItemKey from '../../components/ExpandableListItemKey' @@ -11,7 +11,7 @@ interface Props { } export function AssetSummary({ isWebsite, reference }: Props): ReactElement { - const isHash = Utils.isHexString(reference) && reference.length === 64 + const isHash = Reference.isValid(reference) return ( <> diff --git a/src/pages/files/AssetSyncing.tsx b/src/pages/files/AssetSyncing.tsx index b3265ef5..c6b28262 100644 --- a/src/pages/files/AssetSyncing.tsx +++ b/src/pages/files/AssetSyncing.tsx @@ -1,9 +1,9 @@ -import { Context as SettingsContext } from '../../providers/Settings' import { Box } from '@material-ui/core' +import { Tag } from '@upcoming/bee-js' import { ReactElement, useContext, useEffect, useRef, useState } from 'react' import { DocumentationText } from '../../components/DocumentationText' import { LinearProgressWithLabel } from '../../components/ProgressBar' -import { Tag } from '@ethersphere/bee-js' +import { Context as SettingsContext } from '../../providers/Settings' interface Props { reference: string diff --git a/src/pages/files/Download.tsx b/src/pages/files/Download.tsx index a514230d..d5755aa5 100644 --- a/src/pages/files/Download.tsx +++ b/src/pages/files/Download.tsx @@ -1,4 +1,4 @@ -import { BeeModes, Utils } from '@ethersphere/bee-js' +import { BeeModes, MantarayNode, Reference } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' import { useNavigate } from 'react-router-dom' @@ -11,7 +11,6 @@ import { Context as SettingsContext } from '../../providers/Settings' import { ROUTES } from '../../routes' import { recognizeEnsOrSwarmHash, regexpEns } from '../../utils' import { HISTORY_KEYS, determineHistoryName, putHistory } from '../../utils/local-storage' -import { ManifestJs } from '../../utils/manifest' import { FileNavigation } from './FileNavigation' export function Download(): ReactElement { @@ -26,41 +25,43 @@ export function Download(): ReactElement { const navigate = useNavigate() const validateChange = (value: string) => { - if ( - Utils.isHexString(value, 64) || - Utils.isHexString(value, 128) || - !value.trim().length || - regexpEns.test(value) - ) { + if (Reference.isValid(value) || regexpEns.test(value)) { setReferenceError(undefined) } else { setReferenceError('Incorrect format of swarm hash. Expected 64 or 128 hexstring characters or ENS domain.') } } + // TODO: Test this for feeds, bzz, and bytes async function onSwarmIdentifier(identifier: string) { - setLoading(true) - if (!beeApi) { setLoading(false) return } + setLoading(true) + try { - const manifestJs = new ManifestJs(beeApi) - const feedIdentifier = await manifestJs.resolveFeedManifest(identifier) + let manifest = await MantarayNode.unmarshal(beeApi, identifier) + await manifest.loadRecursively(beeApi) - if (feedIdentifier) { - identifier = feedIdentifier - } - const isManifest = await manifestJs.isManifest(identifier) + // If the manifest is a feed, resolve it and overwrite the manifest + await manifest.resolveFeed(beeApi).then( + async feed => + await feed.ifPresentAsync(async feedUpdate => { + manifest = MantarayNode.unmarshalFromData(feedUpdate.payload.toUint8Array()) + await manifest.loadRecursively(beeApi) + }), + ) - if (!isManifest) { - throw Error('The specified hash does not contain valid content.') - } - const indexDocument = await manifestJs.getIndexDocumentPath(identifier) - putHistory(HISTORY_KEYS.DOWNLOAD_HISTORY, identifier, determineHistoryName(identifier, indexDocument)) + const rootMetadata = manifest.getDocsMetadata() + + putHistory( + HISTORY_KEYS.DOWNLOAD_HISTORY, + identifier, + determineHistoryName(identifier, rootMetadata.indexDocument), + ) setUploadOrigin(defaultUploadOrigin) navigate(ROUTES.HASH.replace(':hash', identifier)) } catch (error: unknown) { diff --git a/src/pages/files/SelectStamp.tsx b/src/pages/files/SelectStamp.tsx index 16296beb..06927476 100644 --- a/src/pages/files/SelectStamp.tsx +++ b/src/pages/files/SelectStamp.tsx @@ -27,7 +27,7 @@ export default function SimpleMenu({ stamps, selectedStamp, setSelected }: Props {stamps.map(stamp => ( { setSelected(stamp) handleClose() @@ -35,7 +35,7 @@ export default function SimpleMenu({ stamps, selectedStamp, setSelected }: Props selected={stamp.batchID === selectedStamp?.batchID} > {stamp.usageText} - {stamp.batchID.slice(0, 8)}[…] + {stamp.batchID.toHex().slice(0, 8)}[…] ))} diff --git a/src/pages/files/Share.tsx b/src/pages/files/Share.tsx index f6b160ab..0c1b77e4 100644 --- a/src/pages/files/Share.tsx +++ b/src/pages/files/Share.tsx @@ -1,4 +1,5 @@ import { Box, Typography } from '@material-ui/core' +import { MantarayNode } from '@upcoming/bee-js' import { saveAs } from 'file-saver' import JSZip from 'jszip' import { useSnackbar } from 'notistack' @@ -12,11 +13,10 @@ import { Context as BeeContext } from '../../providers/Bee' import { Context as SettingsContext } from '../../providers/Settings' import { ROUTES } from '../../routes' import { determineHistoryName, HISTORY_KEYS, putHistory } from '../../utils/local-storage' -import { ManifestJs } from '../../utils/manifest' import { AssetPreview } from './AssetPreview' import { AssetSummary } from './AssetSummary' -import { DownloadActionBar } from './DownloadActionBar' import { AssetSyncing } from './AssetSyncing' +import { DownloadActionBar } from './DownloadActionBar' export function Share(): ReactElement { const { apiUrl, beeApi } = useContext(SettingsContext) @@ -41,44 +41,57 @@ export function Share(): ReactElement { return } - const manifestJs = new ManifestJs(beeApi) - const isManifest = await manifestJs.isManifest(reference) - - if (!isManifest) { + try { + let manifest = await MantarayNode.unmarshal(beeApi, reference) + await manifest.loadRecursively(beeApi) + + // If the manifest is a feed, resolve it and overwrite the manifest + await manifest.resolveFeed(beeApi).then( + async feed => + await feed.ifPresentAsync(async feedUpdate => { + manifest = MantarayNode.unmarshalFromData(feedUpdate.payload.toUint8Array()) + await manifest.loadRecursively(beeApi) + }), + ) + + const entries = manifest.collectAndMap() + delete entries[META_FILE_NAME] + setSwarmEntries(entries) + + const docsMetadata = manifest.getDocsMetadata() + + // needed in catch block, shadows the outer variable + const indexDocument = docsMetadata.indexDocument + setIndexDocument(indexDocument) + + try { + const remoteMetadata = await beeApi.downloadFile(reference, META_FILE_NAME) + const formattedMetadata = remoteMetadata.data.toJSON() as Metadata + + if (formattedMetadata.isVideo || formattedMetadata.isImage) { + setPreview(`${apiUrl}/bzz/${reference}`) + } + setMetadata({ ...formattedMetadata, hash }) + } catch (e) { + // if metadata is not available or invalid go with the default one + const count = Object.keys(entries).length + setMetadata({ + hash, + type: count > 1 ? 'folder' : 'unknown', + name: reference, + count, + isWebsite: Boolean(indexDocument && /.*\.html?$/i.test(indexDocument)), + isVideo: Boolean(indexDocument && /.*\.(mp4|webm|ogg|mp3|ogg|wav)$/i.test(indexDocument)), + isImage: Boolean(indexDocument && /.*\.(jpg|jpeg|png|gif|webp|svg)$/i.test(indexDocument)), + // naive assumption based on indexDocument, we don't want to download the whole manifest + }) + } + } catch { setNotFound(true) enqueueSnackbar('The specified hash does not contain valid content.', { variant: 'error' }) return } - - const entries = await manifestJs.getHashes(reference, { exclude: [META_FILE_NAME] }) - setSwarmEntries(entries) - - const indexDocument = await manifestJs.getIndexDocumentPath(reference) - setIndexDocument(indexDocument) - - try { - const remoteMetadata = await beeApi.downloadFile(reference, META_FILE_NAME) - const formattedMetadata = JSON.parse(remoteMetadata.data.text()) as Metadata - - if (formattedMetadata.isVideo || formattedMetadata.isImage) { - setPreview(`${apiUrl}/bzz/${reference}`) - } - setMetadata({ ...formattedMetadata, hash }) - } catch (e) { - // if metadata is not available or invalid go with the default one - const count = Object.keys(entries).length - setMetadata({ - hash, - type: count > 1 ? 'folder' : 'unknown', - name: reference, - count, - isWebsite: Boolean(indexDocument && /.*\.html?$/i.test(indexDocument)), - isVideo: Boolean(indexDocument && /.*\.(mp4|webm|ogg|mp3|ogg|wav)$/i.test(indexDocument)), - isImage: Boolean(indexDocument && /.*\.(jpg|jpeg|png|gif|webp|svg)$/i.test(indexDocument)), - // naive assumption based on indexDocument, we don't want to donwload the whole manifest - }) - } } function onOpen() { @@ -119,7 +132,7 @@ export function Share(): ReactElement { } else { const zip = new JSZip() for (const [path, hash] of Object.entries(swarmEntries)) { - zip.file(path, await beeApi.downloadData(hash)) + zip.file(path, (await beeApi.downloadData(hash)).toUint8Array()) } const content = await zip.generateAsync({ type: 'blob' }) saveAs(content, reference + '.zip') diff --git a/src/pages/files/Upload.tsx b/src/pages/files/Upload.tsx index f51fa5b9..12aef381 100644 --- a/src/pages/files/Upload.tsx +++ b/src/pages/files/Upload.tsx @@ -114,10 +114,10 @@ export function Upload(): ReactElement { beeApi .uploadFiles(stamp.batchID, fls, { indexDocument, deferred: true }) .then(hash => { - putHistory(HISTORY_KEYS.UPLOAD_HISTORY, hash.reference, getAssetNameFromFiles(files)) + putHistory(HISTORY_KEYS.UPLOAD_HISTORY, hash.reference.toHex(), getAssetNameFromFiles(files)) if (uploadOrigin.origin === 'UPLOAD') { - navigate(ROUTES.HASH.replace(':hash', hash.reference), { replace: true }) + navigate(ROUTES.HASH.replace(':hash', hash.reference.toHex()), { replace: true }) } else { updateFeed(beeApi, identity as Identity, hash.reference, stamp.batchID, password as string).then(() => { persistIdentity(identities, identity as Identity) @@ -164,7 +164,7 @@ export function Upload(): ReactElement { <> {hasAnyStamps && stampMode === 'SELECT' ? ( - setStamp(stamp)} defaultValue={stamp?.batchID} /> + setStamp(stamp)} defaultValue={stamp?.batchID.toHex()} /> ) : ( setStampMode('SELECT')} /> )} diff --git a/src/pages/gift-code/index.tsx b/src/pages/gift-code/index.tsx index 1edd9319..77f624ea 100644 --- a/src/pages/gift-code/index.tsx +++ b/src/pages/gift-code/index.tsx @@ -1,4 +1,5 @@ import { Box, Tooltip, Typography } from '@material-ui/core' +import { BZZ, DAI } from '@upcoming/bee-js' import { Wallet } from 'ethers' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useEffect, useState } from 'react' @@ -11,20 +12,19 @@ import ExpandableListItemKey from '../../components/ExpandableListItemKey' import { HistoryHeader } from '../../components/HistoryHeader' import { Loading } from '../../components/Loading' import { SwarmButton } from '../../components/SwarmButton' -import { Token } from '../../models/Token' +import { Context as BeeContext } from '../../providers/Bee' import { Context as SettingsContext } from '../../providers/Settings' import { Context as TopUpContext } from '../../providers/TopUp' -import { Context as BalanceProvider } from '../../providers/WalletBalance' import { createGiftWallet } from '../../utils/desktop' import { ResolvedWallet } from '../../utils/wallet' -const GIFT_WALLET_FUND_DAI_AMOUNT = Token.fromDecimal('0.1', 18) -const GIFT_WALLET_FUND_BZZ_AMOUNT = Token.fromDecimal('0.5', 16) +const GIFT_WALLET_FUND_DAI_AMOUNT = DAI.fromDecimalString('0.1') +const GIFT_WALLET_FUND_BZZ_AMOUNT = BZZ.fromDecimalString('0.5') export default function Index(): ReactElement { const { giftWallets, addGiftWallet } = useContext(TopUpContext) const { rpcProvider, desktopUrl } = useContext(SettingsContext) - const { balance } = useContext(BalanceProvider) + const { walletBalance } = useContext(BeeContext) const [loading, setLoading] = useState(false) const [balances, setBalances] = useState([]) @@ -67,13 +67,13 @@ export default function Index(): ReactElement { navigate(-1) } - if (!balance) { + if (!walletBalance) { return } const notEnoughFundsCheck = - balance.dai.toBigNumber.isLessThanOrEqualTo(GIFT_WALLET_FUND_DAI_AMOUNT.toBigNumber) || - balance.bzz.toBigNumber.isLessThan(GIFT_WALLET_FUND_BZZ_AMOUNT.toBigNumber) + walletBalance.nativeTokenBalance.lte(GIFT_WALLET_FUND_DAI_AMOUNT) || + walletBalance.bzzBalance.lt(GIFT_WALLET_FUND_BZZ_AMOUNT) return ( <> @@ -86,10 +86,13 @@ export default function Index(): ReactElement { - + - + {balances.map((x, i) => ( diff --git a/src/pages/info/ChequebookInfoCard.tsx b/src/pages/info/ChequebookInfoCard.tsx index 40317677..fecdbd45 100644 --- a/src/pages/info/ChequebookInfoCard.tsx +++ b/src/pages/info/ChequebookInfoCard.tsx @@ -1,3 +1,4 @@ +import { BZZ } from '@upcoming/bee-js' import { useContext } from 'react' import { useNavigate } from 'react-router' import ExchangeFunds from 'remixicon-react/ExchangeFundsLineIcon' @@ -9,10 +10,7 @@ export function ChequebookInfoCard() { const { chequebookBalance } = useContext(BeeContext) const navigate = useNavigate() - if ( - chequebookBalance?.availableBalance !== undefined && - chequebookBalance?.availableBalance.toBigNumber.isGreaterThan(0) - ) { + if (chequebookBalance?.availableBalance !== undefined && chequebookBalance?.availableBalance.gt(BZZ.fromPLUR('0'))) { return ( - {chainId !== null && } + {walletBalance !== null && ( + + )}
) } diff --git a/src/pages/restart/LightModeRestart.tsx b/src/pages/restart/LightModeRestart.tsx index 594a1374..936e8313 100644 --- a/src/pages/restart/LightModeRestart.tsx +++ b/src/pages/restart/LightModeRestart.tsx @@ -1,5 +1,5 @@ -import { BeeModes } from '@ethersphere/bee-js' import { Box, Grid, Typography } from '@material-ui/core' +import { BeeModes } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useEffect } from 'react' import { useNavigate } from 'react-router' diff --git a/src/pages/stamps/PostageStamp.tsx b/src/pages/stamps/PostageStamp.tsx index 4b2a36ab..5d4ad69b 100644 --- a/src/pages/stamps/PostageStamp.tsx +++ b/src/pages/stamps/PostageStamp.tsx @@ -9,7 +9,7 @@ interface Props { } export function PostageStamp({ stamp, shorten }: Props): ReactElement { - const batchId = shorten ? stamp.batchID.slice(0, 8) : stamp.batchID + const batchId = shorten ? stamp.batchID.toHex().slice(0, 8) : stamp.batchID const label = `${batchId}${stamp.label ? ` - ${stamp.label}` : ''}` return ( diff --git a/src/pages/stamps/PostageStampAdvancedCreation.tsx b/src/pages/stamps/PostageStampAdvancedCreation.tsx index cf1bf6c7..37f312a5 100644 --- a/src/pages/stamps/PostageStampAdvancedCreation.tsx +++ b/src/pages/stamps/PostageStampAdvancedCreation.tsx @@ -1,5 +1,5 @@ -import { PostageBatchOptions, Utils } from '@ethersphere/bee-js' import { Box, Grid, IconButton, Typography, createStyles, makeStyles } from '@material-ui/core' +import { PostageBatchOptions, Utils } from '@upcoming/bee-js' import BigNumber from 'bignumber.js' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' @@ -13,7 +13,7 @@ import { Context as BeeContext } from '../../providers/Bee' import { Context as SettingsContext } from '../../providers/Settings' import { Context as StampsContext } from '../../providers/Stamps' import { ROUTES } from '../../routes' -import { calculateStampPrice, convertAmountToSeconds, secondsToTimeString, waitUntilStampExists } from '../../utils' +import { secondsToTimeString } from '../../utils' import { getHumanReadableFileSize } from '../../utils/file' interface Props { @@ -61,18 +61,22 @@ export function PostageStampAdvancedCreation({ onFinished }: Props): ReactElemen const { enqueueSnackbar } = useSnackbar() - function getTtl(amount: number): string { + function getTtl(amount: bigint): string { const isCurrentPriceAvailable = chainState && chainState.currentPrice if (amount <= 0 || !isCurrentPriceAvailable) { return '-' } - const pricePerBlock = Number.parseInt(chainState.currentPrice, 10) + const pricePerBlock = chainState.currentPrice - return `${secondsToTimeString( - convertAmountToSeconds(amount, pricePerBlock), - )} (with price of ${pricePerBlock.toFixed(0)} PLUR per block)` + try { + return `${secondsToTimeString( + Utils.getStampDuration(amount, pricePerBlock).toSeconds(), + )} (with price of ${pricePerBlock} PLUR per block)` + } catch { + return `0 seconds (with price of ${pricePerBlock} PLUR per block)` + } } function getPrice(depth: number, amount: bigint): string { @@ -82,9 +86,9 @@ export function PostageStampAdvancedCreation({ onFinished }: Props): ReactElemen return '-' } - const price = calculateStampPrice(depth, amount) + const price = Utils.getStampCost(depth, amount) - return `${price.toSignificantDigits()} xBZZ` + return `${price.toSignificantDigits(4)} xBZZ` } async function submit() { @@ -107,8 +111,7 @@ export function PostageStampAdvancedCreation({ onFinished }: Props): ReactElemen immutableFlag: immutable, } - const batchId = await beeApi.createPostageBatch(amount.toString(), depth, options) - await waitUntilStampExists(batchId, beeApi) + await beeApi.createPostageBatch(amount.toString(), depth, options) await refresh() onFinished() } catch (e) { @@ -173,7 +176,7 @@ export function PostageStampAdvancedCreation({ onFinished }: Props): ReactElemen return '-' } - const theoreticalMaximumVolume = getHumanReadableFileSize(Utils.getStampMaximumCapacityBytes(depth)) + const theoreticalMaximumVolume = getHumanReadableFileSize(Utils.getStampTheoreticalBytes(depth)) const effectiveVolume = getHumanReadableFileSize(Utils.getStampEffectiveBytes(depth)) return ( @@ -227,7 +230,7 @@ export function PostageStampAdvancedCreation({ onFinished }: Props): ReactElemen Corresponding TTL (Time to live) - {!amountError && amountInput ? getTtl(Number.parseInt(amountInput, 10)) : '-'} + {!amountError && amountInput ? getTtl(BigInt(amountInput)) : '-'} {amountError && {amountError}} diff --git a/src/pages/stamps/PostageStampSelector.tsx b/src/pages/stamps/PostageStampSelector.tsx index b391bdc6..9b3c64e2 100644 --- a/src/pages/stamps/PostageStampSelector.tsx +++ b/src/pages/stamps/PostageStampSelector.tsx @@ -14,7 +14,7 @@ export function PostageStampSelector({ onSelect, defaultValue }: Props): ReactEl if (!stamps) { return } - const stamp = stamps.find(x => x.batchID === stampId) + const stamp = stamps.find(x => x.batchID.toHex() === stampId) if (stamp) { onSelect(stamp) @@ -24,8 +24,8 @@ export function PostageStampSelector({ onSelect, defaultValue }: Props): ReactEl return ( ({ - label: x.label ? x.batchID.slice(0, 8) + ' - ' + x.label : x.batchID.slice(0, 8), - value: x.batchID, + label: x.label ? x.batchID.toHex().slice(0, 8) + ' - ' + x.label : x.batchID.toHex().slice(0, 8), + value: x.batchID.toHex(), }))} onChange={event => onChange(event.target.value as string)} defaultValue={defaultValue} diff --git a/src/pages/stamps/PostageStampStandardCreation.tsx b/src/pages/stamps/PostageStampStandardCreation.tsx index 0356ae6a..0cdb1326 100644 --- a/src/pages/stamps/PostageStampStandardCreation.tsx +++ b/src/pages/stamps/PostageStampStandardCreation.tsx @@ -1,6 +1,6 @@ -import { PostageBatchOptions, Utils } from '@ethersphere/bee-js' import { Box, Button, Grid, Slider, Typography } from '@material-ui/core' import { Theme, createStyles, makeStyles } from '@material-ui/core/styles' +import { Duration, PostageBatchOptions, Size, Utils } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' import { Link } from 'react-router-dom' @@ -10,7 +10,7 @@ import { SwarmTextInput } from '../../components/SwarmTextInput' import { Context as SettingsContext } from '../../providers/Settings' import { Context as StampsContext } from '../../providers/Stamps' import { ROUTES } from '../../routes' -import { calculateStampPrice, convertAmountToSeconds, secondsToTimeString, waitUntilStampExists } from '../../utils' +import { secondsToTimeString } from '../../utils' interface Props { onFinished: () => void @@ -46,8 +46,8 @@ export function PostageStampStandardCreation({ onFinished }: Props): ReactElemen const { refresh } = useContext(StampsContext) const { beeApi } = useContext(SettingsContext) - const [depthInput, setDepthInput] = useState(Utils.getDepthForCapacity(4)) - const [amountInput, setAmountInput] = useState(Utils.getAmountForTtl(30)) + const [depthInput, setDepthInput] = useState(Utils.getDepthForSize(Size.fromGigabytes(4))) + const [amountInput, setAmountInput] = useState(Utils.getAmountForDuration(Duration.fromDays(30), 26500)) const [labelInput, setLabelInput] = useState('') const [submitting, setSubmitting] = useState(false) const [buttonValue, setButtonValue] = useState(4) @@ -56,24 +56,24 @@ export function PostageStampStandardCreation({ onFinished }: Props): ReactElemen if (typeof newValue !== 'number') { return } - const amountValue = Utils.getAmountForTtl(newValue) + const amountValue = Utils.getAmountForDuration(Duration.fromDays(newValue), 26500) setAmountInput(amountValue) } const { enqueueSnackbar } = useSnackbar() - function getTtl(amount: string): string { + function getTtl(amount: bigint): string { const pricePerBlock = 24000 return `${secondsToTimeString( - convertAmountToSeconds(parseInt(amount, 10), pricePerBlock), - )} (with price of ${pricePerBlock.toFixed(0)} PLUR per block)` + Utils.getStampDuration(amount, pricePerBlock).toSeconds(), + )} (with price of ${pricePerBlock} PLUR per block)` } function getPrice(depth: number, amount: bigint): string { - const price = calculateStampPrice(depth, amount) + const price = Utils.getStampCost(depth, amount) - return `${price.toSignificantDigits()} xBZZ` + return `${price.toSignificantDigits(4)} xBZZ` } async function submit() { @@ -96,8 +96,7 @@ export function PostageStampStandardCreation({ onFinished }: Props): ReactElemen immutableFlag: true, } - const batchId = await beeApi.createPostageBatch(amount.toString(), depth, options) - await waitUntilStampExists(batchId, beeApi) + await beeApi.createPostageBatch(amount.toString(), depth, options) await refresh() onFinished() } catch (e) { @@ -109,7 +108,7 @@ export function PostageStampStandardCreation({ onFinished }: Props): ReactElemen function handleBatchSize(gigabytes: number) { setButtonValue(gigabytes) - const capacity = Utils.getDepthForCapacity(gigabytes) + const capacity = Utils.getDepthForSize(Size.fromGigabytes(gigabytes)) setDepthInput(capacity) } diff --git a/src/pages/stamps/SelectPostageStampModal.tsx b/src/pages/stamps/SelectPostageStampModal.tsx index 7096ebed..bdb377d3 100644 --- a/src/pages/stamps/SelectPostageStampModal.tsx +++ b/src/pages/stamps/SelectPostageStampModal.tsx @@ -4,7 +4,7 @@ import Dialog from '@material-ui/core/Dialog' import DialogContent from '@material-ui/core/DialogContent' import DialogTitle from '@material-ui/core/DialogTitle' import { Check, Clear } from '@material-ui/icons' -import React, { ReactElement, useState } from 'react' +import { ReactElement, useState } from 'react' import ExpandableListItemActions from '../../components/ExpandableListItemActions' import { SwarmSelect } from '../../components/SwarmSelect' import { EnrichedPostageBatch } from '../../providers/Stamps' @@ -39,7 +39,7 @@ export function SelectPostageStampModal({ stamps, onSelect, onClose }: Props): R const classes = useStyles() function onChange(stampId: string) { - const stamp = stamps.find(x => x.batchID === stampId) + const stamp = stamps.find(x => x.batchID.toHex() === stampId) if (stamp) { setSelectedStamp(stamp) @@ -66,7 +66,7 @@ export function SelectPostageStampModal({ stamps, onSelect, onClose }: Props): R ({ label: x.batchID, value: x.batchID }))} + options={stamps.map(x => ({ label: x.batchID.toHex(), value: x.batchID.toHex() }))} onChange={event => onChange(event.target.value as string)} /> diff --git a/src/pages/stamps/StampsTable.tsx b/src/pages/stamps/StampsTable.tsx index ec209d7c..63044595 100644 --- a/src/pages/stamps/StampsTable.tsx +++ b/src/pages/stamps/StampsTable.tsx @@ -28,10 +28,10 @@ function StampsTable({ postageStamps }: Props): ReactElement | null { {postageStamps.map(stamp => ( - + - + - diff --git a/src/pages/top-up/Balance.tsx b/src/pages/top-up/Balance.tsx index 084643f2..ccc6a516 100644 --- a/src/pages/top-up/Balance.tsx +++ b/src/pages/top-up/Balance.tsx @@ -1,4 +1,5 @@ import { Box, Grid, Typography } from '@material-ui/core' +import { DAI } from '@upcoming/bee-js' import { ReactElement, useContext } from 'react' import { useNavigate } from 'react-router' import Check from 'remixicon-react/CheckLineIcon' @@ -9,10 +10,9 @@ import { Loading } from '../../components/Loading' import { SwarmButton } from '../../components/SwarmButton' import { SwarmDivider } from '../../components/SwarmDivider' import { Context } from '../../providers/Bee' -import { Context as BalanceProvider } from '../../providers/WalletBalance' import { TopUpProgressIndicator } from './TopUpProgressIndicator' -const MINIMUM_XDAI = '0.5' +const MINIMUM_XDAI = DAI.fromDecimalString('0.5') interface Props { header: string @@ -22,15 +22,14 @@ interface Props { } export default function Index({ header, title, p, next }: Props): ReactElement { - const { nodeAddresses } = useContext(Context) - const { balance } = useContext(BalanceProvider) + const { nodeAddresses, walletBalance } = useContext(Context) const navigate = useNavigate() - if (!balance || !nodeAddresses) { + if (!walletBalance || !nodeAddresses) { return } - const disabled = balance.dai.toDecimal.lt(MINIMUM_XDAI) + const disabled = walletBalance.nativeTokenBalance.lt(MINIMUM_XDAI) return ( <> @@ -44,17 +43,19 @@ export default function Index({ header, title, p, next }: Props): ReactElement { {p} - + - + navigate(next)} disabled={disabled}> Proceed {disabled ? ( - Please deposit at least {MINIMUM_XDAI} xDAI to the address above in order to proceed. + + Please deposit at least {MINIMUM_XDAI.toSignificantDigits(4)} xDAI to the address above in order to proceed. + ) : null} diff --git a/src/pages/top-up/GiftCardFund.tsx b/src/pages/top-up/GiftCardFund.tsx index f8443452..cef57a37 100644 --- a/src/pages/top-up/GiftCardFund.tsx +++ b/src/pages/top-up/GiftCardFund.tsx @@ -1,5 +1,5 @@ -import { BeeModes } from '@ethersphere/bee-js' import { Box, Typography } from '@material-ui/core' +import { BeeModes } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useEffect, useState } from 'react' import { useNavigate, useParams } from 'react-router' @@ -14,16 +14,14 @@ import { SwarmButton } from '../../components/SwarmButton' import { SwarmDivider } from '../../components/SwarmDivider' import { Context as BeeContext } from '../../providers/Bee' import { Context as SettingsContext } from '../../providers/Settings' -import { Context as BalanceProvider } from '../../providers/WalletBalance' import { ROUTES } from '../../routes' import { sleepMs } from '../../utils' import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop' import { ResolvedWallet } from '../../utils/wallet' export function GiftCardFund(): ReactElement { - const { nodeAddresses, nodeInfo } = useContext(BeeContext) + const { nodeAddresses, nodeInfo, walletBalance } = useContext(BeeContext) const { isDesktop, desktopUrl, rpcProvider, rpcProviderUrl } = useContext(SettingsContext) - const { balance } = useContext(BalanceProvider) const [loading, setLoading] = useState(false) const [wallet, setWallet] = useState(null) @@ -41,7 +39,7 @@ export function GiftCardFund(): ReactElement { ResolvedWallet.make(privateKeyString, rpcProvider).then(setWallet) }, [privateKeyString, rpcProvider]) - if (!wallet || !balance) { + if (!wallet || !walletBalance) { return } @@ -108,13 +106,20 @@ export function GiftCardFund(): ReactElement { - + - + - + {canUpgradeToLightNode ? 'Send all funds to your node and Upgrade' : 'Send all funds to your node'} diff --git a/src/pages/top-up/GiftCardTopUpIndex.tsx b/src/pages/top-up/GiftCardTopUpIndex.tsx index 3eacd143..c1ca9528 100644 --- a/src/pages/top-up/GiftCardTopUpIndex.tsx +++ b/src/pages/top-up/GiftCardTopUpIndex.tsx @@ -1,17 +1,16 @@ import { Box, Typography } from '@material-ui/core' +import { BZZ, DAI } from '@upcoming/bee-js' import { Wallet } from 'ethers' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useState } from 'react' -import ArrowRight from 'remixicon-react/ArrowRightLineIcon' import { useNavigate } from 'react-router' -import { Context as SettingsContext } from '../../providers/Settings' +import ArrowRight from 'remixicon-react/ArrowRightLineIcon' import { HistoryHeader } from '../../components/HistoryHeader' import { ProgressIndicator } from '../../components/ProgressIndicator' import { SwarmButton } from '../../components/SwarmButton' import { SwarmDivider } from '../../components/SwarmDivider' import { SwarmTextInput } from '../../components/SwarmTextInput' -import { BzzToken } from '../../models/BzzToken' -import { DaiToken } from '../../models/DaiToken' +import { Context as SettingsContext } from '../../providers/Settings' import { ROUTES } from '../../routes' import { Rpc } from '../../utils/rpc' @@ -29,10 +28,10 @@ export function GiftCardTopUpIndex(): ReactElement { setLoading(true) try { const wallet = new Wallet(giftCode, rpcProvider) - const dai = new DaiToken(await Rpc._eth_getBalance(wallet.address, rpcProvider)) - const bzz = new BzzToken(await Rpc._eth_getBalanceERC20(wallet.address, rpcProvider)) + const dai = await Rpc._eth_getBalance(wallet.address, rpcProvider) + const bzz = await Rpc._eth_getBalanceERC20(wallet.address, rpcProvider) - if (dai.toDecimal.lt(0.001) || bzz.toDecimal.lt(0.001)) { + if (dai.lt(DAI.fromDecimalString('0.001')) || bzz.lt(BZZ.fromDecimalString('0.001'))) { throw Error('Gift wallet does not have enough funds') } enqueueSnackbar('Successfully verified gift wallet', { variant: 'success' }) diff --git a/src/pages/top-up/Swap.tsx b/src/pages/top-up/Swap.tsx index ffe0bc59..12508e29 100644 --- a/src/pages/top-up/Swap.tsx +++ b/src/pages/top-up/Swap.tsx @@ -1,5 +1,5 @@ -import { BeeModes } from '@ethersphere/bee-js' import { Box, Typography } from '@material-ui/core' +import { BeeModes, BZZ, DAI } from '@upcoming/bee-js' import { useSnackbar } from 'notistack' import { ReactElement, useContext, useEffect, useState } from 'react' import { useNavigate } from 'react-router' @@ -13,14 +13,11 @@ import { Loading } from '../../components/Loading' import { SwarmButton } from '../../components/SwarmButton' import { SwarmDivider } from '../../components/SwarmDivider' import { SwarmTextInput } from '../../components/SwarmTextInput' -import { BZZ_DECIMAL_PLACES, BzzToken } from '../../models/BzzToken' -import { DaiToken } from '../../models/DaiToken' import { Context as BeeContext } from '../../providers/Bee' import { Context as SettingsContext } from '../../providers/Settings' -import { Context as BalanceProvider } from '../../providers/WalletBalance' import { ROUTES } from '../../routes' import { sleepMs } from '../../utils' -import { SwapError, isSwapError, wrapWithSwapError } from '../../utils/SwapError' +import { isSwapError, SwapError, wrapWithSwapError } from '../../utils/SwapError' import { getBzzPriceAsDai, getDesktopConfiguration, @@ -31,8 +28,8 @@ import { import { Rpc } from '../../utils/rpc' import { TopUpProgressIndicator } from './TopUpProgressIndicator' -const MINIMUM_XDAI = '0.1' -const MINIMUM_XBZZ = '0.1' +const MINIMUM_XDAI = DAI.fromDecimalString('0.1') +const MINIMUM_XBZZ = BZZ.fromDecimalString('0.1') const GENERIC_SWAP_FAILED_ERROR_MESSAGE = 'Failed to swap. The full error is printed to the console.' @@ -44,15 +41,14 @@ export function Swap({ header }: Props): ReactElement { const [loading, setLoading] = useState(false) const [hasSwapped, setSwapped] = useState(false) const [userInputSwap, setUserInputSwap] = useState(null) - const [price, setPrice] = useState(DaiToken.fromDecimal('0.6')) + const [price, setPrice] = useState(DAI.fromDecimalString('0.3')) const [error, setError] = useState(null) - const [daiToSwap, setDaiToSwap] = useState(null) - const [bzzAfterSwap, setBzzAfterSwap] = useState(null) - const [daiAfterSwap, setDaiAfterSwap] = useState(null) + const [daiToSwap, setDaiToSwap] = useState(null) + const [bzzAfterSwap, setBzzAfterSwap] = useState(null) + const [daiAfterSwap, setDaiAfterSwap] = useState(null) const { rpcProviderUrl, isDesktop, desktopUrl } = useContext(SettingsContext) - const { nodeAddresses, nodeInfo } = useContext(BeeContext) - const { balance } = useContext(BalanceProvider) + const { nodeAddresses, nodeInfo, walletBalance } = useContext(BeeContext) const navigate = useNavigate() const { enqueueSnackbar } = useSnackbar() @@ -65,30 +61,30 @@ export function Swap({ header }: Props): ReactElement { // Set the initial xDAI to swap useEffect(() => { - if (!balance || userInputSwap) { + if (!walletBalance || userInputSwap) { return } - const minimumOptimalValue = DaiToken.fromDecimal('1').plusBaseUnits(MINIMUM_XDAI).toDecimal + const minimumOptimalValue = DAI.fromDecimalString('1').plus(MINIMUM_XDAI) - if (balance.dai.toDecimal.isGreaterThanOrEqualTo(minimumOptimalValue)) { + if (walletBalance.nativeTokenBalance.gte(minimumOptimalValue)) { // Balance has at least 1 + MINIMUM_XDAI xDai - setDaiToSwap(balance.dai.minusBaseUnits('1')) + setDaiToSwap(walletBalance.nativeTokenBalance.minus(DAI.fromDecimalString('1'))) } else { // Balance is low, halve the amount - setDaiToSwap(new DaiToken(balance.dai.toBigNumber.dividedToIntegerBy(2))) + setDaiToSwap(walletBalance.nativeTokenBalance.divide(BigInt(2))) } - }, [balance, userInputSwap]) + }, [walletBalance, userInputSwap]) // Set the xDAI to swap based on user input useEffect(() => { setError(null) try { if (userInputSwap) { - const dai = DaiToken.fromDecimal(userInputSwap) + const dai = DAI.fromDecimalString(userInputSwap) setDaiToSwap(dai) - if (dai.toDecimal.lte(0)) { + if (dai.lte(DAI.fromDecimalString('0'))) { setError('xDAI to swap must be a positive number') } } @@ -99,25 +95,23 @@ export function Swap({ header }: Props): ReactElement { // Calculate the amount of tokens after swap useEffect(() => { - if (!balance || !daiToSwap || error) { + if (!walletBalance || !daiToSwap || error) { return } - const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber)) + const daiAfterSwap = walletBalance.nativeTokenBalance.minus(daiToSwap) setDaiAfterSwap(daiAfterSwap) - const tokensConverted = BzzToken.fromDecimal( - daiToSwap.toBigNumber.dividedBy(price.toBigNumber).decimalPlaces(BZZ_DECIMAL_PLACES), - ) - const bzzAfterSwap = new BzzToken(tokensConverted.toBigNumber.plus(balance.bzz.toBigNumber)) + const tokensConverted = daiToSwap.exchangeToBZZ(price) + const bzzAfterSwap = tokensConverted.plus(walletBalance.bzzBalance) setBzzAfterSwap(bzzAfterSwap) - if (daiAfterSwap.toDecimal.lt(MINIMUM_XDAI)) { - setError(`Must keep at least ${MINIMUM_XDAI} xDAI after swap!`) - } else if (bzzAfterSwap.toDecimal.lt(MINIMUM_XBZZ)) { - setError(`Must have at least ${MINIMUM_XBZZ} xBZZ after swap!`) + if (daiAfterSwap.lt(MINIMUM_XDAI)) { + setError(`Must keep at least ${MINIMUM_XDAI.toSignificantDigits(4)} xDAI after swap!`) + } else if (bzzAfterSwap.lt(MINIMUM_XBZZ)) { + setError(`Must have at least ${MINIMUM_XBZZ.toSignificantDigits(4)} xBZZ after swap!`) } - }, [error, balance, daiToSwap, price]) + }, [error, walletBalance, daiToSwap, price]) - if (!balance || !nodeAddresses || !daiToSwap || !bzzAfterSwap || !daiAfterSwap) { + if (!walletBalance || !nodeAddresses || !daiToSwap || !bzzAfterSwap || !daiAfterSwap) { return } @@ -135,9 +129,9 @@ export function Swap({ header }: Props): ReactElement { } } - async function sendSwapRequest(daiToSwap: DaiToken) { + async function sendSwapRequest(daiToSwap: DAI) { try { - await performSwap(desktopUrl, daiToSwap.toString) + await performSwap(desktopUrl, daiToSwap) } catch (error) { // eslint-disable-next-line no-console console.error(error) @@ -145,7 +139,7 @@ export function Swap({ header }: Props): ReactElement { } } - async function performSwapWithChecks(daiToSwap: DaiToken) { + async function performSwapWithChecks(daiToSwap: DAI) { if (!localStorage.getItem('apiKey')) { throw new SwapError('API key is not set, reopen dashboard through Swarm Desktop') } @@ -186,7 +180,9 @@ export function Swap({ header }: Props): ReactElement { : 'Successfully swapped. Balances will refresh soon. You may now navigate away.' enqueueSnackbar(message, { variant: 'success' }) - if (canUpgradeToLightNode) await restart() + if (canUpgradeToLightNode) { + await restart() + } } catch (error) { if (isSwapError(error)) { // we have a custom and user friendly error message @@ -201,7 +197,6 @@ export function Swap({ header }: Props): ReactElement { console.error(error) // eslint-disable-line } } finally { - balance?.refresh() setLoading(false) } } @@ -217,15 +212,15 @@ export function Swap({ header }: Props): ReactElement { - You need to swap xDAI to xBZZ in order to use Swarm. Make sure to keep at least {MINIMUM_XDAI} xDAI in order - to pay for transaction costs on the network. + You need to swap xDAI to xBZZ in order to use Swarm. Make sure to keep at least{' '} + {MINIMUM_XDAI.toSignificantDigits(4)} xDAI in order to pay for transaction costs on the network. - Your current balance is {balance.dai.toSignificantDigits(4)} xDAI and {balance.bzz.toSignificantDigits(4)}{' '} - xBZZ. + Your current balance is {walletBalance.nativeTokenBalance.toSignificantDigits(4)} xDAI and{' '} + {walletBalance.bzzBalance.toSignificantDigits(4)} xBZZ. @@ -242,7 +237,7 @@ export function Swap({ header }: Props): ReactElement { - + }), ) -const MINIMUM_XDAI = '0.05' -const MINIMUM_XBZZ = '0.1' +const MINIMUM_XDAI = DAI.fromDecimalString('0.05') +const MINIMUM_XBZZ = BZZ.fromDecimalString('0.1') export default function TopUp(): ReactElement { const navigate = useNavigate() const styles = useStyles() const { isDesktop, desktopUrl } = useContext(SettingsContext) - const { nodeInfo, status } = useContext(BeeContext) - const { balance } = useContext(BalanceProvider) + const { nodeInfo, status, walletBalance } = useContext(BeeContext) const { rpcProviderUrl } = useContext(SettingsContext) const [loading, setLoading] = useState(false) const { enqueueSnackbar } = useSnackbar() @@ -49,8 +47,8 @@ export default function TopUp(): ReactElement { const canUpgradeToLightNode = isDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT && - balance?.dai.toDecimal.gte(MINIMUM_XDAI) && - balance?.bzz.toDecimal.gte(MINIMUM_XBZZ) + walletBalance?.nativeTokenBalance.gte(MINIMUM_XDAI) && + walletBalance?.bzzBalance.gte(MINIMUM_XBZZ) async function restart() { setLoading(true) @@ -67,7 +65,7 @@ export default function TopUp(): ReactElement { if (status.all === CheckState.ERROR) return - if (!balance) { + if (!walletBalance) { return } diff --git a/src/providers/Bee.tsx b/src/providers/Bee.tsx index c65d0005..9717650e 100644 --- a/src/providers/Bee.tsx +++ b/src/providers/Bee.tsx @@ -1,18 +1,20 @@ import { + AllSettlements, BeeModes, + BZZ, ChainState, ChequebookAddressResponse, + ChequebookBalanceResponse, LastChequesResponse, NodeAddresses, NodeInfo, Peer, + PeerBalance, Topology, -} from '@ethersphere/bee-js' -import { ReactChild, ReactElement, createContext, useContext, useEffect, useState } from 'react' + WalletBalance, +} from '@upcoming/bee-js' +import { createContext, ReactChild, ReactElement, useContext, useEffect, useState } from 'react' import { useLatestBeeRelease } from '../hooks/apiHooks' -import { BzzToken } from '../models/BzzToken' -import { Token } from '../models/Token' -import type { Balance, ChequebookBalance, Settlements } from '../types' import { Context as SettingsContext } from './Settings' const LAUNCH_GRACE_PERIOD = 15_000 @@ -50,13 +52,13 @@ interface ContextInterface { topology: Topology | null chequebookAddress: ChequebookAddressResponse | null peers: Peer[] | null - chequebookBalance: ChequebookBalance | null - stake: BzzToken | null - peerBalances: Balance[] | null + chequebookBalance: ChequebookBalanceResponse | null + stake: BZZ | null + peerBalances: PeerBalance[] | null peerCheques: LastChequesResponse | null - settlements: Settlements | null + settlements: AllSettlements | null chainState: ChainState | null - chainId: number | null + walletBalance: WalletBalance | null latestBeeRelease: LatestBeeRelease | null isLoading: boolean lastUpdate: number | null @@ -86,7 +88,7 @@ const initialValues: ContextInterface = { peerCheques: null, settlements: null, chainState: null, - chainId: null, + walletBalance: null, latestBeeRelease: null, isLoading: true, lastUpdate: null, @@ -107,7 +109,7 @@ function getStatus( apiHealth: boolean, topology: Topology | null, chequebookAddress: ChequebookAddressResponse | null, - chequebookBalance: ChequebookBalance | null, + chequebookBalance: ChequebookBalanceResponse | null, error: Error | null, startedAt: number, ): Status { @@ -173,13 +175,13 @@ export function Provider({ children }: Props): ReactElement { const [topology, setNodeTopology] = useState(null) const [chequebookAddress, setChequebookAddress] = useState(null) const [peers, setPeers] = useState(null) - const [chequebookBalance, setChequebookBalance] = useState(null) - const [stake, setStake] = useState(null) - const [peerBalances, setPeerBalances] = useState(null) + const [chequebookBalance, setChequebookBalance] = useState(null) + const [stake, setStake] = useState(null) + const [peerBalances, setPeerBalances] = useState(null) const [peerCheques, setPeerCheques] = useState(null) - const [settlements, setSettlements] = useState(null) + const [settlements, setSettlements] = useState(null) const [chainState, setChainState] = useState(null) - const [chainId, setChainId] = useState(null) + const [walletBalance, setWalletBalance] = useState(null) const [startedAt] = useState(Date.now()) const { latestBeeRelease } = useLatestBeeRelease() @@ -232,38 +234,6 @@ export function Provider({ children }: Props): ReactElement { isRefreshing = true setError(null) - // Wrap the chequebook balance call to return BZZ values as Token object - const chequeBalanceWrapper = async () => { - const { totalBalance, availableBalance } = await beeApi.getChequebookBalance({ timeout: TIMEOUT }) - - return { - totalBalance: new Token(totalBalance), - availableBalance: new Token(availableBalance), - } - } - - // Wrap the balances call to return BZZ values as Token object - const peerBalanceWrapper = async () => { - const { balances } = await beeApi.getAllBalances({ timeout: TIMEOUT }) - - return balances.map(({ peer, balance }) => ({ peer, balance: new Token(balance) })) - } - - // Wrap the settlements call to return BZZ values as Token object - const settlementsWrapper = async () => { - const { totalReceived, settlements, totalSent } = await beeApi.getAllSettlements({ timeout: TIMEOUT }) - - return { - totalReceived: new Token(totalReceived), - totalSent: new Token(totalSent), - settlements: settlements.map(({ peer, received, sent }) => ({ - peer, - received: new Token(received), - sent: new Token(sent), - })), - } - } - const promises = [ // API health beeApi @@ -320,26 +290,29 @@ export function Provider({ children }: Props): ReactElement { // Wallet beeApi .getWalletBalance({ timeout: TIMEOUT }) - .then(({ chainID }) => setChainId(chainID)) - .catch(() => setChainId(null)), + .then(setWalletBalance) + .catch(() => setWalletBalance(null)), // Chequebook balance - chequeBalanceWrapper() + beeApi + .getChequebookBalance({ timeout: TIMEOUT }) .then(setChequebookBalance) .catch(() => setChequebookBalance(null)), beeApi .getStake({ timeout: TIMEOUT }) - .then(stake => setStake(new BzzToken(stake))) + .then(stake => setStake(stake)) .catch(() => setStake(null)), // Peer balances - peerBalanceWrapper() - .then(setPeerBalances) + beeApi + .getAllBalances({ timeout: TIMEOUT }) + .then(x => setPeerBalances(x.balances)) .catch(() => setPeerBalances(null)), // Settlements - settlementsWrapper() + beeApi + .getAllSettlements() .then(setSettlements) .catch(() => setSettlements(null)), ] @@ -398,7 +371,7 @@ export function Provider({ children }: Props): ReactElement { peerCheques, settlements, chainState, - chainId, + walletBalance, latestBeeRelease, isLoading, lastUpdate, diff --git a/src/providers/Settings.tsx b/src/providers/Settings.tsx index f85bde0d..6700642e 100644 --- a/src/providers/Settings.tsx +++ b/src/providers/Settings.tsx @@ -1,4 +1,4 @@ -import { Bee } from '@ethersphere/bee-js' +import { Bee } from '@upcoming/bee-js' import { providers } from 'ethers' import { ReactElement, ReactNode, createContext, useEffect, useState } from 'react' import { DEFAULT_BEE_API_HOST, DEFAULT_RPC_URL } from '../constants' diff --git a/src/providers/Stamps.tsx b/src/providers/Stamps.tsx index 72cbb194..54b2654e 100644 --- a/src/providers/Stamps.tsx +++ b/src/providers/Stamps.tsx @@ -1,4 +1,4 @@ -import { PostageBatch } from '@ethersphere/bee-js' +import { PostageBatch } from '@upcoming/bee-js' import { createContext, ReactChild, ReactElement, useContext, useEffect, useState } from 'react' import { Context as SettingsContext } from './Settings' @@ -68,7 +68,7 @@ export function Provider({ children }: Props): ReactElement { setIsLoading(true) const stamps = await beeApi.getAllPostageBatch() - setStamps(stamps.filter(x => x.exists).map(enrichStamp)) + setStamps(stamps.map(enrichStamp)) setLastUpdate(Date.now()) setError(null) } catch (e) { diff --git a/src/providers/WalletBalance.tsx b/src/providers/WalletBalance.tsx deleted file mode 100644 index 3482f990..00000000 --- a/src/providers/WalletBalance.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { createContext, ReactChild, ReactElement, useContext, useEffect, useState } from 'react' -import { Context as SettingsContext } from './Settings' -import { Context as BeeContext } from './Bee' -import { WalletAddress } from '../utils/wallet' - -interface ContextInterface { - balance: WalletAddress | null - error: Error | null - isLoading: boolean - lastUpdate: number | null - start: (frequency?: number) => void - stop: () => void - refresh: () => Promise -} - -const initialValues: ContextInterface = { - balance: null, - error: null, - isLoading: false, - lastUpdate: null, - start: () => {}, // eslint-disable-line - stop: () => {}, // eslint-disable-line - refresh: () => Promise.reject(), -} - -export const Context = createContext(initialValues) -export const Consumer = Context.Consumer - -interface Props { - children: ReactChild -} - -export function Provider({ children }: Props): ReactElement { - const { rpcProvider } = useContext(SettingsContext) - const { nodeAddresses } = useContext(BeeContext) - const [balance, setBalance] = useState(initialValues.balance) - const [error, setError] = useState(initialValues.error) - const [isLoading, setIsLoading] = useState(initialValues.isLoading) - const [lastUpdate, setLastUpdate] = useState(initialValues.lastUpdate) - const [frequency, setFrequency] = useState(null) - - useEffect(() => { - if (nodeAddresses?.ethereum && rpcProvider) { - WalletAddress.make(nodeAddresses.ethereum, rpcProvider).then(setBalance) - } else { - setBalance(null) - } - }, [nodeAddresses, rpcProvider]) - - const refresh = async () => { - // Don't want to refresh when already refreshing - if (isLoading) return - - if (!balance) return - - try { - setIsLoading(true) - - setBalance(await balance.refresh()) - setLastUpdate(Date.now()) - } catch (e) { - setError(e as Error) - } finally { - setIsLoading(false) - } - } - - const start = (freq = 30000) => setFrequency(freq) - const stop = () => setFrequency(null) - - // Start the update loop - useEffect(() => { - refresh() - - // Start autorefresh only if the frequency is set - if (frequency) { - const interval = setInterval(refresh, frequency) - - return () => clearInterval(interval) - } - }, [frequency]) // eslint-disable-line react-hooks/exhaustive-deps - - return ( - - {children} - - ) -} diff --git a/src/setupTests.ts b/src/setupTests.ts index 52aaef1d..7c26635c 100644 --- a/src/setupTests.ts +++ b/src/setupTests.ts @@ -3,3 +3,7 @@ // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom' + +import { TextDecoder, TextEncoder } from 'util' + +Object.assign(global, { TextDecoder, TextEncoder }) diff --git a/src/types.ts b/src/types.ts index ef872be9..db91266f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,5 +1,4 @@ -import type { NodeAddresses, Topology } from '@ethersphere/bee-js' -import type { Token } from './models/Token' +import type { NodeAddresses, Topology } from '@upcoming/bee-js' import { CheckState } from './providers/Bee' export interface StatusHookCommon { @@ -12,31 +11,11 @@ export interface StatusNodeVersionHook extends StatusHookCommon { latestUrl: string isLatestBeeVersion: boolean } + export interface StatusEthereumConnectionHook extends StatusHookCommon { nodeAddresses: NodeAddresses | null } + export interface StatusTopologyHook extends StatusHookCommon { topology: Topology | null } - -export interface ChequebookBalance { - totalBalance: Token - availableBalance: Token -} - -export interface Balance { - peer: string - balance: Token -} - -export interface Settlement { - peer: string - received: Token - sent: Token -} - -export interface Settlements { - totalReceived: Token - totalSent: Token - settlements: Settlement[] -} diff --git a/src/utils/bzz-faucet.ts b/src/utils/bzz-faucet.ts deleted file mode 100644 index 3c13f95b..00000000 --- a/src/utils/bzz-faucet.ts +++ /dev/null @@ -1,5 +0,0 @@ -import axios from 'axios' - -export async function requestBzz(address: string): Promise { - await axios.post(`https://xbzz-faucet.apyos.dev/xbzz/${address}`) -} diff --git a/src/utils/desktop.ts b/src/utils/desktop.ts index a57a1f30..8fd24701 100644 --- a/src/utils/desktop.ts +++ b/src/utils/desktop.ts @@ -1,7 +1,6 @@ +import { DAI } from '@upcoming/bee-js' import axios from 'axios' import { BEE_DESKTOP_LATEST_RELEASE_PAGE_API } from '../constants' -import { DaiToken } from '../models/DaiToken' -import { Token } from '../models/Token' import { getJson, postJson } from './net' export interface BeeConfig { @@ -18,10 +17,10 @@ export interface BeeConfig { 'blockchain-rpc-endpoint'?: string } -export async function getBzzPriceAsDai(desktopUrl: string): Promise { +export async function getBzzPriceAsDai(desktopUrl: string): Promise { const response = await axios.get(`${desktopUrl}/price`) - return DaiToken.fromDecimal(response.data) + return DAI.fromDecimalString(response.data) } export function upgradeToLightNode(desktopUrl: string, rpcProvider: string): Promise { @@ -53,8 +52,8 @@ export async function createGiftWallet(desktopUrl: string, address: string): Pro await postJson(`${desktopUrl}/gift-wallet/${address}`) } -export async function performSwap(desktopUrl: string, daiAmount: string): Promise { - await postJson(`${desktopUrl}/swap`, { dai: daiAmount }) +export async function performSwap(desktopUrl: string, daiAmount: DAI): Promise { + await postJson(`${desktopUrl}/swap`, { dai: daiAmount.toWeiString() }) } export async function getLatestBeeDesktopVersion(): Promise { diff --git a/src/utils/identity.ts b/src/utils/identity.ts index 7c175de2..c76becdd 100644 --- a/src/utils/identity.ts +++ b/src/utils/identity.ts @@ -1,4 +1,4 @@ -import { BatchId, Bee, Reference } from '@ethersphere/bee-js' +import { BatchId, Bee, NULL_TOPIC, Reference } from '@upcoming/bee-js' import { Wallet } from 'ethers' import { uuidV4, waitUntilStampUsable } from '.' import { Identity, IdentityType } from '../providers/Feeds' @@ -80,18 +80,18 @@ async function getWallet(type: IdentityType, data: string, password?: string): P export async function updateFeed( beeApi: Bee, identity: Identity, - hash: string, - stamp: string, + hash: Reference | string, + stamp: BatchId | string, password?: string, ): Promise { const wallet = await getWalletFromIdentity(identity, password) if (!identity.feedHash) { - identity.feedHash = (await beeApi.createFeedManifest(stamp, 'sequence', '00'.repeat(32), wallet.address)).reference + identity.feedHash = (await beeApi.createFeedManifest(stamp, NULL_TOPIC, wallet.address)).toHex() } - const writer = beeApi.makeFeedWriter('sequence', '00'.repeat(32), wallet.privateKey) + const writer = beeApi.makeFeedWriter(NULL_TOPIC, wallet.privateKey) - await waitUntilStampUsable(stamp as BatchId, beeApi) - await writer.upload(stamp, hash as Reference) + await waitUntilStampUsable(stamp, beeApi) + await writer.upload(stamp, hash) } diff --git a/src/utils/index.ts b/src/utils/index.ts index aa110194..cf66b5d8 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -1,8 +1,6 @@ -import { BatchId, Bee, PostageBatch } from '@ethersphere/bee-js' -import { decodeCid } from '@ethersphere/swarm-cid' +import { BatchId, Bee, PostageBatch, Reference } from '@upcoming/bee-js' import { BigNumber } from 'bignumber.js' import { BZZ_LINK_DOMAIN } from '../constants' -import { Token } from '../models/Token' /** * Test if value is an integer @@ -131,13 +129,7 @@ export function extractSwarmCid(s: string): string | undefined { const cid = matches[1] try { - const decodeResult = decodeCid(cid) - - if (!decodeResult.type) { - return - } - - return decodeResult.reference + return new Reference(cid).toHex() } catch (e) { return } @@ -171,48 +163,36 @@ export function formatEnum(string: string): string { return (string.charAt(0).toUpperCase() + string.slice(1).toLowerCase()).replaceAll('_', ' ') } -export function secondsToTimeString(seconds: number): string { +export function secondsToTimeString(seconds: number | bigint): string { + seconds = BigInt(seconds) let unit = seconds if (unit < 120) { return `${seconds} seconds` } - unit /= 60 + unit /= BigInt(60) if (unit < 120) { - return `${Math.round(unit)} minutes` + return `${unit} minutes` } - unit /= 60 + unit /= BigInt(60) if (unit < 48) { - return `${Math.round(unit)} hours` + return `${unit} hours` } - unit /= 24 + unit /= BigInt(24) if (unit < 14) { - return `${Math.round(unit)} days` + return `${unit} days` } - unit /= 7 + unit /= BigInt(7) if (unit < 52) { - return `${Math.round(unit)} weeks` + return `${unit} weeks` } - unit /= 52 - - return `${unit.toFixed(1)} years` -} - -export function convertAmountToSeconds(amount: number, pricePerBlock: number): number { - // TODO: blocktime should come directly from the blockchain as it may differ between different networks - const blockTime = 5 // On mainnet there is 5 seconds between blocks + unit /= BigInt(52) - // See https://github.com/ethersphere/bee/blob/66f079930d739182c4c79eb6008784afeeba1096/pkg/debugapi/postage.go#L410-L413 - return (amount * blockTime) / pricePerBlock -} - -export function calculateStampPrice(depth: number, amount: bigint): Token { - // See https://github.com/ethersphere/bee/blob/66f079930d739182c4c79eb6008784afeeba1096/pkg/debugapi/postage.go#L410-L413 - return new Token(amount * BigInt(2 ** depth)) // FIXME: the 2 ** depth should be performed on bigint already + return `${unit} years` } export function shortenText(text: string, length = 20, separator = '[…]'): string { @@ -231,20 +211,11 @@ interface Options { timeout?: number } -export function waitUntilStampUsable(batchId: BatchId, bee: Bee, options?: Options): Promise { - return waitForStamp(batchId, bee, 'usable', options) +export function waitUntilStampUsable(batchId: BatchId | string, bee: Bee, options?: Options): Promise { + return waitForStamp(batchId, bee, options) } -export function waitUntilStampExists(batchId: BatchId, bee: Bee, options?: Options): Promise { - return waitForStamp(batchId, bee, 'exists', options) -} - -async function waitForStamp( - batchId: BatchId, - bee: Bee, - field: 'exists' | 'usable', - options?: Options, -): Promise { +async function waitForStamp(batchId: BatchId | string, bee: Bee, options?: Options): Promise { const timeout = options?.timeout || DEFAULT_STAMP_USABLE_TIMEOUT const pollingFrequency = options?.pollingFrequency || DEFAULT_POLLING_FREQUENCY @@ -252,7 +223,9 @@ async function waitForStamp( try { const stamp = await bee.getPostageBatch(batchId) - if (stamp[field]) return stamp + if (stamp.usable) { + return stamp + } } catch { // ignore } diff --git a/src/utils/manifest.ts b/src/utils/manifest.ts deleted file mode 100644 index a833d23d..00000000 --- a/src/utils/manifest.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { Bee, Utils } from '@ethersphere/bee-js' -import { MantarayNode, MetadataMapping, Reference, loadAllNodes } from 'mantaray-js' - -interface ValueNode extends MantarayNode { - getEntry: Reference -} - -/** - * The ASCII code of the character `/`. - * - * This prefix of the root node holds metadata such as the index document. - */ -const INDEX_DOCUMENT_FORK_PREFIX = '47' - -export class ManifestJs { - private bee: Bee - - constructor(bee: Bee) { - this.bee = bee - } - - /** - * Tests whether a given Swarm hash is a valid mantaray manifest - */ - public async isManifest(hash: string): Promise { - try { - const data = await this.bee.downloadData(hash) - const node = new MantarayNode() - node.deserialize(data) - - return true - } catch { - return false - } - } - - /** - * Retrieves `website-index-document` from a Swarm hash, or `null` if it is not present - */ - public async getIndexDocumentPath(hash: string): Promise { - const metadata = await this.getRootSlashMetadata(hash) - - if (!metadata) { - return null - } - - return metadata['website-index-document'] || null - } - - /** - * Retrieves all paths with the associated hashes from a Swarm manifest - */ - public async getHashes(hash: string, options?: { exclude: string[] }): Promise> { - const data = await this.bee.downloadData(hash) - const node = new MantarayNode() - node.deserialize(data) - await loadAllNodes(this.load.bind(this), node) - const result: Record = {} - this.extractHashes(result, node) - - if (options?.exclude) { - for (const path of options.exclude) { - delete result[path] - } - } - - return result - } - - /** - * Resolves an arbitrary Swarm feed manifest to its latest update reference. - * @returns `/bzz` root manifest hash, or `Promise` if hash is not a feed manifest - * @throws in case of network errors or bad input - */ - public async resolveFeedManifest(hash: string): Promise { - const metadata = await this.getRootSlashMetadata(hash) - - if (!metadata) { - return null - } - - const owner = metadata['swarm-feed-owner'] - const topic = metadata['swarm-feed-topic'] - - if (!owner || !topic) { - return null - } - - const reader = this.bee.makeFeedReader('sequence', topic, owner) - const response = await reader.download() - - return response.reference - } - - private async getRootSlashMetadata(hash: string): Promise { - const data = await this.bee.downloadData(hash) - const node = new MantarayNode() - node.deserialize(data) - - if (!node.forks) { - return null - } - const fork = node.forks[INDEX_DOCUMENT_FORK_PREFIX] - - if (!fork) { - return null - } - const metadataNode = fork.node - - if (!metadataNode.IsWithMetadataType()) { - return null - } - const metadata = metadataNode.getMetadata - - if (!metadata) { - return null - } - - return metadata - } - - private extractHashes(result: Record, node: MantarayNode, prefix = ''): void { - if (!node.forks) { - return - } - for (const fork of Object.values(node.forks)) { - const path = prefix + this.bytesToUtf8(fork.prefix) - const childNode = fork.node - - if (this.isValueNode(childNode, path)) { - result[path] = Utils.bytesToHex(childNode.getEntry) - } - - if (childNode.isEdgeType()) { - this.extractHashes(result, childNode, path) - } - } - } - - private load(reference: Uint8Array) { - return this.bee.downloadData(Utils.bytesToHex(reference)) - } - - private bytesToUtf8(bytes: Uint8Array): string { - return new TextDecoder('utf-8').decode(bytes) - } - - private isValueNode(node: MantarayNode, path: string): node is ValueNode { - return !this.isRootSlash(node, path) && node.isValueType() && typeof node.getEntry !== 'undefined' - } - - private isRootSlash(node: MantarayNode, path: string): boolean { - return path === '/' && node.IsWithMetadataType() - } -} diff --git a/src/utils/rpc.ts b/src/utils/rpc.ts index 0fe43101..511b0b1b 100644 --- a/src/utils/rpc.ts +++ b/src/utils/rpc.ts @@ -1,6 +1,7 @@ import { debounce } from '@material-ui/core' -import { Contract, providers, Wallet, BigNumber as BN } from 'ethers' -import { bzzABI, BZZ_TOKEN_ADDRESS } from './bzz-abi' +import { BZZ, DAI, EthAddress, PrivateKey } from '@upcoming/bee-js' +import { BigNumber as BN, Contract, providers, Wallet } from 'ethers' +import { BZZ_TOKEN_ADDRESS, bzzABI } from './bzz-abi' const NETWORK_ID = 100 @@ -12,13 +13,12 @@ async function getNetworkChainId(url: string): Promise { return network.chainId } -async function eth_getBalance(address: string, provider: providers.JsonRpcProvider): Promise { - if (!address.startsWith('0x')) { - address = `0x${address}` - } - const balance = await provider.getBalance(address) +async function eth_getBalance(address: EthAddress | string, provider: providers.JsonRpcProvider): Promise { + address = new EthAddress(address) - return balance.toString() + const balance = await provider.getBalance(address.toHex()) + + return DAI.fromWei(balance.toString()) } async function eth_getBlockByNumber(provider: providers.JsonRpcProvider): Promise { @@ -28,17 +28,16 @@ async function eth_getBlockByNumber(provider: providers.JsonRpcProvider): Promis } async function eth_getBalanceERC20( - address: string, + address: EthAddress | string, provider: providers.JsonRpcProvider, tokenAddress = BZZ_TOKEN_ADDRESS, -): Promise { - if (!address.startsWith('0x')) { - address = `0x${address}` - } +): Promise { + address = new EthAddress(address) + const contract = new Contract(tokenAddress, bzzABI, provider) - const balance = await contract.balanceOf(address) + const balance = await contract.balanceOf(address.toHex()) - return balance.toString() + return BZZ.fromPLUR(balance.toString()) } interface TransferResponse { @@ -47,29 +46,34 @@ interface TransferResponse { } export async function estimateNativeTransferTransactionCost( - privateKey: string, + privateKey: PrivateKey | string, jsonRpcProvider: string, -): Promise<{ gasPrice: BN; totalCost: BN }> { +): Promise<{ gasPrice: DAI; totalCost: DAI }> { + privateKey = new PrivateKey(privateKey) + const signer = await makeReadySigner(privateKey, jsonRpcProvider) const gasLimit = '21000' const gasPrice = await signer.getGasPrice() - return { gasPrice, totalCost: gasPrice.mul(gasLimit) } + return { gasPrice: DAI.fromWei(gasPrice.toString()), totalCost: DAI.fromWei(gasPrice.mul(gasLimit).toString()) } } export async function sendNativeTransaction( - privateKey: string, - to: string, - value: string, + privateKey: PrivateKey | string, + to: EthAddress | string, + value: DAI, jsonRpcProvider: string, - externalGasPrice?: BN, + externalGasPrice?: DAI, ): Promise { + privateKey = new PrivateKey(privateKey) + to = new EthAddress(to) + const signer = await makeReadySigner(privateKey, jsonRpcProvider) - const gasPrice = externalGasPrice ?? (await signer.getGasPrice()) + const gasPrice = externalGasPrice ?? DAI.fromWei((await signer.getGasPrice()).toString()) const transaction = await signer.sendTransaction({ - to, - value: BN.from(value), - gasPrice, + to: to.toHex(), + value: BN.from(value.toWeiString()), + gasPrice: BN.from(gasPrice.toWeiString()), gasLimit: BN.from(21000), type: 0, }) @@ -79,11 +83,14 @@ export async function sendNativeTransaction( } export async function sendBzzTransaction( - privateKey: string, - to: string, - value: string, + privateKey: PrivateKey | string, + to: EthAddress | string, + value: BZZ, jsonRpcProvider: string, ): Promise { + privateKey = new PrivateKey(privateKey) + to = new EthAddress(to) + const signer = await makeReadySigner(privateKey, jsonRpcProvider) const gasPrice = await signer.getGasPrice() const bzz = new Contract(BZZ_TOKEN_ADDRESS, bzzABI, signer) @@ -93,10 +100,10 @@ export async function sendBzzTransaction( return { transaction, receipt } } -async function makeReadySigner(privateKey: string, jsonRpcProvider: string) { +async function makeReadySigner(privateKey: PrivateKey, jsonRpcProvider: string) { const provider = new providers.JsonRpcProvider(jsonRpcProvider, NETWORK_ID) await provider.ready - const signer = new Wallet(privateKey, provider) + const signer = new Wallet(privateKey.toUint8Array(), provider) return signer } diff --git a/src/utils/wallet.ts b/src/utils/wallet.ts index b1a487c2..d75145a5 100644 --- a/src/utils/wallet.ts +++ b/src/utils/wallet.ts @@ -1,39 +1,15 @@ +import { BZZ, DAI, EthAddress } from '@upcoming/bee-js' import { providers, Wallet } from 'ethers' -import { BzzToken } from '../models/BzzToken' -import { DaiToken } from '../models/DaiToken' import { estimateNativeTransferTransactionCost, Rpc } from './rpc' -export class WalletAddress { - private constructor( - public address: string, - public bzz: BzzToken, - public dai: DaiToken, - public provider: providers.JsonRpcProvider, - ) {} - - static async make(address: string, provider: providers.JsonRpcProvider): Promise { - const bzz = new BzzToken(await Rpc._eth_getBalanceERC20(address, provider)) - const dai = new DaiToken(await Rpc._eth_getBalance(address, provider)) - - return new WalletAddress(address, bzz, dai, provider) - } - - public async refresh(): Promise { - this.bzz = new BzzToken(await Rpc._eth_getBalanceERC20(this.address, this.provider)) - this.dai = new DaiToken(await Rpc._eth_getBalance(this.address, this.provider)) - - return this - } -} - export class ResolvedWallet { public address: string public privateKey: string private constructor( public wallet: Wallet, - public bzz: BzzToken, - public dai: DaiToken, + public bzz: BZZ, + public dai: DAI, public provider: providers.JsonRpcProvider, ) { this.address = wallet.address @@ -44,32 +20,32 @@ export class ResolvedWallet { const wallet = typeof privateKeyOrWallet === 'string' ? new Wallet(privateKeyOrWallet, provider) : privateKeyOrWallet const address = wallet.address - const bzz = new BzzToken(await Rpc._eth_getBalanceERC20(address, provider)) - const dai = new DaiToken(await Rpc._eth_getBalance(address, provider)) + const bzz = await Rpc._eth_getBalanceERC20(address, provider) + const dai = await Rpc._eth_getBalance(address, provider) return new ResolvedWallet(wallet, bzz, dai, provider) } public async refresh(): Promise { - this.bzz = new BzzToken(await Rpc._eth_getBalanceERC20(this.address, this.provider)) - this.dai = new DaiToken(await Rpc._eth_getBalance(this.address, this.provider)) + this.bzz = await Rpc._eth_getBalanceERC20(this.address, this.provider) + this.dai = await Rpc._eth_getBalance(this.address, this.provider) return this } - public async transfer(destination: string, jsonRpcProvider: string): Promise { - if (this.bzz.toDecimal.gt(0.05)) { - await Rpc.sendBzzTransaction(this.privateKey, destination, this.bzz.toString, jsonRpcProvider) + public async transfer(destination: EthAddress | string, jsonRpcProvider: string): Promise { + if (this.bzz.gt(BZZ.fromDecimalString('0.05'))) { + await Rpc.sendBzzTransaction(this.privateKey, destination, this.bzz, jsonRpcProvider) await this.refresh() } const { gasPrice, totalCost } = await estimateNativeTransferTransactionCost(this.privateKey, jsonRpcProvider) - if (this.dai.toBigNumber.gt(totalCost.toString())) { + if (this.dai.gt(totalCost)) { await Rpc.sendNativeTransaction( this.privateKey, destination, - this.dai.toBigNumber.minus(totalCost.toString()).toString(), + this.dai.minus(totalCost), jsonRpcProvider, gasPrice, )