Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d91c334cf8 | |||
| bce93ce3cd | |||
| 8367f2b76a | |||
| 055a3002b3 | |||
| c9c4e7d7d1 | |||
| d97bc27c14 | |||
| e215c61ea1 | |||
| 8298d0bc66 | |||
| fac72b1299 | |||
| e780b971d9 | |||
| 90f9f91ddb | |||
| 01838dccd1 | |||
| 42b7f080b0 | |||
| a88e78e748 | |||
| 665ae063fa | |||
| dc04e26db4 | |||
| b798fa0e68 | |||
| 4e564dd5c0 | |||
| 1c53364fcd | |||
| 848e61a7a0 | |||
| c3a940c8d7 | |||
| 02469046b0 | |||
| 1ce4a47495 | |||
| 9a8520eb6f | |||
| ec8fdf0315 | |||
| a4b8e7ca25 | |||
| 693609810d | |||
| 73f845a73a | |||
| b6419297f4 | |||
| 9d2d271c20 | |||
| c0456a3bf6 |
@@ -61,6 +61,7 @@ jobs:
|
|||||||
uses: ethersphere/update-supported-bee-action@v1
|
uses: ethersphere/update-supported-bee-action@v1
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
with:
|
with:
|
||||||
|
updateEngine: true
|
||||||
token: ${{ secrets.GHA_PAT_BASIC }}
|
token: ${{ secrets.GHA_PAT_BASIC }}
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -71,6 +72,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create preview
|
- name: Create preview
|
||||||
uses: ethersphere/swarm-actions/pr-preview@v0
|
uses: ethersphere/swarm-actions/pr-preview@v0
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
bee-url: https://unlimited.gateway.ethswarm.org
|
bee-url: https://unlimited.gateway.ethswarm.org
|
||||||
token: ${{ secrets.GHA_PAT_BASIC }}
|
token: ${{ secrets.GHA_PAT_BASIC }}
|
||||||
|
|||||||
@@ -1,5 +1,69 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## [0.24.1](https://github.com/ethersphere/bee-dashboard/compare/v0.24.0...v0.24.1) (2023-10-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* update `swap-endpoint` to `blockchain-rpc-endpoint` ([#628](https://github.com/ethersphere/bee-dashboard/issues/628)) ([bce93ce](https://github.com/ethersphere/bee-dashboard/commit/bce93ce3cdc1ef4b1f50fcf274591ba00726be16))
|
||||||
|
|
||||||
|
## [0.24.0](https://github.com/ethersphere/bee-dashboard/compare/v0.23.0...v0.24.0) (2023-08-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add stamp dilute and topup ([#619](https://github.com/ethersphere/bee-dashboard/issues/619)) ([055a300](https://github.com/ethersphere/bee-dashboard/commit/055a3002b303df45c7010ef4d365e14b979e9084))
|
||||||
|
|
||||||
|
## [0.23.0](https://github.com/ethersphere/bee-dashboard/compare/v0.22.0...v0.23.0) (2023-02-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add staking for full nodes ([#590](https://github.com/ethersphere/bee-dashboard/issues/590)) ([fac72b1](https://github.com/ethersphere/bee-dashboard/commit/fac72b1299353c104231aa038c1bab9df78c1355))
|
||||||
|
* upgrade bee-js to 5.2.0 ([#611](https://github.com/ethersphere/bee-dashboard/issues/611)) ([e215c61](https://github.com/ethersphere/bee-dashboard/commit/e215c61ea1619fc388fe8b1904d160b04a1a5c0d))
|
||||||
|
|
||||||
|
## [0.22.0](https://github.com/ethersphere/bee-dashboard/compare/v0.21.1...v0.22.0) (2023-01-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add node connecting status ([#603](https://github.com/ethersphere/bee-dashboard/issues/603)) ([90f9f91](https://github.com/ethersphere/bee-dashboard/commit/90f9f91ddbefb47b40c7e567125972b800d81972))
|
||||||
|
|
||||||
|
## [0.21.1](https://github.com/ethersphere/bee-dashboard/compare/v0.21.0...v0.21.1) (2022-12-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* do not require chequebook funding ([#599](https://github.com/ethersphere/bee-dashboard/issues/599)) ([42b7f08](https://github.com/ethersphere/bee-dashboard/commit/42b7f080b00a94f068d2fad4779d02ddcf58e27d))
|
||||||
|
|
||||||
|
## [0.21.0](https://github.com/ethersphere/bee-dashboard/compare/v0.20.2...v0.21.0) (2022-12-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add prerequisite checks before swap ([#588](https://github.com/ethersphere/bee-dashboard/issues/588)) ([4e564dd](https://github.com/ethersphere/bee-dashboard/commit/4e564dd5c08b938c95f07818bc60957a7df4f5bb))
|
||||||
|
* add starting state to sidebar indicator ([#587](https://github.com/ethersphere/bee-dashboard/issues/587)) ([848e61a](https://github.com/ethersphere/bee-dashboard/commit/848e61a7a0fc9b31cae4f603473b37d467f9e914))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add loading state to info page ([#584](https://github.com/ethersphere/bee-dashboard/issues/584)) ([0246904](https://github.com/ethersphere/bee-dashboard/commit/02469046b05512d6617d8b21ca93b41d6a8a6827))
|
||||||
|
* always consider user input when performing swap ([#572](https://github.com/ethersphere/bee-dashboard/issues/572)) ([ec8fdf0](https://github.com/ethersphere/bee-dashboard/commit/ec8fdf0315ed7ee75c7612780c602cba49a2321d))
|
||||||
|
* always set rpc to newly provided value in desktop ([#591](https://github.com/ethersphere/bee-dashboard/issues/591)) ([b798fa0](https://github.com/ethersphere/bee-dashboard/commit/b798fa0e68b367fe324ef64507b1405b642da6e0))
|
||||||
|
* change status page depending on desktop mode ([#573](https://github.com/ethersphere/bee-dashboard/issues/573)) ([a4b8e7c](https://github.com/ethersphere/bee-dashboard/commit/a4b8e7ca2596028e7c8192c92202c0361610e307))
|
||||||
|
* change version mismatch to a warning ([#594](https://github.com/ethersphere/bee-dashboard/issues/594)) ([dc04e26](https://github.com/ethersphere/bee-dashboard/commit/dc04e26db4fe6beb9e76fad79c732794b0b7f77d))
|
||||||
|
* fix conditional rendering for blockchain network ([#583](https://github.com/ethersphere/bee-dashboard/issues/583)) ([1ce4a47](https://github.com/ethersphere/bee-dashboard/commit/1ce4a474954a5ba4debee53b40bb66a46fb19ffc))
|
||||||
|
* handle auth and server error during swap ([#593](https://github.com/ethersphere/bee-dashboard/issues/593)) ([665ae06](https://github.com/ethersphere/bee-dashboard/commit/665ae063fa49bc94762ea10a9098b57e95327d9c))
|
||||||
|
* hide swap in standalone mode ([#582](https://github.com/ethersphere/bee-dashboard/issues/582)) ([9a8520e](https://github.com/ethersphere/bee-dashboard/commit/9a8520eb6fe9f40a77c4230ab79d3731ebdd4b42))
|
||||||
|
* refresh after chequebook withdraw deposit ([#576](https://github.com/ethersphere/bee-dashboard/issues/576)) ([6936098](https://github.com/ethersphere/bee-dashboard/commit/693609810d735d1e54691b13ea0e4db33e678a53))
|
||||||
|
|
||||||
|
## [0.20.2](https://github.com/ethersphere/bee-dashboard/compare/v0.20.1...v0.20.2) (2022-09-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* stamp purchasing ([#551](https://github.com/ethersphere/bee-dashboard/issues/551)) ([c0456a3](https://github.com/ethersphere/bee-dashboard/commit/c0456a3bf6d541457b706670b1a757d2b1d70f10))
|
||||||
|
|
||||||
## [0.20.1](https://github.com/ethersphere/bee-dashboard/compare/v0.20.0...v0.20.1) (2022-09-15)
|
## [0.20.1](https://github.com/ethersphere/bee-dashboard/compare/v0.20.0...v0.20.1) (2022-09-15)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
**Warning: This project is in alpha state. There might (and most probably will) be changes in the future to its API and
|
**Warning: This project is in alpha state. There might (and most probably will) be changes in the future to its API and
|
||||||
working. Also, no guarantees can be made about its stability, efficiency, and security at this stage.**
|
working. Also, no guarantees can be made about its stability, efficiency, and security at this stage.**
|
||||||
|
|
||||||
This project is intended to be used with **Bee version <!-- SUPPORTED_BEE_START -->1.7.0-bbf13011<!-- SUPPORTED_BEE_END -->**.
|
This project is intended to be used with **Bee version <!-- SUPPORTED_BEE_START -->1.12.0-88c1d236<!-- SUPPORTED_BEE_END -->**.
|
||||||
Using it with older or newer Bee versions is not recommended and may not work. Stay up to date by joining the
|
Using it with older or newer Bee versions is not recommended and may not work. Stay up to date by joining the
|
||||||
[official Discord](https://discord.gg/GU22h2utj6) and by keeping an eye on the
|
[official Discord](https://discord.gg/GU22h2utj6) and by keeping an eye on the
|
||||||
[releases tab](https://github.com/ethersphere/bee-dashboard/releases).
|
[releases tab](https://github.com/ethersphere/bee-dashboard/releases).
|
||||||
@@ -107,10 +107,10 @@ We support following variables:
|
|||||||
|
|
||||||
#### Swarm Desktop development
|
#### Swarm Desktop development
|
||||||
|
|
||||||
If you want to develop Bee Dashboard in the Swarm Desktop mode, then spin up `swarm-desktop` to the point where you see Bee Dashboard (eq. install Bee etc.) and:
|
If you want to develop Bee Dashboard in the Swarm Desktop mode, then spin up `swarm-desktop` to the point where Desktop is initialized (eq. the splash screen disappear) and:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
echo "REACT_APP_BEE_DESKTOP_URL=http://localhost:3000
|
echo "REACT_APP_BEE_DESKTOP_URL=http://localhost:3054
|
||||||
REACT_APP_BEE_DESKTOP_ENABLED=true" > .env.development.local
|
REACT_APP_BEE_DESKTOP_ENABLED=true" > .env.development.local
|
||||||
|
|
||||||
npm start
|
npm start
|
||||||
|
|||||||
Generated
+100
-211
@@ -1,16 +1,15 @@
|
|||||||
{
|
{
|
||||||
"name": "@ethersphere/bee-dashboard",
|
"name": "@ethersphere/bee-dashboard",
|
||||||
"version": "0.20.1",
|
"version": "0.24.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@ethersphere/bee-dashboard",
|
"name": "@ethersphere/bee-dashboard",
|
||||||
"version": "0.20.1",
|
"version": "0.24.1",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersphere/bee-js": "^5.0.0",
|
"@ethersphere/bee-js": "^6.2.0",
|
||||||
"@ethersphere/manifest-js": "1.2.1",
|
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@material-ui/core": "4.12.3",
|
"@material-ui/core": "4.12.3",
|
||||||
"@material-ui/icons": "4.11.2",
|
"@material-ui/icons": "4.11.2",
|
||||||
@@ -27,13 +26,14 @@
|
|||||||
"formik": "2.2.9",
|
"formik": "2.2.9",
|
||||||
"formik-material-ui": "3.0.1",
|
"formik-material-ui": "3.0.1",
|
||||||
"jszip": "^3.7.1",
|
"jszip": "^3.7.1",
|
||||||
|
"mantaray-js": "^1.0.3",
|
||||||
"material-ui-dropzone": "3.5.0",
|
"material-ui-dropzone": "3.5.0",
|
||||||
"notistack": "1.0.10",
|
"notistack": "1.0.10",
|
||||||
"opener": "1.5.2",
|
"opener": "1.5.2",
|
||||||
"qrcode.react": "1.0.1",
|
"qrcode.react": "1.0.1",
|
||||||
"react": ">=17.0.0 || >=18.0.0",
|
"react": ">= 17.0.2",
|
||||||
"react-copy-to-clipboard": "5.0.4",
|
"react-copy-to-clipboard": "5.0.4",
|
||||||
"react-dom": ">=17.0.0 || >=18.0.0",
|
"react-dom": ">= 17.0.2",
|
||||||
"react-identicons": "1.2.5",
|
"react-identicons": "1.2.5",
|
||||||
"react-router": "6.2.1",
|
"react-router": "6.2.1",
|
||||||
"react-router-dom": "6.2.1",
|
"react-router-dom": "6.2.1",
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
"webpack-cli": "^4.10.0"
|
"webpack-cli": "^4.10.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"bee": ">=0.6.0",
|
"bee": "1.16.1-8e269c8",
|
||||||
"node": ">=14.0.0",
|
"node": ">=14.0.0",
|
||||||
"npm": ">=6.9.0"
|
"npm": ">=6.9.0"
|
||||||
},
|
},
|
||||||
@@ -2440,33 +2440,54 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ethersphere/bee-js": {
|
"node_modules/@ethersphere/bee-js": {
|
||||||
"version": "5.0.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-6.2.0.tgz",
|
||||||
"integrity": "sha512-Dr5Xon0UZvi37fvbyGj46kw3/0D8fydwfDtVtFHKi2p7mNEizG0uok2mXvwLZrMvUMOS8uXkFhbQjTFBjB+pWA==",
|
"integrity": "sha512-QWuVvW+c9z+AFWuRL+YBZECDyV3G5qeD9L0J7Tx7HYMugoDjMAjeRyNHjkf0a5np57q3i9MAE2P678rjSJ1Yaw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@types/readable-stream": "^2.3.13",
|
"@types/readable-stream": "^2.3.13",
|
||||||
"bufferutil": "^4.0.6",
|
"axios": "^1.3.4",
|
||||||
|
"cafe-utility": "^10.8.1",
|
||||||
"elliptic": "^6.5.4",
|
"elliptic": "^6.5.4",
|
||||||
"fetch-blob": "2.1.2",
|
"fetch-blob": "2.1.2",
|
||||||
"isomorphic-ws": "^4.0.1",
|
"isomorphic-ws": "^4.0.1",
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"ky": "^0.25.1",
|
|
||||||
"ky-universal": "^0.8.2",
|
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"tar-js": "^0.3.0",
|
"tar-js": "^0.3.0",
|
||||||
"utf-8-validate": "^5.0.9",
|
"web-streams-polyfill": "^4.0.0-beta.3",
|
||||||
"web-streams-polyfill": "^4.0.0-beta.1",
|
|
||||||
"ws": "^8.7.0"
|
"ws": "^8.7.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"bee": "1.7.0-bbf13011",
|
"bee": "1.13.0-f1067884",
|
||||||
"beeApiVersion": "3.0.2",
|
"beeApiVersion": "4.0.0",
|
||||||
"beeDebugApiVersion": "3.0.2",
|
"beeDebugApiVersion": "4.0.0",
|
||||||
"node": ">=14.0.0",
|
"node": ">=14.0.0",
|
||||||
"npm": ">=6.0.0"
|
"npm": ">=6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@ethersphere/bee-js/node_modules/axios": {
|
||||||
|
"version": "1.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
|
||||||
|
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"follow-redirects": "^1.15.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@ethersphere/bee-js/node_modules/form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@ethersphere/bee-js/node_modules/web-streams-polyfill": {
|
"node_modules/@ethersphere/bee-js/node_modules/web-streams-polyfill": {
|
||||||
"version": "4.0.0-beta.3",
|
"version": "4.0.0-beta.3",
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
||||||
@@ -2495,22 +2516,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@ethersphere/manifest-js": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/manifest-js/-/manifest-js-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-HfeQ5h9KuH8xTxYY6bmSNwmpalrdDyOu4Sl6mrAN2W2iJlIjuG5DeirseSEFXElKPwEdv03PzZt2vARPna8sfw==",
|
|
||||||
"dependencies": {
|
|
||||||
"mantaray-js": "^1.0.3"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"bee": "1.6.0-6ceadd35",
|
|
||||||
"node": ">=12.0.0",
|
|
||||||
"npm": ">=6.0.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@ethersphere/bee-js": ">=4.x"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@ethersphere/swarm-cid": {
|
"node_modules/@ethersphere/swarm-cid": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/swarm-cid/-/swarm-cid-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersphere/swarm-cid/-/swarm-cid-0.1.0.tgz",
|
||||||
@@ -5656,17 +5661,6 @@
|
|||||||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/abort-controller": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
|
||||||
"dependencies": {
|
|
||||||
"event-target-shim": "^5.0.0"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6.5"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/accepts": {
|
"node_modules/accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||||
@@ -6058,8 +6052,7 @@
|
|||||||
"node_modules/asynckit": {
|
"node_modules/asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/at-least-node": {
|
"node_modules/at-least-node": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -6899,6 +6892,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
|
||||||
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
|
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-gyp-build": "^4.3.0"
|
"node-gyp-build": "^4.3.0"
|
||||||
},
|
},
|
||||||
@@ -6926,6 +6921,11 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cafe-utility": {
|
||||||
|
"version": "10.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cafe-utility/-/cafe-utility-10.9.1.tgz",
|
||||||
|
"integrity": "sha512-/gq+ANoYvMJKrXXI/2YAiB2KhNlRhxB5XcWbbMWFA39LLCxkPhG5A9Ehy4QGv28EvndZLbBV44lJyCG+JIoDuw=="
|
||||||
|
},
|
||||||
"node_modules/call-bind": {
|
"node_modules/call-bind": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||||
@@ -7337,7 +7337,6 @@
|
|||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
},
|
},
|
||||||
@@ -8211,14 +8210,6 @@
|
|||||||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/data-uri-to-buffer": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/data-urls": {
|
"node_modules/data-urls": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
||||||
@@ -8331,7 +8322,6 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
@@ -9903,14 +9893,6 @@
|
|||||||
"ws": "7.4.6"
|
"ws": "7.4.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/event-target-shim": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/eventemitter3": {
|
"node_modules/eventemitter3": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
@@ -10512,9 +10494,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/follow-redirects": {
|
"node_modules/follow-redirects": {
|
||||||
"version": "1.14.5",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==",
|
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@@ -13693,41 +13675,6 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ky": {
|
|
||||||
"version": "0.25.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ky/-/ky-0.25.1.tgz",
|
|
||||||
"integrity": "sha512-PjpCEWlIU7VpiMVrTwssahkYXX1by6NCT0fhTUX34F3DTinARlgMpriuroolugFPcMgpPWrOW4mTb984Qm1RXA==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sindresorhus/ky?sponsor=1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/ky-universal": {
|
|
||||||
"version": "0.8.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ky-universal/-/ky-universal-0.8.2.tgz",
|
|
||||||
"integrity": "sha512-xe0JaOH9QeYxdyGLnzUOVGK4Z6FGvDVzcXFTdrYA1f33MZdEa45sUDaMBy98xQMcsd2XIBrTXRrRYnegcSdgVQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"abort-controller": "^3.0.0",
|
|
||||||
"node-fetch": "3.0.0-beta.9"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10.17"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"url": "https://github.com/sindresorhus/ky-universal?sponsor=1"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"ky": ">=0.17.0",
|
|
||||||
"web-streams-polyfill": ">=2.0.0"
|
|
||||||
},
|
|
||||||
"peerDependenciesMeta": {
|
|
||||||
"web-streams-polyfill": {
|
|
||||||
"optional": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/language-subtag-registry": {
|
"node_modules/language-subtag-registry": {
|
||||||
"version": "0.3.21",
|
"version": "0.3.21",
|
||||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||||
@@ -14112,7 +14059,6 @@
|
|||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
@@ -14121,7 +14067,6 @@
|
|||||||
"version": "2.1.35",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"mime-db": "1.52.0"
|
"mime-db": "1.52.0"
|
||||||
},
|
},
|
||||||
@@ -14364,22 +14309,6 @@
|
|||||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
|
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/node-fetch": {
|
|
||||||
"version": "3.0.0-beta.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0-beta.9.tgz",
|
|
||||||
"integrity": "sha512-RdbZCEynH2tH46+tj0ua9caUHVWrd/RHnRfvly2EVdqGmI3ndS1Vn/xjm5KuGejDt2RNDQsVRLPNd2QPwcewVg==",
|
|
||||||
"dependencies": {
|
|
||||||
"data-uri-to-buffer": "^3.0.1",
|
|
||||||
"fetch-blob": "^2.1.1"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^10.17 || >=12.3"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/node-fetch"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-forge": {
|
"node_modules/node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||||
@@ -14393,6 +14322,8 @@
|
|||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
|
||||||
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
|
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"node-gyp-build": "bin.js",
|
"node-gyp-build": "bin.js",
|
||||||
"node-gyp-build-optional": "optional.js",
|
"node-gyp-build-optional": "optional.js",
|
||||||
@@ -16560,8 +16491,7 @@
|
|||||||
"node_modules/proxy-from-env": {
|
"node_modules/proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/psl": {
|
"node_modules/psl": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
@@ -19579,6 +19509,8 @@
|
|||||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
|
||||||
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
|
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-gyp-build": "^4.3.0"
|
"node-gyp-build": "^4.3.0"
|
||||||
},
|
},
|
||||||
@@ -19734,16 +19666,6 @@
|
|||||||
"minimalistic-assert": "^1.0.0"
|
"minimalistic-assert": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/web-streams-polyfill": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/web-vitals": {
|
"node_modules/web-vitals": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.2.tgz",
|
||||||
@@ -22383,26 +22305,44 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ethersphere/bee-js": {
|
"@ethersphere/bee-js": {
|
||||||
"version": "5.0.0",
|
"version": "6.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersphere/bee-js/-/bee-js-6.2.0.tgz",
|
||||||
"integrity": "sha512-Dr5Xon0UZvi37fvbyGj46kw3/0D8fydwfDtVtFHKi2p7mNEizG0uok2mXvwLZrMvUMOS8uXkFhbQjTFBjB+pWA==",
|
"integrity": "sha512-QWuVvW+c9z+AFWuRL+YBZECDyV3G5qeD9L0J7Tx7HYMugoDjMAjeRyNHjkf0a5np57q3i9MAE2P678rjSJ1Yaw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@types/readable-stream": "^2.3.13",
|
"@types/readable-stream": "^2.3.13",
|
||||||
"bufferutil": "^4.0.6",
|
"axios": "^1.3.4",
|
||||||
|
"cafe-utility": "^10.8.1",
|
||||||
"elliptic": "^6.5.4",
|
"elliptic": "^6.5.4",
|
||||||
"fetch-blob": "2.1.2",
|
"fetch-blob": "2.1.2",
|
||||||
"isomorphic-ws": "^4.0.1",
|
"isomorphic-ws": "^4.0.1",
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"ky": "^0.25.1",
|
|
||||||
"ky-universal": "^0.8.2",
|
|
||||||
"semver": "^7.3.5",
|
"semver": "^7.3.5",
|
||||||
"tar-js": "^0.3.0",
|
"tar-js": "^0.3.0",
|
||||||
"utf-8-validate": "^5.0.9",
|
"web-streams-polyfill": "^4.0.0-beta.3",
|
||||||
"web-streams-polyfill": "^4.0.0-beta.1",
|
|
||||||
"ws": "^8.7.0"
|
"ws": "^8.7.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": {
|
||||||
|
"version": "1.3.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
|
||||||
|
"integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
|
||||||
|
"requires": {
|
||||||
|
"follow-redirects": "^1.15.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"proxy-from-env": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"form-data": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
|
||||||
|
"requires": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"web-streams-polyfill": {
|
"web-streams-polyfill": {
|
||||||
"version": "4.0.0-beta.3",
|
"version": "4.0.0-beta.3",
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
|
||||||
@@ -22416,14 +22356,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@ethersphere/manifest-js": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/manifest-js/-/manifest-js-1.2.1.tgz",
|
|
||||||
"integrity": "sha512-HfeQ5h9KuH8xTxYY6bmSNwmpalrdDyOu4Sl6mrAN2W2iJlIjuG5DeirseSEFXElKPwEdv03PzZt2vARPna8sfw==",
|
|
||||||
"requires": {
|
|
||||||
"mantaray-js": "^1.0.3"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@ethersphere/swarm-cid": {
|
"@ethersphere/swarm-cid": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@ethersphere/swarm-cid/-/swarm-cid-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ethersphere/swarm-cid/-/swarm-cid-0.1.0.tgz",
|
||||||
@@ -24680,14 +24612,6 @@
|
|||||||
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
"integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"abort-controller": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
|
||||||
"requires": {
|
|
||||||
"event-target-shim": "^5.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"accepts": {
|
"accepts": {
|
||||||
"version": "1.3.8",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||||
@@ -24986,8 +24910,7 @@
|
|||||||
"asynckit": {
|
"asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"at-least-node": {
|
"at-least-node": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
@@ -25626,6 +25549,8 @@
|
|||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz",
|
||||||
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
|
"integrity": "sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"node-gyp-build": "^4.3.0"
|
"node-gyp-build": "^4.3.0"
|
||||||
}
|
}
|
||||||
@@ -25641,6 +25566,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
|
||||||
"integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="
|
"integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="
|
||||||
},
|
},
|
||||||
|
"cafe-utility": {
|
||||||
|
"version": "10.9.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/cafe-utility/-/cafe-utility-10.9.1.tgz",
|
||||||
|
"integrity": "sha512-/gq+ANoYvMJKrXXI/2YAiB2KhNlRhxB5XcWbbMWFA39LLCxkPhG5A9Ehy4QGv28EvndZLbBV44lJyCG+JIoDuw=="
|
||||||
|
},
|
||||||
"call-bind": {
|
"call-bind": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||||
@@ -25958,7 +25888,6 @@
|
|||||||
"version": "1.0.8",
|
"version": "1.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
}
|
}
|
||||||
@@ -26624,11 +26553,6 @@
|
|||||||
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"data-uri-to-buffer": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og=="
|
|
||||||
},
|
|
||||||
"data-urls": {
|
"data-urls": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
|
||||||
@@ -26711,8 +26635,7 @@
|
|||||||
"delayed-stream": {
|
"delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"depcheck": {
|
"depcheck": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
@@ -27902,11 +27825,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"event-target-shim": {
|
|
||||||
"version": "5.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
|
||||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
|
||||||
},
|
|
||||||
"eventemitter3": {
|
"eventemitter3": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
|
||||||
@@ -28387,9 +28305,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"follow-redirects": {
|
"follow-redirects": {
|
||||||
"version": "1.14.5",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.5.tgz",
|
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||||
"integrity": "sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA=="
|
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
|
||||||
},
|
},
|
||||||
"for-each": {
|
"for-each": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
@@ -30734,20 +30652,6 @@
|
|||||||
"integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==",
|
"integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ky": {
|
|
||||||
"version": "0.25.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/ky/-/ky-0.25.1.tgz",
|
|
||||||
"integrity": "sha512-PjpCEWlIU7VpiMVrTwssahkYXX1by6NCT0fhTUX34F3DTinARlgMpriuroolugFPcMgpPWrOW4mTb984Qm1RXA=="
|
|
||||||
},
|
|
||||||
"ky-universal": {
|
|
||||||
"version": "0.8.2",
|
|
||||||
"resolved": "https://registry.npmjs.org/ky-universal/-/ky-universal-0.8.2.tgz",
|
|
||||||
"integrity": "sha512-xe0JaOH9QeYxdyGLnzUOVGK4Z6FGvDVzcXFTdrYA1f33MZdEa45sUDaMBy98xQMcsd2XIBrTXRrRYnegcSdgVQ==",
|
|
||||||
"requires": {
|
|
||||||
"abort-controller": "^3.0.0",
|
|
||||||
"node-fetch": "3.0.0-beta.9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"language-subtag-registry": {
|
"language-subtag-registry": {
|
||||||
"version": "0.3.21",
|
"version": "0.3.21",
|
||||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||||
@@ -31063,14 +30967,12 @@
|
|||||||
"mime-db": {
|
"mime-db": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"mime-types": {
|
"mime-types": {
|
||||||
"version": "2.1.35",
|
"version": "2.1.35",
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"mime-db": "1.52.0"
|
"mime-db": "1.52.0"
|
||||||
}
|
}
|
||||||
@@ -31260,15 +31162,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node-fetch": {
|
|
||||||
"version": "3.0.0-beta.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.0.0-beta.9.tgz",
|
|
||||||
"integrity": "sha512-RdbZCEynH2tH46+tj0ua9caUHVWrd/RHnRfvly2EVdqGmI3ndS1Vn/xjm5KuGejDt2RNDQsVRLPNd2QPwcewVg==",
|
|
||||||
"requires": {
|
|
||||||
"data-uri-to-buffer": "^3.0.1",
|
|
||||||
"fetch-blob": "^2.1.1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node-forge": {
|
"node-forge": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
|
||||||
@@ -31278,7 +31171,9 @@
|
|||||||
"node-gyp-build": {
|
"node-gyp-build": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
|
||||||
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q=="
|
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true
|
||||||
},
|
},
|
||||||
"node-int64": {
|
"node-int64": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
@@ -32725,8 +32620,7 @@
|
|||||||
"proxy-from-env": {
|
"proxy-from-env": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"psl": {
|
"psl": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
@@ -35030,6 +34924,8 @@
|
|||||||
"version": "5.0.9",
|
"version": "5.0.9",
|
||||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
|
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz",
|
||||||
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
|
"integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==",
|
||||||
|
"optional": true,
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"node-gyp-build": "^4.3.0"
|
"node-gyp-build": "^4.3.0"
|
||||||
}
|
}
|
||||||
@@ -35163,13 +35059,6 @@
|
|||||||
"minimalistic-assert": "^1.0.0"
|
"minimalistic-assert": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"web-streams-polyfill": {
|
|
||||||
"version": "3.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
|
|
||||||
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true
|
|
||||||
},
|
|
||||||
"web-vitals": {
|
"web-vitals": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-2.1.2.tgz",
|
||||||
|
|||||||
+8
-7
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ethersphere/bee-dashboard",
|
"name": "@ethersphere/bee-dashboard",
|
||||||
"version": "0.20.1",
|
"version": "0.24.1",
|
||||||
"description": "An app which helps users to setup their Bee node and do actions like cash out cheques",
|
"description": "An app which helps users to setup their Bee node and do actions like cash out cheques",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"bee",
|
"bee",
|
||||||
@@ -26,8 +26,7 @@
|
|||||||
"url": "https://github.com/ethersphere/bee-dashboard.git"
|
"url": "https://github.com/ethersphere/bee-dashboard.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ethersphere/bee-js": "^5.0.0",
|
"@ethersphere/bee-js": "^6.2.0",
|
||||||
"@ethersphere/manifest-js": "1.2.1",
|
|
||||||
"@ethersphere/swarm-cid": "^0.1.0",
|
"@ethersphere/swarm-cid": "^0.1.0",
|
||||||
"@material-ui/core": "4.12.3",
|
"@material-ui/core": "4.12.3",
|
||||||
"@material-ui/icons": "4.11.2",
|
"@material-ui/icons": "4.11.2",
|
||||||
@@ -44,13 +43,14 @@
|
|||||||
"formik": "2.2.9",
|
"formik": "2.2.9",
|
||||||
"formik-material-ui": "3.0.1",
|
"formik-material-ui": "3.0.1",
|
||||||
"jszip": "^3.7.1",
|
"jszip": "^3.7.1",
|
||||||
|
"mantaray-js": "^1.0.3",
|
||||||
"material-ui-dropzone": "3.5.0",
|
"material-ui-dropzone": "3.5.0",
|
||||||
"notistack": "1.0.10",
|
"notistack": "1.0.10",
|
||||||
"opener": "1.5.2",
|
"opener": "1.5.2",
|
||||||
"qrcode.react": "1.0.1",
|
"qrcode.react": "1.0.1",
|
||||||
"react": ">=17.0.0 || >=18.0.0",
|
"react": ">= 17.0.2",
|
||||||
"react-copy-to-clipboard": "5.0.4",
|
"react-copy-to-clipboard": "5.0.4",
|
||||||
"react-dom": ">=17.0.0 || >=18.0.0",
|
"react-dom": ">= 17.0.2",
|
||||||
"react-identicons": "1.2.5",
|
"react-identicons": "1.2.5",
|
||||||
"react-router": "6.2.1",
|
"react-router": "6.2.1",
|
||||||
"react-router-dom": "6.2.1",
|
"react-router-dom": "6.2.1",
|
||||||
@@ -136,7 +136,8 @@
|
|||||||
"lint": "eslint --fix \"src/**/*.ts\" \"src/**/*.tsx\" && prettier --write \"src/**/*.ts\" \"src/**/*.tsx\"",
|
"lint": "eslint --fix \"src/**/*.ts\" \"src/**/*.tsx\" && prettier --write \"src/**/*.ts\" \"src/**/*.tsx\"",
|
||||||
"lint:check": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" && prettier --check \"src/**/*.ts\" \"src/**/*.tsx\"",
|
"lint:check": "eslint \"src/**/*.ts\" \"src/**/*.tsx\" && prettier --check \"src/**/*.ts\" \"src/**/*.tsx\"",
|
||||||
"check:types": "tsc --project tsconfig.lib.json",
|
"check:types": "tsc --project tsconfig.lib.json",
|
||||||
"update-map-data": "node ./utils/update-map-data.js"
|
"update-map-data": "node ./utils/update-map-data.js",
|
||||||
|
"bee": "npx bee-factory start"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"lib",
|
"lib",
|
||||||
@@ -158,6 +159,6 @@
|
|||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=14.0.0",
|
"node": ">=14.0.0",
|
||||||
"npm": ">=6.9.0",
|
"npm": ">=6.9.0",
|
||||||
"bee": ">=0.6.0"
|
"bee": "1.16.1-8e269c8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
import CssBaseline from '@material-ui/core/CssBaseline'
|
import CssBaseline from '@material-ui/core/CssBaseline'
|
||||||
import { ThemeProvider } from '@material-ui/core/styles'
|
import { ThemeProvider } from '@material-ui/core/styles'
|
||||||
import { SnackbarProvider } from 'notistack'
|
import { SnackbarProvider } from 'notistack'
|
||||||
import React, { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import { HashRouter as Router } from 'react-router-dom'
|
import { HashRouter as Router } from 'react-router-dom'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
import Dashboard from './layout/Dashboard'
|
import Dashboard from './layout/Dashboard'
|
||||||
@@ -47,7 +47,7 @@ const App = ({
|
|||||||
desktopUrl={desktopUrl}
|
desktopUrl={desktopUrl}
|
||||||
>
|
>
|
||||||
<TopUpProvider>
|
<TopUpProvider>
|
||||||
<BeeProvider>
|
<BeeProvider isDesktop={isDesktop}>
|
||||||
<BalanceProvider>
|
<BalanceProvider>
|
||||||
<StampsProvider>
|
<StampsProvider>
|
||||||
<FileProvider>
|
<FileProvider>
|
||||||
|
|||||||
+16
-2
@@ -2,6 +2,8 @@ import { createStyles, makeStyles, Theme, Typography } from '@material-ui/core'
|
|||||||
import { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import Check from 'remixicon-react/CheckLineIcon'
|
import Check from 'remixicon-react/CheckLineIcon'
|
||||||
import AlertCircle from 'remixicon-react/ErrorWarningFillIcon'
|
import AlertCircle from 'remixicon-react/ErrorWarningFillIcon'
|
||||||
|
import Connecting from 'remixicon-react/LinksLineIcon'
|
||||||
|
import RefreshLine from 'remixicon-react/RefreshLineIcon'
|
||||||
import { SwarmButton, SwarmButtonProps } from './SwarmButton'
|
import { SwarmButton, SwarmButtonProps } from './SwarmButton'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -9,7 +11,7 @@ interface Props {
|
|||||||
title: string
|
title: string
|
||||||
subtitle: string
|
subtitle: string
|
||||||
buttonProps: SwarmButtonProps
|
buttonProps: SwarmButtonProps
|
||||||
status: 'ok' | 'error'
|
status: 'ok' | 'error' | 'loading' | 'connecting'
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = (backgroundColor: string) =>
|
const useStyles = (backgroundColor: string) =>
|
||||||
@@ -56,12 +58,24 @@ export default function Card({ buttonProps, icon, title, subtitle, status }: Pro
|
|||||||
const { className, ...rest } = buttonProps
|
const { className, ...rest } = buttonProps
|
||||||
const classes = useStyles(backgroundColor)()
|
const classes = useStyles(backgroundColor)()
|
||||||
|
|
||||||
|
let statusIcon = null
|
||||||
|
|
||||||
|
if (status === 'ok') {
|
||||||
|
statusIcon = <Check size="13" color="#09ca6c" />
|
||||||
|
} else if (status === 'error') {
|
||||||
|
statusIcon = <AlertCircle size="13" color="#f44336" />
|
||||||
|
} else if (status === 'loading') {
|
||||||
|
statusIcon = <RefreshLine size="13" color="orange" />
|
||||||
|
} else if (status === 'connecting') {
|
||||||
|
statusIcon = <Connecting size="13" color="#0074D9" />
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<div className={classes.wrapper}>
|
<div className={classes.wrapper}>
|
||||||
<div className={classes.iconWrapper}>
|
<div className={classes.iconWrapper}>
|
||||||
{icon}
|
{icon}
|
||||||
{status === 'ok' ? <Check size="13" color="#09ca6c" /> : <AlertCircle size="13" color="#f44336" />}
|
{statusIcon}
|
||||||
</div>
|
</div>
|
||||||
<Typography variant="h2" style={{ marginBottom: '8px' }}>
|
<Typography variant="h2" style={{ marginBottom: '8px' }}>
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { ReactElement, ReactNode } from 'react'
|
import { Grid, IconButton, Tooltip, Typography } from '@material-ui/core'
|
||||||
import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'
|
|
||||||
import { Typography, Grid, IconButton, Tooltip } from '@material-ui/core'
|
|
||||||
import Info from 'remixicon-react/InformationLineIcon'
|
|
||||||
import ListItem from '@material-ui/core/ListItem'
|
import ListItem from '@material-ui/core/ListItem'
|
||||||
|
import { Theme, createStyles, makeStyles } from '@material-ui/core/styles'
|
||||||
|
import { ReactElement, ReactNode } from 'react'
|
||||||
|
import Info from 'remixicon-react/InformationLineIcon'
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import { useLocation, matchPath } from 'react-router-dom'
|
import { matchPath, useLocation } from 'react-router-dom'
|
||||||
import ArrowRight from 'remixicon-react/ArrowRightLineIcon'
|
import ArrowRight from 'remixicon-react/ArrowRightLineIcon'
|
||||||
|
|
||||||
import { createStyles, Theme, makeStyles } from '@material-ui/core/styles'
|
import { ListItem, ListItemIcon, ListItemText, Typography } from '@material-ui/core'
|
||||||
import { ListItemText, ListItemIcon, ListItem, Typography } from '@material-ui/core'
|
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'
|
||||||
import { Context } from '../providers/Bee'
|
import { Context } from '../providers/Bee'
|
||||||
import StatusIcon from './StatusIcon'
|
import StatusIcon from './StatusIcon'
|
||||||
|
|
||||||
@@ -44,6 +44,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
},
|
},
|
||||||
smallerText: {
|
smallerText: {
|
||||||
fontSize: '0.9rem',
|
fontSize: '0.9rem',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
import { BeeDebug } from '@ethersphere/bee-js'
|
||||||
|
import Button from '@material-ui/core/Button'
|
||||||
|
import Dialog from '@material-ui/core/Dialog'
|
||||||
|
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 { useSnackbar } from 'notistack'
|
||||||
|
import { ReactElement, ReactNode, useState } from 'react'
|
||||||
|
import { SwarmSelect } from './SwarmSelect'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
label: string
|
||||||
|
icon: ReactNode
|
||||||
|
beeDebug: BeeDebug
|
||||||
|
stamp: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function StampExtensionModal({ label, icon, beeDebug, stamp }: Props): ReactElement {
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const [amount, setAmount] = useState('')
|
||||||
|
const [type, setType] = useState<'Topup' | 'Dilute'>('Topup')
|
||||||
|
const { enqueueSnackbar } = useSnackbar()
|
||||||
|
|
||||||
|
const handleClickOpen = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
setOpen(true)
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAction = async () => {
|
||||||
|
if (type === 'Topup') {
|
||||||
|
try {
|
||||||
|
await beeDebug.topUpBatch(stamp, amount)
|
||||||
|
enqueueSnackbar(`Successfully topped up stamp, your changes will appear soon`, { variant: 'success' })
|
||||||
|
} catch (error) {
|
||||||
|
enqueueSnackbar(`Failed to topup stamp: ${error || 'Unknown reason'}`, { variant: 'error' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'Dilute') {
|
||||||
|
try {
|
||||||
|
await beeDebug.diluteBatch(stamp, parseInt(amount, 10))
|
||||||
|
enqueueSnackbar(`Successfully diluted stamp, your changes will appear soon`, { variant: 'success' })
|
||||||
|
} catch (error) {
|
||||||
|
enqueueSnackbar(`Failed to dilute stamp: ${error || 'Unknown reason'}`, { variant: 'error' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
|
||||||
|
setAmount(event.target.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button variant="contained" onClick={handleClickOpen} startIcon={icon}>
|
||||||
|
{label}
|
||||||
|
</Button>
|
||||||
|
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
|
||||||
|
<DialogTitle id="form-dialog-title">{label}</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<SwarmSelect
|
||||||
|
label="Action"
|
||||||
|
defaultValue="Topup"
|
||||||
|
onChange={event => setType(event.target.value as 'Topup' | 'Dilute')}
|
||||||
|
options={[
|
||||||
|
{ value: 'Topup', label: 'Topup' },
|
||||||
|
{ value: 'Dilute', label: 'Dilute' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
autoFocus
|
||||||
|
margin="dense"
|
||||||
|
id="name"
|
||||||
|
type="text"
|
||||||
|
placeholder={type === 'Topup' ? 'Amount to add' : 'New depth to dilute'}
|
||||||
|
fullWidth
|
||||||
|
value={amount}
|
||||||
|
onChange={handleChange}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleClose} color="primary">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleAction} color="primary">
|
||||||
|
{type}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { ReactElement } from 'react'
|
|
||||||
import { CircularProgress } from '@material-ui/core'
|
import { CircularProgress } from '@material-ui/core'
|
||||||
|
import type { ReactElement } from 'react'
|
||||||
import { CheckState } from '../providers/Bee'
|
import { CheckState } from '../providers/Bee'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -25,6 +25,12 @@ export default function StatusIcon({ checkState, size, className, isLoading }: P
|
|||||||
case CheckState.ERROR:
|
case CheckState.ERROR:
|
||||||
backgroundColor = '#ff3a52'
|
backgroundColor = '#ff3a52'
|
||||||
break
|
break
|
||||||
|
case CheckState.STARTING:
|
||||||
|
backgroundColor = 'orange'
|
||||||
|
break
|
||||||
|
case CheckState.CONNECTING:
|
||||||
|
backgroundColor = '#0074D9'
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
// Default is error
|
// Default is error
|
||||||
backgroundColor = '#ff3a52'
|
backgroundColor = '#ff3a52'
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ interface Props {
|
|||||||
formik?: boolean
|
formik?: boolean
|
||||||
defaultValue?: string
|
defaultValue?: string
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
|
disabled?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
@@ -60,6 +61,7 @@ export function SwarmSelect({
|
|||||||
onChange,
|
onChange,
|
||||||
label,
|
label,
|
||||||
placeholder,
|
placeholder,
|
||||||
|
disabled = false,
|
||||||
}: Props): ReactElement {
|
}: Props): ReactElement {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
|
|
||||||
@@ -69,6 +71,7 @@ export function SwarmSelect({
|
|||||||
{label && <FormHelperText>{label}</FormHelperText>}
|
{label && <FormHelperText>{label}</FormHelperText>}
|
||||||
<Field
|
<Field
|
||||||
required
|
required
|
||||||
|
disabled={disabled}
|
||||||
component={Select}
|
component={Select}
|
||||||
name={name}
|
name={name}
|
||||||
fullWidth
|
fullWidth
|
||||||
@@ -94,6 +97,7 @@ export function SwarmSelect({
|
|||||||
{label && <FormHelperText>{label}</FormHelperText>}
|
{label && <FormHelperText>{label}</FormHelperText>}
|
||||||
<MuiSelect
|
<MuiSelect
|
||||||
required
|
required
|
||||||
|
disabled={disabled}
|
||||||
name={name}
|
name={name}
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
|
import { BigNumber } from 'bignumber.js'
|
||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import Download from 'remixicon-react/DownloadLineIcon'
|
import Download from 'remixicon-react/DownloadLineIcon'
|
||||||
import { Context as SettingsContext } from '../providers/Settings'
|
|
||||||
|
|
||||||
import WithdrawDepositModal from '../components/WithdrawDepositModal'
|
import WithdrawDepositModal from '../components/WithdrawDepositModal'
|
||||||
import { BigNumber } from 'bignumber.js'
|
import { Context as BeeContext } from '../providers/Bee'
|
||||||
|
import { Context as SettingsContext } from '../providers/Settings'
|
||||||
|
|
||||||
export default function DepositModal(): ReactElement {
|
export default function DepositModal(): ReactElement {
|
||||||
const { beeDebugApi } = useContext(SettingsContext)
|
const { beeDebugApi } = useContext(SettingsContext)
|
||||||
|
const { refresh } = useContext(BeeContext)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WithdrawDepositModal
|
<WithdrawDepositModal
|
||||||
@@ -16,10 +17,13 @@ export default function DepositModal(): ReactElement {
|
|||||||
label="Deposit"
|
label="Deposit"
|
||||||
icon={<Download size="1rem" />}
|
icon={<Download size="1rem" />}
|
||||||
min={new BigNumber(0)}
|
min={new BigNumber(0)}
|
||||||
action={(amount: bigint) => {
|
action={async (amount: bigint) => {
|
||||||
if (!beeDebugApi) throw new Error('Bee Debug URL is not valid')
|
if (!beeDebugApi) throw new Error('Bee Debug URL is not valid')
|
||||||
|
|
||||||
return beeDebugApi.depositTokens(amount.toString())
|
const transactionHash = await beeDebugApi.depositTokens(amount.toString())
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
return transactionHash
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { BigNumber } from 'bignumber.js'
|
||||||
|
import { ReactElement, useContext } from 'react'
|
||||||
|
import Download from 'remixicon-react/DownloadLineIcon'
|
||||||
|
import WithdrawDepositModal from '../components/WithdrawDepositModal'
|
||||||
|
import { Context as BeeContext } from '../providers/Bee'
|
||||||
|
import { Context as SettingsContext } from '../providers/Settings'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onStarted: () => void
|
||||||
|
onFinished: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function StakeModal({ onStarted, onFinished }: Props): ReactElement {
|
||||||
|
const { beeDebugApi } = useContext(SettingsContext)
|
||||||
|
const { refresh } = useContext(BeeContext)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WithdrawDepositModal
|
||||||
|
successMessage="Successfully deposited stake."
|
||||||
|
errorMessage="Error with depositing"
|
||||||
|
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={<Download size="1rem" />}
|
||||||
|
min={new BigNumber(0)}
|
||||||
|
action={async (amount: bigint) => {
|
||||||
|
if (!beeDebugApi) throw new Error('Bee Debug URL is not valid')
|
||||||
|
|
||||||
|
onStarted()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await beeDebugApi.depositStake(amount.toString())
|
||||||
|
} finally {
|
||||||
|
refresh()
|
||||||
|
onFinished()
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'unknown'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -2,10 +2,12 @@ import { BigNumber } from 'bignumber.js'
|
|||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import Upload from 'remixicon-react/UploadLineIcon'
|
import Upload from 'remixicon-react/UploadLineIcon'
|
||||||
import WithdrawDepositModal from '../components/WithdrawDepositModal'
|
import WithdrawDepositModal from '../components/WithdrawDepositModal'
|
||||||
|
import { Context as BeeContext } from '../providers/Bee'
|
||||||
import { Context as SettingsContext } from '../providers/Settings'
|
import { Context as SettingsContext } from '../providers/Settings'
|
||||||
|
|
||||||
export default function WithdrawModal(): ReactElement {
|
export default function WithdrawModal(): ReactElement {
|
||||||
const { beeDebugApi } = useContext(SettingsContext)
|
const { beeDebugApi } = useContext(SettingsContext)
|
||||||
|
const { refresh } = useContext(BeeContext)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WithdrawDepositModal
|
<WithdrawDepositModal
|
||||||
@@ -15,10 +17,13 @@ export default function WithdrawModal(): ReactElement {
|
|||||||
label="Withdraw"
|
label="Withdraw"
|
||||||
icon={<Upload size="1rem" />}
|
icon={<Upload size="1rem" />}
|
||||||
min={new BigNumber(0)}
|
min={new BigNumber(0)}
|
||||||
action={(amount: bigint) => {
|
action={async (amount: bigint) => {
|
||||||
if (!beeDebugApi) throw new Error('Bee Debug URL is not valid')
|
if (!beeDebugApi) throw new Error('Bee Debug URL is not valid')
|
||||||
|
|
||||||
return beeDebugApi.withdrawTokens(amount.toString())
|
const transactionHash = await beeDebugApi.withdrawTokens(amount.toString())
|
||||||
|
refresh()
|
||||||
|
|
||||||
|
return transactionHash
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
+27
-20
@@ -1,8 +1,7 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { getLatestBeeDesktopVersion } from '../utils/desktop'
|
|
||||||
import { getJson } from '../utils/net'
|
|
||||||
import { GITHUB_REPO_URL } from '../constants'
|
import { GITHUB_REPO_URL } from '../constants'
|
||||||
|
import { BeeConfig, getDesktopConfiguration, getLatestBeeDesktopVersion } from '../utils/desktop'
|
||||||
|
|
||||||
export interface LatestBeeReleaseHook {
|
export interface LatestBeeReleaseHook {
|
||||||
latestBeeRelease: LatestBeeRelease | null
|
latestBeeRelease: LatestBeeRelease | null
|
||||||
@@ -11,6 +10,7 @@ export interface LatestBeeReleaseHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface BeeDesktopHook {
|
export interface BeeDesktopHook {
|
||||||
|
reachable: boolean
|
||||||
error: Error | null
|
error: Error | null
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
beeDesktopVersion: string
|
beeDesktopVersion: string
|
||||||
@@ -22,11 +22,34 @@ export interface NewDesktopVersionHook {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const useBeeDesktop = (isBeeDesktop = false, desktopUrl: string): BeeDesktopHook => {
|
export const useBeeDesktop = (isBeeDesktop = false, desktopUrl: string): BeeDesktopHook => {
|
||||||
|
const [reachable, setReachable] = useState(false)
|
||||||
const [desktopAutoUpdateEnabled, setDesktopAutoUpdateEnabled] = useState<boolean>(true)
|
const [desktopAutoUpdateEnabled, setDesktopAutoUpdateEnabled] = useState<boolean>(true)
|
||||||
const [beeDesktopVersion, setBeeDesktopVersion] = useState<string>('')
|
const [beeDesktopVersion, setBeeDesktopVersion] = useState<string>('')
|
||||||
const [isLoading, setLoading] = useState<boolean>(true)
|
const [isLoading, setLoading] = useState<boolean>(true)
|
||||||
const [error, setError] = useState<Error | null>(null)
|
const [error, setError] = useState<Error | null>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isBeeDesktop) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
function runReachabilityCheck() {
|
||||||
|
axios
|
||||||
|
.get(`${desktopUrl}/info`)
|
||||||
|
.then(() => {
|
||||||
|
setReachable(true)
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setReachable(false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
runReachabilityCheck()
|
||||||
|
const interval = setInterval(runReachabilityCheck, 10_000)
|
||||||
|
|
||||||
|
return () => clearInterval(interval)
|
||||||
|
}, [desktopUrl, isBeeDesktop])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isBeeDesktop) {
|
if (!isBeeDesktop) {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@@ -48,7 +71,7 @@ export const useBeeDesktop = (isBeeDesktop = false, desktopUrl: string): BeeDesk
|
|||||||
}
|
}
|
||||||
}, [desktopUrl, isBeeDesktop])
|
}, [desktopUrl, isBeeDesktop])
|
||||||
|
|
||||||
return { error, isLoading, beeDesktopVersion, desktopAutoUpdateEnabled }
|
return { error, isLoading, beeDesktopVersion, desktopAutoUpdateEnabled, reachable }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkNewVersion(desktopUrl: string): Promise<string> {
|
async function checkNewVersion(desktopUrl: string): Promise<string> {
|
||||||
@@ -85,22 +108,6 @@ export function useNewBeeDesktopVersion(
|
|||||||
return { newBeeDesktopVersion }
|
return { newBeeDesktopVersion }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BeeConfig {
|
|
||||||
'api-addr': string
|
|
||||||
'debug-api-addr': string
|
|
||||||
'debug-api-enable': boolean
|
|
||||||
password: string
|
|
||||||
'swap-enable': boolean
|
|
||||||
'swap-initial-deposit': bigint
|
|
||||||
mainnet: boolean
|
|
||||||
'full-node': boolean
|
|
||||||
'cors-allowed-origins': string
|
|
||||||
'resolver-options': string
|
|
||||||
'use-postage-snapshot': boolean
|
|
||||||
'data-dir': string
|
|
||||||
'swap-endpoint'?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GetBeeConfig {
|
export interface GetBeeConfig {
|
||||||
config: BeeConfig | null
|
config: BeeConfig | null
|
||||||
isLoading: boolean
|
isLoading: boolean
|
||||||
@@ -113,7 +120,7 @@ export const useGetBeeConfig = (desktopUrl: string): GetBeeConfig => {
|
|||||||
const [error, setError] = useState<Error | null>(null)
|
const [error, setError] = useState<Error | null>(null)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getJson<BeeConfig>(`${desktopUrl}/config`)
|
getDesktopConfiguration(desktopUrl)
|
||||||
.then(beeConf => {
|
.then(beeConf => {
|
||||||
setBeeConfig(beeConf)
|
setBeeConfig(beeConf)
|
||||||
setError(null)
|
setError(null)
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import { BigNumber } from 'bignumber.js'
|
import { BigNumber } from 'bignumber.js'
|
||||||
import { Token } from './Token'
|
import { Token } from './Token'
|
||||||
|
|
||||||
|
export const BZZ_DECIMAL_PLACES = 16
|
||||||
|
|
||||||
export class BzzToken extends Token {
|
export class BzzToken extends Token {
|
||||||
constructor(amount: BigNumber | string | bigint) {
|
constructor(value: BigNumber | string | bigint) {
|
||||||
super(amount, 16)
|
super(value, BZZ_DECIMAL_PLACES)
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromDecimal(value: BigNumber | string | bigint): BzzToken {
|
||||||
|
return Token.fromDecimal(value, BZZ_DECIMAL_PLACES)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,14 @@
|
|||||||
import { BigNumber } from 'bignumber.js'
|
import { BigNumber } from 'bignumber.js'
|
||||||
import { Token } from './Token'
|
import { Token } from './Token'
|
||||||
|
|
||||||
|
const DAI_DECIMAL_PLACES = 18
|
||||||
|
|
||||||
export class DaiToken extends Token {
|
export class DaiToken extends Token {
|
||||||
constructor(amount: BigNumber | string | bigint) {
|
constructor(value: BigNumber | string | bigint) {
|
||||||
super(amount, 18)
|
super(value, DAI_DECIMAL_PLACES)
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromDecimal(value: BigNumber | string | bigint): DaiToken {
|
||||||
|
return Token.fromDecimal(value, DAI_DECIMAL_PLACES)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,4 +87,11 @@ export class Token {
|
|||||||
this.decimals,
|
this.decimals,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plusBaseUnits(amount: string): Token {
|
||||||
|
return new Token(
|
||||||
|
this.toBigNumber.plus(new BigNumber(amount).multipliedBy(new BigNumber(10).pow(this.decimals))),
|
||||||
|
this.decimals,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { BeeModes } from '@ethersphere/bee-js'
|
||||||
import { createStyles, makeStyles, Tab, Tabs, Theme } from '@material-ui/core'
|
import { createStyles, makeStyles, Tab, Tabs, Theme } from '@material-ui/core'
|
||||||
import { ReactElement } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import { Context } from '../../providers/Bee'
|
||||||
import { ACCOUNT_TABS } from '../../routes'
|
import { ACCOUNT_TABS } from '../../routes'
|
||||||
|
|
||||||
const tabMap = {
|
const tabMap = {
|
||||||
@@ -8,10 +10,11 @@ const tabMap = {
|
|||||||
CHEQUEBOOK: 1,
|
CHEQUEBOOK: 1,
|
||||||
STAMPS: 2,
|
STAMPS: 2,
|
||||||
FEEDS: 3,
|
FEEDS: 3,
|
||||||
|
STAKING: 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
active: 'WALLET' | 'CHEQUEBOOK' | 'STAMPS' | 'FEEDS'
|
active: 'WALLET' | 'CHEQUEBOOK' | 'STAMPS' | 'FEEDS' | 'STAKING'
|
||||||
}
|
}
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
@@ -20,16 +23,12 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
marginBottom: theme.spacing(4),
|
marginBottom: theme.spacing(4),
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
|
marginLeft: theme.spacing(-0.25),
|
||||||
|
marginRight: theme.spacing(-0.25),
|
||||||
},
|
},
|
||||||
leftTab: {
|
tab: {
|
||||||
marginRight: theme.spacing(0.125),
|
marginLeft: theme.spacing(0.25),
|
||||||
},
|
marginRight: theme.spacing(0.25),
|
||||||
centerTab: {
|
|
||||||
marginLeft: theme.spacing(0.125),
|
|
||||||
marginRight: theme.spacing(0.125),
|
|
||||||
},
|
|
||||||
rightTab: {
|
|
||||||
marginLeft: theme.spacing(0.125),
|
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
@@ -37,6 +36,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||||||
export function AccountNavigation({ active }: Props): ReactElement {
|
export function AccountNavigation({ active }: Props): ReactElement {
|
||||||
const classes = useStyles()
|
const classes = useStyles()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { nodeInfo } = useContext(Context)
|
||||||
|
|
||||||
function onChange(event: React.ChangeEvent<Record<string, never>>, newValue: number) {
|
function onChange(event: React.ChangeEvent<Record<string, never>>, newValue: number) {
|
||||||
navigate(ACCOUNT_TABS[newValue])
|
navigate(ACCOUNT_TABS[newValue])
|
||||||
@@ -45,10 +45,11 @@ export function AccountNavigation({ active }: Props): ReactElement {
|
|||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
<Tabs value={tabMap[active]} onChange={onChange} variant="fullWidth">
|
<Tabs value={tabMap[active]} onChange={onChange} variant="fullWidth">
|
||||||
<Tab className={classes.leftTab} key="WALLET" label="Wallet" />
|
<Tab className={classes.tab} key="WALLET" label="Wallet" />
|
||||||
<Tab className={classes.centerTab} key="CHEQUEBOOK" label="Chequebook" />
|
<Tab className={classes.tab} key="CHEQUEBOOK" label="Chequebook" />
|
||||||
<Tab className={classes.centerTab} key="STAMPS" label="Stamps" />
|
<Tab className={classes.tab} key="STAMPS" label="Stamps" />
|
||||||
<Tab className={classes.rightTab} key="FEEDS" label="Feeds" />
|
<Tab className={classes.tab} key="FEEDS" label="Feeds" />
|
||||||
|
{nodeInfo?.beeMode === BeeModes.FULL ? <Tab className={classes.tab} key="STAKING" label="Staking" /> : null}
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { ReactElement, useContext, useState } from 'react'
|
||||||
|
import ExpandableList from '../../../components/ExpandableList'
|
||||||
|
import ExpandableListItem from '../../../components/ExpandableListItem'
|
||||||
|
import ExpandableListItemActions from '../../../components/ExpandableListItemActions'
|
||||||
|
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 { 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)
|
||||||
|
|
||||||
|
if (status.all === CheckState.ERROR) return <TroubleshootConnectionCard />
|
||||||
|
|
||||||
|
function onStarted() {
|
||||||
|
setLoading(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onFinished() {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<AccountNavigation active="STAKING" />
|
||||||
|
<div>
|
||||||
|
{loading || stake?.toDecimal === undefined ? (
|
||||||
|
<Loading />
|
||||||
|
) : (
|
||||||
|
<ExpandableList label="Staking" defaultOpen>
|
||||||
|
<ExpandableListItem label="Staked BZZ" value={`${stake?.toSignificantDigits()} xBZZ`} />
|
||||||
|
{balance?.bzz ? (
|
||||||
|
<ExpandableListItem
|
||||||
|
label="Available xBZZ balance"
|
||||||
|
value={`${balance?.bzz.toSignificantDigits(4)} xBZZ`}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
<ExpandableListItemActions>
|
||||||
|
<StakeModal onStarted={onStarted} onFinished={onFinished} />
|
||||||
|
</ExpandableListItemActions>
|
||||||
|
</ExpandableList>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
import { CircularProgress, Container, createStyles, makeStyles } from '@material-ui/core'
|
import { CircularProgress, createStyles, makeStyles } from '@material-ui/core'
|
||||||
import { ReactElement, useContext, useEffect } from 'react'
|
import { ReactElement, useContext, useEffect } from 'react'
|
||||||
import PlusSquare from 'remixicon-react/AddBoxLineIcon'
|
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
|
import PlusSquare from 'remixicon-react/AddBoxLineIcon'
|
||||||
|
import { Loading } from '../../../components/Loading'
|
||||||
import { SwarmButton } from '../../../components/SwarmButton'
|
import { SwarmButton } from '../../../components/SwarmButton'
|
||||||
import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard'
|
import TroubleshootConnectionCard from '../../../components/TroubleshootConnectionCard'
|
||||||
import { CheckState, Context as BeeContext } from '../../../providers/Bee'
|
import { Context as BeeContext, CheckState } from '../../../providers/Bee'
|
||||||
import { Context as StampsContext } from '../../../providers/Stamps'
|
import { Context as StampsContext } from '../../../providers/Stamps'
|
||||||
import { ROUTES } from '../../../routes'
|
import { ROUTES } from '../../../routes'
|
||||||
import StampsTable from '../../stamps/StampsTable'
|
import StampsTable from '../../stamps/StampsTable'
|
||||||
@@ -53,11 +54,7 @@ export function AccountStamps(): ReactElement {
|
|||||||
<Header />
|
<Header />
|
||||||
<AccountNavigation active="STAMPS" />
|
<AccountNavigation active="STAMPS" />
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
{error && (
|
{error && <Loading />}
|
||||||
<Container style={{ textAlign: 'center', padding: '50px' }}>
|
|
||||||
Error loading postage stamps details: {error.message}
|
|
||||||
</Container>
|
|
||||||
)}
|
|
||||||
{!error && (
|
{!error && (
|
||||||
<>
|
<>
|
||||||
<div className={classes.actions}>
|
<div className={classes.actions}>
|
||||||
|
|||||||
@@ -46,9 +46,11 @@ export function AccountWallet(): ReactElement {
|
|||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
<Grid container direction="row" justifyContent="space-between" alignItems="center">
|
<Grid container direction="row" justifyContent="space-between" alignItems="center">
|
||||||
<Typography variant="h2">Wallet balance</Typography>
|
<Typography variant="h2">Wallet balance</Typography>
|
||||||
|
{isDesktop && (
|
||||||
<SwarmButton onClick={onDeposit} iconType={Download}>
|
<SwarmButton onClick={onDeposit} iconType={Download}>
|
||||||
Top up wallet
|
Top up wallet
|
||||||
</SwarmButton>
|
</SwarmButton>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
{balance && nodeAddresses ? (
|
{balance && nodeAddresses ? (
|
||||||
|
|||||||
@@ -14,13 +14,15 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function PeerBalances({ accounting, isLoadingUncashed, totalUncashed }: Props): ReactElement | null {
|
export default function PeerBalances({ accounting, isLoadingUncashed, totalUncashed }: Props): ReactElement | null {
|
||||||
|
const uncashedPeers = accounting?.filter(({ uncashedAmount }) => uncashedAmount.toBigNumber.isGreaterThan('0')) || []
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExpandableList
|
<ExpandableList
|
||||||
label={`Peers (${accounting?.length || 0})`}
|
label={`Peers (${uncashedPeers.length})`}
|
||||||
info={`${totalUncashed.toFixedDecimal()} xBZZ (uncashed)`}
|
info={`${totalUncashed.toFixedDecimal()} xBZZ (uncashed)`}
|
||||||
>
|
>
|
||||||
<ExpandableListItem label="Uncashed Amount Total" value={`${totalUncashed.toFixedDecimal()} xBZZ`} />
|
<ExpandableListItem label="Uncashed Amount Total" value={`${totalUncashed.toFixedDecimal()} xBZZ`} />
|
||||||
{accounting?.map(({ peer, balance, received, sent, uncashedAmount, total }) => (
|
{uncashedPeers.map(({ peer, balance, received, sent, uncashedAmount, total }) => (
|
||||||
<ExpandableList
|
<ExpandableList
|
||||||
key={peer}
|
key={peer}
|
||||||
label={`Peer ${peer.slice(0, 8)}[…]`}
|
label={`Peer ${peer.slice(0, 8)}[…]`}
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import * as swarmCid from '@ethersphere/swarm-cid'
|
|
||||||
import { Box } from '@material-ui/core'
|
import { Box } from '@material-ui/core'
|
||||||
import { ReactElement, useContext, useEffect, useState } from 'react'
|
import { ReactElement, useContext, useEffect, useState } from 'react'
|
||||||
import X from 'remixicon-react/CloseLineIcon'
|
|
||||||
import { useNavigate, useParams } from 'react-router-dom'
|
import { useNavigate, useParams } from 'react-router-dom'
|
||||||
|
import X from 'remixicon-react/CloseLineIcon'
|
||||||
import { DocumentationText } from '../../components/DocumentationText'
|
import { DocumentationText } from '../../components/DocumentationText'
|
||||||
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
||||||
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
||||||
import ExpandableListItemLink from '../../components/ExpandableListItemLink'
|
|
||||||
import { HistoryHeader } from '../../components/HistoryHeader'
|
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||||
import { SwarmButton } from '../../components/SwarmButton'
|
import { SwarmButton } from '../../components/SwarmButton'
|
||||||
import { Context as BeeContext } from '../../providers/Bee'
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
@@ -55,14 +53,8 @@ export function FeedSubpage(): ReactElement {
|
|||||||
<UploadArea showHelp={false} uploadOrigin={{ origin: 'FEED', uuid }} />
|
<UploadArea showHelp={false} uploadOrigin={{ origin: 'FEED', uuid }} />
|
||||||
{available && identity.feedHash ? (
|
{available && identity.feedHash ? (
|
||||||
<>
|
<>
|
||||||
<Box mb={0.25}>
|
|
||||||
<ExpandableListItemKey label="Feed hash" value={identity.feedHash} />
|
|
||||||
</Box>
|
|
||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
<ExpandableListItemLink
|
<ExpandableListItemKey label="Feed hash" value={identity.feedHash} />
|
||||||
label="BZZ Link"
|
|
||||||
value={`https://${swarmCid.encodeFeedReference(identity.feedHash)}.bzz.link`}
|
|
||||||
/>
|
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import * as swarmCid from '@ethersphere/swarm-cid'
|
import { Utils } from '@ethersphere/bee-js'
|
||||||
import { Box } from '@material-ui/core'
|
import { Box } from '@material-ui/core'
|
||||||
import { ReactElement } from 'react'
|
import { ReactElement } from 'react'
|
||||||
import { Utils } from '@ethersphere/bee-js'
|
|
||||||
import { DocumentationText } from '../../components/DocumentationText'
|
import { DocumentationText } from '../../components/DocumentationText'
|
||||||
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
||||||
import ExpandableListItemLink from '../../components/ExpandableListItemLink'
|
import ExpandableListItemLink from '../../components/ExpandableListItemLink'
|
||||||
@@ -19,16 +18,6 @@ export function AssetSummary({ isWebsite, reference }: Props): ReactElement {
|
|||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
{isHash && <ExpandableListItemKey label="Swarm hash" value={reference} />}
|
{isHash && <ExpandableListItemKey label="Swarm hash" value={reference} />}
|
||||||
{!isHash && <ExpandableListItemLink label="ENS" value={reference} />}
|
{!isHash && <ExpandableListItemLink label="ENS" value={reference} />}
|
||||||
<ExpandableListItemLink
|
|
||||||
label="Share on Swarm Gateway"
|
|
||||||
value={`https://gateway.ethswarm.org/access/${reference}`}
|
|
||||||
/>
|
|
||||||
{isWebsite && isHash && (
|
|
||||||
<ExpandableListItemLink
|
|
||||||
label="BZZ Link"
|
|
||||||
value={`https://${swarmCid.encodeManifestReference(reference).toString()}.bzz.link`}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
<DocumentationText>
|
<DocumentationText>
|
||||||
The Swarm Gateway is graciously provided by the Swarm Foundation. This service is under development and provided
|
The Swarm Gateway is graciously provided by the Swarm Foundation. This service is under development and provided
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { BeeModes, Utils } from '@ethersphere/bee-js'
|
import { BeeModes, Utils } from '@ethersphere/bee-js'
|
||||||
import { ManifestJs } from '@ethersphere/manifest-js'
|
|
||||||
import { useSnackbar } from 'notistack'
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useState } from 'react'
|
import { ReactElement, useContext, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import Search from 'remixicon-react/SearchLineIcon'
|
import Search from 'remixicon-react/SearchLineIcon'
|
||||||
import ExpandableListItemInput from '../../components/ExpandableListItemInput'
|
import ExpandableListItemInput from '../../components/ExpandableListItemInput'
|
||||||
import { History } from '../../components/History'
|
import { History } from '../../components/History'
|
||||||
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
import { Context as FileContext, defaultUploadOrigin } from '../../providers/File'
|
import { Context as FileContext, defaultUploadOrigin } from '../../providers/File'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
import { Context as BeeContext } from '../../providers/Bee'
|
|
||||||
import { ROUTES } from '../../routes'
|
import { ROUTES } from '../../routes'
|
||||||
import { recognizeEnsOrSwarmHash, regexpEns } from '../../utils'
|
import { recognizeEnsOrSwarmHash, regexpEns } from '../../utils'
|
||||||
import { determineHistoryName, HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
import { determineHistoryName, HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
||||||
|
import { ManifestJs } from '../../utils/manifest'
|
||||||
import { FileNavigation } from './FileNavigation'
|
import { FileNavigation } from './FileNavigation'
|
||||||
|
|
||||||
export function Download(): ReactElement {
|
export function Download(): ReactElement {
|
||||||
@@ -34,9 +34,7 @@ export function Download(): ReactElement {
|
|||||||
) {
|
) {
|
||||||
setReferenceError(undefined)
|
setReferenceError(undefined)
|
||||||
} else {
|
} else {
|
||||||
setReferenceError(
|
setReferenceError('Incorrect format of swarm hash. Expected 64 or 128 hexstring characters or ENS domain.')
|
||||||
'Incorrect format of swarm hash. Expected 64 or 128 hexstring characters, bzz.link url or ENS domain.',
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ManifestJs } from '@ethersphere/manifest-js'
|
|
||||||
import { Box, Typography } from '@material-ui/core'
|
import { Box, Typography } from '@material-ui/core'
|
||||||
import { saveAs } from 'file-saver'
|
import { saveAs } from 'file-saver'
|
||||||
import JSZip from 'jszip'
|
import JSZip from 'jszip'
|
||||||
@@ -13,6 +12,7 @@ import { Context as BeeContext } from '../../providers/Bee'
|
|||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
import { ROUTES } from '../../routes'
|
import { ROUTES } from '../../routes'
|
||||||
import { determineHistoryName, HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
import { determineHistoryName, HISTORY_KEYS, putHistory } from '../../utils/local-storage'
|
||||||
|
import { ManifestJs } from '../../utils/manifest'
|
||||||
import { AssetPreview } from './AssetPreview'
|
import { AssetPreview } from './AssetPreview'
|
||||||
import { AssetSummary } from './AssetSummary'
|
import { AssetSummary } from './AssetSummary'
|
||||||
import { DownloadActionBar } from './DownloadActionBar'
|
import { DownloadActionBar } from './DownloadActionBar'
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import { HistoryHeader } from '../../components/HistoryHeader'
|
|||||||
import { ProgressIndicator } from '../../components/ProgressIndicator'
|
import { ProgressIndicator } from '../../components/ProgressIndicator'
|
||||||
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
|
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
|
||||||
import { META_FILE_NAME, PREVIEW_FILE_NAME } from '../../constants'
|
import { META_FILE_NAME, PREVIEW_FILE_NAME } from '../../constants'
|
||||||
import { CheckState, Context as BeeContext } from '../../providers/Bee'
|
import { Context as BeeContext, CheckState } from '../../providers/Bee'
|
||||||
import { Context as IdentityContext, Identity } from '../../providers/Feeds'
|
import { Identity, Context as IdentityContext } from '../../providers/Feeds'
|
||||||
import { Context as FileContext } from '../../providers/File'
|
import { Context as FileContext } from '../../providers/File'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
import { Context as StampsContext, EnrichedPostageBatch } from '../../providers/Stamps'
|
import { EnrichedPostageBatch, Context as StampsContext } from '../../providers/Stamps'
|
||||||
import { ROUTES } from '../../routes'
|
import { ROUTES } from '../../routes'
|
||||||
import { waitUntilStampUsable } from '../../utils'
|
import { waitUntilStampUsable } from '../../utils'
|
||||||
import { detectIndexHtml, getAssetNameFromFiles, packageFile } from '../../utils/file'
|
import { detectIndexHtml, getAssetNameFromFiles, packageFile } from '../../utils/file'
|
||||||
@@ -130,7 +130,7 @@ export function Upload(): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beeApi
|
beeApi
|
||||||
.uploadFiles(stamp.batchID, fls, { indexDocument })
|
.uploadFiles(stamp.batchID, fls, { indexDocument, deferred: true })
|
||||||
.then(hash => {
|
.then(hash => {
|
||||||
putHistory(HISTORY_KEYS.UPLOAD_HISTORY, hash.reference, getAssetNameFromFiles(files))
|
putHistory(HISTORY_KEYS.UPLOAD_HISTORY, hash.reference, getAssetNameFromFiles(files))
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
import { Box, Tooltip, Typography } from '@material-ui/core'
|
import { Box, Tooltip, Typography } from '@material-ui/core'
|
||||||
|
import { Wallet } from 'ethers'
|
||||||
import { useSnackbar } from 'notistack'
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useEffect, useState } from 'react'
|
import { ReactElement, useContext, useEffect, useState } from 'react'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
import Check from 'remixicon-react/CheckLineIcon'
|
import Check from 'remixicon-react/CheckLineIcon'
|
||||||
import X from 'remixicon-react/CloseLineIcon'
|
import X from 'remixicon-react/CloseLineIcon'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
import { Wallet } from 'ethers'
|
|
||||||
import ExpandableListItem from '../../components/ExpandableListItem'
|
import ExpandableListItem from '../../components/ExpandableListItem'
|
||||||
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
||||||
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
||||||
import { HistoryHeader } from '../../components/HistoryHeader'
|
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||||
import { Loading } from '../../components/Loading'
|
import { Loading } from '../../components/Loading'
|
||||||
import { SwarmButton } from '../../components/SwarmButton'
|
import { SwarmButton } from '../../components/SwarmButton'
|
||||||
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
import { Token } from '../../models/Token'
|
||||||
import { Context as TopUpContext } from '../../providers/TopUp'
|
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
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 { createGiftWallet } from '../../utils/desktop'
|
||||||
import { ResolvedWallet } from '../../utils/wallet'
|
import { ResolvedWallet } from '../../utils/wallet'
|
||||||
import { Token } from '../../models/Token'
|
|
||||||
|
|
||||||
const GIFT_WALLET_FUND_DAI_AMOUNT = Token.fromDecimal('0.1', 18)
|
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_BZZ_AMOUNT = Token.fromDecimal('0.5', 16)
|
||||||
@@ -31,6 +31,9 @@ export default function Index(): ReactElement {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function mapGiftWallets() {
|
async function mapGiftWallets() {
|
||||||
|
if (!rpcProvider) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const results = []
|
const results = []
|
||||||
for (const giftWallet of giftWallets) {
|
for (const giftWallet of giftWallets) {
|
||||||
results.push(await ResolvedWallet.make(giftWallet, rpcProvider))
|
results.push(await ResolvedWallet.make(giftWallet, rpcProvider))
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
import ExchangeFunds from 'remixicon-react/ExchangeFundsLineIcon'
|
||||||
|
import Card from '../../components/Card'
|
||||||
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
|
import { ROUTES } from '../../routes'
|
||||||
|
|
||||||
|
export function ChequebookInfoCard() {
|
||||||
|
const { chequebookBalance } = useContext(BeeContext)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
if (
|
||||||
|
chequebookBalance?.availableBalance !== undefined &&
|
||||||
|
chequebookBalance?.availableBalance.toBigNumber.isGreaterThan(0)
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
buttonProps={{
|
||||||
|
iconType: ExchangeFunds,
|
||||||
|
children: 'View chequebook',
|
||||||
|
onClick: () => navigate(ROUTES.ACCOUNT_CHEQUEBOOK),
|
||||||
|
}}
|
||||||
|
icon={<ExchangeFunds />}
|
||||||
|
title={`${chequebookBalance?.availableBalance.toSignificantDigits(4)} xBZZ`}
|
||||||
|
subtitle="Current chequebook balance."
|
||||||
|
status="ok"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
buttonProps={{
|
||||||
|
iconType: ExchangeFunds,
|
||||||
|
children: 'View chequebook',
|
||||||
|
onClick: () => navigate(ROUTES.ACCOUNT_CHEQUEBOOK),
|
||||||
|
}}
|
||||||
|
icon={<ExchangeFunds />}
|
||||||
|
title={
|
||||||
|
chequebookBalance?.availableBalance
|
||||||
|
? `${chequebookBalance.availableBalance.toSignificantDigits(4)} xBZZ`
|
||||||
|
: 'No available balance.'
|
||||||
|
}
|
||||||
|
subtitle="Chequebook not setup."
|
||||||
|
status="error"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,17 +1,41 @@
|
|||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import Search from 'remixicon-react/SearchLineIcon'
|
|
||||||
import Globe from 'remixicon-react/GlobalLineIcon'
|
import Globe from 'remixicon-react/GlobalLineIcon'
|
||||||
|
import Search from 'remixicon-react/SearchLineIcon'
|
||||||
import Settings from 'remixicon-react/Settings2LineIcon'
|
import Settings from 'remixicon-react/Settings2LineIcon'
|
||||||
|
|
||||||
import { CheckState, Context as BeeContext } from '../../providers/Bee'
|
|
||||||
import Card from '../../components/Card'
|
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
|
import Card from '../../components/Card'
|
||||||
|
import { CheckState, Context as BeeContext } from '../../providers/Bee'
|
||||||
import { ROUTES } from '../../routes'
|
import { ROUTES } from '../../routes'
|
||||||
|
|
||||||
export default function NodeInfoCard(): ReactElement {
|
export default function NodeInfoCard(): ReactElement {
|
||||||
const { status } = useContext(BeeContext)
|
const { status } = useContext(BeeContext)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
if (status.all === CheckState.CONNECTING) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
buttonProps={{ iconType: Settings, children: 'Open node setup', onClick: () => navigate(ROUTES.STATUS) }}
|
||||||
|
icon={<Globe />}
|
||||||
|
title="Connecting..."
|
||||||
|
subtitle="Attempting to establish connection to your Bee node."
|
||||||
|
status="connecting"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status.all === CheckState.STARTING) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
buttonProps={{ iconType: Settings, children: 'Open node setup', onClick: () => navigate(ROUTES.STATUS) }}
|
||||||
|
icon={<Globe />}
|
||||||
|
title="Starting up..."
|
||||||
|
subtitle="Your Bee node is currently launching."
|
||||||
|
status="loading"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (status.all === CheckState.ERROR) {
|
if (status.all === CheckState.ERROR) {
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import { useContext } from 'react'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
import Upload from 'remixicon-react/UploadLineIcon'
|
||||||
|
import Wallet from 'remixicon-react/Wallet3LineIcon'
|
||||||
|
import Card from '../../components/Card'
|
||||||
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
|
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
||||||
|
import { ROUTES } from '../../routes'
|
||||||
|
|
||||||
|
export function WalletInfoCard() {
|
||||||
|
const { nodeInfo } = useContext(BeeContext)
|
||||||
|
const { balance, error } = useContext(BalanceProvider)
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
let balanceText = 'Loading...'
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
balanceText = 'Could not load...'
|
||||||
|
console.error(error) // eslint-disable-line
|
||||||
|
} else if (balance) {
|
||||||
|
balanceText = `${balance.bzz.toSignificantDigits(4)} xBZZ | ${balance.dai.toSignificantDigits(4)} xDAI`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nodeInfo?.beeMode && ['light', 'full', 'dev'].includes(nodeInfo.beeMode)) {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
buttonProps={{
|
||||||
|
iconType: Wallet,
|
||||||
|
children: 'Manage your wallet',
|
||||||
|
onClick: () => navigate(ROUTES.ACCOUNT_WALLET),
|
||||||
|
}}
|
||||||
|
icon={<Wallet />}
|
||||||
|
title={balanceText}
|
||||||
|
subtitle="Current wallet balance."
|
||||||
|
status="ok"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
buttonProps={{
|
||||||
|
iconType: Wallet,
|
||||||
|
children: 'Setup wallet',
|
||||||
|
onClick: () => navigate(ROUTES.TOP_UP),
|
||||||
|
}}
|
||||||
|
icon={<Upload />}
|
||||||
|
title="Your wallet is not setup."
|
||||||
|
subtitle="To share content on Swarm, please setup your wallet."
|
||||||
|
status="error"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
+10
-79
@@ -1,110 +1,41 @@
|
|||||||
import { Button } from '@material-ui/core'
|
import { Button } from '@material-ui/core'
|
||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
|
||||||
import ExchangeFunds from 'remixicon-react/ExchangeFundsLineIcon'
|
|
||||||
import Upload from 'remixicon-react/UploadLineIcon'
|
|
||||||
import Wallet from 'remixicon-react/Wallet3LineIcon'
|
|
||||||
import Card from '../../components/Card'
|
|
||||||
import ExpandableListItem from '../../components/ExpandableListItem'
|
import ExpandableListItem from '../../components/ExpandableListItem'
|
||||||
import Map from '../../components/Map'
|
import Map from '../../components/Map'
|
||||||
|
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../../constants'
|
||||||
import { useBeeDesktop, useNewBeeDesktopVersion } from '../../hooks/apiHooks'
|
import { useBeeDesktop, useNewBeeDesktopVersion } from '../../hooks/apiHooks'
|
||||||
import { Context as BeeContext } from '../../providers/Bee'
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
|
||||||
import { ROUTES } from '../../routes'
|
|
||||||
import { chainIdToName } from '../../utils/chain'
|
import { chainIdToName } from '../../utils/chain'
|
||||||
|
import { ChequebookInfoCard } from './ChequebookInfoCard'
|
||||||
import NodeInfoCard from './NodeInfoCard'
|
import NodeInfoCard from './NodeInfoCard'
|
||||||
import { BEE_DESKTOP_LATEST_RELEASE_PAGE } from '../../constants'
|
import { WalletInfoCard } from './WalletInfoCard'
|
||||||
|
|
||||||
export default function Status(): ReactElement {
|
export default function Status(): ReactElement {
|
||||||
const {
|
const {
|
||||||
|
debugApiReadiness,
|
||||||
status,
|
status,
|
||||||
latestUserVersion,
|
latestUserVersion,
|
||||||
isLatestBeeVersion,
|
isLatestBeeVersion,
|
||||||
latestBeeVersionUrl,
|
latestBeeVersionUrl,
|
||||||
topology,
|
topology,
|
||||||
nodeInfo,
|
nodeInfo,
|
||||||
chequebookBalance,
|
|
||||||
chainId,
|
chainId,
|
||||||
} = useContext(BeeContext)
|
} = useContext(BeeContext)
|
||||||
const { isDesktop, desktopUrl } = useContext(SettingsContext)
|
const { isDesktop, desktopUrl } = useContext(SettingsContext)
|
||||||
const { balance, error } = useContext(BalanceProvider)
|
|
||||||
const { beeDesktopVersion } = useBeeDesktop(isDesktop, desktopUrl)
|
const { beeDesktopVersion } = useBeeDesktop(isDesktop, desktopUrl)
|
||||||
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, false)
|
const { newBeeDesktopVersion } = useNewBeeDesktopVersion(isDesktop, desktopUrl, false)
|
||||||
const navigate = useNavigate()
|
|
||||||
|
|
||||||
let balanceText = 'Loading...'
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
balanceText = 'Could not load...'
|
|
||||||
console.error(error) // eslint-disable-line
|
|
||||||
} else if (balance) {
|
|
||||||
balanceText = `${balance.bzz.toSignificantDigits(4)} xBZZ | ${balance.dai.toSignificantDigits(4)} xDAI`
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'stretch', alignContent: 'stretch' }}>
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'stretch', alignContent: 'stretch' }}>
|
||||||
<NodeInfoCard />
|
<NodeInfoCard />
|
||||||
<div style={{ width: '8px' }}></div>
|
{debugApiReadiness && (
|
||||||
{nodeInfo?.beeMode && ['light', 'full', 'dev'].includes(nodeInfo.beeMode) ? (
|
|
||||||
<Card
|
|
||||||
buttonProps={{
|
|
||||||
iconType: Wallet,
|
|
||||||
children: 'Manage your wallet',
|
|
||||||
onClick: () => navigate(ROUTES.ACCOUNT_WALLET),
|
|
||||||
}}
|
|
||||||
icon={<Wallet />}
|
|
||||||
title={balanceText}
|
|
||||||
subtitle="Current wallet balance."
|
|
||||||
status="ok"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Card
|
|
||||||
buttonProps={{
|
|
||||||
iconType: Wallet,
|
|
||||||
children: 'Setup wallet',
|
|
||||||
onClick: () => navigate(ROUTES.TOP_UP),
|
|
||||||
}}
|
|
||||||
icon={<Upload />}
|
|
||||||
title="Your wallet is not setup."
|
|
||||||
subtitle="To share content on Swarm, please setup your wallet."
|
|
||||||
status="error"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{nodeInfo?.beeMode && ['light', 'full', 'dev'].includes(nodeInfo.beeMode) && (
|
|
||||||
<>
|
<>
|
||||||
<div style={{ width: '8px' }} />
|
<div style={{ width: '8px' }}></div>
|
||||||
{chequebookBalance?.availableBalance !== undefined &&
|
<WalletInfoCard />
|
||||||
chequebookBalance?.availableBalance.toBigNumber.isGreaterThan(0) ? (
|
<div style={{ width: '8px' }}></div>
|
||||||
<Card
|
<ChequebookInfoCard />
|
||||||
buttonProps={{
|
|
||||||
iconType: ExchangeFunds,
|
|
||||||
children: 'View chequebook',
|
|
||||||
onClick: () => navigate(ROUTES.ACCOUNT_CHEQUEBOOK),
|
|
||||||
}}
|
|
||||||
icon={<ExchangeFunds />}
|
|
||||||
title={`${chequebookBalance?.availableBalance.toSignificantDigits(4)} xBZZ`}
|
|
||||||
subtitle="Current chequebook balance."
|
|
||||||
status="ok"
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Card
|
|
||||||
buttonProps={{
|
|
||||||
iconType: ExchangeFunds,
|
|
||||||
children: 'View chequebook',
|
|
||||||
onClick: () => navigate(ROUTES.ACCOUNT_CHEQUEBOOK),
|
|
||||||
}}
|
|
||||||
icon={<ExchangeFunds />}
|
|
||||||
title={
|
|
||||||
chequebookBalance?.availableBalance
|
|
||||||
? `${chequebookBalance.availableBalance.toSignificantDigits(4)} xBZZ`
|
|
||||||
: 'No available balance.'
|
|
||||||
}
|
|
||||||
subtitle="Chequebook not setup."
|
|
||||||
status="error"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -158,7 +89,7 @@ export default function Status(): ReactElement {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ExpandableListItem label="Mode" value={nodeInfo?.beeMode} />
|
<ExpandableListItem label="Mode" value={nodeInfo?.beeMode} />
|
||||||
{chainId && <ExpandableListItem label="Blockchain network" value={chainIdToName(chainId)} />}
|
{chainId !== null && <ExpandableListItem label="Blockchain network" value={chainIdToName(chainId)} />}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { BeeModes } from '@ethersphere/bee-js'
|
import { BeeModes } from '@ethersphere/bee-js'
|
||||||
import { Box, Grid, Typography } from '@material-ui/core'
|
import { Box, Grid, Typography } from '@material-ui/core'
|
||||||
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useEffect, useState } from 'react'
|
import { ReactElement, useContext, useEffect, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
import { Waiting } from '../../components/Waiting'
|
import { Waiting } from '../../components/Waiting'
|
||||||
@@ -12,6 +13,7 @@ export default function LightModeRestart(): ReactElement {
|
|||||||
const [startedAt] = useState(Number.parseInt(localStorage.getItem(STARTED_UPGRADE_AT) ?? Date.now().toFixed()))
|
const [startedAt] = useState(Number.parseInt(localStorage.getItem(STARTED_UPGRADE_AT) ?? Date.now().toFixed()))
|
||||||
const { apiHealth, nodeInfo } = useContext(Context)
|
const { apiHealth, nodeInfo } = useContext(Context)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const { enqueueSnackbar } = useSnackbar()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
localStorage.setItem(STARTED_UPGRADE_AT, startedAt.toFixed())
|
localStorage.setItem(STARTED_UPGRADE_AT, startedAt.toFixed())
|
||||||
@@ -23,10 +25,11 @@ export default function LightModeRestart(): ReactElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (apiHealth && nodeInfo?.beeMode === BeeModes.LIGHT) {
|
if (apiHealth && nodeInfo?.beeMode === BeeModes.LIGHT) {
|
||||||
|
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
||||||
localStorage.removeItem(STARTED_UPGRADE_AT)
|
localStorage.removeItem(STARTED_UPGRADE_AT)
|
||||||
navigate(ROUTES.INFO)
|
navigate(ROUTES.INFO)
|
||||||
}
|
}
|
||||||
}, [startedAt, navigate, nodeInfo, apiHealth])
|
}, [startedAt, navigate, nodeInfo, apiHealth, enqueueSnackbar])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container direction="column" justifyContent="center" alignItems="center">
|
<Grid container direction="column" justifyContent="center" alignItems="center">
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
import CircularProgress from '@material-ui/core/CircularProgress'
|
import CircularProgress from '@material-ui/core/CircularProgress'
|
||||||
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
import ExpandableList from '../../components/ExpandableList'
|
import ExpandableList from '../../components/ExpandableList'
|
||||||
import ExpandableListItemInput from '../../components/ExpandableListItemInput'
|
import ExpandableListItemInput from '../../components/ExpandableListItemInput'
|
||||||
import { Context as BeeContext } from '../../providers/Bee'
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
import { useSnackbar } from 'notistack'
|
import { getDesktopConfiguration, restartBeeNode, setJsonRpcInDesktop } from '../../utils/desktop'
|
||||||
import { restartBeeNode, setJsonRpcInDesktop } from '../../utils/desktop'
|
|
||||||
import { BeeModes } from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
export default function SettingsPage(): ReactElement {
|
export default function SettingsPage(): ReactElement {
|
||||||
const {
|
const {
|
||||||
@@ -24,17 +23,17 @@ export default function SettingsPage(): ReactElement {
|
|||||||
desktopUrl,
|
desktopUrl,
|
||||||
setAndPersistJsonRpcProvider,
|
setAndPersistJsonRpcProvider,
|
||||||
} = useContext(SettingsContext)
|
} = useContext(SettingsContext)
|
||||||
const { refresh, nodeInfo } = useContext(BeeContext)
|
const { refresh } = useContext(BeeContext)
|
||||||
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
|
const { enqueueSnackbar, closeSnackbar } = useSnackbar()
|
||||||
|
|
||||||
async function handleSetRpcUrl(value: string) {
|
async function handleSetRpcUrl(value: string) {
|
||||||
try {
|
try {
|
||||||
setAndPersistJsonRpcProvider(value)
|
setAndPersistJsonRpcProvider(value)
|
||||||
|
|
||||||
// We can't set the RPC URL to the `swap-endpoint` Bee config value unless the Bee node is already in
|
const shouldUpdateDesktop = isDesktop && (await getDesktopConfiguration(desktopUrl))['blockchain-rpc-endpoint']
|
||||||
// light mode as setting this config value, basically upgrades the node to light mode.
|
|
||||||
if (isDesktop && nodeInfo?.beeMode === BeeModes.LIGHT) {
|
if (shouldUpdateDesktop) {
|
||||||
await setJsonRpcInDesktop(desktopUrl, rpcProviderUrl)
|
await setJsonRpcInDesktop(desktopUrl, value)
|
||||||
const snackKey = enqueueSnackbar('RPC endpoint successfully changed, restarting Bee node...', {
|
const snackKey = enqueueSnackbar('RPC endpoint successfully changed, restarting Bee node...', {
|
||||||
variant: 'success',
|
variant: 'success',
|
||||||
})
|
})
|
||||||
@@ -48,7 +47,7 @@ export default function SettingsPage(): ReactElement {
|
|||||||
await refresh()
|
await refresh()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e) //eslint-disable-line
|
console.error(e) //eslint-disable-line
|
||||||
enqueueSnackbar(`Failed to change RPC endpoint. Error: ${e}`, { variant: 'error' })
|
enqueueSnackbar(`Failed to change RPC endpoint. ${e}`, { variant: 'error' })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import { PostageBatchOptions } from '@ethersphere/bee-js'
|
import { PostageBatchOptions } from '@ethersphere/bee-js'
|
||||||
import { Box, Grid, Typography } from '@material-ui/core'
|
import { Box, Grid, Typography } from '@material-ui/core'
|
||||||
import BigNumber from 'bignumber.js'
|
import BigNumber from 'bignumber.js'
|
||||||
import { Form, Formik, FormikHelpers } from 'formik'
|
|
||||||
import { useSnackbar } from 'notistack'
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext } from 'react'
|
import { ReactElement, useContext, useEffect, useState } from 'react'
|
||||||
import Check from 'remixicon-react/CheckLineIcon'
|
import Check from 'remixicon-react/CheckLineIcon'
|
||||||
import { SwarmButton } from '../../components/SwarmButton'
|
import { SwarmButton } from '../../components/SwarmButton'
|
||||||
|
import { SwarmSelect } from '../../components/SwarmSelect'
|
||||||
import { SwarmTextInput } from '../../components/SwarmTextInput'
|
import { SwarmTextInput } from '../../components/SwarmTextInput'
|
||||||
import { Context as BeeContext } from '../../providers/Bee'
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
@@ -19,18 +19,6 @@ import {
|
|||||||
} from '../../utils'
|
} from '../../utils'
|
||||||
import { getHumanReadableFileSize } from '../../utils/file'
|
import { getHumanReadableFileSize } from '../../utils/file'
|
||||||
|
|
||||||
interface FormValues {
|
|
||||||
depth?: string
|
|
||||||
amount?: string
|
|
||||||
label?: string
|
|
||||||
}
|
|
||||||
type FormErrors = Partial<FormValues>
|
|
||||||
const initialFormValues: FormValues = {
|
|
||||||
depth: '',
|
|
||||||
amount: '',
|
|
||||||
label: '',
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onFinished: () => void
|
onFinished: () => void
|
||||||
}
|
}
|
||||||
@@ -40,6 +28,13 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
|||||||
const { refresh } = useContext(StampsContext)
|
const { refresh } = useContext(StampsContext)
|
||||||
const { beeDebugApi } = useContext(SettingsContext)
|
const { beeDebugApi } = useContext(SettingsContext)
|
||||||
|
|
||||||
|
const [depthInput, setDepthInput] = useState<string>('')
|
||||||
|
const [amountInput, setAmountInput] = useState<string>('')
|
||||||
|
const [labelInput, setLabelInput] = useState('')
|
||||||
|
const [immutable, setImmutable] = useState(false)
|
||||||
|
const [errors, setErrors] = useState<Record<string, string>>({})
|
||||||
|
const [submitting, setSubmitting] = useState(false)
|
||||||
|
|
||||||
const { enqueueSnackbar } = useSnackbar()
|
const { enqueueSnackbar } = useSnackbar()
|
||||||
|
|
||||||
function getFileSize(depth: number): string {
|
function getFileSize(depth: number): string {
|
||||||
@@ -76,6 +71,73 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
|||||||
return `${price.toSignificantDigits()} xBZZ`
|
return `${price.toSignificantDigits()} xBZZ`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function submit() {
|
||||||
|
try {
|
||||||
|
// This is really just a typeguard, the validation pretty much guarantees these will have the right values
|
||||||
|
if (!depthInput || !amountInput) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!beeDebugApi) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setSubmitting(true)
|
||||||
|
const amount = BigInt(amountInput)
|
||||||
|
const depth = Number.parseInt(depthInput)
|
||||||
|
const options: PostageBatchOptions = {
|
||||||
|
waitForUsable: false,
|
||||||
|
label: labelInput || undefined,
|
||||||
|
immutableFlag: immutable,
|
||||||
|
}
|
||||||
|
|
||||||
|
const batchId = await beeDebugApi.createPostageBatch(amount.toString(), depth, options)
|
||||||
|
await waitUntilStampExists(batchId, beeDebugApi)
|
||||||
|
await refresh()
|
||||||
|
onFinished()
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e) // eslint-disable-line
|
||||||
|
enqueueSnackbar(`Error: ${(e as Error).message}`, { variant: 'error' })
|
||||||
|
}
|
||||||
|
setSubmitting(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function validate() {
|
||||||
|
const errors: Record<string, string> = {}
|
||||||
|
|
||||||
|
if (!depthInput) {
|
||||||
|
errors.depth = 'Required field'
|
||||||
|
} else {
|
||||||
|
const depth = new BigNumber(depthInput)
|
||||||
|
|
||||||
|
if (!depth.isInteger()) {
|
||||||
|
errors.depth = 'Depth must be an integer'
|
||||||
|
} else if (depth.isLessThan(17)) {
|
||||||
|
errors.depth = 'Minimal depth is 17'
|
||||||
|
} else if (depth.isGreaterThan(255)) {
|
||||||
|
errors.depth = 'Depth has to be at most 255'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amountInput) {
|
||||||
|
errors.amount = 'Required field'
|
||||||
|
} else {
|
||||||
|
const amount = new BigNumber(amountInput)
|
||||||
|
|
||||||
|
if (!amount.isInteger()) {
|
||||||
|
errors.amount = 'Amount must be an integer'
|
||||||
|
} else if (amount.isLessThanOrEqualTo(0)) {
|
||||||
|
errors.amount = 'Amount must be greater than 0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors
|
||||||
|
}
|
||||||
|
|
||||||
|
setErrors(validate())
|
||||||
|
}, [depthInput, amountInput])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
@@ -92,102 +154,72 @@ export function PostageStampCreation({ onFinished }: Props): ReactElement {
|
|||||||
.
|
.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
<Formik
|
|
||||||
initialValues={initialFormValues}
|
|
||||||
onSubmit={async (values: FormValues, actions: FormikHelpers<FormValues>) => {
|
|
||||||
try {
|
|
||||||
// This is really just a typeguard, the validation pretty much guarantees these will have the right values
|
|
||||||
if (!values.depth || !values.amount) return
|
|
||||||
|
|
||||||
if (!beeDebugApi) return
|
|
||||||
|
|
||||||
const amount = BigInt(values.amount)
|
|
||||||
const depth = Number.parseInt(values.depth)
|
|
||||||
const options: PostageBatchOptions = { waitForUsable: false, label: values.label || undefined }
|
|
||||||
const batchId = await beeDebugApi.createPostageBatch(amount.toString(), depth, options)
|
|
||||||
await waitUntilStampExists(batchId, beeDebugApi)
|
|
||||||
actions.resetForm()
|
|
||||||
await refresh()
|
|
||||||
onFinished()
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e) // eslint-disable-line
|
|
||||||
enqueueSnackbar(`Error: ${(e as Error).message}`, { variant: 'error' })
|
|
||||||
actions.setSubmitting(false)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
validate={(values: FormValues) => {
|
|
||||||
const errors: FormErrors = {}
|
|
||||||
|
|
||||||
// Depth
|
|
||||||
if (!values.depth) errors.depth = 'Required field'
|
|
||||||
else {
|
|
||||||
const depth = new BigNumber(values.depth)
|
|
||||||
|
|
||||||
if (!depth.isInteger()) errors.depth = 'Depth must be an integer'
|
|
||||||
else if (depth.isLessThan(17)) errors.depth = 'Minimal depth is 17'
|
|
||||||
else if (depth.isGreaterThan(255)) errors.depth = 'Depth has to be at most 255'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Amount
|
|
||||||
if (!values.amount) errors.amount = 'Required field'
|
|
||||||
else {
|
|
||||||
const amount = new BigNumber(values.amount)
|
|
||||||
|
|
||||||
if (!amount.isInteger()) errors.amount = 'Amount must be an integer'
|
|
||||||
else if (amount.isLessThanOrEqualTo(0)) errors.amount = 'Amount must be greater than 0'
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{({ submitForm, isValid, isSubmitting, values, errors }) => (
|
|
||||||
<Form>
|
|
||||||
<Box mb={2}>
|
<Box mb={2}>
|
||||||
<SwarmTextInput name="depth" label="Depth" formik />
|
<SwarmTextInput name="depth" label="Depth" onChange={event => setDepthInput(event.target.value)} />
|
||||||
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography>Corresponding file size</Typography>
|
<Typography>Corresponding file size</Typography>
|
||||||
<Typography>
|
<Typography>{!errors.depth && depthInput ? getFileSize(parseInt(depthInput, 10)) : '-'}</Typography>
|
||||||
{!errors.depth && values.depth ? getFileSize(parseInt(values.depth, 10)) : '-'}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={2}>
|
<Box mb={2}>
|
||||||
<SwarmTextInput name="amount" label="Amount" formik />
|
<SwarmTextInput name="amount" label="Amount" onChange={event => setAmountInput(event.target.value)} />
|
||||||
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography>Corresponding TTL (Time to live)</Typography>
|
<Typography>Corresponding TTL (Time to live)</Typography>
|
||||||
<Typography>
|
<Typography>{!errors.amount && amountInput ? getTtl(Number.parseInt(amountInput, 10)) : '-'}</Typography>
|
||||||
{!errors.amount && values.amount ? getTtl(Number.parseInt(values.amount, 10)) : '-'}
|
|
||||||
</Typography>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={2}>
|
<Box mb={2}>
|
||||||
<SwarmTextInput name="label" label="Label" optional formik />
|
<SwarmTextInput name="label" label="Label" optional onChange={event => setLabelInput(event.target.value)} />
|
||||||
|
</Box>
|
||||||
|
<Box mb={2}>
|
||||||
|
<SwarmSelect
|
||||||
|
label="Immutable"
|
||||||
|
defaultValue="No"
|
||||||
|
onChange={event => setImmutable(event.target.value === 'Yes')}
|
||||||
|
options={[
|
||||||
|
{ value: 'Yes', label: 'Yes' },
|
||||||
|
{ value: 'No', label: 'No' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Box mt={0.25} sx={{ bgcolor: '#f6f6f6' }} p={2}>
|
||||||
|
<Grid container justifyContent="space-between">
|
||||||
|
{immutable && (
|
||||||
|
<Typography>
|
||||||
|
Once an immutable stamp is maxed out, it disallows further content uploads, thereby safeguarding your
|
||||||
|
previously uploaded content from unintentional overwriting.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
{!immutable && (
|
||||||
|
<Typography>
|
||||||
|
When a mutable stamp reaches full capacity, it still permits new content uploads. However, this comes
|
||||||
|
with the caveat of overwriting previously uploaded content associated with the same stamp.
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={4} sx={{ bgcolor: '#fcf2e8' }} p={2}>
|
<Box mb={4} sx={{ bgcolor: '#fcf2e8' }} p={2}>
|
||||||
<Grid container justifyContent="space-between">
|
<Grid container justifyContent="space-between">
|
||||||
<Typography>Indicative Price</Typography>
|
<Typography>Indicative Price</Typography>
|
||||||
<Typography>
|
<Typography>
|
||||||
{!errors.amount && !errors.depth && values.amount && values.depth
|
{!errors.amount && !errors.depth && amountInput && depthInput
|
||||||
? getPrice(parseInt(values.depth, 10), BigInt(values.amount))
|
? getPrice(parseInt(depthInput, 10), BigInt(amountInput))
|
||||||
: '-'}
|
: '-'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Box>
|
</Box>
|
||||||
<SwarmButton
|
<SwarmButton
|
||||||
disabled={isSubmitting || !isValid || !values.amount || !values.depth}
|
disabled={submitting || Object.keys(errors).length > 0}
|
||||||
onClick={submitForm}
|
onClick={submit}
|
||||||
iconType={Check}
|
iconType={Check}
|
||||||
loading={isSubmitting}
|
loading={submitting}
|
||||||
>
|
>
|
||||||
Buy New Stamp
|
Buy New Stamp
|
||||||
</SwarmButton>
|
</SwarmButton>
|
||||||
</Form>
|
|
||||||
)}
|
|
||||||
</Formik>
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import type { ReactElement } from 'react'
|
import { ReactElement, useContext } from 'react'
|
||||||
|
import TimerFlash from 'remixicon-react/TimerFlashFillIcon'
|
||||||
import ExpandableElement from '../../components/ExpandableElement'
|
import ExpandableElement from '../../components/ExpandableElement'
|
||||||
import ExpandableList from '../../components/ExpandableList'
|
import ExpandableList from '../../components/ExpandableList'
|
||||||
import ExpandableListItem from '../../components/ExpandableListItem'
|
import ExpandableListItem from '../../components/ExpandableListItem'
|
||||||
|
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
||||||
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
||||||
|
import StampExtensionModal from '../../components/StampExtensionModal'
|
||||||
|
import { Context } from '../../providers/Settings'
|
||||||
import { EnrichedPostageBatch } from '../../providers/Stamps'
|
import { EnrichedPostageBatch } from '../../providers/Stamps'
|
||||||
import { secondsToTimeString } from '../../utils'
|
import { secondsToTimeString } from '../../utils'
|
||||||
import { getHumanReadableFileSize } from '../../utils/file'
|
import { getHumanReadableFileSize } from '../../utils/file'
|
||||||
@@ -13,7 +17,11 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function StampsTable({ postageStamps }: Props): ReactElement | null {
|
function StampsTable({ postageStamps }: Props): ReactElement | null {
|
||||||
if (postageStamps === null) return null
|
const { beeDebugApi } = useContext(Context)
|
||||||
|
|
||||||
|
if (!postageStamps || !beeDebugApi) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ExpandableList label="Postage Stamps" defaultOpen>
|
<ExpandableList label="Postage Stamps" defaultOpen>
|
||||||
@@ -38,7 +46,16 @@ function StampsTable({ postageStamps }: Props): ReactElement | null {
|
|||||||
<ExpandableListItem label="Label" value={stamp.label} />
|
<ExpandableListItem label="Label" value={stamp.label} />
|
||||||
<ExpandableListItem label="Usable" value={stamp.usable ? 'yes' : 'no'} />
|
<ExpandableListItem label="Usable" value={stamp.usable ? 'yes' : 'no'} />
|
||||||
<ExpandableListItem label="Exists" value={stamp.exists ? 'yes' : 'no'} />
|
<ExpandableListItem label="Exists" value={stamp.exists ? 'yes' : 'no'} />
|
||||||
|
<ExpandableListItem label="Immutable" value={stamp.immutableFlag ? 'yes' : 'no'} />
|
||||||
<ExpandableListItem label="Purchase Block Number" value={stamp.blockNumber} />
|
<ExpandableListItem label="Purchase Block Number" value={stamp.blockNumber} />
|
||||||
|
<ExpandableListItemActions>
|
||||||
|
<StampExtensionModal
|
||||||
|
label="Topup & Dilute"
|
||||||
|
icon={<TimerFlash size="1rem" />}
|
||||||
|
beeDebug={beeDebugApi}
|
||||||
|
stamp={stamp.batchID}
|
||||||
|
/>
|
||||||
|
</ExpandableListItemActions>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -11,23 +11,21 @@ import { CheckState, Context } from '../../../providers/Bee'
|
|||||||
const ChequebookDeployFund = (): ReactElement | null => {
|
const ChequebookDeployFund = (): ReactElement | null => {
|
||||||
const { status, isLoading, chequebookAddress } = useContext(Context)
|
const { status, isLoading, chequebookAddress } = useContext(Context)
|
||||||
const { checkState, isEnabled } = status.chequebook
|
const { checkState, isEnabled } = status.chequebook
|
||||||
|
const { checkState: debugApiCheckState } = status.debugApiConnection
|
||||||
|
|
||||||
if (!isEnabled) return null
|
if (!isEnabled || debugApiCheckState === CheckState.ERROR) return null
|
||||||
|
|
||||||
let text: ReactNode
|
let text: ReactNode
|
||||||
|
|
||||||
switch (checkState) {
|
switch (checkState) {
|
||||||
case CheckState.OK:
|
case CheckState.OK:
|
||||||
text = 'Your chequebook is deployed and funded'
|
|
||||||
break
|
|
||||||
case CheckState.WARNING:
|
|
||||||
text = (
|
text = (
|
||||||
<>
|
<>
|
||||||
Your chequebook is not funded. Please deposit some xBZZ to your chequebook address. You may need to aquire BZZ
|
Your chequebook is deployed. You may deposit some xBZZ to your chequebook to afford more traffic. You can
|
||||||
(e.g. <a href="https://bzz.exchange/">bzz.exchange</a>) and bridge it to the Gnosis Chain network through the{' '}
|
acquire BZZ (e.g. <a href="https://bzz.exchange/">bzz.exchange</a>) and bridge it to the Gnosis Chain network
|
||||||
<a href="https://omni.gnosischain.com/bridge">omni bridge</a>. To pay the transaction fees, you will also need
|
through the <a href="https://omni.gnosischain.com/bridge">omni bridge</a>. To pay the transaction fees, you
|
||||||
xDAI token. You can purchase DAI on the Ethereum mainnet network and bridge it to Gnosis Chain network through
|
will also need xDAI token. You can purchase DAI on the Ethereum mainnet network and bridge it to Gnosis Chain
|
||||||
the <a href="https://bridge.gnosischain.com">xDai Bridge</a>. See the{' '}
|
network through the <a href="https://bridge.gnosischain.com">xDai Bridge</a>. See the{' '}
|
||||||
<a href="https://www.gnosischain.com">official Gnosis Chain website</a> for more information.
|
<a href="https://www.gnosischain.com">official Gnosis Chain website</a> for more information.
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { Context as SettingsContext } from '../../../providers/Settings'
|
|||||||
|
|
||||||
export default function NodeConnectionCheck(): ReactElement | null {
|
export default function NodeConnectionCheck(): ReactElement | null {
|
||||||
const { status, isLoading } = useContext(Context)
|
const { status, isLoading } = useContext(Context)
|
||||||
const { setDebugApiUrl, apiDebugUrl } = useContext(SettingsContext)
|
const { setDebugApiUrl, apiDebugUrl, isDesktop } = useContext(SettingsContext)
|
||||||
const { checkState, isEnabled } = status.debugApiConnection
|
const { checkState, isEnabled } = status.debugApiConnection
|
||||||
|
|
||||||
if (!isEnabled) return null
|
if (!isEnabled) return null
|
||||||
@@ -26,12 +26,12 @@ export default function NodeConnectionCheck(): ReactElement | null {
|
|||||||
>
|
>
|
||||||
<ExpandableListItemNote>
|
<ExpandableListItemNote>
|
||||||
{checkState === CheckState.OK
|
{checkState === CheckState.OK
|
||||||
? 'The connection to the Bee nodes debug API has been successful'
|
? 'The connection to the Bee node debug API has been successful'
|
||||||
: 'We cannot connect to your nodes debug API. Please check the following to troubleshoot your issue.'}
|
: 'Could not connect to your Bee node debug API.'}
|
||||||
</ExpandableListItemNote>
|
</ExpandableListItemNote>
|
||||||
<ExpandableListItemInput label="Bee Debug API" value={apiDebugUrl} onConfirm={setDebugApiUrl} />
|
<ExpandableListItemInput label="Bee Debug API" value={apiDebugUrl} onConfirm={setDebugApiUrl} />
|
||||||
|
|
||||||
{checkState === CheckState.ERROR && (
|
{checkState === CheckState.ERROR && !isDesktop && (
|
||||||
<ExpandableList level={1} label="Troubleshoot">
|
<ExpandableList level={1} label="Troubleshoot">
|
||||||
<ExpandableListItem
|
<ExpandableListItem
|
||||||
label={
|
label={
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { ReactElement, useContext } from 'react'
|
||||||
|
|
||||||
|
import ExpandableList from '../../../components/ExpandableList'
|
||||||
|
import ExpandableListItem from '../../../components/ExpandableListItem'
|
||||||
|
import ExpandableListItemNote from '../../../components/ExpandableListItemNote'
|
||||||
|
import StatusIcon from '../../../components/StatusIcon'
|
||||||
|
import { useBeeDesktop } from '../../../hooks/apiHooks'
|
||||||
|
import { CheckState } from '../../../providers/Bee'
|
||||||
|
import { Context as SettingsContext } from '../../../providers/Settings'
|
||||||
|
|
||||||
|
export default function DesktopConnectionCheck(): ReactElement | null {
|
||||||
|
const { isDesktop, desktopUrl } = useContext(SettingsContext)
|
||||||
|
const { reachable } = useBeeDesktop(isDesktop, desktopUrl)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ExpandableList
|
||||||
|
label={
|
||||||
|
<>
|
||||||
|
<StatusIcon checkState={reachable ? CheckState.OK : CheckState.ERROR} isLoading={false} /> Connection to Swarm
|
||||||
|
Desktop
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<ExpandableListItemNote>
|
||||||
|
{reachable
|
||||||
|
? 'The connection to the Swarm Desktop API has been successful'
|
||||||
|
: 'Could not connect to the Swarm Desktop API'}
|
||||||
|
</ExpandableListItemNote>
|
||||||
|
<ExpandableListItem label="Swarm Desktop API" value={desktopUrl} />
|
||||||
|
</ExpandableList>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -34,7 +34,7 @@ export default function EthereumConnectionCheck(): ReactElement | null {
|
|||||||
Getblock
|
Getblock
|
||||||
</a>
|
</a>
|
||||||
. By default, Bee expects a local node at http://localhost:8545. To use a provider instead, simply change
|
. By default, Bee expects a local node at http://localhost:8545. To use a provider instead, simply change
|
||||||
the <strong>swap-endpoint</strong> in your configuration file.
|
the <strong>blockchain-rpc-endpoint</strong> in your configuration file.
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</ExpandableListItemNote>
|
</ExpandableListItemNote>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import StatusIcon from '../../../components/StatusIcon'
|
|||||||
import { CheckState, Context } from '../../../providers/Bee'
|
import { CheckState, Context } from '../../../providers/Bee'
|
||||||
|
|
||||||
export default function NodeConnectionCheck(): ReactElement | null {
|
export default function NodeConnectionCheck(): ReactElement | null {
|
||||||
const { setApiUrl, apiUrl } = useContext(SettingsContext)
|
const { setApiUrl, apiUrl, isDesktop } = useContext(SettingsContext)
|
||||||
const { status, isLoading } = useContext(Context)
|
const { status, isLoading } = useContext(Context)
|
||||||
const { isEnabled, checkState } = status.apiConnection
|
const { isEnabled, checkState } = status.apiConnection
|
||||||
|
|
||||||
@@ -26,11 +26,11 @@ export default function NodeConnectionCheck(): ReactElement | null {
|
|||||||
>
|
>
|
||||||
<ExpandableListItemNote>
|
<ExpandableListItemNote>
|
||||||
{checkState === CheckState.OK
|
{checkState === CheckState.OK
|
||||||
? 'The connection to the Bee nodes API has been successful'
|
? 'The connection to the Bee node API has been successful'
|
||||||
: 'Could not connect to your Bee nodes API. Please check the troubleshoot below on how you may resolve it.'}
|
: 'Could not connect to your Bee node API.'}
|
||||||
</ExpandableListItemNote>
|
</ExpandableListItemNote>
|
||||||
<ExpandableListItemInput label="Bee API" value={apiUrl} onConfirm={setApiUrl} />
|
<ExpandableListItemInput label="Bee API" value={apiUrl} onConfirm={setApiUrl} />
|
||||||
{checkState === CheckState.ERROR && (
|
{checkState === CheckState.ERROR && !isDesktop && (
|
||||||
<ExpandableList level={1} label="Troubleshoot">
|
<ExpandableList level={1} label="Troubleshoot">
|
||||||
<ExpandableListItem
|
<ExpandableListItem
|
||||||
label={
|
label={
|
||||||
|
|||||||
@@ -8,8 +8,9 @@ import { CheckState, Context } from '../../../providers/Bee'
|
|||||||
export default function PeerConnection(): ReactElement | null {
|
export default function PeerConnection(): ReactElement | null {
|
||||||
const { status, isLoading, topology } = useContext(Context)
|
const { status, isLoading, topology } = useContext(Context)
|
||||||
const { isEnabled, checkState } = status.topology
|
const { isEnabled, checkState } = status.topology
|
||||||
|
const { checkState: debugApiCheckState } = status.debugApiConnection
|
||||||
|
|
||||||
if (!isEnabled) return null
|
if (!isEnabled || debugApiCheckState === CheckState.ERROR) return null
|
||||||
|
|
||||||
let text: ReactNode
|
let text: ReactNode
|
||||||
switch (checkState) {
|
switch (checkState) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import type { ReactElement } from 'react'
|
import { Context } from '../../providers/Settings'
|
||||||
|
import { ReactElement, useContext } from 'react'
|
||||||
|
|
||||||
import DebugConnectionCheck from './SetupSteps/DebugConnectionCheck'
|
import DebugConnectionCheck from './SetupSteps/DebugConnectionCheck'
|
||||||
|
import DesktopConnection from './SetupSteps/DesktopConnectionCheck'
|
||||||
import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck'
|
import NodeConnectionCheck from './SetupSteps/NodeConnectionCheck'
|
||||||
import VersionCheck from './SetupSteps/VersionCheck'
|
import VersionCheck from './SetupSteps/VersionCheck'
|
||||||
import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck'
|
import EthereumConnectionCheck from './SetupSteps/EthereumConnectionCheck'
|
||||||
@@ -8,13 +10,16 @@ import ChequebookDeployFund from './SetupSteps/ChequebookDeployFund'
|
|||||||
import PeerConnection from './SetupSteps/PeerConnection'
|
import PeerConnection from './SetupSteps/PeerConnection'
|
||||||
|
|
||||||
export default function NodeSetupWorkflow(): ReactElement {
|
export default function NodeSetupWorkflow(): ReactElement {
|
||||||
|
const { isDesktop } = useContext(Context)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
{isDesktop && <DesktopConnection />}
|
||||||
|
<NodeConnectionCheck />
|
||||||
<DebugConnectionCheck />
|
<DebugConnectionCheck />
|
||||||
<VersionCheck />
|
{!isDesktop && <VersionCheck />}
|
||||||
<EthereumConnectionCheck />
|
<EthereumConnectionCheck />
|
||||||
<ChequebookDeployFund />
|
<ChequebookDeployFund />
|
||||||
<NodeConnectionCheck />
|
|
||||||
<PeerConnection />
|
<PeerConnection />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
import { BeeModes } from '@ethersphere/bee-js'
|
||||||
import { Box, Typography } from '@material-ui/core'
|
import { Box, Typography } from '@material-ui/core'
|
||||||
import { useSnackbar } from 'notistack'
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useEffect, useState } from 'react'
|
import { ReactElement, useContext, useEffect, useState } from 'react'
|
||||||
import Check from 'remixicon-react/CheckLineIcon'
|
|
||||||
import ArrowDown from 'remixicon-react/ArrowDownLineIcon'
|
|
||||||
import { useNavigate, useParams } from 'react-router'
|
import { useNavigate, useParams } from 'react-router'
|
||||||
|
import ArrowDown from 'remixicon-react/ArrowDownLineIcon'
|
||||||
|
import Check from 'remixicon-react/CheckLineIcon'
|
||||||
import ExpandableListItem from '../../components/ExpandableListItem'
|
import ExpandableListItem from '../../components/ExpandableListItem'
|
||||||
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
import ExpandableListItemKey from '../../components/ExpandableListItemKey'
|
||||||
import { HistoryHeader } from '../../components/HistoryHeader'
|
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||||
@@ -18,7 +19,6 @@ import { ROUTES } from '../../routes'
|
|||||||
import { sleepMs } from '../../utils'
|
import { sleepMs } from '../../utils'
|
||||||
import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
|
import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
|
||||||
import { ResolvedWallet } from '../../utils/wallet'
|
import { ResolvedWallet } from '../../utils/wallet'
|
||||||
import { BeeModes } from '@ethersphere/bee-js'
|
|
||||||
|
|
||||||
export function GiftCardFund(): ReactElement {
|
export function GiftCardFund(): ReactElement {
|
||||||
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
|
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
|
||||||
@@ -52,7 +52,6 @@ export function GiftCardFund(): ReactElement {
|
|||||||
await sleepMs(5_000)
|
await sleepMs(5_000)
|
||||||
await upgradeToLightNode(desktopUrl, rpcProviderUrl)
|
await upgradeToLightNode(desktopUrl, rpcProviderUrl)
|
||||||
await restartBeeNode(desktopUrl)
|
await restartBeeNode(desktopUrl)
|
||||||
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
|
||||||
navigate(ROUTES.RESTART_LIGHT)
|
navigate(ROUTES.RESTART_LIGHT)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error) // eslint-disable-line
|
console.error(error) // eslint-disable-line
|
||||||
|
|||||||
+133
-46
@@ -1,6 +1,5 @@
|
|||||||
import { BeeModes } from '@ethersphere/bee-js'
|
import { BeeModes } from '@ethersphere/bee-js'
|
||||||
import { Box, Typography } from '@material-ui/core'
|
import { Box, Typography } from '@material-ui/core'
|
||||||
import BigNumber from 'bignumber.js'
|
|
||||||
import { useSnackbar } from 'notistack'
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useEffect, useState } from 'react'
|
import { ReactElement, useContext, useEffect, useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
@@ -14,36 +13,42 @@ import { Loading } from '../../components/Loading'
|
|||||||
import { SwarmButton } from '../../components/SwarmButton'
|
import { SwarmButton } from '../../components/SwarmButton'
|
||||||
import { SwarmDivider } from '../../components/SwarmDivider'
|
import { SwarmDivider } from '../../components/SwarmDivider'
|
||||||
import { SwarmTextInput } from '../../components/SwarmTextInput'
|
import { SwarmTextInput } from '../../components/SwarmTextInput'
|
||||||
import { BzzToken } from '../../models/BzzToken'
|
import { BzzToken, BZZ_DECIMAL_PLACES } from '../../models/BzzToken'
|
||||||
import { DaiToken } from '../../models/DaiToken'
|
import { DaiToken } from '../../models/DaiToken'
|
||||||
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
|
||||||
import { Context as BeeContext } from '../../providers/Bee'
|
import { Context as BeeContext } from '../../providers/Bee'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
|
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
||||||
import { ROUTES } from '../../routes'
|
import { ROUTES } from '../../routes'
|
||||||
import { sleepMs } from '../../utils'
|
import { sleepMs } from '../../utils'
|
||||||
import { getBzzPriceAsDai, performSwap, restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
|
import {
|
||||||
|
getBzzPriceAsDai,
|
||||||
|
getDesktopConfiguration,
|
||||||
|
performSwap,
|
||||||
|
restartBeeNode,
|
||||||
|
upgradeToLightNode,
|
||||||
|
} from '../../utils/desktop'
|
||||||
|
import { Rpc } from '../../utils/rpc'
|
||||||
|
import { isSwapError, SwapError, wrapWithSwapError } from '../../utils/SwapError'
|
||||||
import { TopUpProgressIndicator } from './TopUpProgressIndicator'
|
import { TopUpProgressIndicator } from './TopUpProgressIndicator'
|
||||||
|
|
||||||
const MINIMUM_XDAI = '0.1'
|
const MINIMUM_XDAI = '0.1'
|
||||||
const MINIMUM_XBZZ = '0.1'
|
const MINIMUM_XBZZ = '0.1'
|
||||||
|
|
||||||
|
const GENERIC_SWAP_FAILED_ERROR_MESSAGE = 'Failed to swap. The full error is printed to the console.'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
header: string
|
header: string
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPositiveDecimal(value: string): boolean {
|
|
||||||
try {
|
|
||||||
return new BigNumber(value).isPositive()
|
|
||||||
} catch {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function Swap({ header }: Props): ReactElement {
|
export function Swap({ header }: Props): ReactElement {
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [hasSwapped, setSwapped] = useState(false)
|
const [hasSwapped, setSwapped] = useState(false)
|
||||||
const [userInputSwap, setUserInputSwap] = useState<string | null>(null)
|
const [userInputSwap, setUserInputSwap] = useState<string | null>(null)
|
||||||
const [price, setPrice] = useState(DaiToken.fromDecimal('0.6', 18))
|
const [price, setPrice] = useState(DaiToken.fromDecimal('0.6'))
|
||||||
|
const [error, setError] = useState<string | null>(null)
|
||||||
|
const [daiToSwap, setDaiToSwap] = useState<DaiToken | null>(null)
|
||||||
|
const [bzzAfterSwap, setBzzAfterSwap] = useState<BzzToken | null>(null)
|
||||||
|
const [daiAfterSwap, setDaiAfterSwap] = useState<DaiToken | null>(null)
|
||||||
|
|
||||||
const { rpcProviderUrl, isDesktop, desktopUrl } = useContext(SettingsContext)
|
const { rpcProviderUrl, isDesktop, desktopUrl } = useContext(SettingsContext)
|
||||||
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
|
const { nodeAddresses, nodeInfo } = useContext(BeeContext)
|
||||||
@@ -52,38 +57,77 @@ export function Swap({ header }: Props): ReactElement {
|
|||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { enqueueSnackbar } = useSnackbar()
|
const { enqueueSnackbar } = useSnackbar()
|
||||||
|
|
||||||
|
// Fetch current price of BZZ
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
getBzzPriceAsDai(desktopUrl).then(setPrice).catch(console.error)
|
getBzzPriceAsDai(desktopUrl).then(setPrice).catch(console.error)
|
||||||
}, [desktopUrl])
|
}, [desktopUrl])
|
||||||
|
|
||||||
if (!balance || !nodeAddresses) {
|
// Set the initial xDAI to swap
|
||||||
|
useEffect(() => {
|
||||||
|
if (!balance || userInputSwap) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const minimumOptimalValue = DaiToken.fromDecimal('1').plusBaseUnits(MINIMUM_XDAI).toDecimal
|
||||||
|
|
||||||
|
if (balance.dai.toDecimal.isGreaterThanOrEqualTo(minimumOptimalValue)) {
|
||||||
|
// Balance has at least 1 + MINIMUM_XDAI xDai
|
||||||
|
setDaiToSwap(balance.dai.minusBaseUnits('1'))
|
||||||
|
} else {
|
||||||
|
// Balance is low, halve the amount
|
||||||
|
setDaiToSwap(new DaiToken(balance.dai.toBigNumber.dividedToIntegerBy(2)))
|
||||||
|
}
|
||||||
|
}, [balance, userInputSwap])
|
||||||
|
|
||||||
|
// Set the xDAI to swap based on user input
|
||||||
|
useEffect(() => {
|
||||||
|
setError(null)
|
||||||
|
try {
|
||||||
|
if (userInputSwap) {
|
||||||
|
const dai = DaiToken.fromDecimal(userInputSwap)
|
||||||
|
setDaiToSwap(dai)
|
||||||
|
|
||||||
|
if (dai.toDecimal.lte(0)) {
|
||||||
|
setError('xDAI to swap must be a positive number')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
setError('Cannot parse xDAI amount')
|
||||||
|
}
|
||||||
|
}, [userInputSwap])
|
||||||
|
|
||||||
|
// Calculate the amount of tokens after swap
|
||||||
|
useEffect(() => {
|
||||||
|
if (!balance || !daiToSwap || error) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber))
|
||||||
|
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))
|
||||||
|
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!`)
|
||||||
|
}
|
||||||
|
}, [error, balance, daiToSwap, price])
|
||||||
|
|
||||||
|
if (!balance || !nodeAddresses || !daiToSwap || !bzzAfterSwap || !daiAfterSwap) {
|
||||||
return <Loading />
|
return <Loading />
|
||||||
}
|
}
|
||||||
|
|
||||||
const optimalSwap = balance.dai.minusBaseUnits('1')
|
|
||||||
const lowAmountSwap = new DaiToken(balance.dai.toBigNumber.dividedToIntegerBy(2))
|
|
||||||
|
|
||||||
let daiToSwap: DaiToken
|
|
||||||
|
|
||||||
if (userInputSwap && isPositiveDecimal(userInputSwap)) {
|
|
||||||
daiToSwap = DaiToken.fromDecimal(userInputSwap, 18)
|
|
||||||
} else {
|
|
||||||
daiToSwap = lowAmountSwap.toBigNumber.gt(optimalSwap.toBigNumber) ? lowAmountSwap : optimalSwap
|
|
||||||
}
|
|
||||||
|
|
||||||
const daiAfterSwap = new DaiToken(balance.dai.toBigNumber.minus(daiToSwap.toBigNumber))
|
|
||||||
const bzzAfterSwap = new BzzToken(daiToSwap.toBigNumber.dividedBy(100).dividedToIntegerBy(price.toDecimal))
|
|
||||||
|
|
||||||
const canUpgradeToLightNode = isDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT
|
const canUpgradeToLightNode = isDesktop && nodeInfo?.beeMode === BeeModes.ULTRA_LIGHT
|
||||||
|
|
||||||
async function restart() {
|
async function restart() {
|
||||||
try {
|
try {
|
||||||
await sleepMs(5_000)
|
await sleepMs(5_000)
|
||||||
await upgradeToLightNode(desktopUrl, rpcProviderUrl)
|
|
||||||
await restartBeeNode(desktopUrl)
|
await restartBeeNode(desktopUrl)
|
||||||
|
|
||||||
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
|
||||||
navigate(ROUTES.RESTART_LIGHT)
|
navigate(ROUTES.RESTART_LIGHT)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error) // eslint-disable-line
|
console.error(error) // eslint-disable-line
|
||||||
@@ -91,21 +135,71 @@ export function Swap({ header }: Props): ReactElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function sendSwapRequest(daiToSwap: DaiToken) {
|
||||||
|
try {
|
||||||
|
await performSwap(desktopUrl, daiToSwap.toString)
|
||||||
|
} catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function performSwapWithChecks(daiToSwap: DaiToken) {
|
||||||
|
if (!localStorage.getItem('apiKey')) {
|
||||||
|
throw new SwapError('API key is not set, reopen dashboard through Swarm Desktop')
|
||||||
|
}
|
||||||
|
|
||||||
|
let desktopConfiguration = await wrapWithSwapError(
|
||||||
|
getDesktopConfiguration(desktopUrl),
|
||||||
|
'Unable to reach Desktop API, Swarm Desktop may not be running',
|
||||||
|
)
|
||||||
|
|
||||||
|
if (canUpgradeToLightNode) {
|
||||||
|
desktopConfiguration = await wrapWithSwapError(
|
||||||
|
upgradeToLightNode(desktopUrl, rpcProviderUrl),
|
||||||
|
'Failed to update the configuration file with the new swap values using the Desktop API',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!desktopConfiguration['blockchain-rpc-endpoint']) {
|
||||||
|
throw new SwapError('Blockchain RPC endpoint is not configured in Swarm Desktop')
|
||||||
|
}
|
||||||
|
await wrapWithSwapError(
|
||||||
|
Rpc.getNetworkChainId(desktopConfiguration['blockchain-rpc-endpoint']),
|
||||||
|
`Blockchain RPC endpoint not reachable at ${desktopConfiguration['blockchain-rpc-endpoint']}`,
|
||||||
|
)
|
||||||
|
await wrapWithSwapError(sendSwapRequest(daiToSwap), GENERIC_SWAP_FAILED_ERROR_MESSAGE)
|
||||||
|
}
|
||||||
|
|
||||||
async function onSwap() {
|
async function onSwap() {
|
||||||
if (hasSwapped) {
|
if (hasSwapped || !daiToSwap) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
setSwapped(true)
|
setSwapped(true)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await performSwap(desktopUrl, daiToSwap.toString)
|
await performSwapWithChecks(daiToSwap)
|
||||||
enqueueSnackbar('Successfully swapped', { variant: 'success' })
|
const message = canUpgradeToLightNode
|
||||||
|
? 'Successfully swapped. Beginning light node upgrade...'
|
||||||
|
: '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) {
|
} catch (error) {
|
||||||
|
if (isSwapError(error)) {
|
||||||
|
// we have a custom and user friendly error message
|
||||||
|
enqueueSnackbar(error.snackbarMessage, { variant: 'error' })
|
||||||
|
|
||||||
|
if (error.originalError) {
|
||||||
|
console.error(error.originalError) // eslint-disable-line
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// we have an unexpected error
|
||||||
|
enqueueSnackbar(`${GENERIC_SWAP_FAILED_ERROR_MESSAGE} ${error}`, { variant: 'error' })
|
||||||
console.error(error) // eslint-disable-line
|
console.error(error) // eslint-disable-line
|
||||||
enqueueSnackbar(`Failed to swap: ${error}`, { variant: 'error' })
|
}
|
||||||
} finally {
|
} finally {
|
||||||
balance?.refresh()
|
balance?.refresh()
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@@ -136,18 +230,13 @@ export function Swap({ header }: Props): ReactElement {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
<SwarmTextInput
|
<SwarmTextInput
|
||||||
label="Amount to swap"
|
label="xDAI to swap"
|
||||||
defaultValue={`${daiToSwap.toSignificantDigits(4)} xDAI`}
|
defaultValue={daiToSwap.toSignificantDigits(4)}
|
||||||
placeholder={`${daiToSwap.toSignificantDigits(4)} xDAI`}
|
placeholder={daiToSwap.toSignificantDigits(4)}
|
||||||
name="x"
|
name="x"
|
||||||
onChange={event => setUserInputSwap(event.target.value)}
|
onChange={event => setUserInputSwap(event.target.value)}
|
||||||
/>
|
/>
|
||||||
{daiAfterSwap.toDecimal.lt(MINIMUM_XDAI) ? (
|
{error && <Typography>{error}</Typography>}
|
||||||
<Typography>Must keep at least {MINIMUM_XDAI} xDAI after swap!</Typography>
|
|
||||||
) : null}
|
|
||||||
{bzzAfterSwap.toDecimal.lt(MINIMUM_XBZZ) ? (
|
|
||||||
<Typography>Must have at least {MINIMUM_XBZZ} xBZZ after swap!</Typography>
|
|
||||||
) : null}
|
|
||||||
</Box>
|
</Box>
|
||||||
<Box mb={4}>
|
<Box mb={4}>
|
||||||
<ArrowDown size={24} color="#aaaaaa" />
|
<ArrowDown size={24} color="#aaaaaa" />
|
||||||
@@ -171,9 +260,7 @@ export function Swap({ header }: Props): ReactElement {
|
|||||||
<SwarmButton
|
<SwarmButton
|
||||||
iconType={Check}
|
iconType={Check}
|
||||||
onClick={onSwap}
|
onClick={onSwap}
|
||||||
disabled={
|
disabled={hasSwapped || loading || error !== null}
|
||||||
hasSwapped || loading || daiAfterSwap.toDecimal.lt(MINIMUM_XDAI) || bzzAfterSwap.toDecimal.lt(MINIMUM_XBZZ)
|
|
||||||
}
|
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
{canUpgradeToLightNode ? 'Swap Now and Upgrade' : 'Swap Now'}
|
{canUpgradeToLightNode ? 'Swap Now and Upgrade' : 'Swap Now'}
|
||||||
|
|||||||
@@ -1,23 +1,23 @@
|
|||||||
|
import { BeeModes } from '@ethersphere/bee-js'
|
||||||
import { Box, createStyles, Grid, makeStyles, Typography } from '@material-ui/core'
|
import { Box, createStyles, Grid, makeStyles, Typography } from '@material-ui/core'
|
||||||
|
import { useSnackbar } from 'notistack'
|
||||||
import { ReactElement, useContext, useState } from 'react'
|
import { ReactElement, useContext, useState } from 'react'
|
||||||
|
import { useNavigate } from 'react-router'
|
||||||
|
import BankCard from 'remixicon-react/BankCard2LineIcon'
|
||||||
import Check from 'remixicon-react/CheckLineIcon'
|
import Check from 'remixicon-react/CheckLineIcon'
|
||||||
import Download from 'remixicon-react/DownloadLineIcon'
|
import Download from 'remixicon-react/DownloadLineIcon'
|
||||||
import BankCard from 'remixicon-react/BankCard2LineIcon'
|
|
||||||
import MoneyDollarCircle from 'remixicon-react/MoneyDollarCircleLineIcon'
|
|
||||||
import Gift from 'remixicon-react/GiftLineIcon'
|
import Gift from 'remixicon-react/GiftLineIcon'
|
||||||
import { useNavigate } from 'react-router'
|
import MoneyDollarCircle from 'remixicon-react/MoneyDollarCircleLineIcon'
|
||||||
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
import ExpandableListItemActions from '../../components/ExpandableListItemActions'
|
||||||
import { HistoryHeader } from '../../components/HistoryHeader'
|
import { HistoryHeader } from '../../components/HistoryHeader'
|
||||||
|
import { Loading } from '../../components/Loading'
|
||||||
import { SwarmButton } from '../../components/SwarmButton'
|
import { SwarmButton } from '../../components/SwarmButton'
|
||||||
import { ROUTES } from '../../routes'
|
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
|
||||||
import { CheckState, Context as BeeContext } from '../../providers/Bee'
|
import { CheckState, Context as BeeContext } from '../../providers/Bee'
|
||||||
import { Context as SettingsContext } from '../../providers/Settings'
|
import { Context as SettingsContext } from '../../providers/Settings'
|
||||||
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
import { Context as BalanceProvider } from '../../providers/WalletBalance'
|
||||||
import { BeeModes } from '@ethersphere/bee-js'
|
import { ROUTES } from '../../routes'
|
||||||
import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
|
import { restartBeeNode, upgradeToLightNode } from '../../utils/desktop'
|
||||||
import { Loading } from '../../components/Loading'
|
|
||||||
import { useSnackbar } from 'notistack'
|
|
||||||
import TroubleshootConnectionCard from '../../components/TroubleshootConnectionCard'
|
|
||||||
|
|
||||||
const useStyles = makeStyles(() =>
|
const useStyles = makeStyles(() =>
|
||||||
createStyles({
|
createStyles({
|
||||||
@@ -57,7 +57,6 @@ export default function TopUp(): ReactElement {
|
|||||||
try {
|
try {
|
||||||
await upgradeToLightNode(desktopUrl, rpcProviderUrl)
|
await upgradeToLightNode(desktopUrl, rpcProviderUrl)
|
||||||
await restartBeeNode(desktopUrl)
|
await restartBeeNode(desktopUrl)
|
||||||
enqueueSnackbar('Upgraded to light node', { variant: 'success' })
|
|
||||||
navigate(ROUTES.RESTART_LIGHT)
|
navigate(ROUTES.RESTART_LIGHT)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error) // eslint-disable-line
|
console.error(error) // eslint-disable-line
|
||||||
|
|||||||
+72
-23
@@ -9,22 +9,26 @@ import {
|
|||||||
Peer,
|
Peer,
|
||||||
Topology,
|
Topology,
|
||||||
} from '@ethersphere/bee-js'
|
} from '@ethersphere/bee-js'
|
||||||
import { createContext, ReactChild, ReactElement, useContext, useEffect, useState } from 'react'
|
import { ReactChild, ReactElement, createContext, useContext, useEffect, useState } from 'react'
|
||||||
import semver from 'semver'
|
import semver from 'semver'
|
||||||
import PackageJson from '../../package.json'
|
import PackageJson from '../../package.json'
|
||||||
import { useLatestBeeRelease } from '../hooks/apiHooks'
|
import { useLatestBeeRelease } from '../hooks/apiHooks'
|
||||||
|
import { BzzToken } from '../models/BzzToken'
|
||||||
import { Token } from '../models/Token'
|
import { Token } from '../models/Token'
|
||||||
import type { Balance, ChequebookBalance, Settlements } from '../types'
|
import type { Balance, ChequebookBalance, Settlements } from '../types'
|
||||||
import { Context as SettingsContext } from './Settings'
|
import { Context as SettingsContext } from './Settings'
|
||||||
|
|
||||||
|
const LAUNCH_GRACE_PERIOD = 15_000
|
||||||
const REFRESH_WHEN_OK = 30_000
|
const REFRESH_WHEN_OK = 30_000
|
||||||
const REFRESH_WHEN_ERROR = 5_000
|
const REFRESH_WHEN_ERROR = 5_000
|
||||||
const TIMEOUT = 3_000
|
const TIMEOUT = 3_000
|
||||||
|
|
||||||
export enum CheckState {
|
export enum CheckState {
|
||||||
|
CONNECTING = 'Connecting',
|
||||||
OK = 'OK',
|
OK = 'OK',
|
||||||
WARNING = 'Warning',
|
WARNING = 'Warning',
|
||||||
ERROR = 'Error',
|
ERROR = 'Error',
|
||||||
|
STARTING = 'Starting',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StatusItem {
|
interface StatusItem {
|
||||||
@@ -52,12 +56,14 @@ interface ContextInterface {
|
|||||||
error: Error | null
|
error: Error | null
|
||||||
apiHealth: boolean
|
apiHealth: boolean
|
||||||
debugApiHealth: Health | null
|
debugApiHealth: Health | null
|
||||||
|
debugApiReadiness: boolean
|
||||||
nodeAddresses: NodeAddresses | null
|
nodeAddresses: NodeAddresses | null
|
||||||
nodeInfo: NodeInfo | null
|
nodeInfo: NodeInfo | null
|
||||||
topology: Topology | null
|
topology: Topology | null
|
||||||
chequebookAddress: ChequebookAddressResponse | null
|
chequebookAddress: ChequebookAddressResponse | null
|
||||||
peers: Peer[] | null
|
peers: Peer[] | null
|
||||||
chequebookBalance: ChequebookBalance | null
|
chequebookBalance: ChequebookBalance | null
|
||||||
|
stake: BzzToken | null
|
||||||
peerBalances: Balance[] | null
|
peerBalances: Balance[] | null
|
||||||
peerCheques: LastChequesResponse | null
|
peerCheques: LastChequesResponse | null
|
||||||
settlements: Settlements | null
|
settlements: Settlements | null
|
||||||
@@ -89,10 +95,12 @@ const initialValues: ContextInterface = {
|
|||||||
error: null,
|
error: null,
|
||||||
apiHealth: false,
|
apiHealth: false,
|
||||||
debugApiHealth: null,
|
debugApiHealth: null,
|
||||||
|
debugApiReadiness: false,
|
||||||
nodeAddresses: null,
|
nodeAddresses: null,
|
||||||
nodeInfo: null,
|
nodeInfo: null,
|
||||||
topology: null,
|
topology: null,
|
||||||
chequebookAddress: null,
|
chequebookAddress: null,
|
||||||
|
stake: null,
|
||||||
peers: null,
|
peers: null,
|
||||||
chequebookBalance: null,
|
chequebookBalance: null,
|
||||||
peerBalances: null,
|
peerBalances: null,
|
||||||
@@ -117,25 +125,27 @@ interface Props {
|
|||||||
|
|
||||||
function getStatus(
|
function getStatus(
|
||||||
debugApiHealth: Health | null,
|
debugApiHealth: Health | null,
|
||||||
nodeAddresses: NodeAddresses | null,
|
debugApiReadiness: boolean,
|
||||||
nodeInfo: NodeInfo | null,
|
nodeInfo: NodeInfo | null,
|
||||||
apiHealth: boolean,
|
apiHealth: boolean,
|
||||||
topology: Topology | null,
|
topology: Topology | null,
|
||||||
chequebookAddress: ChequebookAddressResponse | null,
|
chequebookAddress: ChequebookAddressResponse | null,
|
||||||
chequebookBalance: ChequebookBalance | null,
|
chequebookBalance: ChequebookBalance | null,
|
||||||
error: Error | null,
|
error: Error | null,
|
||||||
|
isDesktop: boolean,
|
||||||
|
startedAt: number,
|
||||||
): Status {
|
): Status {
|
||||||
const status: Status = { ...initialValues.status }
|
const status: Status = { ...initialValues.status }
|
||||||
|
|
||||||
// Version check
|
// Version check
|
||||||
status.version.isEnabled = true
|
status.version.isEnabled = !isDesktop
|
||||||
status.version.checkState =
|
status.version.checkState =
|
||||||
debugApiHealth &&
|
debugApiHealth &&
|
||||||
semver.satisfies(debugApiHealth.version, PackageJson.engines.bee, {
|
semver.satisfies(debugApiHealth.version, PackageJson.engines.bee, {
|
||||||
includePrerelease: true,
|
includePrerelease: true,
|
||||||
})
|
})
|
||||||
? CheckState.OK
|
? CheckState.OK
|
||||||
: CheckState.ERROR
|
: CheckState.WARNING
|
||||||
|
|
||||||
// Blockchain connection check
|
// Blockchain connection check
|
||||||
status.blockchainConnection.isEnabled = true
|
status.blockchainConnection.isEnabled = true
|
||||||
@@ -159,48 +169,72 @@ function getStatus(
|
|||||||
if (error || (nodeInfo && [BeeModes.FULL, BeeModes.LIGHT].includes(nodeInfo.beeMode))) {
|
if (error || (nodeInfo && [BeeModes.FULL, BeeModes.LIGHT].includes(nodeInfo.beeMode))) {
|
||||||
status.chequebook.isEnabled = true
|
status.chequebook.isEnabled = true
|
||||||
|
|
||||||
if (
|
if (chequebookAddress?.chequebookAddress && chequebookBalance !== null) {
|
||||||
chequebookAddress?.chequebookAddress &&
|
|
||||||
chequebookBalance !== null &&
|
|
||||||
chequebookBalance?.totalBalance.toBigNumber.isGreaterThan(0)
|
|
||||||
) {
|
|
||||||
status.chequebook.checkState = CheckState.OK
|
status.chequebook.checkState = CheckState.OK
|
||||||
} else if (chequebookAddress?.chequebookAddress) status.chequebook.checkState = CheckState.WARNING
|
} else status.chequebook.checkState = CheckState.OK
|
||||||
else status.chequebook.checkState = CheckState.OK
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine overall status
|
status.all = determineOverallStatus(debugApiHealth, debugApiReadiness, status, startedAt)
|
||||||
if (Object.values(status).some(({ isEnabled, checkState }) => isEnabled && checkState === CheckState.ERROR)) {
|
|
||||||
status.all = CheckState.ERROR
|
|
||||||
} else if (
|
|
||||||
Object.values(status).some(({ isEnabled, checkState }) => isEnabled && checkState === CheckState.WARNING)
|
|
||||||
) {
|
|
||||||
status.all = CheckState.WARNING
|
|
||||||
} else {
|
|
||||||
status.all = CheckState.OK
|
|
||||||
}
|
|
||||||
|
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function determineOverallStatus(
|
||||||
|
debugApiHealth: Health | null,
|
||||||
|
debugApiReadiness: boolean,
|
||||||
|
status: Status,
|
||||||
|
startedAt: number,
|
||||||
|
): CheckState {
|
||||||
|
const hasErrors = Object.values(status).some(
|
||||||
|
({ isEnabled, checkState }) => isEnabled && checkState === CheckState.ERROR,
|
||||||
|
)
|
||||||
|
const hasWarnings = Object.values(status).some(
|
||||||
|
({ isEnabled, checkState }) => isEnabled && checkState === CheckState.WARNING,
|
||||||
|
)
|
||||||
|
const isInGracePeriod = Date.now() - startedAt < LAUNCH_GRACE_PERIOD
|
||||||
|
|
||||||
|
if (debugApiHealth?.status === 'ok' && !debugApiReadiness) {
|
||||||
|
return CheckState.STARTING
|
||||||
|
} else if (hasErrors && isInGracePeriod) {
|
||||||
|
return CheckState.CONNECTING
|
||||||
|
} else if (hasErrors) {
|
||||||
|
return CheckState.ERROR
|
||||||
|
} else if (hasWarnings) {
|
||||||
|
return CheckState.WARNING
|
||||||
|
} else {
|
||||||
|
return CheckState.OK
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This does not need to be exposed and works much better as variable than state variable which may trigger some unnecessary re-renders
|
// This does not need to be exposed and works much better as variable than state variable which may trigger some unnecessary re-renders
|
||||||
let isRefreshing = false
|
let isRefreshing = false
|
||||||
|
|
||||||
export function Provider({ children }: Props): ReactElement {
|
interface InitialSettings {
|
||||||
|
isDesktop?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props extends InitialSettings {
|
||||||
|
children: ReactChild
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Provider({ children, isDesktop }: Props): ReactElement {
|
||||||
const { beeApi, beeDebugApi } = useContext(SettingsContext)
|
const { beeApi, beeDebugApi } = useContext(SettingsContext)
|
||||||
const [apiHealth, setApiHealth] = useState<boolean>(false)
|
const [apiHealth, setApiHealth] = useState<boolean>(false)
|
||||||
const [debugApiHealth, setDebugApiHealth] = useState<Health | null>(null)
|
const [debugApiHealth, setDebugApiHealth] = useState<Health | null>(null)
|
||||||
|
const [debugApiReadiness, setDebugApiReadiness] = useState(false)
|
||||||
const [nodeAddresses, setNodeAddresses] = useState<NodeAddresses | null>(null)
|
const [nodeAddresses, setNodeAddresses] = useState<NodeAddresses | null>(null)
|
||||||
const [nodeInfo, setNodeInfo] = useState<NodeInfo | null>(null)
|
const [nodeInfo, setNodeInfo] = useState<NodeInfo | null>(null)
|
||||||
const [topology, setNodeTopology] = useState<Topology | null>(null)
|
const [topology, setNodeTopology] = useState<Topology | null>(null)
|
||||||
const [chequebookAddress, setChequebookAddress] = useState<ChequebookAddressResponse | null>(null)
|
const [chequebookAddress, setChequebookAddress] = useState<ChequebookAddressResponse | null>(null)
|
||||||
const [peers, setPeers] = useState<Peer[] | null>(null)
|
const [peers, setPeers] = useState<Peer[] | null>(null)
|
||||||
const [chequebookBalance, setChequebookBalance] = useState<ChequebookBalance | null>(null)
|
const [chequebookBalance, setChequebookBalance] = useState<ChequebookBalance | null>(null)
|
||||||
|
const [stake, setStake] = useState<BzzToken | null>(null)
|
||||||
const [peerBalances, setPeerBalances] = useState<Balance[] | null>(null)
|
const [peerBalances, setPeerBalances] = useState<Balance[] | null>(null)
|
||||||
const [peerCheques, setPeerCheques] = useState<LastChequesResponse | null>(null)
|
const [peerCheques, setPeerCheques] = useState<LastChequesResponse | null>(null)
|
||||||
const [settlements, setSettlements] = useState<Settlements | null>(null)
|
const [settlements, setSettlements] = useState<Settlements | null>(null)
|
||||||
const [chainState, setChainState] = useState<ChainState | null>(null)
|
const [chainState, setChainState] = useState<ChainState | null>(null)
|
||||||
const [chainId, setChainId] = useState<number | null>(null)
|
const [chainId, setChainId] = useState<number | null>(null)
|
||||||
|
const [startedAt] = useState(Date.now())
|
||||||
|
|
||||||
const { latestBeeRelease } = useLatestBeeRelease()
|
const { latestBeeRelease } = useLatestBeeRelease()
|
||||||
|
|
||||||
@@ -299,6 +333,12 @@ export function Provider({ children }: Props): ReactElement {
|
|||||||
.then(setDebugApiHealth)
|
.then(setDebugApiHealth)
|
||||||
.catch(() => setDebugApiHealth(null)),
|
.catch(() => setDebugApiHealth(null)),
|
||||||
|
|
||||||
|
// Debug API readiness
|
||||||
|
beeDebugApi
|
||||||
|
.getReadiness({ timeout: TIMEOUT })
|
||||||
|
.then(setDebugApiReadiness)
|
||||||
|
.catch(() => setDebugApiReadiness(false)),
|
||||||
|
|
||||||
// Node Addresses
|
// Node Addresses
|
||||||
beeDebugApi
|
beeDebugApi
|
||||||
.getNodeAddresses({ timeout: TIMEOUT })
|
.getNodeAddresses({ timeout: TIMEOUT })
|
||||||
@@ -352,6 +392,11 @@ export function Provider({ children }: Props): ReactElement {
|
|||||||
.then(setChequebookBalance)
|
.then(setChequebookBalance)
|
||||||
.catch(() => setChequebookBalance(null)),
|
.catch(() => setChequebookBalance(null)),
|
||||||
|
|
||||||
|
beeDebugApi
|
||||||
|
.getStake({ timeout: TIMEOUT })
|
||||||
|
.then(stake => setStake(new BzzToken(stake)))
|
||||||
|
.catch(() => setStake(null)),
|
||||||
|
|
||||||
// Peer balances
|
// Peer balances
|
||||||
peerBalanceWrapper()
|
peerBalanceWrapper()
|
||||||
.then(setPeerBalances)
|
.then(setPeerBalances)
|
||||||
@@ -381,13 +426,15 @@ export function Provider({ children }: Props): ReactElement {
|
|||||||
|
|
||||||
const status = getStatus(
|
const status = getStatus(
|
||||||
debugApiHealth,
|
debugApiHealth,
|
||||||
nodeAddresses,
|
debugApiReadiness,
|
||||||
nodeInfo,
|
nodeInfo,
|
||||||
apiHealth,
|
apiHealth,
|
||||||
topology,
|
topology,
|
||||||
chequebookAddress,
|
chequebookAddress,
|
||||||
chequebookBalance,
|
chequebookBalance,
|
||||||
error,
|
error,
|
||||||
|
Boolean(isDesktop),
|
||||||
|
startedAt,
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -426,12 +473,14 @@ export function Provider({ children }: Props): ReactElement {
|
|||||||
error,
|
error,
|
||||||
apiHealth,
|
apiHealth,
|
||||||
debugApiHealth,
|
debugApiHealth,
|
||||||
|
debugApiReadiness,
|
||||||
nodeAddresses,
|
nodeAddresses,
|
||||||
nodeInfo,
|
nodeInfo,
|
||||||
topology,
|
topology,
|
||||||
chequebookAddress,
|
chequebookAddress,
|
||||||
peers,
|
peers,
|
||||||
chequebookBalance,
|
chequebookBalance,
|
||||||
|
stake,
|
||||||
peerBalances,
|
peerBalances,
|
||||||
peerCheques,
|
peerCheques,
|
||||||
settlements,
|
settlements,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Bee, BeeDebug } from '@ethersphere/bee-js'
|
import { Bee, BeeDebug } from '@ethersphere/bee-js'
|
||||||
import { providers } from 'ethers'
|
import { providers } from 'ethers'
|
||||||
import { createContext, ReactNode, ReactElement, useEffect, useState } from 'react'
|
import { ReactElement, ReactNode, createContext, useEffect, useState } from 'react'
|
||||||
import { useGetBeeConfig } from '../hooks/apiHooks'
|
|
||||||
import { DEFAULT_BEE_API_HOST, DEFAULT_BEE_DEBUG_API_HOST, DEFAULT_RPC_URL } from '../constants'
|
import { DEFAULT_BEE_API_HOST, DEFAULT_BEE_DEBUG_API_HOST, DEFAULT_RPC_URL } from '../constants'
|
||||||
|
import { useGetBeeConfig } from '../hooks/apiHooks'
|
||||||
|
|
||||||
const LocalStorageKeys = {
|
const LocalStorageKeys = {
|
||||||
providerUrl: 'json-rpc-provider',
|
providerUrl: 'json-rpc-provider',
|
||||||
@@ -18,7 +18,7 @@ interface ContextInterface {
|
|||||||
isDesktop: boolean
|
isDesktop: boolean
|
||||||
desktopUrl: string
|
desktopUrl: string
|
||||||
rpcProviderUrl: string
|
rpcProviderUrl: string
|
||||||
rpcProvider: providers.JsonRpcProvider
|
rpcProvider: providers.JsonRpcProvider | null
|
||||||
cors: string | null
|
cors: string | null
|
||||||
dataDir: string | null
|
dataDir: string | null
|
||||||
ensResolver: string | null
|
ensResolver: string | null
|
||||||
@@ -42,7 +42,7 @@ const initialValues: ContextInterface = {
|
|||||||
desktopUrl: window.location.origin,
|
desktopUrl: window.location.origin,
|
||||||
setAndPersistJsonRpcProvider: async () => {}, // eslint-disable-line
|
setAndPersistJsonRpcProvider: async () => {}, // eslint-disable-line
|
||||||
rpcProviderUrl: '',
|
rpcProviderUrl: '',
|
||||||
rpcProvider: new providers.JsonRpcProvider(''),
|
rpcProvider: null,
|
||||||
cors: null,
|
cors: null,
|
||||||
dataDir: null,
|
dataDir: null,
|
||||||
ensResolver: null,
|
ensResolver: null,
|
||||||
|
|||||||
+5
-1
@@ -2,6 +2,7 @@ import { ReactElement, useContext } from 'react'
|
|||||||
import { Route, Routes } from 'react-router-dom'
|
import { Route, Routes } from 'react-router-dom'
|
||||||
import { AccountChequebook } from './pages/account/chequebook/AccountChequebook'
|
import { AccountChequebook } from './pages/account/chequebook/AccountChequebook'
|
||||||
import { AccountFeeds } from './pages/account/feeds/AccountFeeds'
|
import { AccountFeeds } from './pages/account/feeds/AccountFeeds'
|
||||||
|
import { AccountStaking } from './pages/account/staking/AccountStaking'
|
||||||
import { AccountStamps } from './pages/account/stamps/AccountStamps'
|
import { AccountStamps } from './pages/account/stamps/AccountStamps'
|
||||||
import { AccountWallet } from './pages/account/wallet/AccountWallet'
|
import { AccountWallet } from './pages/account/wallet/AccountWallet'
|
||||||
import CreateNewFeed from './pages/feeds/CreateNewFeed'
|
import CreateNewFeed from './pages/feeds/CreateNewFeed'
|
||||||
@@ -14,10 +15,10 @@ import { UploadLander } from './pages/files/UploadLander'
|
|||||||
import GiftCards from './pages/gift-code'
|
import GiftCards from './pages/gift-code'
|
||||||
import Info from './pages/info'
|
import Info from './pages/info'
|
||||||
import LightModeRestart from './pages/restart/LightModeRestart'
|
import LightModeRestart from './pages/restart/LightModeRestart'
|
||||||
import TopUp from './pages/top-up'
|
|
||||||
import Settings from './pages/settings'
|
import Settings from './pages/settings'
|
||||||
import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampPage'
|
import { CreatePostageStampPage } from './pages/stamps/CreatePostageStampPage'
|
||||||
import Status from './pages/status'
|
import Status from './pages/status'
|
||||||
|
import TopUp from './pages/top-up'
|
||||||
import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex'
|
import { BankCardTopUpIndex } from './pages/top-up/BankCardTopUpIndex'
|
||||||
import { CryptoTopUpIndex } from './pages/top-up/CryptoTopUpIndex'
|
import { CryptoTopUpIndex } from './pages/top-up/CryptoTopUpIndex'
|
||||||
import { GiftCardFund } from './pages/top-up/GiftCardFund'
|
import { GiftCardFund } from './pages/top-up/GiftCardFund'
|
||||||
@@ -51,6 +52,7 @@ export enum ROUTES {
|
|||||||
ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash',
|
ACCOUNT_FEEDS_UPDATE = '/account/feeds/update/:hash',
|
||||||
ACCOUNT_FEEDS_VIEW = '/account/feeds/:uuid',
|
ACCOUNT_FEEDS_VIEW = '/account/feeds/:uuid',
|
||||||
ACCOUNT_INVITATIONS = '/account/invitations',
|
ACCOUNT_INVITATIONS = '/account/invitations',
|
||||||
|
ACCOUNT_STAKING = '/account/staking',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ACCOUNT_TABS = [
|
export const ACCOUNT_TABS = [
|
||||||
@@ -58,6 +60,7 @@ export const ACCOUNT_TABS = [
|
|||||||
ROUTES.ACCOUNT_CHEQUEBOOK,
|
ROUTES.ACCOUNT_CHEQUEBOOK,
|
||||||
ROUTES.ACCOUNT_STAMPS,
|
ROUTES.ACCOUNT_STAMPS,
|
||||||
ROUTES.ACCOUNT_FEEDS,
|
ROUTES.ACCOUNT_FEEDS,
|
||||||
|
ROUTES.ACCOUNT_STAKING,
|
||||||
]
|
]
|
||||||
|
|
||||||
const BaseRouter = (): ReactElement => {
|
const BaseRouter = (): ReactElement => {
|
||||||
@@ -88,6 +91,7 @@ const BaseRouter = (): ReactElement => {
|
|||||||
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
|
<Route path={ROUTES.ACCOUNT_FEEDS_NEW} element={<CreateNewFeed />} />
|
||||||
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
|
<Route path={ROUTES.ACCOUNT_FEEDS_UPDATE} element={<UpdateFeed />} />
|
||||||
<Route path={ROUTES.ACCOUNT_FEEDS_VIEW} element={<FeedSubpage />} />
|
<Route path={ROUTES.ACCOUNT_FEEDS_VIEW} element={<FeedSubpage />} />
|
||||||
|
<Route path={ROUTES.ACCOUNT_STAKING} element={<AccountStaking />} />
|
||||||
{isDesktop && <Route path={ROUTES.ACCOUNT_INVITATIONS} element={<GiftCards />} />}
|
{isDesktop && <Route path={ROUTES.ACCOUNT_INVITATIONS} element={<GiftCards />} />}
|
||||||
</Routes>
|
</Routes>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
export class AuthError extends Error {
|
||||||
|
constructor() {
|
||||||
|
super('Bad API key')
|
||||||
|
this.name = 'AuthError'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAuthError(error: unknown): error is AuthError {
|
||||||
|
return error instanceof Error && error.name === 'AuthError'
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { isAuthError } from './AuthError'
|
||||||
|
|
||||||
|
export class SwapError extends Error {
|
||||||
|
snackbarMessage: string
|
||||||
|
originalError?: Error
|
||||||
|
|
||||||
|
constructor(snackbarMessage: string, error?: Error) {
|
||||||
|
super(error?.message || snackbarMessage)
|
||||||
|
this.name = 'SwapError'
|
||||||
|
this.originalError = error
|
||||||
|
this.snackbarMessage = snackbarMessage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isSwapError(error: unknown): error is SwapError {
|
||||||
|
return error instanceof Error && error.name === 'SwapError'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function wrapWithSwapError<T>(promise: Promise<T>, snackbarMessage: string): Promise<T> {
|
||||||
|
return promise.catch((error: Error) => {
|
||||||
|
if (isAuthError(error)) {
|
||||||
|
throw new SwapError('Bad API key, reopen dashboard through Swarm Desktop', error)
|
||||||
|
}
|
||||||
|
throw new SwapError(snackbarMessage, error)
|
||||||
|
})
|
||||||
|
}
|
||||||
+29
-9
@@ -1,30 +1,50 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { BEE_DESKTOP_LATEST_RELEASE_PAGE_API } from '../constants'
|
||||||
import { DaiToken } from '../models/DaiToken'
|
import { DaiToken } from '../models/DaiToken'
|
||||||
import { Token } from '../models/Token'
|
import { Token } from '../models/Token'
|
||||||
import { postJson } from './net'
|
import { getJson, postJson } from './net'
|
||||||
import { BEE_DESKTOP_LATEST_RELEASE_PAGE_API } from '../constants'
|
|
||||||
|
export interface BeeConfig {
|
||||||
|
'api-addr': string
|
||||||
|
'debug-api-addr': string
|
||||||
|
'debug-api-enable': boolean
|
||||||
|
password: string
|
||||||
|
'swap-enable': boolean
|
||||||
|
'swap-initial-deposit': bigint
|
||||||
|
mainnet: boolean
|
||||||
|
'full-node': boolean
|
||||||
|
'cors-allowed-origins': string
|
||||||
|
'resolver-options': string
|
||||||
|
'use-postage-snapshot': boolean
|
||||||
|
'data-dir': string
|
||||||
|
'blockchain-rpc-endpoint'?: string
|
||||||
|
}
|
||||||
|
|
||||||
export async function getBzzPriceAsDai(desktopUrl: string): Promise<Token> {
|
export async function getBzzPriceAsDai(desktopUrl: string): Promise<Token> {
|
||||||
const response = await axios.get(`${desktopUrl}/price`)
|
const response = await axios.get(`${desktopUrl}/price`)
|
||||||
|
|
||||||
return DaiToken.fromDecimal(response.data, 18)
|
return DaiToken.fromDecimal(response.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function upgradeToLightNode(desktopUrl: string, rpcProvider: string): Promise<void> {
|
export function upgradeToLightNode(desktopUrl: string, rpcProvider: string): Promise<BeeConfig> {
|
||||||
await updateDesktopConfiguration(desktopUrl, {
|
return updateDesktopConfiguration(desktopUrl, {
|
||||||
'swap-enable': true,
|
'swap-enable': true,
|
||||||
'swap-endpoint': rpcProvider,
|
'blockchain-rpc-endpoint': rpcProvider,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setJsonRpcInDesktop(desktopUrl: string, value: string): Promise<void> {
|
export async function setJsonRpcInDesktop(desktopUrl: string, value: string): Promise<void> {
|
||||||
await updateDesktopConfiguration(desktopUrl, {
|
await updateDesktopConfiguration(desktopUrl, {
|
||||||
'swap-endpoint': value,
|
'blockchain-rpc-endpoint': value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateDesktopConfiguration(desktopUrl: string, values: Record<string, unknown>): Promise<void> {
|
export function getDesktopConfiguration(desktopUrl: string): Promise<BeeConfig> {
|
||||||
await postJson(`${desktopUrl}/config`, values)
|
return getJson(`${desktopUrl}/config`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateDesktopConfiguration(desktopUrl: string, values: Record<string, unknown>): Promise<BeeConfig> {
|
||||||
|
return postJson(`${desktopUrl}/config`, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function restartBeeNode(desktopUrl: string): Promise<void> {
|
export async function restartBeeNode(desktopUrl: string): Promise<void> {
|
||||||
|
|||||||
+6
-1
@@ -229,7 +229,7 @@ export function shortenText(text: string, length = 20, separator = '[…]'): str
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_POLLING_FREQUENCY = 1_000
|
const DEFAULT_POLLING_FREQUENCY = 1_000
|
||||||
const DEFAULT_STAMP_USABLE_TIMEOUT = 240_000
|
const DEFAULT_STAMP_USABLE_TIMEOUT = 5 * 60_000
|
||||||
|
|
||||||
interface Options {
|
interface Options {
|
||||||
pollingFrequency?: number
|
pollingFrequency?: number
|
||||||
@@ -254,9 +254,14 @@ async function waitForStamp(
|
|||||||
const pollingFrequency = options?.pollingFrequency || DEFAULT_POLLING_FREQUENCY
|
const pollingFrequency = options?.pollingFrequency || DEFAULT_POLLING_FREQUENCY
|
||||||
|
|
||||||
for (let i = 0; i < timeout; i += pollingFrequency) {
|
for (let i = 0; i < timeout; i += pollingFrequency) {
|
||||||
|
try {
|
||||||
const stamp = await beeDebug.getPostageBatch(batchId)
|
const stamp = await beeDebug.getPostageBatch(batchId)
|
||||||
|
|
||||||
if (stamp[field]) return stamp
|
if (stamp[field]) return stamp
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
await sleepMs(pollingFrequency)
|
await sleepMs(pollingFrequency)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
import { Bee, Utils } from '@ethersphere/bee-js'
|
||||||
|
import { loadAllNodes, MantarayNode, MetadataMapping, Reference } 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<boolean> {
|
||||||
|
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<string | null> {
|
||||||
|
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): Promise<Record<string, string>> {
|
||||||
|
const data = await this.bee.downloadData(hash)
|
||||||
|
const node = new MantarayNode()
|
||||||
|
node.deserialize(data)
|
||||||
|
await loadAllNodes(this.load.bind(this), node)
|
||||||
|
const result = {}
|
||||||
|
this.extractHashes(result, node)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves an arbitrary Swarm feed manifest to its latest update reference.
|
||||||
|
* @returns `/bzz` root manifest hash, or `Promise<null>` if hash is not a feed manifest
|
||||||
|
* @throws in case of network errors or bad input
|
||||||
|
*/
|
||||||
|
public async resolveFeedManifest(hash: string): Promise<string | null> {
|
||||||
|
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<MetadataMapping | null> {
|
||||||
|
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<string, string>, 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-1
@@ -1,12 +1,13 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
import { AuthError } from './AuthError'
|
||||||
|
|
||||||
export function getJson<T extends Record<string, any>>(url: string): Promise<T> {
|
export function getJson<T extends Record<string, any>>(url: string): Promise<T> {
|
||||||
return sendRequest(url, 'GET') as Promise<T>
|
return sendRequest(url, 'GET') as Promise<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function postJson<T extends Record<string, any>>(url: string, data?: T): Promise<T> {
|
export function postJson<T extends Record<string, any>>(url: string, data?: Record<string, any>): Promise<T> {
|
||||||
return sendRequest(url, 'POST', data) as Promise<T>
|
return sendRequest(url, 'POST', data) as Promise<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,6 +28,15 @@ export async function sendRequest(
|
|||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
data,
|
data,
|
||||||
|
}).catch(error => {
|
||||||
|
if (error?.response?.status === 401) {
|
||||||
|
throw new AuthError()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error?.response?.data) {
|
||||||
|
throw Error(`Request ${method} ${url} failed: ${JSON.stringify(error.response.data)}`)
|
||||||
|
}
|
||||||
|
throw error
|
||||||
})
|
})
|
||||||
|
|
||||||
return response.data
|
return response.data
|
||||||
|
|||||||
+12
-1
@@ -2,6 +2,16 @@ import { debounce } from '@material-ui/core'
|
|||||||
import { Contract, providers, Wallet, BigNumber as BN } from 'ethers'
|
import { Contract, providers, Wallet, BigNumber as BN } from 'ethers'
|
||||||
import { bzzABI, BZZ_TOKEN_ADDRESS } from './bzz-abi'
|
import { bzzABI, BZZ_TOKEN_ADDRESS } from './bzz-abi'
|
||||||
|
|
||||||
|
const NETWORK_ID = 100
|
||||||
|
|
||||||
|
async function getNetworkChainId(url: string): Promise<number> {
|
||||||
|
const provider = new providers.JsonRpcProvider(url, NETWORK_ID)
|
||||||
|
await provider.ready
|
||||||
|
const network = await provider.getNetwork()
|
||||||
|
|
||||||
|
return network.chainId
|
||||||
|
}
|
||||||
|
|
||||||
async function eth_getBalance(address: string, provider: providers.JsonRpcProvider): Promise<string> {
|
async function eth_getBalance(address: string, provider: providers.JsonRpcProvider): Promise<string> {
|
||||||
if (!address.startsWith('0x')) {
|
if (!address.startsWith('0x')) {
|
||||||
address = `0x${address}`
|
address = `0x${address}`
|
||||||
@@ -78,7 +88,7 @@ export async function sendBzzTransaction(
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function makeReadySigner(privateKey: string, jsonRpcProvider: string) {
|
async function makeReadySigner(privateKey: string, jsonRpcProvider: string) {
|
||||||
const provider = new providers.JsonRpcProvider(jsonRpcProvider, 100)
|
const provider = new providers.JsonRpcProvider(jsonRpcProvider, NETWORK_ID)
|
||||||
await provider.ready
|
await provider.ready
|
||||||
const signer = new Wallet(privateKey, provider)
|
const signer = new Wallet(privateKey, provider)
|
||||||
|
|
||||||
@@ -86,6 +96,7 @@ async function makeReadySigner(privateKey: string, jsonRpcProvider: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const Rpc = {
|
export const Rpc = {
|
||||||
|
getNetworkChainId,
|
||||||
sendNativeTransaction,
|
sendNativeTransaction,
|
||||||
sendBzzTransaction,
|
sendBzzTransaction,
|
||||||
_eth_getBalance: eth_getBalance,
|
_eth_getBalance: eth_getBalance,
|
||||||
|
|||||||
Reference in New Issue
Block a user