Compare commits

..

40 Commits

Author SHA1 Message Date
Tommy Verrall 4d72d052fe remove assets directory 2025-06-12 09:52:04 +02:00
Tommy Verrall 0c52ee89c8 Merge pull request #5821 from nymtech/dependabot/npm_and_yarn/sdk/typescript/tests/integration-tests/mix-fetch/tar-fs-3.0.9
build(deps): bump tar-fs from 3.0.8 to 3.0.9 in /sdk/typescript/tests/integration-tests/mix-fetch
2025-06-12 08:43:47 +01:00
Tommy Verrall f324d45721 Merge pull request #5449 from indmind/patch-1
chore: fixed typo in API endpoint parameter
2025-06-12 08:42:50 +01:00
Tommy Verrall 470e88f46c Merge pull request #5843 from nymtech/dependabot/npm_and_yarn/wasm/mix-fetch/internal-dev/webpack-dev-server-5.2.1
build(deps-dev): bump webpack-dev-server from 4.13.2 to 5.2.1 in /wasm/mix-fetch/internal-dev
2025-06-12 08:41:20 +01:00
Tommy Verrall 42a5016822 Merge pull request #5845 from nymtech/remove/old-mock-nym-api-client
remove not used old mock-api
2025-06-12 08:40:35 +01:00
Tommy Verrall 579cff358d Merge pull request #5849 from nymtech/feature/remove-browser-extension
Updated browser extension piece removal
2025-06-12 08:38:38 +01:00
benedetta davico f95dda0f2f Merge pull request #5844 from nymtech/feature/remove-bity
remove bity dir
2025-06-12 09:37:19 +02:00
benedetta davico fc666fb984 Merge pull request #5848 from nymtech/remove/old-env-references
Remove/old env references
2025-06-12 09:37:08 +02:00
benedetta davico 1264fd9bfb Update ci-build.yml 2025-06-11 17:48:24 +02:00
Tommy Verrall 3e8451f292 updated browser extension piece
- keep all the internal-dev wasm pieces as future examples
- everything previously was going to be removed
- shows functioning wasm interaction with the js
2025-06-11 17:15:20 +02:00
benedetta davico 53f4582202 Merge pull request #5835 from nymtech/benny/node-version-test
Update publish-nym-binaries.yml
2025-06-11 16:39:18 +02:00
benedettadavico c7c6dcab65 remove old env references 2025-06-11 16:13:59 +02:00
benedettadavico 3422c49e85 remove qa env 2025-06-11 16:07:32 +02:00
benedettadavico deee0b8e14 remove bity integration from cargo toml 2025-06-11 16:05:03 +02:00
Tommy Verrall 7243cb57b5 remove not used old mock-api 2025-06-11 15:58:01 +02:00
Tommy Verrall 0276bd7b0b Merge pull request #5840 from nymtech/remove-testnet-faucet
Removing test-net faucet
2025-06-11 14:47:08 +01:00
Tommy Verrall 457759bb57 Merge pull request #5841 from nymtech/feature/add-buy-locations
Amended the buy section
2025-06-11 14:20:59 +01:00
dependabot[bot] de0f8ee2d3 build(deps): bump next from 14.2.15 to 14.2.26 in /documentation/docs (#5772)
Bumps [next](https://github.com/vercel/next.js) from 14.2.15 to 14.2.26.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v14.2.15...v14.2.26)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 14.2.26
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 13:36:30 +01:00
dependabot[bot] ebf97ece9b build(deps-dev): bump webpack-dev-server in /wasm/mix-fetch/internal-dev
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 4.13.2 to 5.2.1.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v4.13.2...v5.2.1)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-11 12:23:47 +00:00
dependabot[bot] 50a55f4bfb build(deps-dev): bump webpack-dev-server (#5826)
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 4.15.2 to 5.2.1.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v4.15.2...v5.2.1)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-version: 5.2.1
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-11 13:22:07 +01:00
Tommy Verrall 4ee5c6457b remove images dir 2025-06-11 13:18:01 +02:00
Tommy Verrall d7b5fce7aa amended the buy section
- change the wallet to include the buy options for nym
- remove legacy code
2025-06-11 13:15:37 +02:00
benedetta davico c3d9c1131b Merge pull request #5838 from nymtech/release/2025.11-cheddar
merge release/2025.11-cheddar to develop
2025-06-11 13:09:57 +02:00
Tommy Verrall 5bdfb1ba5c removing test-net faucet 2025-06-11 12:00:44 +02:00
benedettadavico 94e51f0047 remove bity dir 2025-06-11 10:28:44 +02:00
benedetta davico f313e95e2f Merge pull request #5837 from nymtech/yana/replace-mintscan
Replace mintscan with ping.pub
2025-06-11 10:14:36 +02:00
Yana 2b13ac99b4 Replace mintscan with ping.pub 2025-06-10 19:34:19 +03:00
benedetta davico ef220882d4 update the workflow file again with a temp fix
reference: https://github.com/softprops/action-gh-release/issues/628
2025-06-10 11:39:20 +02:00
benedetta davico 59e26178ee Update publish-nym-binaries.yml 2025-06-10 11:20:19 +02:00
benedetta davico 0d420fb0a5 remove explorer-api in workflow 2025-06-10 11:01:24 +02:00
benedettadavico fce195fdba update changelog 2025-06-10 10:28:47 +02:00
Jędrzej Stuczyński 554b1eb022 bugfix: fix swapped total and circulating supplies (#5822) 2025-06-09 08:41:21 +01:00
import this 5b67403fb9 [DOCs/operators]: Add auto scraping of staking_supply_scale_factor & update api outputs (#5832) 2025-06-06 09:57:48 +00:00
Bogdan-Ștefan Neacşu 3a528d3b89 No autoremoval of peers (#5831)
* No autoremoval

* Remove startup_timestamp
2025-06-06 12:48:34 +03:00
Bogdan-Ștefan Neacşu 466bb97bc7 Use the same client bandwidth for top up (#5813)
* Use the same client bandwidth for top up

* Fix clippy
2025-06-06 10:12:50 +03:00
Simon Wicky 0d78416454 [Stats API] IP from nginx headers if available (#5830)
* proper IP handling

* workflow doesn't like fancy versions
2025-06-06 09:08:58 +02:00
benedettadavico e9bb9792ab bump binaries 2025-06-04 14:42:04 +02:00
Bogdan-Ștefan Neacşu 88d4a9b111 Set cached storage counters to 0 (#5812)
* Set cached storage counters to 0

* u64 to i64 log possible error

* Check addition too
2025-06-04 12:11:46 +03:00
dependabot[bot] b323c62a6e build(deps): bump tar-fs
Bumps [tar-fs](https://github.com/mafintosh/tar-fs) from 3.0.8 to 3.0.9.
- [Commits](https://github.com/mafintosh/tar-fs/compare/v3.0.8...v3.0.9)

---
updated-dependencies:
- dependency-name: tar-fs
  dependency-version: 3.0.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-03 06:50:43 +00:00
indmind d511aac301 chore: fixed typo in API endpoint parameter 2025-02-11 05:39:00 -06:00
252 changed files with 3679 additions and 10871 deletions
+1 -2
View File
@@ -5,7 +5,6 @@ on:
paths:
- 'clients/**'
- 'common/**'
- 'explorer-api/**'
- 'gateway/**'
- 'integrations/**'
- 'nym-api/**'
@@ -39,7 +38,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ arc-ubuntu-22.04, custom-windows-11, custom-runner-mac-m1 ]
os: [ arc-ubuntu-22.04, custom-windows-11, custom-macos-15 ]
runs-on: ${{ matrix.os }}
env:
CARGO_TERM_COLOR: always
+2 -4
View File
@@ -66,7 +66,6 @@ jobs:
with:
name: my-artifact
path: |
target/release/explorer-api
target/release/nym-client
target/release/nym-socks5-client
target/release/nym-api
@@ -75,14 +74,13 @@ jobs:
target/release/nymvisor
target/release/nym-node
retention-days: 30
- id: create-release
name: Upload to release based on tag name
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
if: github.event_name == 'release'
with:
files: |
target/release/explorer-api
target/release/nym-client
target/release/nym-socks5-client
target/release/nym-api
-1
View File
@@ -40,7 +40,6 @@ validator-config
validator-api-config.toml
dist
storybook-static
envs/qwerty.env
.parcel-cache
**/.DS_Store
cpu-cycles/libcpucycles/build
+24
View File
@@ -4,6 +4,30 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
## [Unreleased]
## [2025.11-cheddar] (2025-06-10)
- No autoremoval of peers ([#5831])
- Set cached storage counters to 0 ([#5812])
- hack: temporarily use next.config.js instead of next.config.ts ([#5805])
- chore: resolve 1.87 clippy warnings ([#5802])
- Nym Statistics API ([#5800])
- QoL: RequestPath trait for http-api-client ([#5788])
- Fix contains ticketbook function that always returned true ([#5787])
- swap a decode into a fromrow to please future postgres feature ([#5785])
- Make address cache configurable ([#5784])
- Track wireguard credential retries ([#5783])
[#5831]: https://github.com/nymtech/nym/pull/5831
[#5812]: https://github.com/nymtech/nym/pull/5812
[#5805]: https://github.com/nymtech/nym/pull/5805
[#5802]: https://github.com/nymtech/nym/pull/5802
[#5800]: https://github.com/nymtech/nym/pull/5800
[#5788]: https://github.com/nymtech/nym/pull/5788
[#5787]: https://github.com/nymtech/nym/pull/5787
[#5785]: https://github.com/nymtech/nym/pull/5785
[#5784]: https://github.com/nymtech/nym/pull/5784
[#5783]: https://github.com/nymtech/nym/pull/5783
## [2025.10-brie] (2025-05-27)
- Backport PR 5779 ([#5801])
Generated
+9 -24
View File
@@ -2550,7 +2550,7 @@ dependencies = [
[[package]]
name = "extension-storage"
version = "1.3.0-rc.0"
version = "1.4.0-rc.0"
dependencies = [
"bip39",
"console_error_panic_hook",
@@ -4795,7 +4795,7 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "nym-api"
version = "1.1.59"
version = "1.1.60"
dependencies = [
"anyhow",
"async-trait",
@@ -5082,24 +5082,9 @@ dependencies = [
"vergen",
]
[[package]]
name = "nym-bity-integration"
version = "0.1.0"
dependencies = [
"anyhow",
"cosmrs",
"eyre",
"k256",
"nym-cli-commands",
"nym-validator-client 0.1.0",
"serde",
"serde_json",
"thiserror 2.0.12",
]
[[package]]
name = "nym-cli"
version = "1.1.56"
version = "1.1.57"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -5181,7 +5166,7 @@ dependencies = [
[[package]]
name = "nym-client"
version = "1.1.56"
version = "1.1.57"
dependencies = [
"bs58",
"clap",
@@ -6423,7 +6408,7 @@ dependencies = [
[[package]]
name = "nym-network-requester"
version = "1.1.57"
version = "1.1.58"
dependencies = [
"addr",
"anyhow",
@@ -6473,7 +6458,7 @@ dependencies = [
[[package]]
name = "nym-node"
version = "1.12.0"
version = "1.13.0"
dependencies = [
"anyhow",
"arc-swap",
@@ -6959,7 +6944,7 @@ dependencies = [
[[package]]
name = "nym-socks5-client"
version = "1.1.56"
version = "1.1.57"
dependencies = [
"bs58",
"clap",
@@ -7224,7 +7209,7 @@ dependencies = [
[[package]]
name = "nym-statistics-api"
version = "0.1.2-dev1"
version = "0.1.3"
dependencies = [
"anyhow",
"axum 0.7.9",
@@ -7694,7 +7679,7 @@ dependencies = [
[[package]]
name = "nymvisor"
version = "0.1.21"
version = "0.1.22"
dependencies = [
"anyhow",
"bytes",
-1
View File
@@ -101,7 +101,6 @@ members = [
"common/wireguard-types",
"documentation/autodoc",
"gateway",
"integrations/bity",
"nym-api",
"nym-api/nym-api-requests",
"nym-browser-extension/storage",
-12
View File
@@ -1,12 +0,0 @@
# Shared assets
This directory contains asset files shared by many projects in this repo.
You will find:
- favicons
- logos
- shared fonts
- shared icon SVGs
See [ts-packages/react-webpack-with-theme-example](../ts-packages/react-webpack-with-theme-example) for examples of usage.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

-10
View File
@@ -1,10 +0,0 @@
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
<stop offset="0.09375" stop-color="#FB6E4E"/>
<stop offset="1" stop-color="#F51473"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 672 B

Binary file not shown.
-6
View File
@@ -1,6 +0,0 @@
@font-face {
font-family: 'Open Sans';
src: url('./OpenSans-VariableFont_wdth,wght.ttf') format('truetype-variations'),
url('./OpenSans-Italic-VariableFont_wdth,wght.ttf') format('truetype-variations');
font-weight: 100 1000;
}
-8
View File
@@ -1,8 +0,0 @@
Update fonts by doing the following:
1. Go to https://fonts.google.com/specimen/Open+Sans
2. Add all the styles you want and select `@import`
3. Copy the url (e.g. curl https://fonts.googleapis.com/css2\?family\=Open+Sans:ital,wght@0,300\;0,400\;0,500\;0,600\;0,700\;0,800\;1,300\;1,400\;1,500\;1,600\;1,700\;1,800\&display\=swap)
4. Run `curl curl https://fonts.googleapis.com/css2\?family\=Open+Sans:ital,wght@0,300\;0,400\;0,500\;0,600\;0,700\;0,800\;1,300\;1,400\;1,500\;1,600\;1,700\;1,800\&display\=swap`
5. Use the response as the CSS import directives and download the font files for each font weight
6. Remember to delete any old font files
-96
View File
@@ -1,96 +0,0 @@
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 300;
font-stretch: normal;
font-display: swap;
src: url(./memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk5hkaVc.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
font-stretch: normal;
font-display: swap;
src: url(./memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk8ZkaVc.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 500;
font-stretch: normal;
font-display: swap;
src: url(./memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk_RkaVc.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 600;
font-stretch: normal;
font-display: swap;
src: url(./memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkxhjaVc.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
font-stretch: normal;
font-display: swap;
src: url(./memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0RkyFjaVc.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 800;
font-stretch: normal;
font-display: swap;
src: url(./memQYaGs126MiZpBA-UFUIcVXSCEkx2cmqvXlWq8tWZ0Pw86hd0Rk0ZjaVc.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 300;
font-stretch: normal;
font-display: swap;
src: url(./memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0C4n.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
font-stretch: normal;
font-display: swap;
src: url(./memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0C4n.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 500;
font-stretch: normal;
font-display: swap;
src: url(./memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjr0C4n.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 600;
font-stretch: normal;
font-display: swap;
src: url(./memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsgH1y4n.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
font-stretch: normal;
font-display: swap;
src: url(./memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsg-1y4n.ttf) format('truetype');
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 800;
font-stretch: normal;
font-display: swap;
src: url(./memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgshZ1y4n.ttf) format('truetype');
}
-53
View File
@@ -1,53 +0,0 @@
<svg
width="100%"
height="100%"
viewBox="0 0 80 80"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0_421_13045)">
<path
d="M40 80C62.0914 80 80 62.0914 80 40C80 17.9086 62.0914 0 40 0C17.9086 0 0 17.9086 0 40C0 62.0914 17.9086 80 40 80Z"
fill="black"
/>
<path
d="M40 77.2636C60.5801 77.2636 77.2636 60.5801 77.2636 40C77.2636 19.4199 60.5801 2.73645 40 2.73645C19.4199 2.73645 2.73645 19.4199 2.73645 40C2.73645 60.5801 19.4199 77.2636 40 77.2636Z"
fill="white"
/>
<path
d="M24.0224 32.471H23.9776V32.5084V45.5775L18.4673 32.4934L18.4598 32.471H18.4299H15.3047H11.7981H11.7607V32.5084V47.4916V47.529H11.7981H15.3047H15.3421V47.4916V34.4L20.8748 47.5065L20.8822 47.529H20.9121H24.0224H27.5215H27.5589V47.4916V32.5084V32.471H27.5215H24.0224Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M23.8965 32.39H27.64V47.6101H20.8238L20.7989 47.5352L15.4232 34.8006V47.6101H11.6797V32.39H18.5183L18.5432 32.4649L23.8965 45.1761V32.39ZM23.9776 45.5776L18.4673 32.4935L18.4598 32.471H11.7608V47.529H15.3421V34.4L20.8748 47.5065L20.8823 47.529H27.5589V32.471H23.9776V45.5776Z"
fill="black"
/>
<path
d="M68.2019 32.471H61.5178H61.4804L61.4729 32.5009L58.0486 45.6374L54.6169 32.5009L54.6094 32.471H54.5795H47.8804H47.8355V32.5084V47.4916V47.529H47.8804H51.3795H51.4169V47.4916V34.5047L54.8038 47.499L54.8112 47.529H54.8486H61.2337H61.2636L61.2711 47.499L64.658 34.5047V47.4916V47.529H64.6954H68.2019H68.2393V47.4916V32.5084V32.471H68.2019Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M61.4171 32.39H68.3204V47.6101H64.5769V35.1372L61.3497 47.5187L61.3495 47.5195L61.3269 47.6101H54.7479L54.7253 47.5195L54.7251 47.5187L51.4979 35.1372V47.6101H47.7545V32.39H54.6727L54.6953 32.4804L54.6955 32.4813L58.0485 45.3163L61.3943 32.4813L61.3945 32.4805L61.4171 32.39ZM58.0486 45.6374L54.6168 32.5009L54.6094 32.471H47.8355V47.529H51.4168V34.5047L54.8038 47.4991L54.8112 47.529H61.2636L61.2711 47.4991L64.658 34.5047V47.529H68.2393V32.471H61.4804L61.4729 32.5009L58.0486 45.6374Z"
fill="black"
/>
<path
d="M42.0711 32.471H42.0486L42.0412 32.486L37.7869 39.8804L33.5103 32.486L33.5028 32.471H33.4804H29.4355H29.3608L29.3982 32.5308L35.9851 43.9402V47.4916V47.529H36.0225H39.529H39.5664V47.4916V43.9402L46.1533 32.5308L46.1907 32.471H46.1159H42.0711Z"
fill="black"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M41.9985 32.39H46.337L46.2228 32.5726L39.6475 43.9619V47.6101H35.904V43.9619L29.3286 32.5726L29.2145 32.39H33.5529L33.5817 32.4475L37.7868 39.7181L41.9697 32.4476L41.9985 32.39ZM42.0411 32.486L37.7869 39.8804L33.5103 32.486L33.5028 32.471H29.3608L29.3981 32.5308L35.9851 43.9402V47.529H39.5664V43.9402L46.1533 32.5308L46.1907 32.471H42.0486L42.0411 32.486Z"
fill="black"
/>
</g>
<defs>
<clipPath id="clip0_421_13045">
<rect width="80" height="80" fill="white" />
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.0 KiB

-10
View File
@@ -1,10 +0,0 @@
<svg width="64" height="64" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M40 78.5C61.263 78.5 78.5 61.263 78.5 40C78.5 18.737 61.263 1.5 40 1.5C18.737 1.5 1.5 18.737 1.5 40C1.5 61.263 18.737 78.5 40 78.5Z" fill="#070B15" stroke="url(#paint0_linear_0_1)" stroke-width="3"/>
<path d="M31.4894 27.56L41.8623 56H48.5106H56V24H48.5106V52.4L38.1777 24H31.4894H24V56H31.4894V27.56Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_0_1" x1="0.839161" y1="80" x2="80" y2="80" gradientUnits="userSpaceOnUse">
<stop offset="0.09375" stop-color="#FB6E4E"/>
<stop offset="1" stop-color="#F51473"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 714 B

-13
View File
@@ -1,13 +0,0 @@
<svg width="300" height="300" viewBox="0 0 296 296" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M148 296C229.738 296 296 229.738 296 148C296 66.2619 229.738 0 148 0C66.2619 0 0 66.2619 0 148C0 229.738 66.2619 296 148 296Z" fill="url(#paint0_linear_113_1244)"/>
<path d="M148 285.875C224.147 285.875 285.875 224.146 285.875 148C285.875 71.8536 224.147 10.1248 148 10.1248C71.8538 10.1248 10.125 71.8536 10.125 148C10.125 224.146 71.8538 285.875 148 285.875Z" fill="#121725"/>
<path d="M88.8829 120.143H88.7169V120.281V168.637L68.3289 120.226L68.3012 120.143H68.1905H56.6272H43.653H43.5146V120.281V175.719V175.857H43.653H56.6272H56.7655V175.719V127.28L77.2365 175.774L77.2642 175.857H77.3748H88.8829H101.829H101.968V175.719V120.281V120.143H101.829H88.8829Z" fill="white"/>
<path d="M252.347 120.143H227.616H227.477L227.45 120.253L214.78 168.858L202.082 120.253L202.054 120.143H201.944H177.157H176.991V120.281V175.719V175.857H177.157H190.104H190.242V175.719V127.667L202.774 175.747L202.801 175.857H202.94H226.564H226.675L226.703 175.747L239.234 127.667V175.719V175.857H239.373H252.347H252.485V175.719V120.281V120.143H252.347Z" fill="white"/>
<path d="M155.663 120.143H155.58L155.552 120.198L139.812 147.557L123.988 120.198L123.96 120.143H123.877H108.911H108.635L108.773 120.364L133.145 162.579V175.719V175.857H133.283H146.257H146.396V175.719V162.579L170.767 120.364L170.905 120.143H170.629H155.663Z" fill="white"/>
<defs>
<linearGradient id="paint0_linear_113_1244" x1="0" y1="148" x2="296" y2="148" gradientUnits="userSpaceOnUse">
<stop offset="0.09375" stop-color="#FB6E4E"/>
<stop offset="1" stop-color="#FC1D60"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg viewBox="0 0 210 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M45.8829 0.142822H45.7169V0.28114V48.637L25.3289 0.225818L25.3012 0.142822H25.1905H13.6272H0.652966H0.514648V0.28114V55.7189V55.8572H0.652966H13.6272H13.7655V55.7189V7.28002L34.2365 55.7742L34.2642 55.8572H34.3748H45.8829H58.8294H58.9677V55.7189V0.28114V0.142822H58.8294H45.8829Z"/>
<path d="M209.347 0.142822H184.616H184.477L184.45 0.253483L171.78 48.8583L159.082 0.253483L159.054 0.142822H158.944H134.157H133.991V0.28114V55.7189V55.8572H134.157H147.104H147.242V55.7189V7.66731L159.774 55.7466L159.801 55.8572H159.94H183.564H183.675L183.703 55.7466L196.234 7.66731V55.7189V55.8572H196.373H209.347H209.485V55.7189V0.28114V0.142822H209.347Z"/>
<path d="M112.663 0.142822H112.58L112.552 0.198153L96.8116 27.5574L80.988 0.198153L80.9604 0.142822H80.8774H65.9114H65.6348L65.7731 0.364136L90.1447 42.5787V55.7189V55.8572H90.283H103.257H103.396V55.7189V42.5787L127.767 0.364136L127.905 0.142822H127.629H112.663Z"/>
</svg>

Before

Width:  |  Height:  |  Size: 1011 B

-7
View File
@@ -1,7 +0,0 @@
<svg viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M171.7,30.3001 C132.7,-8.7999 69.3001,-8.7999 30.3001,30.3001 C-8.7999,69.4001 -8.7999,132.7 30.3001,171.7 C69.4001,210.8 132.7,210.8 171.7,171.7 C210.8,132.7 210.8,69.3001 171.7,30.3001 Z M163.1,163.1 C128.8,197.4 73.1001,197.4 38.8001,163.1 C4.5001,128.8 4.5001,73.1001 38.8001,38.8001 C73.1001,4.5001 128.8,4.5001 163.1,38.8001 C197.5,73.2001 197.5,128.8 163.1,163.1 Z" id="Shape" fill="#fff"></path>
<path d="M163.1,38.9 C128.8,4.60005 73.1002,4.60005 38.8002,38.9 C4.50019,73.2 4.50019,128.9 38.8002,163.2 C73.1002,197.5 128.8,197.5 163.1,163.2 C197.5,128.8 197.5,73.2 163.1,38.9 Z" id="Shape" fill="#000"></path>
<g id="T" transform="translate(25, 25) scale(5,5)">
<path d="M18.4804688,24 C19.203125,24 19.7182617,23.8608398 20.0258789,23.5825195 C20.3334961,23.3041992 20.4873047,22.9453125 20.4873047,22.5058594 C20.4873047,22.0566406 20.3334961,21.6928711 20.0258789,21.4145508 C19.7182617,21.1362305 19.203125,20.9970703 18.4804688,20.9970703 L18.4804688,20.9970703 L16.4589844,20.9970703 L16.4589844,9.24902344 L19.7548828,9.24902344 L19.7548828,12.0908203 C19.7548828,12.8134766 19.894043,13.3286133 20.1723633,13.6362305 C20.4506836,13.9438477 20.8095703,14.0976562 21.2490234,14.0976562 C21.6982422,14.0976562 22.0620117,13.9438477 22.340332,13.6362305 C22.6186523,13.3286133 22.7578125,12.8134766 22.7578125,12.0908203 L22.7578125,12.0908203 L22.7578125,6.24609375 L7.20117188,6.23144531 L7.20117188,12.0908203 C7.20117188,12.8134766 7.34033203,13.3286133 7.61865234,13.6362305 C7.89697266,13.9438477 8.25585938,14.0976562 8.6953125,14.0976562 C9.14453125,14.0976562 9.50830078,13.9438477 9.78662109,13.6362305 C10.0649414,13.3286133 10.2041016,12.8134766 10.2041016,12.0908203 L10.2041016,12.0908203 L10.2041016,9.24902344 L13.4560547,9.24902344 L13.4560547,20.9970703 L11.4492188,20.9970703 C10.7265625,20.9970703 10.2114258,21.1362305 9.90380859,21.4145508 C9.59619141,21.6928711 9.44238281,22.0517578 9.44238281,22.4912109 C9.44238281,22.9404297 9.59619141,23.3041992 9.90380859,23.5825195 C10.2114258,23.8608398 10.7265625,24 11.4492188,24 L11.4492188,24 L18.4804688,24 Z" id="T" fill="#fff"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="white"/>
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="#070B15"/>
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

-7
View File
@@ -1,7 +0,0 @@
<svg viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M171.7,30.3001 C132.7,-8.7999 69.3001,-8.7999 30.3001,30.3001 C-8.7999,69.4001 -8.7999,132.7 30.3001,171.7 C69.4001,210.8 132.7,210.8 171.7,171.7 C210.8,132.7 210.8,69.3001 171.7,30.3001 Z M163.1,163.1 C128.8,197.4 73.1001,197.4 38.8001,163.1 C4.5001,128.8 4.5001,73.1001 38.8001,38.8001 C73.1001,4.5001 128.8,4.5001 163.1,38.8001 C197.5,73.2001 197.5,128.8 163.1,163.1 Z" id="Shape" fill="#141521"></path>
<path d="M163.1,38.9 C128.8,4.60005 73.1002,4.60005 38.8002,38.9 C4.50019,73.2 4.50019,128.9 38.8002,163.2 C73.1002,197.5 128.8,197.5 163.1,163.2 C197.5,128.8 197.5,73.2 163.1,38.9 Z" id="Shape" fill="#FFFFFF"></path>
<g id="T" transform="translate(25, 25) scale(5,5)">
<path d="M18.4804688,24 C19.203125,24 19.7182617,23.8608398 20.0258789,23.5825195 C20.3334961,23.3041992 20.4873047,22.9453125 20.4873047,22.5058594 C20.4873047,22.0566406 20.3334961,21.6928711 20.0258789,21.4145508 C19.7182617,21.1362305 19.203125,20.9970703 18.4804688,20.9970703 L18.4804688,20.9970703 L16.4589844,20.9970703 L16.4589844,9.24902344 L19.7548828,9.24902344 L19.7548828,12.0908203 C19.7548828,12.8134766 19.894043,13.3286133 20.1723633,13.6362305 C20.4506836,13.9438477 20.8095703,14.0976562 21.2490234,14.0976562 C21.6982422,14.0976562 22.0620117,13.9438477 22.340332,13.6362305 C22.6186523,13.3286133 22.7578125,12.8134766 22.7578125,12.0908203 L22.7578125,12.0908203 L22.7578125,6.24609375 L7.20117188,6.23144531 L7.20117188,12.0908203 C7.20117188,12.8134766 7.34033203,13.3286133 7.61865234,13.6362305 C7.89697266,13.9438477 8.25585938,14.0976562 8.6953125,14.0976562 C9.14453125,14.0976562 9.50830078,13.9438477 9.78662109,13.6362305 C10.0649414,13.3286133 10.2041016,12.8134766 10.2041016,12.0908203 L10.2041016,12.0908203 L10.2041016,9.24902344 L13.4560547,9.24902344 L13.4560547,20.9970703 L11.4492188,20.9970703 C10.7265625,20.9970703 10.2114258,21.1362305 9.90380859,21.4145508 C9.59619141,21.6928711 9.44238281,22.0517578 9.44238281,22.4912109 C9.44238281,22.9404297 9.59619141,23.3041992 9.90380859,23.5825195 C10.2114258,23.8608398 10.7265625,24 11.4492188,24 L11.4492188,24 L18.4804688,24 Z" id="T" fill="#000" fill-rule="nonzero"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

-5
View File
@@ -1,5 +0,0 @@
<svg viewBox="0 0 200 200" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M170.7 29.3001C131.7 -9.7999 68.3001 -9.7999 29.3001 29.3001C-9.7999 68.4001 -9.7999 131.7 29.3001 170.7C68.4001 209.8 131.7 209.8 170.7 170.7C209.8 131.7 209.8 68.3001 170.7 29.3001ZM162.1 162.1C127.8 196.4 72.1001 196.4 37.8001 162.1C3.5001 127.8 3.5001 72.1001 37.8001 37.8001C72.1001 3.5001 127.8 3.5001 162.1 37.8001C196.5 72.2001 196.5 127.8 162.1 162.1Z" fill="#141521"/>
<path d="M162.1 37.9C127.8 3.60005 72.1002 3.60005 37.8002 37.9C3.50019 72.2 3.50019 127.9 37.8002 162.2C72.1002 196.5 127.8 196.5 162.1 162.2C196.5 127.8 196.5 72.2 162.1 37.9ZM63.0002 170.7C56.8002 167.4 51.1002 163.2 46.1002 158.4V41.7C51.3002 36.7 57.2002 32.5 63.6002 29.1L137 140.9V29.3C143.2 32.6 148.9 36.8 153.9 41.6V158.3C148.7 163.3 142.8 167.5 136.4 170.9L63.0002 59.1V170.7Z" fill="white"/>
<path d="M154 158.3V41.7C148.9 36.9 143.2 32.7 137.1 29.4V140.9L63.5 29C57.1 32.4 51.2 36.6 46 41.6V158.3C51.1 163.1 56.8 167.3 62.9 170.6V59.1L136.5 171C142.9 167.6 148.8 163.3 154 158.3Z" fill="#141521"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-client"
version = "1.1.56"
version = "1.1.57"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
description = "Implementation of the Nym Client"
edition = "2021"
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "nym-socks5-client"
version = "1.1.56"
version = "1.1.57"
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
description = "A SOCKS5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address"
edition = "2021"
@@ -16,8 +16,8 @@ async fn main() {
let prefix = "n";
let denom: Denom = "unym".parse().unwrap();
let signer_mnemonic: bip39::Mnemonic = "<MNEMONIC WITH FUNDS HERE>".parse().unwrap();
let validator = "https://qwerty-validator.qa.nymte.ch";
let to_address: AccountId = "n19kdst4srf76xgwe55jg32mpcpcyf6aqgp6qrdk".parse().unwrap();
let validator = "https://rpc.sandbox.nymtech.net";
let to_address: AccountId = "n1pefc2utwpy5w78p2kqdsfmpjxfwmn9d39k5mqa".parse().unwrap();
let signer = DirectSecp256k1HdWallet::from_mnemonic(prefix, signer_mnemonic);
let signer_address = signer.try_derive_accounts().unwrap()[0].address().clone();
@@ -60,7 +60,7 @@ pub async fn send(args: Args, client: &SigningClient) {
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.hash
);
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
println!("Mintscan: https://ping.pub/nyx/tx/{}", &res.hash);
println!("Transaction result code: {}", &res.tx_result.code.value());
println!("Transaction hash: {}", &res.hash);
}
@@ -95,7 +95,7 @@ pub async fn send_multiple(args: Args, client: &SigningClient) {
"Nodesguru: https://nym.explorers.guru/transaction/{}",
&res.hash
);
println!("Mintscan: https://www.mintscan.io/nyx/txs/{}", &res.hash);
println!("Mintscan: https://ping.pub/nyx/tx/{}", &res.hash);
println!("Transaction result code: {}", &res.tx_result.code.value());
println!("Transaction hash: {}", &res.hash);
@@ -76,7 +76,7 @@ pub async fn execute(args: Args, client: SigningClient) {
&res.transaction_hash
);
println!(
"Mintscan: https://www.mintscan.io/nyx/txs/{}",
"Mintscan: https://ping.pub/nyx/tx/{}",
&res.transaction_hash
);
println!("Transaction hash: {}", &res.transaction_hash);
@@ -40,6 +40,10 @@ impl BandwidthStorageManager {
}
}
pub fn client_bandwidth(&self) -> ClientBandwidth {
self.client_bandwidth.clone()
}
pub async fn available_bandwidth(&self) -> i64 {
self.client_bandwidth.available().await
}
@@ -73,7 +73,7 @@ impl ClientBandwidth {
false
}
pub(crate) async fn available(&self) -> i64 {
pub async fn available(&self) -> i64 {
self.inner.read().await.bandwidth.bytes
}
+20
View File
@@ -45,6 +45,10 @@ pub enum PeerControlRequest {
key: Key,
response_tx: oneshot::Sender<QueryBandwidthControlResponse>,
},
GetClientBandwidth {
key: Key,
response_tx: oneshot::Sender<GetClientBandwidthControlResponse>,
},
}
pub struct AddPeerControlResponse {
@@ -65,6 +69,10 @@ pub struct QueryBandwidthControlResponse {
pub bandwidth_data: Option<RemainingBandwidthData>,
}
pub struct GetClientBandwidthControlResponse {
pub client_bandwidth: Option<ClientBandwidth>,
}
pub struct PeerController {
storage: GatewayStorage,
@@ -267,6 +275,14 @@ impl PeerController {
}))
}
async fn handle_get_client_bandwidth(&self, key: &Key) -> Option<ClientBandwidth> {
if let Some(Some(bandwidth_storage_manager)) = self.bw_storage_managers.get(key) {
Some(bandwidth_storage_manager.read().await.client_bandwidth())
} else {
None
}
}
async fn update_metrics(&self, new_host: &Host) {
let now = SystemTime::now();
const ACTIVITY_THRESHOLD: Duration = Duration::from_secs(180);
@@ -388,6 +404,10 @@ impl PeerController {
response_tx.send(QueryBandwidthControlResponse { success: false, bandwidth_data: None }).ok();
}
}
Some(PeerControlRequest::GetClientBandwidth { key, response_tx }) => {
let client_bandwidth = self.handle_get_client_bandwidth(&key).await;
response_tx.send(GetClientBandwidthControlResponse { client_bandwidth }).ok();
}
None => {
log::trace!("PeerController [main loop]: stopping since channel closed");
break;
+46 -40
View File
@@ -13,12 +13,10 @@ use nym_gateway_storage::models::WireguardPeer;
use nym_task::TaskClient;
use nym_wireguard_types::DEFAULT_PEER_TIMEOUT_CHECK;
use std::sync::Arc;
use std::time::{Duration, SystemTime};
use tokio::sync::{mpsc, RwLock};
use tokio_stream::{wrappers::IntervalStream, StreamExt};
pub(crate) type SharedBandwidthStorageManager = Arc<RwLock<BandwidthStorageManager>>;
const AUTO_REMOVE_AFTER: Duration = Duration::from_secs(60 * 60); // 1 hour
pub struct PeerHandle {
public_key: Key,
@@ -28,7 +26,6 @@ pub struct PeerHandle {
request_tx: mpsc::Sender<PeerControlRequest>,
timeout_check_interval: IntervalStream,
task_client: TaskClient,
startup_timestamp: SystemTime,
}
impl PeerHandle {
@@ -53,7 +50,6 @@ impl PeerHandle {
request_tx,
timeout_check_interval,
task_client,
startup_timestamp: SystemTime::now(),
}
}
@@ -73,26 +69,49 @@ impl PeerHandle {
Ok(success)
}
async fn active_peer(
&mut self,
storage_peer: &WireguardPeer,
kernel_peer: &Peer,
) -> Result<bool, Error> {
if let Some(bandwidth_manager) = &self.bandwidth_storage_manager {
if kernel_peer.last_handshake.is_none()
&& SystemTime::now().duration_since(self.startup_timestamp)? >= AUTO_REMOVE_AFTER
{
let success = self.remove_peer().await?;
self.peer_storage_manager.remove_peer();
tracing::debug!(
"Peer {} has not been active for more then {} seconds, removing it",
kernel_peer.public_key.to_string(),
AUTO_REMOVE_AFTER.as_secs()
fn compute_spent_bandwidth(kernel_peer: &Peer, storage_peer: &WireguardPeer) -> Option<u64> {
let storage_peer_rx_bytes = u64::try_from(storage_peer.rx_bytes)
.inspect_err(|e| tracing::error!("Storage rx bytes could not be converted: {e}"))
.ok()?;
let storage_peer_tx_bytes = u64::try_from(storage_peer.tx_bytes)
.inspect_err(|e| tracing::error!("Storage tx bytes could not be converted: {e}"))
.ok()?;
let kernel_total = kernel_peer
.rx_bytes
.checked_add(kernel_peer.tx_bytes)
.or_else(|| {
tracing::error!(
"Overflow on kernel adding bytes: {} + {}",
kernel_peer.rx_bytes,
kernel_peer.tx_bytes
);
return Ok(!success);
}
let spent_bandwidth = (kernel_peer.rx_bytes + kernel_peer.tx_bytes)
.checked_sub(storage_peer.rx_bytes as u64 + storage_peer.tx_bytes as u64)
None
})?;
let storage_total = storage_peer_rx_bytes
.checked_add(storage_peer_tx_bytes)
.or_else(|| {
tracing::error!("Overflow on storage adding bytes: {storage_peer_rx_bytes} + {storage_peer_tx_bytes}");
None
})?;
kernel_total.checked_sub(storage_total).or_else(|| {
tracing::error!("Overflow on spent bandwidth subtraction: kernel - storage = {kernel_total} - {storage_total}");
None
})
}
async fn active_peer(&mut self, kernel_peer: &Peer) -> Result<bool, Error> {
let Some(storage_peer) = self.peer_storage_manager.get_peer() else {
log::debug!(
"Peer {:?} not in storage anymore, shutting down handle",
self.public_key
);
return Ok(false);
};
if let Some(bandwidth_manager) = &self.bandwidth_storage_manager {
let spent_bandwidth = Self::compute_spent_bandwidth(kernel_peer, &storage_peer)
.unwrap_or_else(|| {
// if gateway restarted, the kernel values restart from 0
// and we should restart from 0 in storage as well
@@ -100,8 +119,10 @@ impl PeerHandle {
self.peer_storage_manager.peer_information.as_mut()
{
peer_information.force_sync = true;
peer_information.peer.rx_bytes = kernel_peer.rx_bytes;
peer_information.peer.tx_bytes = kernel_peer.tx_bytes;
}
kernel_peer.rx_bytes + kernel_peer.tx_bytes
0
})
.try_into()
.map_err(|_| Error::InconsistentConsumedBytes)?;
@@ -124,14 +145,6 @@ impl PeerHandle {
}
}
} else {
if SystemTime::now().duration_since(self.startup_timestamp)? >= AUTO_REMOVE_AFTER {
log::debug!(
"Peer {} has been present for 30 days, removing it",
self.public_key
);
let success = self.remove_peer().await?;
return Ok(!success);
}
let spent_bandwidth = kernel_peer.rx_bytes + kernel_peer.tx_bytes;
if spent_bandwidth >= BANDWIDTH_CAP_PER_DAY {
log::debug!(
@@ -158,14 +171,7 @@ impl PeerHandle {
// the host information hasn't beed updated yet
return Ok(true);
};
let Some(storage_peer) = self.peer_storage_manager.get_peer() else {
log::debug!(
"Peer {:?} not in storage anymore, shutting down handle",
self.public_key
);
return Ok(false);
};
if !self.active_peer(&storage_peer, &kernel_peer).await? {
if !self.active_peer(&kernel_peer).await? {
log::debug!(
"Peer {:?} is not active anymore, shutting down handle",
self.public_key
-136
View File
@@ -1,136 +0,0 @@
version: "3.7"
x-network: &NETWORK
BECH32_PREFIX: nymt
DENOM: nymt
STAKE_DENOM: nyxt
WASMD_VERSION: v0.27.0
services:
genesis_validator:
build:
context: docker/validator
args: *NETWORK
image: validator:latest
ports:
- "26657:26657"
- "1317:1317"
container_name: genesis_validator
volumes:
- "genesis_volume:/genesis_volume"
- "genesis_nyxd:/root/.nyxd"
environment: *NETWORK
networks:
localnet:
ipv4_address: 172.168.10.2
command: ["genesis"]
secondary_validator:
build:
context: docker/validator
args: *NETWORK
image: validator:latest
ports:
- "36657:26657"
- "2317:1317"
volumes:
- "genesis_volume:/genesis_volume"
- "secondary_nyxd:/root/.nyxd"
environment: *NETWORK
networks:
localnet:
ipv4_address: 172.168.10.3
depends_on:
- "genesis_validator"
command: ["secondary"]
# mixnet_contract:
# build: docker/mixnet_contract
# image: contract:latest
# volumes:
# - ".:/nym"
# vesting_contract:
# build: docker/vesting_contract
# image: vesting_contract:latest
# volumes:
# - ".:/nym"
# contract_uploader:
# build: docker/typescript_client
# image: contract_uploader:typescript
# volumes:
# - "genesis_volume:/genesis_volume:ro"
# - "contract_volume:/contract_volume"
# - ".:/nym"
# depends_on:
# - "genesis_validator"
# - "secondary_validator"
# - "mixnet_contract"
# environment:
# BECH32_PREFIX: *BECH32_PREFIX
mnemonic_echo:
build: docker/mnemonic_echo
image: mnemonic_echo:latest
volumes:
- "genesis_volume:/genesis_volume:ro"
depends_on:
- "genesis_validator"
- "secondary_validator"
# mongo:
# image: mongo:latest
# command:
# - --storageEngine=wiredTiger
# volumes:
# - mongo_data:/data/db
# block_explorer:
# build:
# context: https://github.com/forbole/big-dipper.git#v0.41.x-7
# image: block_explorer:v0.41.x-7
# ports:
# - "3080:3000"
# depends_on:
# - "mongo"
# environment:
# ROOT_URL: ${APP_ROOT_URL:-http://localhost}
# MONGO_URL: mongodb://mongo:27017/meteor
# PORT: 3000
# METEOR_SETTINGS: ${METEOR_SETTINGS}
# explorer:
# build:
# context: docker/explorer
# image: explorer:latest
# ports:
# - "3040:3000"
# depends_on:
# - "genesis_validator"
# - "block_explorer"
# service to update geoip binary database, for explorer-api
geoipupdate:
container_name: geoipupdate
image: maxmindinc/geoipupdate
restart: unless-stopped
environment:
GEOIPUPDATE_ACCOUNT_ID: ${GEOIPUPDATE_ACCOUNT_ID}
GEOIPUPDATE_LICENSE_KEY: ${GEOIPUPDATE_LICENSE_KEY}
GEOIPUPDATE_EDITION_IDS: ${GEOIPUPDATE_EDITION_IDS}
GEOIPUPDATE_FREQUENCY: ${GEOIPUPDATE_FREQUENCY}
networks:
- geoipupdate
volumes:
- ${GEOIP_DB_DIRECTORY}:/usr/share/GeoIP
volumes:
genesis_volume:
genesis_nyxd:
secondary_nyxd:
# contract_volume:
# mongo_data:
networks:
geoipupdate:
localnet:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.168.10.0/25
@@ -13,10 +13,6 @@ Stake saturation is a node reputation done in a form of self bond or stakers del
> **rewarded_set_size = active_set_size + standby_set_size**
</Callout>
{/*
With current circulating supply of <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM, staking target of <span style={{display: 'inline-block'}}><StakingTarget /></span> NYM, divided by the sum of nodes in the [rewarded set](https://validator.nymtech.net/api/v1/epoch/reward_params), <b>the stake saturation level is <span style={{display: 'inline-block'}}><StakeSaturation /></span> NYM per node.</b>
*/}
With current circulating supply of <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM, staking target of <span style={{display: 'inline-block'}}><StakingSupply /></span> NYM, divided by the sum of nodes in the [rewarded set](https://validator.nymtech.net/api/v1/epoch/reward_params), <b>the stake saturation level is <span style={{display: 'inline-block'}}><StakeSaturation /></span> NYM per node.</b>
Node stake saturation is a value between `0` and `1` following this logic.
@@ -5,7 +5,7 @@
},
"mixmining_reserve": {
"denom": "unym",
"amount": "188691142067690"
"amount": "187227500568584"
},
"vesting_tokens": {
"denom": "unym",
@@ -13,6 +13,6 @@
},
"circulating_supply": {
"denom": "unym",
"amount": "811308857932310"
"amount": "812772499431416"
}
}
@@ -1 +1 @@
811_308_857
812_772_499
@@ -1 +1 @@
1_034_081
1_037_131
@@ -1 +1 @@
405_654_428
248_911_577
@@ -1 +1 @@
248_179_643
248_911_577
@@ -1,7 +1,7 @@
| **Item** | **Description** | **Amount in NYM** |
|:-------------------|:------------------------------------------------------|--------------------:|
| Total Supply | Maximum amount of NYM token in existence | 1_000_000_000 |
| Mixmining Reserve | Tokens releasing for operators rewards | 188_691_142 |
| Mixmining Reserve | Tokens releasing for operators rewards | 187_227_500 |
| Vesting Tokens | Tokens locked outside of cicrulation for future claim | 0 |
| Circulating Supply | Amount of unlocked tokens | 811_308_857 |
| Stake Saturation | Optimal size of node self-bond + delegation | 1_034_081 |
| Circulating Supply | Amount of unlocked tokens | 812_772_499 |
| Stake Saturation | Optimal size of node self-bond + delegation | 1_037_131 |
@@ -1,10 +1,10 @@
{
"interval": {
"reward_pool": "188691142067690.265566584946684804",
"staking_supply": "248179643769563.241524591796100959",
"staking_supply_scale_factor": "0.5",
"epoch_reward_budget": "5241420612.991396265738470741",
"stake_saturation_point": "1034081849039.84683968579915042",
"reward_pool": "187227500568584.066152911712126276",
"staking_supply": "248911577950871.129740670788161327",
"staking_supply_scale_factor": "0.30625",
"epoch_reward_budget": "5200763904.682890726469769781",
"stake_saturation_point": "1037131574795.296373919461617338",
"sybil_resistance": "0.3",
"active_set_work_factor": "10",
"interval_pool_emission": "0.02"
@@ -1 +1 @@
Wednesday, May 28th 2025, 11:39:51 UTC
Friday, June 6th 2025, 09:33:10 UTC
+1 -1
View File
@@ -45,7 +45,7 @@
"chain-registry": "^1.19.0",
"cosmjs-types": "^0.9.0",
"lucide-react": "^0.438.0",
"next": "^14.2.15",
"next": "^15.2.4",
"nextra": "2",
"nextra-theme-docs": "2",
"react": "^18.2.0",
@@ -104,6 +104,7 @@ To get a full comprehension of [node operators rewards](tokenomics/mixnet-reward
```
#### Supply
<br />
<b>Circulating supply is <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM.</b>
@@ -118,15 +119,10 @@ A number of aimed NYM tokens to be staked in the network. The staking target a i
> **staking_target = staking_supply_scale_factor \* circulating_supply**
</Callout>
{/*
Staking supply scale factor is currently it's set to be <span style={{display: 'inline-block'}}><StakingScaleFactor /></span>.
Staking supply scale factor is currently at <span style={{display: 'inline-block'}}><StakingScaleFactor /></span>.
The value of this variable can is changed from time to time to optimize the metrics of the network. With a current circulating supply of <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM and staking supply scale factor <span style={{display: 'inline-block'}}><StakingScaleFactor /></span>, <b>the staking target is <span style={{display: 'inline-block'}}><StakingTarget /></span> NYM.</b>
*/}
Staking supply scale factor is currently at 30.5%.
The value of this variable is changed from time to time to optimize the metrics of the network. With a current circulating supply of <span style={{display: 'inline-block'}}><CirculatingSupply /></span> NYM and staking supply scale factor 30.5%, <b>the staking target is <span style={{display: 'inline-block'}}><StakingSupply /></span> NYM.</b>
#### Stake saturation
+1631 -500
View File
File diff suppressed because it is too large Load Diff
@@ -140,6 +140,7 @@ def get_nested_value(response, args):
def _return_percent_annotation(value):
value = float(value) * 100
value = round(value, 2)
value = f"{value}%"
return value
@@ -269,7 +270,7 @@ def parser_main():
action="store_true",
help="A multiplier of staking supply scale factor and circulating supply"
)
parser_calculate.add_argument(
"-s", "--separator",
type=str,
-25
View File
@@ -1,25 +0,0 @@
CONFIGURED=true
RUST_LOG=info
RUST_BACKTRACE=1
NETWORK_NAME=qa
BECH32_PREFIX=n
MIX_DENOM=unym
MIX_DENOM_DISPLAY=nym
STAKE_DENOM=unyx
STAKE_DENOM_DISPLAY=nyx
DENOMS_EXPONENT=6
MIXNET_CONTRACT_ADDRESS=n1hm4y6fzgxgu688jgf7ek66px6xkrtmn3gyk8fax3eawhp68c2d5qujz296
ECASH_CONTRACT_ADDRESS=n13xspq62y9gq6nueqmywxcdv2yep4p6nzv98w2889k25v3nhdy2dq2rkrk7
GROUP_CONTRACT_ADDRESS=n13l7rwuwktklrwskc7m6lv70zws07en85uma28j7dxwsz9y5hvvhspl7a2t
MULTISIG_CONTRACT_ADDRESS=n138c9pyf7f3hyx0j3t6vmsz7ultnw2wj0lu6hzndep9z5grgq9haqlc25k0
COCONUT_DKG_CONTRACT_ADDRESS=n1pk8jgr6y4c5k93gz7qf3xc0hvygmp7csk88c2tf8l39tkq6834wq2a6dtr
VESTING_CONTRACT_ADDRESS=n1jlzdxnyces4hrhqz68dqk28mrw5jgwtcfq0c2funcwrmw0dx9l9s8nnnvj
REWARDING_VALIDATOR_ADDRESS=n1rfvpsynktze6wvn6ldskj8xgwfzzk5v6pnff39
EXPLORER_API=https://qa-network-explorer.qa.nymte.ch/api/
NYXD=https://rpc.qa-validator.qa.nymte.ch
NYXD_WS=wss://rpc.qa-validator.qa.nymte.ch/websocket
NYM_API=https://qa-nym-api.qa.nymte.ch/api/
NYM_VPN_API=https://nym-vpn-api-git-deploy-qa-nyx-network-staging.vercel.app/api/
-21
View File
@@ -1,21 +0,0 @@
[package]
name = "nym-bity-integration"
version = "0.1.0"
edition = "2021"
rust-version = "1.56"
license.workspace = true
[dependencies]
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
k256 = { workspace = true, features = ["ecdsa", "sha256"] }
eyre = { workspace = true }
cosmrs = { workspace = true }
nym-cli-commands = { path = "../../common/commands" }
nym-validator-client = { path = "../../common/client-libs/validator-client" }
[dev-dependencies]
anyhow = { workspace = true }
-53
View File
@@ -1,53 +0,0 @@
# Buy NYM with Bity
This crate allows Bity to verify orders for purchasing NYM tokens. The same crate is used by the wallet to sign orders for purchases.
## Signing
The Nym Wallet user will sign an order message provided by Bity to create a signed order with the following fields:
```
account_id: n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf
message: "This is the order message from Bity"
order signature:
{
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A/zqdyeyPhCEXB9pyVLdNb5er+eds5ayboCdEEHK3Uom"
},
"signature_as_hex": "31C522B9B5C522A93CE14BE38E2D380CA166F69E952DF6F5D45B3B9CCDAAFE9115FBDF8539092986391C46885242E6E4CF806EEC1BB869A28D0E6D347C52121A"
}
```
The `signature` field of the order contains a JSON representation of:
- the Cosmos address of the signer (`account_id`)
- the Cosmos public key
- a hex string digest of the Bity order message signed by the user
Note: the `signature_as_hex` is not in recoverable form (e.g. allows recovering the public key from the signature in `secp256k1`). This is why the public key is supplied along with the account id, as the prefix cannot be recovered.
## Verification
Verification has been wrapped up into taking a single struct that can be parsed from JSON:
```
{
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"message": "This is the order message from Bity",
"signature": << ORDER SIGNATURE JSON GOES HERE >>
}
```
The following will be checked:
- the `account_id` supplied matches:
- the account id derived from the public key
- the account id field in the order signature JSON
- the account id is for Nym mainnet
- the signature is for the message
- all data structures parse correctly
- nested structs
- account ids
- Cosmos public keys
-220
View File
@@ -1,220 +0,0 @@
pub mod order;
pub mod sign;
pub mod verify;
#[cfg(test)]
mod tests {
use crate::order::{Order, OrderSignature};
use crate::{sign, verify};
use cosmrs::AccountId;
use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet;
use std::str::FromStr;
fn get_order(prefix: &str) -> anyhow::Result<(OrderSignature, String)> {
let mnemonic = "crush minute paddle tobacco message debate cabin peace bar jacket execute twenty winner view sure mask popular couch penalty fragile demise fresh pizza stove";
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.parse()?);
let accounts = wallet.try_derive_accounts()?;
let message = "This is the order message from Bity";
let signature = sign::sign_order(&wallet, &accounts[0], message.to_string())?;
Ok((signature, message.to_string()))
}
#[test]
fn integration_happy_path() -> anyhow::Result<()> {
let (signature, message) = get_order("n")?;
let account_id = AccountId::from_str("n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf").unwrap();
assert_eq!(account_id.to_string(), signature.account_id.to_string());
println!("Order signature:");
println!("{}", ::serde_json::to_string_pretty(&signature)?);
Ok(verify::verify_order(Order {
account_id,
signature,
message,
})?)
}
#[test]
fn integration_fails_on_non_mainnet_address() -> anyhow::Result<()> {
let (signature, message) = get_order("nymt")?;
println!("Order signature:");
println!("{}", ::serde_json::to_string_pretty(&signature)?);
let res = verify::verify_order(Order {
account_id: signature.clone().account_id,
signature,
message,
});
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
#[test]
fn integration_fails_on_non_mainnet_address_variant2() -> anyhow::Result<()> {
let (signature, message) = get_order("atom")?;
println!("Order signature:");
println!("{}", ::serde_json::to_string_pretty(&signature)?);
let res = verify::verify_order(Order {
account_id: signature.clone().account_id,
signature,
message,
});
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
#[test]
fn integration_change_account_id() -> anyhow::Result<()> {
let (signature, message) = get_order("n")?;
let OrderSignature {
signature_as_hex,
public_key,
account_id: _,
} = signature;
// use a different account id to the one that signed the order
let account_id = AccountId::from_str("n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es").unwrap();
let res = verify::verify_order(Order {
account_id: account_id.clone(),
signature: OrderSignature {
account_id,
signature_as_hex,
public_key,
},
message,
});
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
#[test]
fn integration_change_signature() -> anyhow::Result<()> {
let (signature, message) = get_order("n")?;
let OrderSignature {
signature_as_hex: _,
public_key,
account_id,
} = signature;
let res = verify::verify_order(Order {
account_id: account_id.clone(),
signature: OrderSignature {
account_id,
signature_as_hex: "this is not the signature you were looking for".to_string(),
public_key,
},
message,
});
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
#[test]
fn integration_with_json_happy_path() -> anyhow::Result<()> {
let json_order = r#"{
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"message": "This is the order message from Bity",
"signature": {
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A/zqdyeyPhCEXB9pyVLdNb5er+eds5ayboCdEEHK3Uom"
},
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"signature_as_hex": "31C522B9B5C522A93CE14BE38E2D380CA166F69E952DF6F5D45B3B9CCDAAFE9115FBDF8539092986391C46885242E6E4CF806EEC1BB869A28D0E6D347C52121A"
}
}"#;
let order: Order = serde_json::from_str(json_order)?;
Ok(verify::verify_order(order)?)
}
#[test]
fn integration_with_json_bad_signature() -> anyhow::Result<()> {
let json_order = r#"{
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"message": "A different message to the one signed",
"signature": {
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A/zqdyeyPhCEXB9pyVLdNb5er+eds5ayboCdEEHK3Uom"
},
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"signature_as_hex": "31C522B9B5C522A93CE14BE38E2D380CA166F69E952DF6F5D45B3B9CCDAAFE9115FBDF8539092986391C46885242E6E4CF806EEC1BB869A28D0E6D347C52121A"
}
}"#;
let order: Order = serde_json::from_str(json_order)?;
let res = verify::verify_order(order);
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
#[test]
fn integration_with_json_bad_account_id() -> anyhow::Result<()> {
let json_order = r#"{
"account_id": "n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"message": "This is the order message from Bity",
"signature": {
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A/zqdyeyPhCEXB9pyVLdNb5er+eds5ayboCdEEHK3Uom"
},
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"signature_as_hex": "31C522B9B5C522A93CE14BE38E2D380CA166F69E952DF6F5D45B3B9CCDAAFE9115FBDF8539092986391C46885242E6E4CF806EEC1BB869A28D0E6D347C52121A"
}
}"#;
let order: Order = serde_json::from_str(json_order)?;
let res = verify::verify_order(order);
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
#[test]
fn integration_with_json_bad_account_id_variation_2() -> anyhow::Result<()> {
let json_order = r#"{
"account_id": "n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
"message": "This is the order message from Bity",
"signature": {
"public_key": {
"@type": "/cosmos.crypto.secp256k1.PubKey",
"key": "A/zqdyeyPhCEXB9pyVLdNb5er+eds5ayboCdEEHK3Uom"
},
"account_id": "n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
"signature_as_hex": "31C522B9B5C522A93CE14BE38E2D380CA166F69E952DF6F5D45B3B9CCDAAFE9115FBDF8539092986391C46885242E6E4CF806EEC1BB869A28D0E6D347C52121A"
}
}"#;
let order: Order = serde_json::from_str(json_order)?;
let res = verify::verify_order(order);
println!("Expecting error, got: {:?}", res);
assert!(res.is_err());
Ok(())
}
}
-17
View File
@@ -1,17 +0,0 @@
use cosmrs::crypto::PublicKey;
use cosmrs::AccountId;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OrderSignature {
pub public_key: PublicKey,
pub account_id: AccountId,
pub signature_as_hex: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Order {
pub account_id: AccountId,
pub message: String,
pub signature: OrderSignature,
}
-20
View File
@@ -1,20 +0,0 @@
use crate::order::OrderSignature;
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::signing::direct_wallet::DirectSecp256k1HdWallet;
use nym_validator_client::signing::signer::OfflineSigner;
use nym_validator_client::signing::AccountData;
/// Signs an order message to purchase Nym with Bity
pub fn sign_order(
wallet: &DirectSecp256k1HdWallet,
signer: &AccountData,
message: String,
) -> Result<OrderSignature, NyxdError> {
Ok(OrderSignature {
account_id: signer.address().clone(),
public_key: signer.public_key(),
signature_as_hex: wallet
.sign_raw_with_account(signer, message.into_bytes())?
.to_string(),
})
}
-59
View File
@@ -1,59 +0,0 @@
use thiserror::Error;
use nym_cli_commands::validator::signature::helpers::secp256k1_verify_with_public_key;
use crate::order::Order;
#[derive(Error, Debug)]
pub enum VerifyOrderError {
#[error("{source}")]
K256Error {
#[from]
source: k256::ecdsa::Error,
},
#[error("{source}")]
ErrorReport {
#[from]
source: eyre::Report,
},
#[error("Account id does not match public key")]
AccountIdDoesNotMatchPubKey,
#[error("Unsupported key type. Only secp256k1 is currently supported.")]
UnsupportedKeyType,
#[error("Signature error - {0}")]
SignatureError(k256::ecdsa::signature::Error),
#[error("Account id is not a Nyx mainnet account")]
AccountIdPrefixIncorrect,
}
/// Verifies an order
pub fn verify_order(order: Order) -> Result<(), VerifyOrderError> {
let account_id = order.signature.public_key.account_id("n")?;
if order.signature.account_id.prefix() != "n" || order.account_id.prefix() != "n" {
return Err(VerifyOrderError::AccountIdPrefixIncorrect);
}
// the account id in the order must match the account id derived from the public key
if account_id != order.signature.account_id {
return Err(VerifyOrderError::AccountIdDoesNotMatchPubKey);
}
// the user provided account id in the order must match the derived account id
if account_id != order.account_id || account_id != order.signature.account_id {
return Err(VerifyOrderError::AccountIdDoesNotMatchPubKey);
}
if order.signature.public_key.type_url() != cosmrs::crypto::PublicKey::SECP256K1_TYPE_URL {
return Err(VerifyOrderError::UnsupportedKeyType);
}
match secp256k1_verify_with_public_key(
&order.signature.public_key.to_bytes(),
order.signature.signature_as_hex,
order.message,
) {
Ok(()) => Ok(()),
Err(e) => Err(VerifyOrderError::SignatureError(e)),
}
}
+1 -1
View File
@@ -4,7 +4,7 @@
[package]
name = "nym-api"
license = "GPL-3.0"
version = "1.1.59"
version = "1.1.60"
authors.workspace = true
edition = "2021"
rust-version.workspace = true
@@ -13,13 +13,10 @@ pub(crate) fn circulating_supply_routes() -> Router<AppState> {
Router::new()
.route("/", axum::routing::get(get_full_circulating_supply))
.route(
"/total-supply-value",
"/circulating-supply-value",
axum::routing::get(get_circulating_supply),
)
.route(
"/circulating-supply-value",
axum::routing::get(get_total_supply),
)
.route("/total-supply-value", axum::routing::get(get_total_supply))
}
#[utoipa::path(
-8
View File
@@ -1,8 +0,0 @@
{
"extends": [
"@nymproject/eslint-config-react-typescript"
],
"parserOptions": {
"project": "./tsconfig.eslint.json"
}
}
+14 -5
View File
@@ -1,5 +1,14 @@
# environment
.env.dev
# error logs
yarn-error.log
dist/
build/
**/*.wasm
**/*.js.map
.env*
!.env.example
.vscode/
.idea/
*.swp
*.swo
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
-1
View File
@@ -1 +0,0 @@
16
-6
View File
@@ -1,6 +0,0 @@
{
"trailingComma": "all",
"singleQuote": true,
"printWidth": 120,
"tabWidth": 2
}
-7
View File
@@ -1,7 +0,0 @@
RPC_URL=
VALIDATOR_URL=
PREFIX=
MIXNET_CONTRACT_ADDRESS=
VESTING_CONTRACT_ADDRESS=
DENOM=
BLOCK_EXPLORER_URL=
View File
+108 -23
View File
@@ -1,40 +1,125 @@
# Nym Browser Extension
# Nym Browser Extension Storage
The Nym browser extension lets you access your Nym wallet via the browser.
A WebAssembly-based storage component for securely managing mnemonics in extensions. This component provides encrypted storage functionality using IndexedDB with password-based encryption.
## Getting started
## Overview
You will need:
This storage component is built in Rust and compiled to WebAssembly, providing:
- NodeJS (use `nvm install` to automatically install the correct version)
- `npm`
- `yarn`
- **Secure mnemonic storage**: Password-encrypted storage of BIP39 mnemonics
- **IndexedDB integration**: Browser-native persistent storage
- **Multiple account support**: Store and manage multiple mnemonic phrases with custom names
- **Type-safe API**: Promise-based JavaScript API with proper error handling
> **Note**: This project is part of a mono repo, so you will need to build the shared packages before starting. And any time they change, you'll need to rebuild them.
## Getting Started
From the [root of the repository](../README.md) run the following to build shared packages:
### Prerequisites
```
yarn
yarn build
- Rust (latest stable)
- `wasm-pack` tool for building WebAssembly
- Node.js (for the demo server)
### Building
```bash
cd storage
make wasm-pack
```
From the `nym-browser-extension` directory of the `nym` monorepo, run:
This will compile the Rust code to WebAssembly and generate the necessary JavaScript bindings.
`yarn dev` to run the extension in dev mode.
### Example Usage
You can then open a browser to http://localhost:9000 and start development.
See the [internal-dev example](./storage/internal-dev/index.js) for complete usage examples.
OR
Basic usage:
`yarn build` to build the extension.
```javascript
import init, { ExtensionStorage, set_panic_hook } from "@nymproject/extension-storage"
The extension will build to the `nym-browser-extension/dist` directory.
// Initialize the WASM module first
await init();
## Load extension
// Set up better error handling
set_panic_hook();
To load the extension into a Chrome browser
// Create storage instance with password
const storage = await new ExtensionStorage("your-secure-password");
- Go to `settings > extensions > manage extensions`
- Select `Load unpacked`
- Select the `nym-browser-extension/dist`
// Store a mnemonic
const mnemonic = "your twenty four word mnemonic phrase goes here...";
await storage.store_mnemonic("my-wallet", mnemonic);
// Read a mnemonic
const retrievedMnemonic = await storage.read_mnemonic("my-wallet");
// Check if a mnemonic exists
const exists = await storage.has_mnemonic("my-wallet");
// Get all stored mnemonic keys
const allKeys = await storage.get_all_mnemonic_keys();
// Remove a mnemonic
await storage.remove_mnemonic("my-wallet");
```
## Development
To run the internal development example:
```bash
cd storage
make demo
# Option 2: Manual server setup
cd internal-dev && node serve.js
# Then open http://localhost:8000 in your browser
```
**Note**: The demo requires a server that properly serves WASM files with `application/wasm` MIME type. The Node.js server is recommended as it handles MIME types more reliably.
## API Reference
### Initialization
- `init()` - **Required**: Initialize the WASM module before using other functions
### Constructor
- `new ExtensionStorage(password: string)` - Creates a new storage instance with the given password
### Static Methods
- `ExtensionStorage.exists()` - Check if storage database exists
### Instance Methods
- `store_mnemonic(name: string, mnemonic: string)` - Store a mnemonic with the given name
- `read_mnemonic(name: string)` - Retrieve a mnemonic by name (returns null if not found)
- `has_mnemonic(name: string)` - Check if a mnemonic with the given name exists
- `get_all_mnemonic_keys()` - Get all stored mnemonic names
- `remove_mnemonic(name: string)` - Remove a mnemonic by name
### Error Handling
- `set_panic_hook()` - Set up better stack traces for Rust panics in development
## Security Features
- **Password-based encryption**: All data is encrypted using the provided password
- **BIP39 validation**: Mnemonics are validated before storage
- **Secure memory handling**: Sensitive data is zeroed from memory when no longer needed
- **Browser sandbox**: Runs within the browser's security model
## Architecture
The storage component consists of:
- **Rust core** (`src/storage.rs`): Main storage implementation with encryption
- **WASM bindings** (`src/lib.rs`): WebAssembly interface layer
- **Error handling** (`src/error.rs`): Comprehensive error types
- **Build configuration** (`Cargo.toml`, `Makefile`): Build and dependency management
## Important Notes
1. **WASM Initialization**: Always call `await init()` before using any other functions
2. **MIME Types**: The demo requires a server that properly serves WASM files
3. **Browser Compatibility**: Requires modern browsers with WebAssembly support
4. **Module Loading**: Uses ES modules - ensure your build system supports them
-86
View File
@@ -1,86 +0,0 @@
{
"name": "@nym/browser-extension",
"version": "0.1.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"dev": "yarn webpack serve --config webpack.dev.js",
"build": "yarn preinstall && webpack build --progress --config webpack.prod.js",
"lint": "eslint src",
"lint:fix": "eslint src --fix",
"lint:ts": "tsc --noEmit",
"storybook": "start-storybook -p 6006",
"storybook:build": "build-storybook"
},
"dependencies": {
"@emotion/react": "^11.7.0",
"@emotion/styled": "^11.7.0",
"@hookform/resolvers": "^3.1.0",
"@mui/icons-material": "^5.11.11",
"@mui/material": "^5.11.15",
"@mui/system": "^5.11.15",
"@nymproject/mui-theme": "^1.0.0",
"@nymproject/nym-validator-client": ">=1.2.0-rc.0 || 1",
"@nymproject/react": "^1.0.0",
"@nymproject/types": "^1.0.0",
"@nymproject/extension-storage": ">=1.2.0-rc.0 || 1",
"@storybook/react": "^6.5.16",
"big.js": "^6.2.1",
"crypto-js": "^4.1.1",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.3",
"react-hook-form": "^7.43.9",
"react-router-dom": "^6.9.0",
"zod": "^3.21.4"
},
"devDependencies": {
"@nymproject/eslint-config-react-typescript": "^1.0.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.4",
"@svgr/webpack": "^6.1.1",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^14.0.0",
"@types/big.js": "^6.1.6",
"@types/crypto-js": "4.1.1",
"@types/jest": "^27.0.1",
"@types/node": "^18.16.1",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@typescript-eslint/eslint-plugin": "^5.13.0",
"@typescript-eslint/parser": "^5.13.0",
"copy-webpack-plugin": "^11.0.0",
"dotenv-webpack": "^8.0.1",
"eslint": "^8.10.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^16.1.0",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-root-import": "^1.0.4",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^26.1.1",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-react": "^7.29.2",
"eslint-plugin-react-hooks": "^4.3.0",
"eslint-plugin-storybook": "^0.5.12",
"favicons-webpack-plugin": "^5.0.2",
"html-webpack-plugin": "^5.3.2",
"jest": "^27.1.0",
"mini-css-extract-plugin": "^2.2.2",
"prettier": "^2.8.7",
"react-refresh": "^0.14.0",
"react-refresh-typescript": "^2.0.8",
"style-loader": "^3.3.1",
"ts-jest": "^27.0.5",
"ts-loader": "^9.4.2",
"tsconfig-paths-webpack-plugin": "^3.5.2",
"typescript": "^4.6.2",
"url-loader": "^4.1.1",
"util": "^0.12.5",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1",
"webpack-dev-server": "^4.5.0",
"webpack-favicons": "^1.3.8",
"webpack-merge": "^5.8.0"
}
}
-15
View File
@@ -1,15 +0,0 @@
import React from 'react';
import { NymBrowserExtThemeWithMode } from './theme/NymBrowserExtensionTheme';
import { AppRoutes } from './routes';
import { AppLayout } from './layouts/AppLayout';
import { AppProvider } from './context';
export const App = () => (
<NymBrowserExtThemeWithMode mode="light">
<AppProvider>
<AppLayout>
<AppRoutes />
</AppLayout>
</AppProvider>
</NymBrowserExtThemeWithMode>
);
@@ -1,47 +0,0 @@
import React from 'react';
import { Avatar, ListItem, ListItemAvatar, ListItemButton, ListItemText } from '@mui/material';
import { useNavigate } from 'react-router-dom';
import { useAppContext } from 'src/context';
import { AccountActions } from './Actions';
const AccountItem = ({
accountName,
disabled,
onSelect,
}: {
accountName: string;
disabled: boolean;
onSelect: () => void;
}) => (
<ListItem disableGutters disablePadding secondaryAction={<AccountActions accountName={accountName} />} divider>
<ListItemButton onClick={onSelect} disabled={disabled}>
<ListItemAvatar>
<Avatar>{accountName[0]}</Avatar>
</ListItemAvatar>
<ListItemText primary={accountName} secondary={disabled && '(Selected)'} />
</ListItemButton>
</ListItem>
);
export const AccountList = () => {
const navigate = useNavigate();
const { accounts, selectAccount, selectedAccount } = useAppContext();
const handleSelectAccount = async (accountName: string) => {
await selectAccount(accountName);
navigate('/user/balance');
};
return (
<>
{accounts.map((accountName) => (
<AccountItem
disabled={selectedAccount === accountName}
accountName={accountName}
key={accountName}
onSelect={() => handleSelectAccount(accountName)}
/>
))}
</>
);
};
@@ -1,55 +0,0 @@
import React from 'react';
import { IconButton, ListItemIcon, ListItemText, Menu, MenuItem } from '@mui/material';
import { MoreVert, VisibilityOutlined } from '@mui/icons-material';
import { useAppContext } from 'src/context';
type ActionType = {
title: string;
Icon: React.ReactNode;
onSelect: () => void;
};
const ActionItem = ({ action }: { action: ActionType }) => (
<MenuItem dense onClick={action.onSelect}>
<ListItemIcon>{action.Icon}</ListItemIcon>
<ListItemText>{action.title}</ListItemText>
</MenuItem>
);
export const AccountActions = ({ accountName }: { accountName: string }) => {
const { setShowSeedForAccount } = useAppContext();
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
const actions: Array<ActionType> = [
{
title: 'View seed phrase',
Icon: <VisibilityOutlined />,
onSelect: () => {
setShowSeedForAccount(accountName);
},
},
];
return (
<>
<IconButton onClick={handleClick}>
<MoreVert />
</IconButton>
<Menu anchorEl={anchorEl} id="account-menu" open={open} onClose={handleClose} onClick={handleClose}>
{actions.map((action) => (
<ActionItem action={action} key={action.title} />
))}
</Menu>
</>
);
};
@@ -1,68 +0,0 @@
import React, { useState } from 'react';
import { Box, Card, CardContent, Typography } from '@mui/material';
import { PasswordInput } from '@nymproject/react/textfields/Password';
import { ExtensionStorage } from '@nymproject/extension-storage';
import { Button, ConfirmationModal } from 'src/components/ui';
const ShowSeedButton = ({ handleShowSeedPhrase }: { handleShowSeedPhrase: () => void }) => (
<Button fullWidth variant="contained" onClick={handleShowSeedPhrase}>
Show seed phrase
</Button>
);
const DoneButton = ({ onDone }: { onDone: () => void }) => (
<Button fullWidth variant="contained" onClick={onDone}>
Done
</Button>
);
const Seed = ({ seed }: { seed: string }) => (
<Card>
<CardContent>
<Typography>{seed}</Typography>
</CardContent>
</Card>
);
export const ViewSeedPhrase = ({ accountName, onDone }: { accountName: string; onDone: () => void }) => {
const [seed, setSeed] = useState<string>();
const [password, setPassword] = useState('');
const [error, setError] = useState<string>();
const handleShowSeedPhrase = async () => {
try {
const storage = await new ExtensionStorage(password);
const accountSeed = await storage.read_mnemonic(accountName);
setSeed(accountSeed);
} catch (e) {
setError('Could not retrieve seed phrase. Please check your password');
}
};
return (
<ConfirmationModal
open
onClose={onDone}
title={seed ? 'Account seed phrase' : 'Password'}
subtitle={seed ? '' : 'Enter your account password'}
ConfirmButton={
seed ? <DoneButton onDone={onDone} /> : <ShowSeedButton handleShowSeedPhrase={handleShowSeedPhrase} />
}
>
{seed ? (
<Seed seed={seed} />
) : (
<Box sx={{ mt: 2 }}>
<PasswordInput
label="Password"
error={error}
password={password}
onUpdatePassword={(pw: string) => {
setPassword(pw);
}}
/>
</Box>
)}
</ConfirmationModal>
);
};
@@ -1,3 +0,0 @@
export * from './Accounts';
export * from './Actions';
export * from './ViewSeedPhrase';
@@ -1,16 +0,0 @@
import React from 'react';
import { Typography } from '@mui/material';
import { Stack } from '@mui/system';
import { ClientAddress } from '@nymproject/react/client-address/ClientAddress';
import { useAppContext } from 'src/context';
export const Address = () => {
const { client } = useAppContext();
return (
<Stack direction="row" justifyContent="space-between" alignItems="center">
<Typography fontWeight={700}>Address</Typography>
<ClientAddress withCopy address={client?.address || ''} />
</Stack>
);
};
@@ -1,23 +0,0 @@
import React, { useEffect } from 'react';
import { Stack, Typography } from '@mui/material';
import { useAppContext } from 'src/context';
export const Balance = () => {
const { balance, fiatBalance, currency, getBalance } = useAppContext();
useEffect(() => {
getBalance();
}, []);
const fiat = fiatBalance ? `~ ${Intl.NumberFormat().format(fiatBalance)} ${currency.toUpperCase()}` : '-';
return (
<Stack alignItems="center" gap={1}>
<Typography sx={{ color: 'grey.600' }}>Available</Typography>
<Typography variant="h4" textAlign="center">
{balance} NYM
</Typography>
<Typography sx={{ color: 'grey.600' }}>{fiat}</Typography>
</Stack>
);
};
@@ -1,6 +0,0 @@
export * from './accounts';
export * from './address';
export * from './balance';
export * from './receive';
export * from './send';
export * from './ui';
@@ -1,35 +0,0 @@
import React from 'react';
import { Card, CardContent, Dialog, DialogContent, DialogTitle, IconButton, Stack, Typography } from '@mui/material';
import { QRCodeSVG } from 'qrcode.react';
import { useAppContext } from 'src/context';
import { ClientAddress } from '@nymproject/react/client-address/ClientAddress';
import { Close } from '@mui/icons-material';
export const ReceiveModal = ({ open, onClose }: { open: boolean; onClose: () => void }) => {
const { client } = useAppContext();
return (
<Dialog open={open} onClose={onClose} maxWidth="xl" fullWidth>
<DialogTitle>
<Stack direction="row" justifyContent="space-between">
<Typography fontWeight={700}>Receive</Typography>
<IconButton size="small" onClick={onClose} sx={{ padding: 0 }}>
<Close fontSize="small" />
</IconButton>
</Stack>
</DialogTitle>
<DialogContent>
<Stack gap={1} alignItems="center">
<Card elevation={3} sx={{ my: 2, width: 200 }}>
<CardContent sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
<QRCodeSVG value={client?.address || ''} />
</CardContent>
</Card>
<Typography variant="body2" fontWeight={700}>
Your Nym address
</Typography>
<ClientAddress address={client?.address || ''} withCopy smallIcons />
</Stack>
</DialogContent>
</Dialog>
);
};
@@ -1 +0,0 @@
export * from './ReceiveModal';
@@ -1,30 +0,0 @@
import React from 'react';
import { Box, Typography } from '@mui/material';
import { Link } from '@nymproject/react/link/Link';
import { ConfirmationModal, Button } from 'src/components/ui';
export const SendConfirmationModal = ({
amount,
txUrl,
onConfirm,
}: {
amount: string;
txUrl: string;
onConfirm: () => void;
}) => (
<ConfirmationModal
open
fullWidth
title="You sent"
ConfirmButton={
<Button fullWidth variant="contained" size="large" onClick={onConfirm}>
Done
</Button>
}
>
<Box>
<Typography variant="h6">{amount}</Typography>
<Link href={txUrl} target="_blank" sx={{ ml: 1 }} text="View on blockchain" />
</Box>
</ConfirmationModal>
);
@@ -1 +0,0 @@
export * from './SendConfirmationModal';
@@ -1,14 +0,0 @@
import * as React from 'react';
import { AppBar as MUIAppBar } from '@mui/material/';
import Box from '@mui/material/Box';
import Toolbar from '@mui/material/Toolbar';
export const AppBar = ({ Action }: { Action: React.ReactNode }) => (
<Box sx={{ flexGrow: 1 }}>
<MUIAppBar position="static" elevation={0} sx={{ bgcolor: 'rgba(103, 80, 164, 0.14)' }}>
<Toolbar variant="dense">{Action}</Toolbar>
</MUIAppBar>
</Box>
);
export default AppBar;
@@ -1,23 +0,0 @@
import React from 'react';
import { useNavigate } from 'react-router-dom';
import { ArrowBackIosRounded } from '@mui/icons-material';
import { IconButton } from '@mui/material';
export const BackButton = ({ onBack }: { onBack?: () => void }) => {
const navigate = useNavigate();
const handleClick = () => {
if (onBack) {
onBack();
} else {
navigate(-1);
}
return undefined;
};
return (
<IconButton size="small" onClick={handleClick}>
<ArrowBackIosRounded fontSize="small" />
</IconButton>
);
};
@@ -1,6 +0,0 @@
import React from 'react';
import { Button as MUIButton, ButtonProps } from '@mui/material';
export const Button = (props: ButtonProps) => (
<MUIButton {...props} disableElevation sx={{ textTransform: 'initial' }} />
);
@@ -1,6 +0,0 @@
import React from 'react';
import { NymLogoBW } from '@nymproject/react/logo/NymLogoBW';
export const Logo = ({ small }: { small?: boolean }) => (
<NymLogoBW width={small ? '37.5px' : '75px'} height={small ? '37.5px' : '75px'} />
);
@@ -1,20 +0,0 @@
import React from 'react';
import { Stack, Typography } from '@mui/material';
import { Logo } from '../Logo';
import { Title } from '../Title';
export const LogoWithText = ({
logoSmall,
title,
description,
}: {
logoSmall?: boolean;
title: string;
description?: string;
}) => (
<Stack alignItems="center" justifyContent="center" gap={3}>
<Logo small={logoSmall} />
<Title>{title}</Title>
<Typography sx={{ color: 'grey.700', textAlign: 'center' }}>{description}</Typography>
</Stack>
);
@@ -1,55 +0,0 @@
import * as React from 'react';
import Box from '@mui/material/Box';
import Drawer from '@mui/material/Drawer';
import List from '@mui/material/List';
import ListItem from '@mui/material/ListItem';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import { AccountBalanceWalletRounded, AccountCircleRounded, ArrowDownwardRounded } from '@mui/icons-material';
import { Link } from 'react-router-dom';
const menuSchema = [
{
title: 'Accounts',
Icon: <AccountCircleRounded />,
path: '/user/accounts',
},
{
title: 'Balance',
Icon: <AccountBalanceWalletRounded />,
path: '/user/balance',
},
{
title: 'Send',
Icon: <ArrowDownwardRounded />,
path: '/user/send',
},
];
export const MenuDrawer = ({ open, onClose }: { open: boolean; onClose: () => void }) => {
const list = () => (
<Box sx={{ width: 250 }} role="presentation" onClick={() => {}}>
<List>
{menuSchema.map(({ title, Icon, path }) => (
<Link to={path} style={{ textDecoration: 'none', color: 'unset' }} key={title}>
<ListItem disablePadding>
<ListItemButton>
<ListItemIcon>{Icon}</ListItemIcon>
<ListItemText primary={title} />
</ListItemButton>
</ListItem>
</Link>
))}
</List>
</Box>
);
return (
<div>
<Drawer anchor="left" open={open} onClose={onClose}>
{list()}
</Drawer>
</div>
);
};
@@ -1,74 +0,0 @@
import React from 'react';
import {
Breakpoint,
Paper,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
SxProps,
Typography,
} from '@mui/material';
import { Button } from '../Button';
export interface ErrorModalProps {
open: boolean;
children?: React.ReactNode;
title: React.ReactNode | string;
subtitle?: React.ReactNode | string;
sx?: SxProps;
fullWidth?: boolean;
maxWidth?: Breakpoint;
backdropProps?: object;
onClose?: () => void;
}
export const ErrorModal = ({
open,
onClose,
children,
title,
subtitle,
sx,
fullWidth,
maxWidth,
backdropProps,
}: ErrorModalProps) => {
const Title = (
<DialogTitle id="responsive-dialog-title" sx={{ pb: 2 }}>
<Typography variant="body2" fontWeight={600}>
{title}
</Typography>
{subtitle &&
(typeof subtitle === 'string' ? (
<Typography fontWeight={400} variant="subtitle1" fontSize={12} sx={{ color: 'grey.400' }}>
{subtitle}
</Typography>
) : (
subtitle
))}
</DialogTitle>
);
return (
<Dialog
open={open}
onClose={onClose}
aria-labelledby="responsive-dialog-title"
maxWidth={maxWidth || 'sm'}
sx={{ textAlign: 'center', ...sx }}
fullWidth={fullWidth}
BackdropProps={backdropProps}
PaperComponent={Paper}
PaperProps={{ elevation: 0 }}
>
{Title}
<DialogContent>{children}</DialogContent>
<DialogActions sx={{ px: 3, pb: 3 }}>
<Button variant="contained" size="large" fullWidth onClick={onClose}>
Close
</Button>
</DialogActions>
</Dialog>
);
};
@@ -1,25 +0,0 @@
import React from 'react';
import { Box, CircularProgress, Modal, Stack, Typography, SxProps } from '@mui/material';
const modalStyle: SxProps = {
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 300,
bgcolor: 'background.paper',
boxShadow: 24,
borderRadius: '16px',
p: 4,
};
export const LoadingModal = ({ sx, backdropProps }: { sx?: SxProps; backdropProps?: object }) => (
<Modal open BackdropProps={backdropProps}>
<Box sx={{ border: (t) => `1px solid ${t.palette.grey[500]}`, ...modalStyle, ...sx }} textAlign="center">
<Stack spacing={4} direction="row" alignItems="center">
<CircularProgress />
<Typography sx={{ color: 'text.primary' }}>Please wait...</Typography>
</Stack>
</Box>
</Modal>
);
@@ -1,71 +0,0 @@
import React from 'react';
import {
Breakpoint,
Paper,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
SxProps,
Typography,
} from '@mui/material';
export interface ConfirmationModalProps {
open: boolean;
children?: React.ReactNode;
title: React.ReactNode | string;
subtitle?: React.ReactNode | string;
ConfirmButton: React.ReactNode;
sx?: SxProps;
fullWidth?: boolean;
maxWidth?: Breakpoint;
backdropProps?: object;
onClose?: () => void;
}
export const ConfirmationModal = ({
open,
onClose,
children,
title,
subtitle,
ConfirmButton,
sx,
fullWidth,
maxWidth,
backdropProps,
}: ConfirmationModalProps) => {
const Title = (
<DialogTitle id="responsive-dialog-title" sx={{ pb: 2 }}>
<Typography variant="body2" fontWeight={600}>
{title}
</Typography>
{subtitle &&
(typeof subtitle === 'string' ? (
<Typography fontWeight={400} variant="subtitle1" fontSize={12} sx={{ color: 'grey.400' }}>
{subtitle}
</Typography>
) : (
subtitle
))}
</DialogTitle>
);
return (
<Dialog
open={open}
onClose={onClose}
aria-labelledby="responsive-dialog-title"
maxWidth={maxWidth || 'sm'}
sx={{ textAlign: 'center', ...sx }}
fullWidth={fullWidth}
BackdropProps={backdropProps}
PaperComponent={Paper}
PaperProps={{ elevation: 0 }}
>
{Title}
<DialogContent>{children}</DialogContent>
<DialogActions sx={{ px: 3, pb: 3 }}>{ConfirmButton}</DialogActions>
</Dialog>
);
};
@@ -1,3 +0,0 @@
export * from './Modal';
export * from './LoadingModal';
export * from './ErrorModal';

Some files were not shown because too many files have changed in this diff Show More