Compare commits
89 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0881d4cbc3 | |||
| 3429e0a8e9 | |||
| 9c19ae322d | |||
| 07893828d8 | |||
| 1167f50543 | |||
| ba1818a903 | |||
| e631219a73 | |||
| 207c6cf2c7 | |||
| c5ece97872 | |||
| 8a2c95d044 | |||
| ba5e3d4efa | |||
| c81623a61a | |||
| 8bb42c2b1b | |||
| 33e161bd59 | |||
| 0233499036 | |||
| a059a29173 | |||
| 83c3398570 | |||
| 93f931459a | |||
| 5a7b19aeb6 | |||
| b901655591 | |||
| a9fdbccb82 | |||
| 9ca3f69aa8 | |||
| c485934b06 | |||
| d62e13c932 | |||
| 47f7a5f795 | |||
| f29200431f | |||
| 0912627e1f | |||
| 70fdcc9be0 | |||
| 90da6f152b | |||
| ad547e516a | |||
| 61c0092f27 | |||
| 851b80aaab | |||
| 1397662fc9 | |||
| 1847c8fe73 | |||
| 8ffe3adf0d | |||
| 3e517b461c | |||
| e42e4ddb9b | |||
| a31f51b7ca | |||
| c41a600bcb | |||
| 7aa34391fb | |||
| f72b56d07e | |||
| 44ddbf9ac3 | |||
| 27c377860a | |||
| 9a3f60f224 | |||
| 5776600db3 | |||
| e851ad8b27 | |||
| 2e0e319511 | |||
| 6dd3e36acb | |||
| 40cbfccb73 | |||
| b49681ef1d | |||
| 7e9409bbef | |||
| a11e674967 | |||
| 2f4e505aac | |||
| 90d8e5305f | |||
| 81a678f9e2 | |||
| 0a4bbf2573 | |||
| 2ae5ebb8cb | |||
| 11be1f8e3e | |||
| 513baba3fd | |||
| 21b87f6af5 | |||
| fe59697aa9 | |||
| 566ceae325 | |||
| 6bc4d32573 | |||
| 1fc3c9f31c | |||
| 3cb08a410e | |||
| 1648aef1d3 | |||
| d98b6b107c | |||
| d3db0fc2cd | |||
| 06b823f4c1 | |||
| 1c0ce9a420 | |||
| dede8899cf | |||
| 70f6059ceb | |||
| fefd2dd267 | |||
| 0fbe77d934 | |||
| 8a267cfe3d | |||
| 5ebb2a3efe | |||
| de605dc3b9 | |||
| 6a01edf5fe | |||
| 806b37bd83 | |||
| ffff596d45 | |||
| ad826da782 | |||
| 3414eeea7a | |||
| 3a32d34fb4 | |||
| 248052aec7 | |||
| 90c00fc343 | |||
| 7bdfbfdcc5 | |||
| 44e22b74a5 | |||
| 7920c27648 | |||
| f02f914ae2 |
+4
-4
@@ -19,10 +19,10 @@
|
|||||||
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
Cargo.* @durch @futurechimp @jstuczyn @neacsu @octol
|
||||||
|
|
||||||
# JS rules:
|
# JS rules:
|
||||||
*.js @mmsinclair @fmtabbara @Aid19801
|
*.js @mmsinclair @fmtabbara
|
||||||
*.ts @mmsinclair @fmtabbara @Aid19801
|
*.ts @mmsinclair @fmtabbara
|
||||||
*.tsx @mmsinclair @fmtabbara @Aid19801
|
*.tsx @mmsinclair @fmtabbara
|
||||||
*.jsx @mmsinclair @fmtabbara @Aid19801
|
*.jsx @mmsinclair @fmtabbara
|
||||||
|
|
||||||
# Something looking like possible documentation rules:
|
# Something looking like possible documentation rules:
|
||||||
*.md @mfahampshire
|
*.md @mfahampshire
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
name: CI for Network Explorer
|
name: CI for Network Explorer
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- 'explorer/**'
|
- 'explorer/**'
|
||||||
@@ -75,3 +76,14 @@ jobs:
|
|||||||
uses: docker://keybaseio/client:stable-node
|
uses: docker://keybaseio/client:stable-node
|
||||||
with:
|
with:
|
||||||
args: .github/workflows/support-files/notifications/entry_point.sh
|
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||||
|
- name: Deploy
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
uses: easingthemes/ssh-deploy@main
|
||||||
|
env:
|
||||||
|
SSH_PRIVATE_KEY: ${{ secrets.CD_PROD_NE_SSH_PRIVATE_KEY }}
|
||||||
|
ARGS: "-rltgoDzvO --delete"
|
||||||
|
SOURCE: "explorer/dist/"
|
||||||
|
REMOTE_HOST: ${{ secrets.CD_PROD_NE_REMOTE_HOST }}
|
||||||
|
REMOTE_USER: ${{ secrets.CD_PROD_NE_REMOTE_USER }}
|
||||||
|
TARGET: ${{ secrets.CD_PROD_NE_REMOTE_TARGET }}
|
||||||
|
EXCLUDE: "/dist/, /node_modules/"
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"os":"ubuntu-latest",
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"os":"windows-latest",
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"macos-latest",
|
||||||
|
"rust":"stable",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"os":"ubuntu-latest",
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"windows-latest",
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"macos-latest",
|
||||||
|
"rust":"beta",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"os":"ubuntu-latest",
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"windows-latest",
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"os":"macos-latest",
|
||||||
|
"rust":"nightly",
|
||||||
|
"runOnEvent":"workflow_dispatch"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
name: Nightly builds on dispatch
|
||||||
|
|
||||||
|
on: workflow_dispatch
|
||||||
|
jobs:
|
||||||
|
matrix_prep:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
||||||
|
steps:
|
||||||
|
# creates the matrix strategy from nightly_build_matrix_includes.json
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- id: set-matrix
|
||||||
|
uses: JoshuaTheMiller/conditional-build-matrix@main
|
||||||
|
with:
|
||||||
|
inputFile: '.github/workflows/nightly_build_matrix_on_dispatch.json'
|
||||||
|
filter: '[?runOnEvent==`${{ github.event_name }}` || runOnEvent==`always`]'
|
||||||
|
build:
|
||||||
|
needs: matrix_prep
|
||||||
|
strategy:
|
||||||
|
matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
continue-on-error: ${{ matrix.rust == 'nightly' || matrix.rust == 'beta' || matrix.rust == 'stable' }}
|
||||||
|
steps:
|
||||||
|
- name: Install Dependencies (Linux)
|
||||||
|
run: sudo apt-get update && sudo apt-get install libwebkit2gtk-4.0-dev build-essential curl wget libssl-dev libgtk-3-dev squashfs-tools
|
||||||
|
if: matrix.os == 'ubuntu-latest'
|
||||||
|
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install rust toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
profile: minimal
|
||||||
|
toolchain: ${{ matrix.rust }}
|
||||||
|
override: true
|
||||||
|
components: rustfmt, clippy
|
||||||
|
|
||||||
|
- name: Build all binaries
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --workspace
|
||||||
|
|
||||||
|
- name: Run all tests
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --workspace
|
||||||
|
|
||||||
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
|
with:
|
||||||
|
command: clean
|
||||||
|
|
||||||
|
- name: Run expensive tests
|
||||||
|
if: github.ref == 'refs/heads/develop' || github.event.pull_request.base.ref == 'develop' || github.event.pull_request.base.ref == 'master'
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --workspace --all-features -- --ignored
|
||||||
|
|
||||||
|
- name: Check formatting
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --all -- --check
|
||||||
|
|
||||||
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
|
with:
|
||||||
|
command: clean
|
||||||
|
|
||||||
|
- uses: actions-rs/clippy-check@v1
|
||||||
|
name: Clippy checks
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
args: --all-features
|
||||||
|
|
||||||
|
- name: Run clippy
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: --workspace --all-targets -- -D warnings
|
||||||
|
|
||||||
|
- name: Reclaim some disk space
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.os == 'windows-latest' || matrix.os == 'ubuntu-latest' }}
|
||||||
|
with:
|
||||||
|
command: clean
|
||||||
|
|
||||||
|
# COCONUT stuff
|
||||||
|
- name: Build all binaries with coconut enabled
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --workspace --features=coconut
|
||||||
|
|
||||||
|
- name: Run all tests with coconut enabled
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --workspace --features=coconut
|
||||||
|
|
||||||
|
- name: Reclaim some disk space (because Windows is being annoying)
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.os == 'windows-latest' }}
|
||||||
|
with:
|
||||||
|
command: clean
|
||||||
|
|
||||||
|
- name: Run clippy with coconut enabled
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: --workspace --all-targets --features=coconut -- -D warnings
|
||||||
|
|
||||||
|
# nym-wallet (the rust part)
|
||||||
|
- name: Build nym-wallet rust code
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: build
|
||||||
|
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
||||||
|
|
||||||
|
- name: Run nym-wallet tests
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: test
|
||||||
|
args: --manifest-path nym-wallet/Cargo.toml --workspace
|
||||||
|
|
||||||
|
- name: Check nym-wallet formatting
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
with:
|
||||||
|
command: fmt
|
||||||
|
args: --manifest-path nym-wallet/Cargo.toml --all -- --check
|
||||||
|
|
||||||
|
- name: Run clippy for nym-wallet
|
||||||
|
uses: actions-rs/cargo@v1
|
||||||
|
if: ${{ matrix.rust != 'nightly' }}
|
||||||
|
with:
|
||||||
|
command: clippy
|
||||||
|
args: --manifest-path nym-wallet/Cargo.toml --workspace --all-targets -- -D warnings
|
||||||
|
|
||||||
|
notification:
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Collect jobs status
|
||||||
|
uses: technote-space/workflow-conclusion-action@v2
|
||||||
|
- name: Check out repository code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Keybase - Node Install
|
||||||
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
|
run: npm install
|
||||||
|
working-directory: .github/workflows/support-files
|
||||||
|
- name: Keybase - Send Notification
|
||||||
|
if: env.WORKFLOW_CONCLUSION == 'failure'
|
||||||
|
env:
|
||||||
|
NYM_NOTIFICATION_KIND: nightly
|
||||||
|
NYM_PROJECT_NAME: "Nym nightly build"
|
||||||
|
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
GIT_COMMIT_MESSAGE: "${{ github.event.head_commit.message }}"
|
||||||
|
GIT_BRANCH: "${GITHUB_REF##*/}"
|
||||||
|
KEYBASE_NYMBOT_USERNAME: "${{ secrets.KEYBASE_NYMBOT_USERNAME }}"
|
||||||
|
KEYBASE_NYMBOT_PAPERKEY: "${{ secrets.KEYBASE_NYMBOT_PAPERKEY }}"
|
||||||
|
KEYBASE_NYMBOT_TEAM: "${{ secrets.KEYBASE_NYMBOT_TEAM }}"
|
||||||
|
KEYBASE_NYM_CHANNEL: "ci-nightly"
|
||||||
|
IS_SUCCESS: "${{ env.WORKFLOW_CONCLUSION == 'success' }}"
|
||||||
|
uses: docker://keybaseio/client:stable-node
|
||||||
|
with:
|
||||||
|
args: .github/workflows/support-files/notifications/entry_point.sh
|
||||||
+40
-4
@@ -8,7 +8,6 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
### Added
|
### Added
|
||||||
|
|
||||||
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
|
- socks5 client/websocket client: add `--force-register-gateway` flag, useful when rerunning init ([#1353])
|
||||||
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
|
|
||||||
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
- all: added network compilation target to `--help` (or `--version`) commands ([#1256]).
|
||||||
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
|
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
|
||||||
- explorer-api: add apy values to `mix_nodes` endpoint
|
- explorer-api: add apy values to `mix_nodes` endpoint
|
||||||
@@ -21,9 +20,11 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
|
- validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261])
|
||||||
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
|
- validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393])
|
||||||
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
|
- network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328])
|
||||||
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
|
|
||||||
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
|
- mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]).
|
||||||
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
|
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
|
||||||
|
- validator-client: add `denom` argument and add simple test for querying an account balance
|
||||||
|
- gateway, validator-api: Checks for coconut credential double spending attempts, taking the coconut bandwidth contract as source of truth ([#1457])
|
||||||
|
- coconut-bandwidth-contract: Record the state of a coconut credential; create specific proposal for releasing funds ([#1457])
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
@@ -34,15 +35,23 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
||||||
- native & socks5 clients: deduplicate big chunks of init logic
|
- native & socks5 clients: deduplicate big chunks of init logic
|
||||||
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
||||||
|
- explorer-api: listen out for SIGTERM and SIGQUIT too, making it play nicely as a system service ([#1482]).
|
||||||
|
- network-requester: fix filter for suffix-only domains ([#1487])
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- nym-connect: reuse config id instead of creating a new id on each connection.
|
|
||||||
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
|
- validator-client: created internal `Coin` type that replaces coins from `cosmrs` and `cosmwasm` for API entrypoints [[#1295]]
|
||||||
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
|
- all: updated all `cosmwasm`-related dependencies to `1.0.0` and `cw-storage-plus` to `0.13.4` [[#1318]]
|
||||||
- all: updated `rocket` to `0.5.0-rc.2`.
|
- all: updated `rocket` to `0.5.0-rc.2`.
|
||||||
- network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328])
|
- network-requester: allow to voluntarily store and send statistical data about the number of bytes the proxied server serves ([#1328])
|
||||||
- gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376])
|
- gateway: allow to voluntarily send statistical data about the number of active inboxes served by a gateway ([#1376])
|
||||||
|
- gateway & mixnode: move detailed build info back to `--version` from `--help`.
|
||||||
|
- socks5 client/websocket client: upgrade to latest clap and switched to declarative commandline parsing.
|
||||||
|
- validator-api: fee payment for multisig operations comes from the gateway account instead of the validator APIs' accounts ([#1419])
|
||||||
|
- multisig-contract: Limit the proposal creating functionality to one address (coconut-bandwidth-contract address) ([#1457])
|
||||||
|
- All binaries and cosmwasm blobs are configured at runtime now; binaries are configured using environment variables or .env files and contracts keep the configuration parameters in storage ([#1463])
|
||||||
|
- gateway, network-statistics: include gateway id in the sent statistical data ([#1478])
|
||||||
|
|
||||||
|
|
||||||
[#1249]: https://github.com/nymtech/nym/pull/1249
|
[#1249]: https://github.com/nymtech/nym/pull/1249
|
||||||
[#1256]: https://github.com/nymtech/nym/pull/1256
|
[#1256]: https://github.com/nymtech/nym/pull/1256
|
||||||
@@ -60,9 +69,36 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
|||||||
[#1329]: https://github.com/nymtech/nym/pull/1329
|
[#1329]: https://github.com/nymtech/nym/pull/1329
|
||||||
[#1353]: https://github.com/nymtech/nym/pull/1353
|
[#1353]: https://github.com/nymtech/nym/pull/1353
|
||||||
[#1376]: https://github.com/nymtech/nym/pull/1376
|
[#1376]: https://github.com/nymtech/nym/pull/1376
|
||||||
[#1388]: https://github.com/nymtech/nym/pull/1388
|
|
||||||
[#1393]: https://github.com/nymtech/nym/pull/1393
|
[#1393]: https://github.com/nymtech/nym/pull/1393
|
||||||
[#1404]: https://github.com/nymtech/nym/pull/1404
|
[#1404]: https://github.com/nymtech/nym/pull/1404
|
||||||
|
[#1419]: https://github.com/nymtech/nym/pull/1419
|
||||||
|
[#1457]: https://github.com/nymtech/nym/pull/1457
|
||||||
|
[#1463]: https://github.com/nymtech/nym/pull/1463
|
||||||
|
[#1478]: https://github.com/nymtech/nym/pull/1478
|
||||||
|
[#1482]: https://github.com/nymtech/nym/pull/1482
|
||||||
|
[#1487]: https://github.com/nymtech/nym/pull/1487
|
||||||
|
|
||||||
|
## [nym-connect-v1.0.1](https://github.com/nymtech/nym/tree/nym-connect-v1.0.1) (2022-07-22)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- nym-connect: initial proof-of-concept of a UI around the socks5 client was added
|
||||||
|
- nym-connect: add ability to select network requester and gateway ([#1427])
|
||||||
|
- nym-connect: add ability to export gateway keys as JSON
|
||||||
|
- nym-connect: add auto updater
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- nym-connect: reuse config id instead of creating a new id on each connection
|
||||||
|
|
||||||
|
[#1427]: https://github.com/nymtech/nym/pull/1427
|
||||||
|
|
||||||
|
## [nym-wallet-v1.0.7](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.7) (2022-07-11)
|
||||||
|
|
||||||
|
- wallet: dark mode
|
||||||
|
- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]).
|
||||||
|
|
||||||
|
[#1388]: https://github.com/nymtech/nym/pull/1388
|
||||||
|
|
||||||
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
|
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
|
||||||
|
|
||||||
|
|||||||
Generated
+32
-28
@@ -568,16 +568,16 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "3.1.8"
|
version = "3.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
|
checksum = "190814073e85d238f31ff738fcb0bf6910cedeb73376c87cd69291028966fd83"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atty",
|
"atty",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
"clap_lex",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"lazy_static",
|
"once_cell",
|
||||||
"os_str_bytes",
|
|
||||||
"strsim 0.10.0",
|
"strsim 0.10.0",
|
||||||
"termcolor",
|
"termcolor",
|
||||||
"textwrap 0.15.0",
|
"textwrap 0.15.0",
|
||||||
@@ -585,9 +585,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "3.1.7"
|
version = "3.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
|
checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck 0.4.0",
|
"heck 0.4.0",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
@@ -596,6 +596,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_lex"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
|
||||||
|
dependencies = [
|
||||||
|
"os_str_bytes",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "client-core"
|
name = "client-core"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
@@ -635,6 +644,7 @@ name = "coconut-bandwidth-contract-common"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
|
"multisig-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -773,9 +783,8 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmos-sdk-proto"
|
name = "cosmos-sdk-proto"
|
||||||
version = "0.12.2"
|
version = "0.12.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/neacsu/cosmos-rust?branch=neacsu/feegrant_support#f63ded63ec13e753ebe8bdafe9dc503df265d67d"
|
||||||
checksum = "f109fe191e73898d74b8020c50f86018364ad19bc30318aa074616c382b52856"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost 0.10.3",
|
"prost 0.10.3",
|
||||||
"prost-types 0.10.1",
|
"prost-types 0.10.1",
|
||||||
@@ -784,9 +793,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cosmrs"
|
name = "cosmrs"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/neacsu/cosmos-rust?branch=neacsu/feegrant_support#f63ded63ec13e753ebe8bdafe9dc503df265d67d"
|
||||||
checksum = "8413275b23cb5a0734d9d1e3e33f0b5b94547c1e94776dbc3149dbf46588a533"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bip32",
|
"bip32",
|
||||||
"cosmos-sdk-proto",
|
"cosmos-sdk-proto",
|
||||||
@@ -884,7 +892,7 @@ dependencies = [
|
|||||||
"async-trait",
|
"async-trait",
|
||||||
"bip39",
|
"bip39",
|
||||||
"cfg-if 0.1.10",
|
"cfg-if 0.1.10",
|
||||||
"clap 3.1.8",
|
"clap 3.2.8",
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
"credential-storage",
|
"credential-storage",
|
||||||
"credentials",
|
"credentials",
|
||||||
@@ -920,7 +928,6 @@ dependencies = [
|
|||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
"cosmrs",
|
"cosmrs",
|
||||||
"crypto",
|
"crypto",
|
||||||
"network-defaults",
|
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"url",
|
"url",
|
||||||
@@ -1583,6 +1590,7 @@ name = "explorer-api"
|
|||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"clap 3.2.8",
|
||||||
"humantime-serde",
|
"humantime-serde",
|
||||||
"isocountry",
|
"isocountry",
|
||||||
"itertools",
|
"itertools",
|
||||||
@@ -1598,6 +1606,7 @@ dependencies = [
|
|||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"task",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"validator-client",
|
"validator-client",
|
||||||
@@ -2863,7 +2872,6 @@ dependencies = [
|
|||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"fixed",
|
"fixed",
|
||||||
"log",
|
"log",
|
||||||
"network-defaults",
|
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
@@ -2960,6 +2968,7 @@ name = "network-defaults"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
|
"dotenv",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -3049,7 +3058,7 @@ dependencies = [
|
|||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.34.0",
|
"clap 3.2.8",
|
||||||
"client-core",
|
"client-core",
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
"config",
|
"config",
|
||||||
@@ -3057,7 +3066,6 @@ dependencies = [
|
|||||||
"credentials",
|
"credentials",
|
||||||
"crypto",
|
"crypto",
|
||||||
"dirs",
|
"dirs",
|
||||||
"dotenv",
|
|
||||||
"futures",
|
"futures",
|
||||||
"gateway-client",
|
"gateway-client",
|
||||||
"gateway-requests",
|
"gateway-requests",
|
||||||
@@ -3089,7 +3097,7 @@ dependencies = [
|
|||||||
"bandwidth-claim-contract",
|
"bandwidth-claim-contract",
|
||||||
"bip39",
|
"bip39",
|
||||||
"bs58",
|
"bs58",
|
||||||
"clap 3.1.8",
|
"clap 3.2.8",
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
"colored",
|
"colored",
|
||||||
"config",
|
"config",
|
||||||
@@ -3134,7 +3142,7 @@ version = "1.0.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bs58",
|
"bs58",
|
||||||
"clap 3.1.8",
|
"clap 3.2.8",
|
||||||
"colored",
|
"colored",
|
||||||
"config",
|
"config",
|
||||||
"crypto",
|
"crypto",
|
||||||
@@ -3216,7 +3224,7 @@ dependencies = [
|
|||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.34.0",
|
"clap 3.2.8",
|
||||||
"client-core",
|
"client-core",
|
||||||
"coconut-interface",
|
"coconut-interface",
|
||||||
"config",
|
"config",
|
||||||
@@ -3224,7 +3232,6 @@ dependencies = [
|
|||||||
"credentials",
|
"credentials",
|
||||||
"crypto",
|
"crypto",
|
||||||
"dirs",
|
"dirs",
|
||||||
"dotenv",
|
|
||||||
"futures",
|
"futures",
|
||||||
"gateway-client",
|
"gateway-client",
|
||||||
"gateway-requests",
|
"gateway-requests",
|
||||||
@@ -3291,6 +3298,8 @@ dependencies = [
|
|||||||
"credential-storage",
|
"credential-storage",
|
||||||
"credentials",
|
"credentials",
|
||||||
"crypto",
|
"crypto",
|
||||||
|
"cw-utils",
|
||||||
|
"cw3",
|
||||||
"dirs",
|
"dirs",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -3500,9 +3509,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.10.0"
|
version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
|
checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oorandom"
|
name = "oorandom"
|
||||||
@@ -3567,9 +3576,6 @@ name = "os_str_bytes"
|
|||||||
version = "6.0.0"
|
version = "6.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pairing"
|
name = "pairing"
|
||||||
@@ -5383,7 +5389,6 @@ version = "1.0.1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"log",
|
"log",
|
||||||
"network-defaults",
|
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -6331,7 +6336,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||||||
name = "vesting-contract"
|
name = "vesting-contract"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus",
|
"cw-storage-plus",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
|
|||||||
+1
-1
@@ -81,4 +81,4 @@ default-members = [
|
|||||||
"explorer-api",
|
"explorer-api",
|
||||||
]
|
]
|
||||||
|
|
||||||
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly", "nym-wallet"]
|
exclude = ["explorer", "contracts", "tokenomics-py", "clients/webassembly", "nym-wallet", "nym-connect"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
test: clippy-all cargo-test wasm fmt
|
||||||
test-all: test cargo-test-expensive
|
test-all: test cargo-test-expensive
|
||||||
test: build clippy-all cargo-test wasm fmt
|
|
||||||
no-clippy: build cargo-test wasm fmt
|
no-clippy: build cargo-test wasm fmt
|
||||||
happy: fmt clippy-happy test
|
happy: fmt clippy-happy test
|
||||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
|
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet clippy-all-connect
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ The platform is composed of multiple Rust crates. Top-level executable binary cr
|
|||||||
|
|
||||||
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
* nym-mixnode - shuffles [Sphinx](https://github.com/nymtech/sphinx) packets together to provide privacy against network-level attackers.
|
||||||
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
* nym-client - an executable which you can build into your own applications. Use it for interacting with Nym nodes.
|
||||||
* nym-socks5-client - a Socks5 proxy you can run on your machine, and use with existing applications
|
* nym-socks5-client - a Socks5 proxy you can run on your machine and use with existing applications.
|
||||||
* nym-gateway - acts sort of like a mailbox for mixnet messages, removing the need for directly delivery to potentially offline or firewalled devices.
|
* nym-gateway - acts sort of like a mailbox for mixnet messages, which removes the need for direct delivery to potentially offline or firewalled devices.
|
||||||
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
* nym-network-monitor - sends packets through the full system to check that they are working as expected, and stores node uptime histories as the basis of a rewards system ("mixmining" or "proof-of-mixing").
|
||||||
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
* nym-explorer - a (projected) block explorer and (existing) mixnet viewer.
|
||||||
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
* nym-wallet - a desktop wallet implemented using the [Tauri](https://tauri.studio/en/docs/about/intro) framework.
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use config::defaults::*;
|
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
@@ -366,7 +365,7 @@ impl<T: NymConfig> Default for Client<T> {
|
|||||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||||
id: "".to_string(),
|
id: "".to_string(),
|
||||||
disabled_credentials_mode: true,
|
disabled_credentials_mode: true,
|
||||||
validator_api_urls: default_api_endpoints(),
|
validator_api_urls: vec![],
|
||||||
private_identity_key_file: Default::default(),
|
private_identity_key_file: Default::default(),
|
||||||
public_identity_key_file: Default::default(),
|
public_identity_key_file: Default::default(),
|
||||||
private_encryption_key_file: Default::default(),
|
private_encryption_key_file: Default::default(),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::{MNEMONIC, NYMD_URL};
|
use crate::{MNEMONIC, NYMD_URL};
|
||||||
use bip39::Mnemonic;
|
use bip39::Mnemonic;
|
||||||
use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
|
use network_defaults::{NymNetworkDetails, VOUCHER_INFO};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_client::nymd;
|
use validator_client::nymd;
|
||||||
@@ -13,18 +13,23 @@ use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
|
|||||||
|
|
||||||
pub(crate) struct Client {
|
pub(crate) struct Client {
|
||||||
nymd_client: NymdClient<SigningNymdClient>,
|
nymd_client: NymdClient<SigningNymdClient>,
|
||||||
|
mix_denom_base: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let nymd_url = Url::from_str(NYMD_URL).unwrap();
|
let nymd_url = Url::from_str(NYMD_URL).unwrap();
|
||||||
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
|
let mnemonic = Mnemonic::from_str(MNEMONIC).unwrap();
|
||||||
let config = nymd::Config::try_from_nym_network_details(&DEFAULT_NETWORK.details())
|
let network_details = NymNetworkDetails::new_from_env();
|
||||||
|
let config = nymd::Config::try_from_nym_network_details(&network_details)
|
||||||
.expect("failed to construct valid validator client config with the provided network");
|
.expect("failed to construct valid validator client config with the provided network");
|
||||||
let nymd_client =
|
let nymd_client =
|
||||||
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
|
NymdClient::connect_with_mnemonic(config, nymd_url.as_ref(), mnemonic, None).unwrap();
|
||||||
|
|
||||||
Client { nymd_client }
|
Client {
|
||||||
|
nymd_client,
|
||||||
|
mix_denom_base: network_details.chain_details.mix_denom.base,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn deposit(
|
pub async fn deposit(
|
||||||
@@ -34,7 +39,7 @@ impl Client {
|
|||||||
encryption_key: String,
|
encryption_key: String,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
|
let amount = Coin::new(amount as u128, self.mix_denom_base.clone());
|
||||||
Ok(self
|
Ok(self
|
||||||
.nymd_client
|
.nymd_client
|
||||||
.deposit(
|
.deposit(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name = "nym-client"
|
name = "nym-client"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>", "Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
|
description = "Implementation of the Nym Client"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.56"
|
||||||
|
|
||||||
@@ -19,9 +20,8 @@ futures = "0.3" # bunch of futures stuff, however, now that I think about it, it
|
|||||||
# and the single instance of abortable we have should really be refactored anyway
|
# and the single instance of abortable we have should really be refactored anyway
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
clap = "2.33.0" # for the command line arguments
|
clap = { version = "3.2.8", features = ["cargo", "derive"] }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
dotenv = "0.15.0" # for obtaining environmental variables (only used for RUST_LOG for time being)
|
|
||||||
log = "0.4" # self explanatory
|
log = "0.4" # self explanatory
|
||||||
pretty_env_logger = "0.4" # for formatting log messages
|
pretty_env_logger = "0.4" # for formatting log messages
|
||||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
|
rand = { version = "0.7.3", features = ["wasm-bindgen"] } # rng-related traits + some rng implementation to use
|
||||||
|
|||||||
@@ -1,88 +1,100 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{App, Arg, ArgMatches};
|
use clap::Args;
|
||||||
use client_core::config::GatewayEndpoint;
|
use client_core::config::GatewayEndpoint;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::{
|
||||||
use crate::commands::override_config;
|
client::config::Config,
|
||||||
#[cfg(feature = "eth")]
|
commands::{override_config, OverrideConfig},
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
use crate::commands::{
|
|
||||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ENABLED_CREDENTIALS_MODE_ARG_NAME,
|
|
||||||
ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
let app = App::new("init")
|
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
|
||||||
.about("Initialise a Nym client. Do this first!")
|
|
||||||
.arg(Arg::with_name("id")
|
|
||||||
.long("id")
|
|
||||||
.help("Id of the nym-mixnet-client we want to create config for.")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("gateway")
|
|
||||||
.long("gateway")
|
|
||||||
.help("Id of the gateway we are going to connect to.")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("force-register-gateway")
|
|
||||||
.long("force-register-gateway")
|
|
||||||
.help("Force register gateway. WARNING: this will overwrite any existing keys for the given id, potentially causing loss of access.")
|
|
||||||
.takes_value(false)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("validators")
|
|
||||||
.long("validators")
|
|
||||||
.help("Comma separated list of rest endpoints of the validators")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("disable-socket")
|
|
||||||
.long("disable-socket")
|
|
||||||
.help("Whether to not start the websocket")
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
|
||||||
.short("p")
|
|
||||||
.long("port")
|
|
||||||
.help("Port for the socket (if applicable) to listen on in all subsequent runs")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("fastmode")
|
|
||||||
.long("fastmode")
|
|
||||||
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
|
||||||
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
|
||||||
);
|
|
||||||
#[cfg(feature = "eth")]
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
let app = app
|
|
||||||
.arg(
|
|
||||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.help("Set this client to work in a disabled credentials mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
|
||||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.long(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true)
|
|
||||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
|
||||||
.required(true))
|
|
||||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true)
|
|
||||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
|
||||||
.required(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
app
|
#[derive(Args, Clone)]
|
||||||
|
pub(crate) struct Init {
|
||||||
|
/// Id of the nym-mixnet-client we want to create config for.
|
||||||
|
#[clap(long)]
|
||||||
|
id: String,
|
||||||
|
|
||||||
|
/// Id of the gateway we are going to connect to.
|
||||||
|
#[clap(long)]
|
||||||
|
gateway: Option<String>,
|
||||||
|
|
||||||
|
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
||||||
|
/// potentially causing loss of access.
|
||||||
|
#[clap(long)]
|
||||||
|
force_register_gateway: bool,
|
||||||
|
|
||||||
|
/// Comma separated list of rest endpoints of the validators
|
||||||
|
#[clap(long)]
|
||||||
|
validators: Option<String>,
|
||||||
|
|
||||||
|
/// Whether to not start the websocket
|
||||||
|
#[clap(long)]
|
||||||
|
disable_socket: bool,
|
||||||
|
|
||||||
|
/// Port for the socket (if applicable) to listen on in all subsequent runs
|
||||||
|
#[clap(short, long)]
|
||||||
|
port: Option<u16>,
|
||||||
|
|
||||||
|
/// Mostly debug-related option to increase default traffic rate so that you would not need to
|
||||||
|
/// modify config post init
|
||||||
|
#[clap(long, hidden = true)]
|
||||||
|
fastmode: bool,
|
||||||
|
|
||||||
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
|
/// --eth-private_key don't need to be set.
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_ENDPOINT))
|
||||||
|
)]
|
||||||
|
eth_endpoint: String,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead")
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_PRIVATE_KEY))
|
||||||
|
)]
|
||||||
|
eth_private_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(matches: ArgMatches<'static>) {
|
impl From<Init> for OverrideConfig {
|
||||||
|
fn from(init_config: Init) -> Self {
|
||||||
|
OverrideConfig {
|
||||||
|
validators: init_config.validators,
|
||||||
|
disable_socket: init_config.disable_socket,
|
||||||
|
port: init_config.port,
|
||||||
|
fastmode: init_config.fastmode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Some(init_config.eth_private_key),
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Some(init_config.eth_endpoint),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn execute(args: &Init) {
|
||||||
println!("Initialising client...");
|
println!("Initialising client...");
|
||||||
|
|
||||||
let id = matches.value_of("id").unwrap(); // required for now
|
let id = &args.id;
|
||||||
|
|
||||||
let already_init = Config::default_config_file_path(Some(id)).exists();
|
let already_init = Config::default_config_file_path(Some(id)).exists();
|
||||||
if already_init {
|
if already_init {
|
||||||
@@ -95,7 +107,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
|||||||
|
|
||||||
// Usually you only register with the gateway on the first init, however you can force
|
// Usually you only register with the gateway on the first init, however you can force
|
||||||
// re-registering if wanted.
|
// re-registering if wanted.
|
||||||
let user_wants_force_register = matches.is_present("force-register-gateway");
|
let user_wants_force_register = args.force_register_gateway;
|
||||||
|
|
||||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
// If the client was already initialized, don't generate new keys and don't re-register with
|
||||||
// the gateway (because this would create a new shared key).
|
// the gateway (because this would create a new shared key).
|
||||||
@@ -103,14 +115,11 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
|||||||
let register_gateway = !already_init || user_wants_force_register;
|
let register_gateway = !already_init || user_wants_force_register;
|
||||||
|
|
||||||
// Attempt to use a user-provided gateway, if possible
|
// Attempt to use a user-provided gateway, if possible
|
||||||
let user_chosen_gateway_id = matches.value_of("gateway");
|
let user_chosen_gateway_id = args.gateway.as_deref();
|
||||||
|
|
||||||
let mut config = Config::new(id);
|
let mut config = Config::new(id);
|
||||||
|
let override_config_fields = OverrideConfig::from(args.clone());
|
||||||
config = override_config(config, &matches);
|
config = override_config(config, override_config_fields);
|
||||||
if matches.is_present("fastmode") {
|
|
||||||
config.get_base_mut().set_high_default_traffic_volume();
|
|
||||||
}
|
|
||||||
|
|
||||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
||||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||||
|
|||||||
@@ -2,14 +2,9 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::{Config, SocketType};
|
use crate::client::config::{Config, SocketType};
|
||||||
use clap::ArgMatches;
|
use clap::{Parser, Subcommand};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub(crate) const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode";
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
||||||
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||||
@@ -21,6 +16,87 @@ pub(crate) mod init;
|
|||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
|
fn long_version() -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
"#,
|
||||||
|
"Build Timestamp:",
|
||||||
|
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
|
"Build Version:",
|
||||||
|
env!("VERGEN_BUILD_SEMVER"),
|
||||||
|
"Commit SHA:",
|
||||||
|
env!("VERGEN_GIT_SHA"),
|
||||||
|
"Commit Date:",
|
||||||
|
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
||||||
|
"Commit Branch:",
|
||||||
|
env!("VERGEN_GIT_BRANCH"),
|
||||||
|
"rustc Version:",
|
||||||
|
env!("VERGEN_RUSTC_SEMVER"),
|
||||||
|
"rustc Channel:",
|
||||||
|
env!("VERGEN_RUSTC_CHANNEL"),
|
||||||
|
"cargo Profile:",
|
||||||
|
env!("VERGEN_CARGO_PROFILE"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn long_version_static() -> &'static str {
|
||||||
|
Box::leak(long_version().into_boxed_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
||||||
|
pub(crate) struct Cli {
|
||||||
|
/// Path pointing to an env file that configures the client.
|
||||||
|
#[clap(long)]
|
||||||
|
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
||||||
|
|
||||||
|
#[clap(subcommand)]
|
||||||
|
command: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
pub(crate) enum Commands {
|
||||||
|
/// Initialise a Nym client. Do this first!
|
||||||
|
Init(init::Init),
|
||||||
|
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||||
|
Run(run::Run),
|
||||||
|
/// Try to upgrade the client
|
||||||
|
Upgrade(upgrade::Upgrade),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration that can be overridden.
|
||||||
|
pub(crate) struct OverrideConfig {
|
||||||
|
validators: Option<String>,
|
||||||
|
disable_socket: bool,
|
||||||
|
port: Option<u16>,
|
||||||
|
fastmode: bool,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn execute(args: &Cli) {
|
||||||
|
match &args.command {
|
||||||
|
Commands::Init(m) => init::execute(m).await,
|
||||||
|
Commands::Run(m) => run::execute(m).await,
|
||||||
|
Commands::Upgrade(m) => upgrade::execute(m),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_validators(raw: &str) -> Vec<Url> {
|
fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
raw.split(',')
|
raw.split(',')
|
||||||
.map(|raw_validator| {
|
.map(|raw_validator| {
|
||||||
@@ -32,45 +108,64 @@ fn parse_validators(raw: &str) -> Vec<Url> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
||||||
if let Some(raw_validators) = matches.value_of("validators") {
|
if let Some(raw_validators) = args.validators {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_validator_apis(parse_validators(raw_validators));
|
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||||
|
} else if std::env::var(network_defaults::var_names::CONFIGURED).is_ok() {
|
||||||
|
let raw_validators = std::env::var(network_defaults::var_names::API_VALIDATOR)
|
||||||
|
.expect("api validator not set");
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present("disable-socket") {
|
if args.disable_socket {
|
||||||
config = config.with_socket(SocketType::None);
|
config = config.with_socket(SocketType::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(port) = matches.value_of("port").map(str::parse) {
|
if let Some(port) = args.port {
|
||||||
if let Err(err) = port {
|
config = config.with_port(port);
|
||||||
// if port was overridden, it must be parsable
|
}
|
||||||
panic!("Invalid port value provided - {:?}", err);
|
|
||||||
|
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
{
|
||||||
|
if args.enabled_credentials_mode {
|
||||||
|
config.get_base_mut().with_disabled_credentials(false)
|
||||||
|
}
|
||||||
|
if let Some(eth_endpoint) = args.eth_endpoint {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
}
|
||||||
|
if let Some(eth_private_key) = args.eth_private_key {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
}
|
}
|
||||||
config = config.with_port(port.unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
if args.fastmode {
|
||||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
config.get_base_mut().set_high_default_traffic_volume();
|
||||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
|
||||||
} else if !cfg!(feature = "eth") {
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
|
||||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
|
||||||
} else if !cfg!(feature = "eth") {
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
|
|
||||||
config.get_base_mut().with_disabled_credentials(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use clap::CommandFactory;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_cli() {
|
||||||
|
Cli::command().debug_assert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,68 +1,77 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::{
|
||||||
use crate::client::NymClient;
|
client::{config::Config, NymClient},
|
||||||
use crate::commands::override_config;
|
commands::{override_config, OverrideConfig},
|
||||||
#[cfg(feature = "eth")]
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
use crate::commands::{
|
|
||||||
ENABLED_CREDENTIALS_MODE_ARG_NAME, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
|
||||||
};
|
};
|
||||||
use clap::{App, Arg, ArgMatches};
|
|
||||||
|
use clap::Args;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use log::*;
|
use log::*;
|
||||||
use version_checker::is_minor_version_compatible;
|
use version_checker::is_minor_version_compatible;
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
#[derive(Args, Clone)]
|
||||||
let app = App::new("run")
|
pub(crate) struct Run {
|
||||||
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
/// Id of the nym-mixnet-client we want to run.
|
||||||
.arg(Arg::with_name("id")
|
#[clap(long)]
|
||||||
.long("id")
|
id: String,
|
||||||
.help("Id of the nym-mixnet-client we want to run.")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
)
|
|
||||||
// the rest of arguments are optional, they are used to override settings in config file
|
|
||||||
.arg(Arg::with_name("validators")
|
|
||||||
.long("validators")
|
|
||||||
.help("Comma separated list rest rest endpoints of the validators")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("gateway")
|
|
||||||
.long("gateway")
|
|
||||||
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("disable-socket")
|
|
||||||
.long("disable-socket")
|
|
||||||
.help("Whether to not start the websocket")
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
|
||||||
.short("p")
|
|
||||||
.long("port")
|
|
||||||
.help("Port for the socket (if applicable) to listen on")
|
|
||||||
.takes_value(true)
|
|
||||||
);
|
|
||||||
#[cfg(feature = "eth")]
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
let app = app
|
|
||||||
.arg(
|
|
||||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.help("Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
|
||||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.long(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true))
|
|
||||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true));
|
|
||||||
|
|
||||||
app
|
/// Comma separated list of rest endpoints of the validators
|
||||||
|
#[clap(long)]
|
||||||
|
validators: Option<String>,
|
||||||
|
|
||||||
|
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
|
||||||
|
/// ensure prior registration happened
|
||||||
|
#[clap(long)]
|
||||||
|
gateway: Option<String>,
|
||||||
|
|
||||||
|
/// Whether to not start the websocket
|
||||||
|
#[clap(long)]
|
||||||
|
disable_socket: bool,
|
||||||
|
|
||||||
|
/// Port for the socket to listen on
|
||||||
|
#[clap(short, long)]
|
||||||
|
port: Option<u16>,
|
||||||
|
|
||||||
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
|
/// --eth-private-key don't need to be set.
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead")
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Run> for OverrideConfig {
|
||||||
|
fn from(run_config: Run) -> Self {
|
||||||
|
OverrideConfig {
|
||||||
|
validators: run_config.validators,
|
||||||
|
disable_socket: run_config.disable_socket,
|
||||||
|
port: run_config.port,
|
||||||
|
fastmode: false,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: run_config.eth_private_key,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: run_config.eth_endpoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this only checks compatibility between config the binary. It does not take into consideration
|
// this only checks compatibility between config the binary. It does not take into consideration
|
||||||
@@ -84,8 +93,8 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(matches: ArgMatches<'static>) {
|
pub(crate) async fn execute(args: &Run) {
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = &args.id;
|
||||||
|
|
||||||
let mut config = match Config::load_from_file(Some(id)) {
|
let mut config = match Config::load_from_file(Some(id)) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
@@ -95,7 +104,8 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
config = override_config(config, &matches);
|
let override_config_fields = OverrideConfig::from(args.clone());
|
||||||
|
config = override_config(config, override_config_fields);
|
||||||
|
|
||||||
if !version_check(&config) {
|
if !version_check(&config) {
|
||||||
error!("failed the local version check");
|
error!("failed the local version check");
|
||||||
|
|||||||
@@ -2,12 +2,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
use clap::{App, Arg, ArgMatches};
|
|
||||||
use config::defaults::default_api_endpoints;
|
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
use version_checker::Version;
|
||||||
|
|
||||||
|
use clap::Args;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::process;
|
use std::process;
|
||||||
use version_checker::Version;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||||
@@ -49,14 +50,11 @@ fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> !
|
|||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
#[derive(Args, Clone)]
|
||||||
App::new("upgrade").about("Try to upgrade the client").arg(
|
pub(crate) struct Upgrade {
|
||||||
Arg::with_name("id")
|
/// Id of the nym-client we want to upgrade
|
||||||
.long("id")
|
#[clap(long)]
|
||||||
.help("Id of the nym-client we want to upgrade")
|
id: String,
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_config_version(config: &Config) -> Version {
|
fn parse_config_version(config: &Config) -> Version {
|
||||||
@@ -95,7 +93,7 @@ fn parse_package_version() -> Version {
|
|||||||
|
|
||||||
fn minor_0_12_upgrade(
|
fn minor_0_12_upgrade(
|
||||||
mut config: Config,
|
mut config: Config,
|
||||||
_matches: &ArgMatches<'_>,
|
_matches: &Upgrade,
|
||||||
config_version: &Version,
|
config_version: &Version,
|
||||||
package_version: &Version,
|
package_version: &Version,
|
||||||
) -> Config {
|
) -> Config {
|
||||||
@@ -107,15 +105,6 @@ fn minor_0_12_upgrade(
|
|||||||
|
|
||||||
print_start_upgrade(&config_version, &to_version);
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
println!(
|
|
||||||
"Setting validator API endpoints to {:?}",
|
|
||||||
default_api_endpoints()
|
|
||||||
);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validator_apis(default_api_endpoints());
|
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
.set_custom_version(to_version.to_string().as_ref());
|
||||||
@@ -131,7 +120,7 @@ fn minor_0_12_upgrade(
|
|||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: &Version) {
|
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
|
||||||
loop {
|
loop {
|
||||||
let config_version = parse_config_version(&config);
|
let config_version = parse_config_version(&config);
|
||||||
|
|
||||||
@@ -143,7 +132,7 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: &Ve
|
|||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 | 10 => outdated_upgrade(&config_version, package_version),
|
9 | 10 => outdated_upgrade(&config_version, package_version),
|
||||||
11 => minor_0_12_upgrade(config, matches, &config_version, package_version),
|
11 => minor_0_12_upgrade(config, args, &config_version, package_version),
|
||||||
_ => unsupported_upgrade(&config_version, package_version),
|
_ => unsupported_upgrade(&config_version, package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(&config_version, package_version),
|
_ => unsupported_upgrade(&config_version, package_version),
|
||||||
@@ -151,10 +140,10 @@ fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: &Ve
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(matches: &ArgMatches<'_>) {
|
pub(crate) fn execute(args: &Upgrade) {
|
||||||
let package_version = parse_package_version();
|
let package_version = parse_package_version();
|
||||||
|
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = &args.id;
|
||||||
|
|
||||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||||
eprintln!("failed to load existing config file! - {:?}", err);
|
eprintln!("failed to load existing config file! - {:?}", err);
|
||||||
@@ -167,5 +156,5 @@ pub fn execute(matches: &ArgMatches<'_>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||||
do_upgrade(existing_config, matches, &package_version)
|
do_upgrade(existing_config, args, &package_version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{crate_version, App, ArgMatches};
|
use clap::{crate_version, Parser};
|
||||||
use network_defaults::DEFAULT_NETWORK;
|
use network_defaults::setup_env;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
@@ -10,34 +10,12 @@ pub mod websocket;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
dotenv::dotenv().ok();
|
|
||||||
setup_logging();
|
setup_logging();
|
||||||
println!("{}", banner());
|
println!("{}", banner());
|
||||||
|
|
||||||
let arg_matches = App::new("Nym Client")
|
let args = commands::Cli::parse();
|
||||||
.version(crate_version!())
|
setup_env(args.config_env_file.clone());
|
||||||
.long_version(&*long_version())
|
commands::execute(&args).await;
|
||||||
.author("Nymtech")
|
|
||||||
.about("Implementation of the Nym Client")
|
|
||||||
.subcommand(commands::init::command_args())
|
|
||||||
.subcommand(commands::run::command_args())
|
|
||||||
.subcommand(commands::upgrade::command_args())
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
execute(arg_matches).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn execute(matches: ArgMatches<'static>) {
|
|
||||||
match matches.subcommand() {
|
|
||||||
("init", Some(m)) => commands::init::execute(m.clone()).await,
|
|
||||||
("run", Some(m)) => commands::run::execute(m.clone()).await,
|
|
||||||
("upgrade", Some(m)) => commands::upgrade::execute(m),
|
|
||||||
_ => println!("{}", usage()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage() -> &'static str {
|
|
||||||
"usage: --help to see available options.\n\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn banner() -> String {
|
fn banner() -> String {
|
||||||
@@ -57,40 +35,6 @@ fn banner() -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn long_version() -> String {
|
|
||||||
format!(
|
|
||||||
r#"
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
"#,
|
|
||||||
"Build Timestamp:",
|
|
||||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
|
||||||
"Build Version:",
|
|
||||||
env!("VERGEN_BUILD_SEMVER"),
|
|
||||||
"Commit SHA:",
|
|
||||||
env!("VERGEN_GIT_SHA"),
|
|
||||||
"Commit Date:",
|
|
||||||
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
|
||||||
"Commit Branch:",
|
|
||||||
env!("VERGEN_GIT_BRANCH"),
|
|
||||||
"rustc Version:",
|
|
||||||
env!("VERGEN_RUSTC_SEMVER"),
|
|
||||||
"rustc Channel:",
|
|
||||||
env!("VERGEN_RUSTC_CHANNEL"),
|
|
||||||
"cargo Profile:",
|
|
||||||
env!("VERGEN_CARGO_PROFILE"),
|
|
||||||
"Network:",
|
|
||||||
DEFAULT_NETWORK
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_logging() {
|
fn setup_logging() {
|
||||||
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
||||||
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
name = "nym-socks5-client"
|
name = "nym-socks5-client"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
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"
|
edition = "2021"
|
||||||
rust-version = "1.56"
|
rust-version = "1.56"
|
||||||
|
|
||||||
@@ -10,9 +11,8 @@ name = "nym_socks5"
|
|||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = "2.33.0"
|
clap = { version = "3.2.8", features = ["cargo", "derive"] }
|
||||||
dirs = "4.0"
|
dirs = "4.0"
|
||||||
dotenv = "0.15.0"
|
|
||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pin-project = "1.0"
|
pin-project = "1.0"
|
||||||
|
|||||||
@@ -287,12 +287,15 @@ impl NymClient {
|
|||||||
pub async fn run_and_listen(&mut self, mut receiver: Socks5ControlMessageReceiver) {
|
pub async fn run_and_listen(&mut self, mut receiver: Socks5ControlMessageReceiver) {
|
||||||
self.start().await;
|
self.start().await;
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
message = receiver.next() => match message {
|
message = receiver.next() => {
|
||||||
Some(Socks5ControlMessage::Stop) => {
|
log::debug!("Received message: {:?}", message);
|
||||||
log::info!("Received: {:?}", message);
|
match message {
|
||||||
log::info!("Shutting down");
|
Some(Socks5ControlMessage::Stop) => {
|
||||||
|
log::info!("Shutting down");
|
||||||
|
log::info!("Graceful shutdown of tasks not yet implemented, you might see (harmless) panics until then");
|
||||||
|
}
|
||||||
|
None => log::debug!("None"),
|
||||||
}
|
}
|
||||||
None => log::info!("none"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,100 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{App, Arg, ArgMatches};
|
use clap::Args;
|
||||||
use client_core::config::GatewayEndpoint;
|
use client_core::config::GatewayEndpoint;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::{
|
||||||
use crate::commands::override_config;
|
client::config::Config,
|
||||||
#[cfg(feature = "eth")]
|
commands::{override_config, OverrideConfig},
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
use crate::commands::{
|
|
||||||
DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY, ENABLED_CREDENTIALS_MODE_ARG_NAME,
|
|
||||||
ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
let app = App::new("init")
|
use crate::commands::{DEFAULT_ETH_ENDPOINT, DEFAULT_ETH_PRIVATE_KEY};
|
||||||
.about("Initialise a Nym client. Do this first!")
|
|
||||||
.arg(Arg::with_name("id")
|
|
||||||
.long("id")
|
|
||||||
.help("Id of the nym-mixnet-client we want to create config for.")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("provider")
|
|
||||||
.long("provider")
|
|
||||||
.help("Address of the socks5 provider to send messages to.")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("gateway")
|
|
||||||
.long("gateway")
|
|
||||||
.help("Id of the gateway we are going to connect to.")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("force-register-gateway")
|
|
||||||
.long("force-register-gateway")
|
|
||||||
.help("Force register gateway. WARNING: this will overwrite any existing keys for the given id, potentially causing loss of access.")
|
|
||||||
.takes_value(false)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("validators")
|
|
||||||
.long("validators")
|
|
||||||
.help("Comma separated list of rest endpoints of the validators")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
|
||||||
.short("p")
|
|
||||||
.long("port")
|
|
||||||
.help("Port for the socket to listen on in all subsequent runs")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("fastmode")
|
|
||||||
.long("fastmode")
|
|
||||||
.hidden(true) // this will prevent this flag from being displayed in `--help`
|
|
||||||
.help("Mostly debug-related option to increase default traffic rate so that you would not need to modify config post init")
|
|
||||||
);
|
|
||||||
#[cfg(feature = "eth")]
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
let app = app
|
|
||||||
.arg(
|
|
||||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.help("Set this client to work in a enabled credentials mode that would attempt to use gateway with bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
|
||||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.long(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true)
|
|
||||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_ENDPOINT)
|
|
||||||
.required(true))
|
|
||||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true)
|
|
||||||
.default_value_if(ENABLED_CREDENTIALS_MODE_ARG_NAME, None, DEFAULT_ETH_PRIVATE_KEY)
|
|
||||||
.required(true)
|
|
||||||
);
|
|
||||||
|
|
||||||
app
|
#[derive(Args, Clone)]
|
||||||
|
pub(crate) struct Init {
|
||||||
|
/// Id of the nym-mixnet-client we want to create config for.
|
||||||
|
#[clap(long)]
|
||||||
|
id: String,
|
||||||
|
|
||||||
|
/// Address of the socks5 provider to send messages to.
|
||||||
|
#[clap(long)]
|
||||||
|
provider: String,
|
||||||
|
|
||||||
|
/// Id of the gateway we are going to connect to.
|
||||||
|
#[clap(long)]
|
||||||
|
gateway: Option<String>,
|
||||||
|
|
||||||
|
/// Force register gateway. WARNING: this will overwrite any existing keys for the given id,
|
||||||
|
/// potentially causing loss of access.
|
||||||
|
#[clap(long)]
|
||||||
|
force_register_gateway: bool,
|
||||||
|
|
||||||
|
/// Comma separated list of rest endpoints of the validators
|
||||||
|
#[clap(long)]
|
||||||
|
validators: Option<String>,
|
||||||
|
|
||||||
|
/// Port for the socket to listen on in all subsequent runs
|
||||||
|
#[clap(short, long)]
|
||||||
|
port: Option<u16>,
|
||||||
|
|
||||||
|
/// Mostly debug-related option to increase default traffic rate so that you would not need to
|
||||||
|
/// modify config post init
|
||||||
|
#[clap(long, hidden = true)]
|
||||||
|
fastmode: bool,
|
||||||
|
|
||||||
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
|
/// --eth-private_key don't need to be set.
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_ENDPOINT))
|
||||||
|
)]
|
||||||
|
eth_endpoint: String,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead")
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(
|
||||||
|
long,
|
||||||
|
default_value_if("enabled-credentials-mode", None, Some(DEFAULT_ETH_PRIVATE_KEY))
|
||||||
|
)]
|
||||||
|
eth_private_key: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(matches: ArgMatches<'static>) {
|
impl From<Init> for OverrideConfig {
|
||||||
|
fn from(init_config: Init) -> Self {
|
||||||
|
OverrideConfig {
|
||||||
|
validators: init_config.validators,
|
||||||
|
port: init_config.port,
|
||||||
|
fastmode: init_config.fastmode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
enabled_credentials_mode: init_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Some(init_config.eth_private_key),
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Some(init_config.eth_endpoint),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn execute(args: &Init) {
|
||||||
println!("Initialising client...");
|
println!("Initialising client...");
|
||||||
|
|
||||||
let id = matches.value_of("id").unwrap(); // required for now
|
let id = &args.id;
|
||||||
let provider_address = matches.value_of("provider").unwrap();
|
let provider_address = &args.provider;
|
||||||
|
|
||||||
let already_init = Config::default_config_file_path(Some(id)).exists();
|
let already_init = Config::default_config_file_path(Some(id)).exists();
|
||||||
if already_init {
|
if already_init {
|
||||||
@@ -98,7 +107,7 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
|||||||
|
|
||||||
// Usually you only register with the gateway on the first init, however you can force
|
// Usually you only register with the gateway on the first init, however you can force
|
||||||
// re-registering if wanted.
|
// re-registering if wanted.
|
||||||
let user_wants_force_register = matches.is_present("force-register-gateway");
|
let user_wants_force_register = args.force_register_gateway;
|
||||||
|
|
||||||
// If the client was already initialized, don't generate new keys and don't re-register with
|
// If the client was already initialized, don't generate new keys and don't re-register with
|
||||||
// the gateway (because this would create a new shared key).
|
// the gateway (because this would create a new shared key).
|
||||||
@@ -106,14 +115,11 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
|||||||
let register_gateway = !already_init || user_wants_force_register;
|
let register_gateway = !already_init || user_wants_force_register;
|
||||||
|
|
||||||
// Attempt to use a user-provided gateway, if possible
|
// Attempt to use a user-provided gateway, if possible
|
||||||
let user_chosen_gateway_id = matches.value_of("gateway");
|
let user_chosen_gateway_id = args.gateway.as_deref();
|
||||||
|
|
||||||
let mut config = Config::new(id, provider_address);
|
let mut config = Config::new(id, provider_address);
|
||||||
|
let override_config_fields = OverrideConfig::from(args.clone());
|
||||||
config = override_config(config, &matches);
|
config = override_config(config, override_config_fields);
|
||||||
if matches.is_present("fastmode") {
|
|
||||||
config.get_base_mut().set_high_default_traffic_volume();
|
|
||||||
}
|
|
||||||
|
|
||||||
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
let gateway = setup_gateway(id, register_gateway, user_chosen_gateway_id, &config).await;
|
||||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||||
|
|||||||
@@ -2,18 +2,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::client::config::Config;
|
||||||
use clap::ArgMatches;
|
use clap::{Parser, Subcommand};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub(crate) mod run;
|
pub(crate) mod run;
|
||||||
pub(crate) mod upgrade;
|
pub(crate) mod upgrade;
|
||||||
|
|
||||||
pub(crate) const ENABLED_CREDENTIALS_MODE_ARG_NAME: &str = "enabled-credentials-mode";
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
pub(crate) const ETH_ENDPOINT_ARG_NAME: &str = "eth_endpoint";
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
pub(crate) const ETH_PRIVATE_KEY_ARG_NAME: &str = "eth_private_key";
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
#[cfg(not(feature = "coconut"))]
|
||||||
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
||||||
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
"https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||||
@@ -21,7 +16,87 @@ pub(crate) const DEFAULT_ETH_ENDPOINT: &str =
|
|||||||
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
|
pub(crate) const DEFAULT_ETH_PRIVATE_KEY: &str =
|
||||||
"0000000000000000000000000000000000000000000000000000000000000001";
|
"0000000000000000000000000000000000000000000000000000000000000001";
|
||||||
|
|
||||||
fn parse_validators(raw: &str) -> Vec<Url> {
|
fn long_version() -> String {
|
||||||
|
format!(
|
||||||
|
r#"
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
{:<20}{}
|
||||||
|
"#,
|
||||||
|
"Build Timestamp:",
|
||||||
|
env!("VERGEN_BUILD_TIMESTAMP"),
|
||||||
|
"Build Version:",
|
||||||
|
env!("VERGEN_BUILD_SEMVER"),
|
||||||
|
"Commit SHA:",
|
||||||
|
env!("VERGEN_GIT_SHA"),
|
||||||
|
"Commit Date:",
|
||||||
|
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
||||||
|
"Commit Branch:",
|
||||||
|
env!("VERGEN_GIT_BRANCH"),
|
||||||
|
"rustc Version:",
|
||||||
|
env!("VERGEN_RUSTC_SEMVER"),
|
||||||
|
"rustc Channel:",
|
||||||
|
env!("VERGEN_RUSTC_CHANNEL"),
|
||||||
|
"cargo Profile:",
|
||||||
|
env!("VERGEN_CARGO_PROFILE"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn long_version_static() -> &'static str {
|
||||||
|
Box::leak(long_version().into_boxed_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
#[clap(author = "Nymtech", version, long_version = long_version_static(), about)]
|
||||||
|
pub(crate) struct Cli {
|
||||||
|
/// Path pointing to an env file that configures the client.
|
||||||
|
#[clap(long)]
|
||||||
|
pub(crate) config_env_file: Option<std::path::PathBuf>,
|
||||||
|
|
||||||
|
#[clap(subcommand)]
|
||||||
|
command: Commands,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Subcommand)]
|
||||||
|
pub(crate) enum Commands {
|
||||||
|
/// Initialise a Nym client. Do this first!
|
||||||
|
Init(init::Init),
|
||||||
|
/// Run the Nym client with provided configuration client optionally overriding set parameters
|
||||||
|
Run(run::Run),
|
||||||
|
/// Try to upgrade the client
|
||||||
|
Upgrade(upgrade::Upgrade),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configuration that can be overridden.
|
||||||
|
pub(crate) struct OverrideConfig {
|
||||||
|
validators: Option<String>,
|
||||||
|
port: Option<u16>,
|
||||||
|
fastmode: bool,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn execute(args: &Cli) {
|
||||||
|
match &args.command {
|
||||||
|
Commands::Init(m) => init::execute(m).await,
|
||||||
|
Commands::Run(m) => run::execute(m).await,
|
||||||
|
Commands::Upgrade(m) => upgrade::execute(m),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_validators(raw: &str) -> Vec<Url> {
|
||||||
raw.split(',')
|
raw.split(',')
|
||||||
.map(|raw_validator| {
|
.map(|raw_validator| {
|
||||||
raw_validator
|
raw_validator
|
||||||
@@ -32,41 +107,58 @@ fn parse_validators(raw: &str) -> Vec<Url> {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn override_config(mut config: Config, matches: &ArgMatches<'_>) -> Config {
|
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
|
||||||
if let Some(raw_validators) = matches.value_of("validators") {
|
if let Some(raw_validators) = args.validators {
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_validator_apis(parse_validators(raw_validators));
|
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||||
|
} else if let Ok(raw_validators) = std::env::var(network_defaults::var_names::API_VALIDATOR) {
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.set_custom_validator_apis(parse_validators(&raw_validators));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(port) = matches.value_of("port").map(|port| port.parse::<u16>()) {
|
if let Some(port) = args.port {
|
||||||
if let Err(err) = port {
|
config = config.with_port(port);
|
||||||
// if port was overridden, it must be parsable
|
}
|
||||||
panic!("Invalid port value provided - {:?}", err);
|
|
||||||
|
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||||
|
{
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT.to_string());
|
||||||
|
config
|
||||||
|
.get_base_mut()
|
||||||
|
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
{
|
||||||
|
if args.enabled_credentials_mode {
|
||||||
|
config.get_base_mut().with_disabled_credentials(false)
|
||||||
|
}
|
||||||
|
if let Some(eth_endpoint) = args.eth_endpoint {
|
||||||
|
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
||||||
|
}
|
||||||
|
if let Some(eth_private_key) = args.eth_private_key {
|
||||||
|
config.get_base_mut().with_eth_private_key(eth_private_key);
|
||||||
}
|
}
|
||||||
config = config.with_port(port.unwrap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
if args.fastmode {
|
||||||
if let Some(eth_endpoint) = matches.value_of(ETH_ENDPOINT_ARG_NAME) {
|
config.get_base_mut().set_high_default_traffic_volume();
|
||||||
config.get_base_mut().with_eth_endpoint(eth_endpoint);
|
|
||||||
} else if !cfg!(feature = "eth") {
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.with_eth_endpoint(DEFAULT_ETH_ENDPOINT);
|
|
||||||
}
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
if let Some(eth_private_key) = matches.value_of(ETH_PRIVATE_KEY_ARG_NAME) {
|
|
||||||
config.get_base_mut().with_eth_private_key(eth_private_key);
|
|
||||||
} else if !cfg!(feature = "eth") {
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
|
||||||
}
|
|
||||||
|
|
||||||
if matches.is_present(ENABLED_CREDENTIALS_MODE_ARG_NAME) {
|
|
||||||
config.get_base_mut().with_disabled_credentials(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use clap::CommandFactory;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn verify_cli() {
|
||||||
|
Cli::command().debug_assert();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,74 +1,80 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::Config;
|
use crate::{
|
||||||
use crate::client::NymClient;
|
client::{config::Config, NymClient},
|
||||||
use crate::commands::override_config;
|
commands::{override_config, OverrideConfig},
|
||||||
#[cfg(feature = "eth")]
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
use crate::commands::{
|
|
||||||
ENABLED_CREDENTIALS_MODE_ARG_NAME, ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME,
|
|
||||||
};
|
};
|
||||||
use clap::{App, Arg, ArgMatches};
|
|
||||||
|
use clap::Args;
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use log::*;
|
use log::*;
|
||||||
use version_checker::is_minor_version_compatible;
|
use version_checker::is_minor_version_compatible;
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
#[derive(Args, Clone)]
|
||||||
let app = App::new("run")
|
pub(crate) struct Run {
|
||||||
.about("Run the Nym client with provided configuration client optionally overriding set parameters")
|
/// Id of the nym-mixnet-client we want to run.
|
||||||
.arg(Arg::with_name("id")
|
#[clap(long)]
|
||||||
.long("id")
|
id: String,
|
||||||
.help("Id of the nym-mixnet-client we want to run.")
|
|
||||||
.takes_value(true)
|
|
||||||
.required(true)
|
|
||||||
)
|
|
||||||
// the rest of arguments are optional, they are used to override settings in config file
|
|
||||||
.arg(Arg::with_name("config")
|
|
||||||
.long("config")
|
|
||||||
.help("Custom path to the nym-mixnet-client configuration file")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("provider")
|
|
||||||
.long("provider")
|
|
||||||
.help("Address of the socks5 provider to send messages to.")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("gateway")
|
|
||||||
.long("gateway")
|
|
||||||
.help("Id of the gateway we want to connect to. If overridden, it is user's responsibility to ensure prior registration happened")
|
|
||||||
.takes_value(true)
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("validators")
|
|
||||||
.long("validators")
|
|
||||||
.help("Comma separated list of rest endpoints of the validators")
|
|
||||||
.takes_value(true),
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name("port")
|
|
||||||
.short("p")
|
|
||||||
.long("port")
|
|
||||||
.help("Port for the socket to listen on")
|
|
||||||
.takes_value(true)
|
|
||||||
);
|
|
||||||
#[cfg(feature = "eth")]
|
|
||||||
#[cfg(not(feature = "coconut"))]
|
|
||||||
let app = app
|
|
||||||
.arg(
|
|
||||||
Arg::with_name(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.long(ENABLED_CREDENTIALS_MODE_ARG_NAME)
|
|
||||||
.help("Set this client to work in a disabled credentials mode that would attempt to use gateway without bandwidth credential requirement. If this value is set, --eth_endpoint and --eth_private_key don't need to be set.")
|
|
||||||
.conflicts_with_all(&[ETH_ENDPOINT_ARG_NAME, ETH_PRIVATE_KEY_ARG_NAME])
|
|
||||||
)
|
|
||||||
.arg(Arg::with_name(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.long(ETH_ENDPOINT_ARG_NAME)
|
|
||||||
.help("URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true))
|
|
||||||
.arg(Arg::with_name(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.long(ETH_PRIVATE_KEY_ARG_NAME)
|
|
||||||
.help("Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't want to set this value, use --testnet-mode instead")
|
|
||||||
.takes_value(true));
|
|
||||||
|
|
||||||
app
|
/// Custom path to the nym-mixnet-client configuration file
|
||||||
|
#[clap(long)]
|
||||||
|
config: Option<String>,
|
||||||
|
|
||||||
|
/// Address of the socks5 provider to send messages to.
|
||||||
|
#[clap(long)]
|
||||||
|
provider: Option<String>,
|
||||||
|
|
||||||
|
/// Id of the gateway we want to connect to. If overridden, it is user's responsibility to
|
||||||
|
/// ensure prior registration happened
|
||||||
|
#[clap(long)]
|
||||||
|
gateway: Option<String>,
|
||||||
|
|
||||||
|
/// Comma separated list of rest endpoints of the validators
|
||||||
|
#[clap(long)]
|
||||||
|
validators: Option<String>,
|
||||||
|
|
||||||
|
/// Port for the socket to listen on
|
||||||
|
#[clap(short, long)]
|
||||||
|
port: Option<u16>,
|
||||||
|
|
||||||
|
/// Set this client to work in a enabled credentials mode that would attempt to use gateway
|
||||||
|
/// with bandwidth credential requirement. If this value is set, --eth-endpoint and
|
||||||
|
/// --eth-private-key don't need to be set.
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long, conflicts_with_all = &["eth-endpoint", "eth-private-key"])]
|
||||||
|
enabled_credentials_mode: bool,
|
||||||
|
|
||||||
|
/// URL of an Ethereum full node that we want to use for getting bandwidth tokens from ERC20
|
||||||
|
/// tokens. If you don't want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_endpoint: Option<String>,
|
||||||
|
|
||||||
|
/// Ethereum private key used for obtaining bandwidth tokens from ERC20 tokens. If you don't
|
||||||
|
/// want to set this value, use --enabled-credentials-mode instead
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
#[clap(long)]
|
||||||
|
eth_private_key: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Run> for OverrideConfig {
|
||||||
|
fn from(run_config: Run) -> Self {
|
||||||
|
OverrideConfig {
|
||||||
|
validators: run_config.validators,
|
||||||
|
port: run_config.port,
|
||||||
|
fastmode: false,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
enabled_credentials_mode: run_config.enabled_credentials_mode,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_private_key: run_config.eth_private_key,
|
||||||
|
|
||||||
|
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||||
|
eth_endpoint: run_config.eth_endpoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this only checks compatibility between config the binary. It does not take into consideration
|
// this only checks compatibility between config the binary. It does not take into consideration
|
||||||
@@ -76,8 +82,13 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
|||||||
fn version_check(cfg: &Config) -> bool {
|
fn version_check(cfg: &Config) -> bool {
|
||||||
let binary_version = env!("CARGO_PKG_VERSION");
|
let binary_version = env!("CARGO_PKG_VERSION");
|
||||||
let config_version = cfg.get_base().get_version();
|
let config_version = cfg.get_base().get_version();
|
||||||
if binary_version != config_version {
|
if binary_version == config_version {
|
||||||
warn!("The mixnode binary has different version than what is specified in config file! {} and {}", binary_version, config_version);
|
true
|
||||||
|
} else {
|
||||||
|
warn!(
|
||||||
|
"The mixnode binary has different version than what is specified in config file! {} and {}",
|
||||||
|
binary_version, config_version
|
||||||
|
);
|
||||||
if is_minor_version_compatible(binary_version, config_version) {
|
if is_minor_version_compatible(binary_version, config_version) {
|
||||||
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
info!("but they are still semver compatible. However, consider running the `upgrade` command");
|
||||||
true
|
true
|
||||||
@@ -85,13 +96,11 @@ fn version_check(cfg: &Config) -> bool {
|
|||||||
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
error!("and they are semver incompatible! - please run the `upgrade` command before attempting `run` again");
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(matches: ArgMatches<'static>) {
|
pub(crate) async fn execute(args: &Run) {
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = &args.id;
|
||||||
|
|
||||||
let mut config = match Config::load_from_file(Some(id)) {
|
let mut config = match Config::load_from_file(Some(id)) {
|
||||||
Ok(cfg) => cfg,
|
Ok(cfg) => cfg,
|
||||||
@@ -101,7 +110,8 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
config = override_config(config, &matches);
|
let override_config_fields = OverrideConfig::from(args.clone());
|
||||||
|
config = override_config(config, override_config_fields);
|
||||||
|
|
||||||
if !version_check(&config) {
|
if !version_check(&config) {
|
||||||
error!("failed the local version check");
|
error!("failed the local version check");
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use crate::client::config::{Config, MISSING_VALUE};
|
use crate::client::config::{Config, MISSING_VALUE};
|
||||||
use clap::{App, Arg, ArgMatches};
|
|
||||||
use config::defaults::default_api_endpoints;
|
|
||||||
use config::NymConfig;
|
use config::NymConfig;
|
||||||
use std::fmt::Display;
|
|
||||||
use std::process;
|
|
||||||
use version_checker::Version;
|
use version_checker::Version;
|
||||||
|
|
||||||
|
use clap::Args;
|
||||||
|
use std::{fmt::Display, process};
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
fn fail_upgrade<D1: Display, D2: Display>(from_version: D1, to_version: D2) -> ! {
|
||||||
print_failed_upgrade(from_version, to_version);
|
print_failed_upgrade(from_version, to_version);
|
||||||
@@ -49,14 +49,11 @@ fn unsupported_upgrade(current_version: &Version, config_version: &Version) -> !
|
|||||||
process::exit(1)
|
process::exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn command_args<'a, 'b>() -> App<'a, 'b> {
|
#[derive(Args, Clone)]
|
||||||
App::new("upgrade").about("Try to upgrade the client").arg(
|
pub(crate) struct Upgrade {
|
||||||
Arg::with_name("id")
|
/// Id of the nym-client we want to upgrade
|
||||||
.long("id")
|
#[clap(long)]
|
||||||
.help("Id of the nym-client we want to upgrade")
|
id: String,
|
||||||
.takes_value(true)
|
|
||||||
.required(true),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_config_version(config: &Config) -> Version {
|
fn parse_config_version(config: &Config) -> Version {
|
||||||
@@ -95,7 +92,7 @@ fn parse_package_version() -> Version {
|
|||||||
|
|
||||||
fn minor_0_12_upgrade(
|
fn minor_0_12_upgrade(
|
||||||
mut config: Config,
|
mut config: Config,
|
||||||
_matches: &ArgMatches<'_>,
|
_args: &Upgrade,
|
||||||
config_version: &Version,
|
config_version: &Version,
|
||||||
package_version: &Version,
|
package_version: &Version,
|
||||||
) -> Config {
|
) -> Config {
|
||||||
@@ -107,15 +104,6 @@ fn minor_0_12_upgrade(
|
|||||||
|
|
||||||
print_start_upgrade(&config_version, &to_version);
|
print_start_upgrade(&config_version, &to_version);
|
||||||
|
|
||||||
println!(
|
|
||||||
"Setting validator API endpoints to {:?}",
|
|
||||||
default_api_endpoints()
|
|
||||||
);
|
|
||||||
|
|
||||||
config
|
|
||||||
.get_base_mut()
|
|
||||||
.set_custom_validator_apis(default_api_endpoints());
|
|
||||||
|
|
||||||
config
|
config
|
||||||
.get_base_mut()
|
.get_base_mut()
|
||||||
.set_custom_version(to_version.to_string().as_ref());
|
.set_custom_version(to_version.to_string().as_ref());
|
||||||
@@ -131,30 +119,30 @@ fn minor_0_12_upgrade(
|
|||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
fn do_upgrade(mut config: Config, matches: &ArgMatches<'_>, package_version: Version) {
|
fn do_upgrade(mut config: Config, args: &Upgrade, package_version: &Version) {
|
||||||
loop {
|
loop {
|
||||||
let config_version = parse_config_version(&config);
|
let config_version = parse_config_version(&config);
|
||||||
|
|
||||||
if config_version == package_version {
|
if &config_version == package_version {
|
||||||
println!("You're using the most recent version!");
|
println!("You're using the most recent version!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
config = match config_version.major {
|
config = match config_version.major {
|
||||||
0 => match config_version.minor {
|
0 => match config_version.minor {
|
||||||
9 | 10 => outdated_upgrade(&config_version, &package_version),
|
9 | 10 => outdated_upgrade(&config_version, package_version),
|
||||||
11 => minor_0_12_upgrade(config, matches, &config_version, &package_version),
|
11 => minor_0_12_upgrade(config, args, &config_version, package_version),
|
||||||
_ => unsupported_upgrade(&config_version, &package_version),
|
_ => unsupported_upgrade(&config_version, package_version),
|
||||||
},
|
},
|
||||||
_ => unsupported_upgrade(&config_version, &package_version),
|
_ => unsupported_upgrade(&config_version, package_version),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(matches: &ArgMatches<'_>) {
|
pub(crate) fn execute(args: &Upgrade) {
|
||||||
let package_version = parse_package_version();
|
let package_version = parse_package_version();
|
||||||
|
|
||||||
let id = matches.value_of("id").unwrap();
|
let id = &args.id;
|
||||||
|
|
||||||
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
let existing_config = Config::load_from_file(Some(id)).unwrap_or_else(|err| {
|
||||||
eprintln!("failed to load existing config file! - {:?}", err);
|
eprintln!("failed to load existing config file! - {:?}", err);
|
||||||
@@ -167,5 +155,5 @@ pub fn execute(matches: &ArgMatches<'_>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// here be upgrade path to 0.9.X and beyond based on version number from config
|
// here be upgrade path to 0.9.X and beyond based on version number from config
|
||||||
do_upgrade(existing_config, matches, package_version)
|
do_upgrade(existing_config, args, &package_version)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
use clap::{crate_version, App, ArgMatches};
|
use clap::{crate_version, Parser};
|
||||||
use network_defaults::DEFAULT_NETWORK;
|
use network_defaults::setup_env;
|
||||||
|
|
||||||
pub mod client;
|
pub mod client;
|
||||||
mod commands;
|
mod commands;
|
||||||
@@ -10,34 +10,12 @@ pub mod socks;
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
dotenv::dotenv().ok();
|
|
||||||
setup_logging();
|
setup_logging();
|
||||||
println!("{}", banner());
|
println!("{}", banner());
|
||||||
|
|
||||||
let arg_matches = App::new("Nym Socks5 Proxy")
|
let args = commands::Cli::parse();
|
||||||
.version(env!("CARGO_PKG_VERSION"))
|
setup_env(args.config_env_file.clone());
|
||||||
.author("Nymtech")
|
commands::execute(&args).await;
|
||||||
.long_version(&*long_version())
|
|
||||||
.about("A Socks5 localhost proxy that converts incoming messages to Sphinx and sends them to a Nym address")
|
|
||||||
.subcommand(commands::init::command_args())
|
|
||||||
.subcommand(commands::run::command_args())
|
|
||||||
.subcommand(commands::upgrade::command_args())
|
|
||||||
.get_matches();
|
|
||||||
|
|
||||||
execute(arg_matches).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn execute(matches: ArgMatches<'static>) {
|
|
||||||
match matches.subcommand() {
|
|
||||||
("init", Some(m)) => commands::init::execute(m.clone()).await,
|
|
||||||
("run", Some(m)) => commands::run::execute(m.clone()).await,
|
|
||||||
("upgrade", Some(m)) => commands::upgrade::execute(m),
|
|
||||||
_ => println!("{}", usage()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usage() -> &'static str {
|
|
||||||
"usage: --help to see available options.\n\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn banner() -> String {
|
fn banner() -> String {
|
||||||
@@ -57,40 +35,6 @@ fn banner() -> String {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn long_version() -> String {
|
|
||||||
format!(
|
|
||||||
r#"
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
{:<20}{}
|
|
||||||
"#,
|
|
||||||
"Build Timestamp:",
|
|
||||||
env!("VERGEN_BUILD_TIMESTAMP"),
|
|
||||||
"Build Version:",
|
|
||||||
env!("VERGEN_BUILD_SEMVER"),
|
|
||||||
"Commit SHA:",
|
|
||||||
env!("VERGEN_GIT_SHA"),
|
|
||||||
"Commit Date:",
|
|
||||||
env!("VERGEN_GIT_COMMIT_TIMESTAMP"),
|
|
||||||
"Commit Branch:",
|
|
||||||
env!("VERGEN_GIT_BRANCH"),
|
|
||||||
"rustc Version:",
|
|
||||||
env!("VERGEN_RUSTC_SEMVER"),
|
|
||||||
"rustc Channel:",
|
|
||||||
env!("VERGEN_RUSTC_CHANNEL"),
|
|
||||||
"cargo Profile:",
|
|
||||||
env!("VERGEN_CARGO_PROFILE"),
|
|
||||||
"Network:",
|
|
||||||
DEFAULT_NETWORK
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_logging() {
|
fn setup_logging() {
|
||||||
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
let mut log_builder = pretty_env_logger::formatted_timed_builder();
|
||||||
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
if let Ok(s) = ::std::env::var("RUST_LOG") {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use futures::StreamExt;
|
|||||||
use log::*;
|
use log::*;
|
||||||
use nymsphinx::receiver::ReconstructedMessage;
|
use nymsphinx::receiver::ReconstructedMessage;
|
||||||
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
|
use proxy_helpers::connection_controller::{ControllerCommand, ControllerSender};
|
||||||
use socks5_requests::Response;
|
use socks5_requests::Message;
|
||||||
|
|
||||||
pub(crate) struct MixnetResponseListener {
|
pub(crate) struct MixnetResponseListener {
|
||||||
buffer_requester: ReceivedBufferRequestSender,
|
buffer_requester: ReceivedBufferRequestSender,
|
||||||
@@ -44,12 +44,16 @@ impl MixnetResponseListener {
|
|||||||
warn!("this message had a surb - we didn't do anything with it");
|
warn!("this message had a surb - we didn't do anything with it");
|
||||||
}
|
}
|
||||||
|
|
||||||
let response = match Response::try_from_bytes(&raw_message) {
|
let response = match Message::try_from_bytes(&raw_message) {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("failed to parse received response - {:?}", err);
|
warn!("failed to parse received response - {:?}", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Ok(data) => data,
|
Ok(Message::Request(_)) => {
|
||||||
|
warn!("unexpected request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Ok(Message::Response(data)) => data,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.controller_sender
|
self.controller_sender
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
15.0.1
|
16
|
||||||
@@ -31,9 +31,12 @@
|
|||||||
"eslint-plugin-import": "^2.25.4",
|
"eslint-plugin-import": "^2.25.4",
|
||||||
"eslint-plugin-mocha": "^10.0.3",
|
"eslint-plugin-mocha": "^10.0.3",
|
||||||
"eslint-plugin-prettier": "^4.0.0",
|
"eslint-plugin-prettier": "^4.0.0",
|
||||||
|
"expect": "^28.1.3",
|
||||||
|
"mocha": "^10.0.0",
|
||||||
"prettier": "^2.5.1",
|
"prettier": "^2.5.1",
|
||||||
"typedoc": "^0.22.13",
|
"typedoc": "^0.22.13",
|
||||||
"typescript": "^4.1.3"
|
"ts-mocha": "^10.0.0",
|
||||||
|
"typescript": "^4.6.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cosmjs/cosmwasm-stargate": "^0.28.0",
|
"@cosmjs/cosmwasm-stargate": "^0.28.0",
|
||||||
|
|||||||
@@ -64,23 +64,20 @@ export default class ValidatorClient implements INymClient {
|
|||||||
|
|
||||||
readonly vestingContract: string;
|
readonly vestingContract: string;
|
||||||
|
|
||||||
readonly mainnetDenom = "unym";
|
readonly mainnetDenom = 'unym';
|
||||||
|
|
||||||
readonly mainnetPrefix = "n";
|
readonly mainnetPrefix = 'n';
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
client: SigningClient | QueryClient,
|
client: SigningClient | QueryClient,
|
||||||
prefix: string,
|
prefix: string,
|
||||||
mixnetContract: string,
|
mixnetContract: string,
|
||||||
vestingContract: string
|
vestingContract: string,
|
||||||
|
denom: string,
|
||||||
) {
|
) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.prefix = prefix;
|
this.prefix = prefix;
|
||||||
if (prefix == this.mainnetPrefix) {
|
this.denom = `u${denom}`;
|
||||||
this.denom = this.mainnetDenom;
|
|
||||||
} else {
|
|
||||||
this.denom = `u${prefix}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.mixnetContract = mixnetContract;
|
this.mixnetContract = mixnetContract;
|
||||||
this.vestingContract = vestingContract;
|
this.vestingContract = vestingContract;
|
||||||
@@ -93,11 +90,12 @@ export default class ValidatorClient implements INymClient {
|
|||||||
prefix: string,
|
prefix: string,
|
||||||
mixnetContract: string,
|
mixnetContract: string,
|
||||||
vestingContract: string,
|
vestingContract: string,
|
||||||
|
denom: string,
|
||||||
): Promise<ValidatorClient> {
|
): Promise<ValidatorClient> {
|
||||||
const wallet = await ValidatorClient.buildWallet(mnemonic, prefix);
|
const wallet = await ValidatorClient.buildWallet(mnemonic, prefix);
|
||||||
|
|
||||||
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, validatorApiUrl, prefix);
|
const signingClient = await SigningClient.connectWithNymSigner(wallet, nymdUrl, validatorApiUrl, prefix, denom);
|
||||||
return new ValidatorClient(signingClient, prefix, mixnetContract, vestingContract);
|
return new ValidatorClient(signingClient, prefix, mixnetContract, vestingContract, denom);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async connectForQuery(
|
static async connectForQuery(
|
||||||
@@ -106,9 +104,10 @@ export default class ValidatorClient implements INymClient {
|
|||||||
prefix: string,
|
prefix: string,
|
||||||
mixnetContract: string,
|
mixnetContract: string,
|
||||||
vestingContract: string,
|
vestingContract: string,
|
||||||
|
denom: string,
|
||||||
): Promise<ValidatorClient> {
|
): Promise<ValidatorClient> {
|
||||||
const queryClient = await QueryClient.connectWithNym(nymdUrl, validatorApiUrl);
|
const queryClient = await QueryClient.connectWithNym(nymdUrl, validatorApiUrl);
|
||||||
return new ValidatorClient(queryClient, prefix, mixnetContract, vestingContract);
|
return new ValidatorClient(queryClient, prefix, mixnetContract, vestingContract, denom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get address(): string {
|
public get address(): string {
|
||||||
@@ -457,4 +456,4 @@ export default class ValidatorClient implements INymClient {
|
|||||||
this.assertSigning();
|
this.assertSigning();
|
||||||
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
return (this.client as ISigningClient).updateContractStateParams(this.mixnetContract, newParams, fee, memo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,10 +221,12 @@ export default class SigningClient extends SigningCosmWasmClient implements ISig
|
|||||||
nymdUrl: string,
|
nymdUrl: string,
|
||||||
validatorApiUrl: string,
|
validatorApiUrl: string,
|
||||||
prefix: string,
|
prefix: string,
|
||||||
|
denom: string,
|
||||||
): Promise<SigningClient> {
|
): Promise<SigningClient> {
|
||||||
const [{ address }] = await wallet.getAccounts();
|
const [{ address }] = await wallet.getAccounts();
|
||||||
const signerOptions: SigningCosmWasmClientOptions = {
|
const signerOptions: SigningCosmWasmClientOptions = {
|
||||||
gasPrice: nymGasPrice(prefix),
|
prefix,
|
||||||
|
gasPrice: nymGasPrice(denom),
|
||||||
};
|
};
|
||||||
const tmClient = await Tendermint34Client.connect(nymdUrl);
|
const tmClient = await Tendermint34Client.connect(nymdUrl);
|
||||||
return new SigningClient(address, validatorApiUrl, tmClient, wallet, signerOptions);
|
return new SigningClient(address, validatorApiUrl, tmClient, wallet, signerOptions);
|
||||||
|
|||||||
@@ -7,13 +7,12 @@ const mainnetDenom = 'nym';
|
|||||||
export function nymGasPrice(prefix: string): GasPrice {
|
export function nymGasPrice(prefix: string): GasPrice {
|
||||||
if (typeof prefix === 'string') {
|
if (typeof prefix === 'string') {
|
||||||
if (prefix === mainnetPrefix) {
|
if (prefix === mainnetPrefix) {
|
||||||
prefix = mainnetDenom;
|
return GasPrice.fromString(`0.025u${mainnetDenom}`);
|
||||||
}
|
}
|
||||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
throw new Error(`${prefix} is not of type string`);
|
throw new Error(`${prefix} is not of type string`);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import ValidatorClient from '../../dist';
|
||||||
|
import expect from 'expect';
|
||||||
|
|
||||||
|
describe('Query: balances', () => {
|
||||||
|
it('can query for an account balance', async () => {
|
||||||
|
const client = await ValidatorClient.connectForQuery(
|
||||||
|
'https://rpc.nyx.nodes.guru/', 'https://validator.nymtech.net/api/', 'n', 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g', 'n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw', 'nym');
|
||||||
|
const balance = await client.getBalance('n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy');
|
||||||
|
expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
||||||
|
}).timeout(5000);
|
||||||
|
})
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import ValidatorClient from '../../dist';
|
||||||
|
import expect from 'expect';
|
||||||
|
|
||||||
|
// TODO: implement for QA with .env for mnemonics
|
||||||
|
// describe('Sign: send', () => {
|
||||||
|
// it('can send tokens', async () => {
|
||||||
|
// const client = await ValidatorClient.connect(
|
||||||
|
// '<ADD MNEMONIC HERE>',
|
||||||
|
// 'https://rpc.nyx.nodes.guru/', 'https://validator.nymtech.net/api/', 'n', 'n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g', 'n1nc5tatafv6eyq7llkr2gv50ff9e22mnf70qgjlv737ktmt4eswrq73f2nw', 'nym');
|
||||||
|
// await client.send('<ADD ADDRESS HERE>')
|
||||||
|
// const balance = await client.getBalance('n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy');
|
||||||
|
// expect(Number.parseFloat(balance.amount)).toBeGreaterThan(0);
|
||||||
|
// }).timeout(5000);
|
||||||
|
// })
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"outDir": "./dist"
|
"outDir": "./dist",
|
||||||
|
"skipLibCheck": true
|
||||||
},
|
},
|
||||||
"typedocOptions": {
|
"typedocOptions": {
|
||||||
"entryPoints": [
|
"entryPoints": [
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ validator-api-requests = { path = "../../../validator-api/validator-api-requests
|
|||||||
async-trait = { version = "0.1.51", optional = true }
|
async-trait = { version = "0.1.51", optional = true }
|
||||||
bip39 = { version = "1", features = ["rand"], optional = true }
|
bip39 = { version = "1", features = ["rand"], optional = true }
|
||||||
config = { path = "../../config", optional = true }
|
config = { path = "../../config", optional = true }
|
||||||
cosmrs = { version = "0.7.0", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", features = ["rpc", "bip32", "cosmwasm"], optional = true}
|
||||||
prost = { version = "0.10", default-features = false, optional = true }
|
prost = { version = "0.10", default-features = false, optional = true }
|
||||||
flate2 = { version = "1.0.20", optional = true }
|
flate2 = { version = "1.0.20", optional = true }
|
||||||
sha2 = { version = "0.9.5", optional = true }
|
sha2 = { version = "0.9.5", optional = true }
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use crate::{validator_api, ValidatorClientError};
|
|||||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_api_requests::coconut::{
|
use validator_api_requests::coconut::{
|
||||||
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse, VerificationKeyResponse,
|
||||||
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
|
||||||
VerifyCredentialBody, VerifyCredentialResponse,
|
VerifyCredentialBody, VerifyCredentialResponse,
|
||||||
};
|
};
|
||||||
use validator_api_requests::models::{
|
use validator_api_requests::models::{
|
||||||
@@ -29,7 +28,7 @@ use mixnet_contract_common::{
|
|||||||
RewardedSetUpdateDetails,
|
RewardedSetUpdateDetails,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use network_defaults::{all::Network, NymNetworkDetails};
|
use network_defaults::NymNetworkDetails;
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
@@ -114,9 +113,6 @@ impl Config {
|
|||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
pub struct Client<C> {
|
pub struct Client<C> {
|
||||||
// compatibility : (
|
|
||||||
pub network: Network,
|
|
||||||
|
|
||||||
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
// TODO: we really shouldn't be storing a mnemonic here, but removing it would be
|
||||||
// non-trivial amount of work and it's out of scope of the current branch
|
// non-trivial amount of work and it's out of scope of the current branch
|
||||||
mnemonic: Option<bip39::Mnemonic>,
|
mnemonic: Option<bip39::Mnemonic>,
|
||||||
@@ -135,9 +131,6 @@ pub struct Client<C> {
|
|||||||
impl Client<SigningNymdClient> {
|
impl Client<SigningNymdClient> {
|
||||||
pub fn new_signing(
|
pub fn new_signing(
|
||||||
config: Config,
|
config: Config,
|
||||||
// we need to provide network argument due to compatibility with other components (wallet...)
|
|
||||||
// that rely on its existence...
|
|
||||||
network: Network,
|
|
||||||
mnemonic: bip39::Mnemonic,
|
mnemonic: bip39::Mnemonic,
|
||||||
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
) -> Result<Client<SigningNymdClient>, ValidatorClientError> {
|
||||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||||
@@ -149,7 +142,6 @@ impl Client<SigningNymdClient> {
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
network,
|
|
||||||
mnemonic: Some(mnemonic),
|
mnemonic: Some(mnemonic),
|
||||||
mixnode_page_limit: config.mixnode_page_limit,
|
mixnode_page_limit: config.mixnode_page_limit,
|
||||||
gateway_page_limit: config.gateway_page_limit,
|
gateway_page_limit: config.gateway_page_limit,
|
||||||
@@ -177,18 +169,12 @@ impl Client<SigningNymdClient> {
|
|||||||
|
|
||||||
#[cfg(feature = "nymd-client")]
|
#[cfg(feature = "nymd-client")]
|
||||||
impl Client<QueryNymdClient> {
|
impl Client<QueryNymdClient> {
|
||||||
pub fn new_query(
|
pub fn new_query(config: Config) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
||||||
config: Config,
|
|
||||||
// we need to provide network argument due to compatibility with other components (wallet...)
|
|
||||||
// that rely on its existence...
|
|
||||||
network: Network,
|
|
||||||
) -> Result<Client<QueryNymdClient>, ValidatorClientError> {
|
|
||||||
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
let validator_api_client = validator_api::Client::new(config.api_url.clone());
|
||||||
let nymd_client =
|
let nymd_client =
|
||||||
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
NymdClient::connect(config.nymd_config.clone(), config.nymd_url.as_str())?;
|
||||||
|
|
||||||
Ok(Client {
|
Ok(Client {
|
||||||
network,
|
|
||||||
mnemonic: None,
|
mnemonic: None,
|
||||||
mixnode_page_limit: config.mixnode_page_limit,
|
mixnode_page_limit: config.mixnode_page_limit,
|
||||||
gateway_page_limit: config.gateway_page_limit,
|
gateway_page_limit: config.gateway_page_limit,
|
||||||
@@ -734,6 +720,10 @@ impl ApiClient {
|
|||||||
Ok(self.validator_api.get_coconut_verification_key().await?)
|
Ok(self.validator_api.get_coconut_verification_key().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_cosmos_address(&self) -> Result<CosmosAddressResponse, ValidatorClientError> {
|
||||||
|
Ok(self.validator_api.get_cosmos_address().await?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn verify_bandwidth_credential(
|
pub async fn verify_bandwidth_credential(
|
||||||
&self,
|
&self,
|
||||||
request_body: &VerifyCredentialBody,
|
request_body: &VerifyCredentialBody,
|
||||||
@@ -743,24 +733,4 @@ impl ApiClient {
|
|||||||
.verify_bandwidth_credential(request_body)
|
.verify_bandwidth_credential(request_body)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn propose_release_funds(
|
|
||||||
&self,
|
|
||||||
request_body: &ProposeReleaseFundsRequestBody,
|
|
||||||
) -> Result<ProposeReleaseFundsResponse, ValidatorClientError> {
|
|
||||||
Ok(self
|
|
||||||
.validator_api
|
|
||||||
.propose_release_funds(request_body)
|
|
||||||
.await?)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn execute_release_funds(
|
|
||||||
&self,
|
|
||||||
request_body: &ExecuteReleaseFundsRequestBody,
|
|
||||||
) -> Result<(), ValidatorClientError> {
|
|
||||||
Ok(self
|
|
||||||
.validator_api
|
|
||||||
.execute_release_funds(request_body)
|
|
||||||
.await?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ use cosmrs::rpc::{self, HttpClient, Order};
|
|||||||
use cosmrs::tendermint::abci::Code as AbciCode;
|
use cosmrs::tendermint::abci::Code as AbciCode;
|
||||||
use cosmrs::tendermint::abci::Transaction;
|
use cosmrs::tendermint::abci::Transaction;
|
||||||
use cosmrs::tendermint::{abci, block, chain};
|
use cosmrs::tendermint::{abci, block, chain};
|
||||||
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Denom, Tx};
|
use cosmrs::{tx, AccountId, Coin as CosmosCoin, Tx};
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
@@ -121,7 +121,7 @@ pub trait CosmWasmClient: rpc::Client {
|
|||||||
async fn get_balance(
|
async fn get_balance(
|
||||||
&self,
|
&self,
|
||||||
address: &AccountId,
|
address: &AccountId,
|
||||||
search_denom: Denom,
|
search_denom: String,
|
||||||
) -> Result<Option<Coin>, NymdError> {
|
) -> Result<Option<Coin>, NymdError> {
|
||||||
let path = Some("/cosmos.bank.v1beta1.Query/Balance".parse().unwrap());
|
let path = Some("/cosmos.bank.v1beta1.Query/Balance".parse().unwrap());
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ use crate::nymd::{Coin, GasAdjustable, GasPrice, TxResponse};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cosmrs::bank::MsgSend;
|
use cosmrs::bank::MsgSend;
|
||||||
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
||||||
|
use cosmrs::feegrant::{
|
||||||
|
AllowedMsgAllowance, BasicAllowance, MsgGrantAllowance, MsgRevokeAllowance,
|
||||||
|
};
|
||||||
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
|
use cosmrs::proto::cosmos::tx::signing::v1beta1::SignMode;
|
||||||
use cosmrs::rpc::endpoint::broadcast;
|
use cosmrs::rpc::endpoint::broadcast;
|
||||||
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
|
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl, SimpleRequest};
|
||||||
@@ -23,7 +26,7 @@ use serde::Serialize;
|
|||||||
use sha2::Digest;
|
use sha2::Digest;
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::time::Duration;
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
|
||||||
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
@@ -420,6 +423,63 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
|||||||
.check_response()
|
.check_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
async fn grant_allowance(
|
||||||
|
&self,
|
||||||
|
granter: &AccountId,
|
||||||
|
grantee: &AccountId,
|
||||||
|
spend_limit: Vec<Coin>,
|
||||||
|
expiration: Option<SystemTime>,
|
||||||
|
allowed_messages: Vec<String>,
|
||||||
|
fee: Fee,
|
||||||
|
memo: impl Into<String> + Send + 'static,
|
||||||
|
) -> Result<TxResponse, NymdError> {
|
||||||
|
let basic_allowance = BasicAllowance {
|
||||||
|
spend_limit: spend_limit.into_iter().map(Into::into).collect(),
|
||||||
|
expiration,
|
||||||
|
}
|
||||||
|
.to_any()
|
||||||
|
.map_err(|_| NymdError::SerializationError("BasicAllowance".to_owned()))?;
|
||||||
|
|
||||||
|
let allowed_msg_allowance = AllowedMsgAllowance {
|
||||||
|
allowance: Some(basic_allowance),
|
||||||
|
allowed_messages,
|
||||||
|
}
|
||||||
|
.to_any()
|
||||||
|
.map_err(|_| NymdError::SerializationError("AllowedMsgAllowance".to_owned()))?;
|
||||||
|
|
||||||
|
let grant_allowance_msg = MsgGrantAllowance {
|
||||||
|
granter: granter.to_owned(),
|
||||||
|
grantee: grantee.to_owned(),
|
||||||
|
allowance: Some(allowed_msg_allowance),
|
||||||
|
}
|
||||||
|
.to_any()
|
||||||
|
.map_err(|_| NymdError::SerializationError("MsgGrantAllowance".to_owned()))?;
|
||||||
|
|
||||||
|
self.sign_and_broadcast(granter, vec![grant_allowance_msg], fee, memo)
|
||||||
|
.await?
|
||||||
|
.check_response()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn revoke_allowance(
|
||||||
|
&self,
|
||||||
|
granter: &AccountId,
|
||||||
|
grantee: &AccountId,
|
||||||
|
fee: Fee,
|
||||||
|
memo: impl Into<String> + Send + 'static,
|
||||||
|
) -> Result<TxResponse, NymdError> {
|
||||||
|
let revoke_allowance_msg = MsgRevokeAllowance {
|
||||||
|
granter: granter.to_owned(),
|
||||||
|
grantee: grantee.to_owned(),
|
||||||
|
}
|
||||||
|
.to_any()
|
||||||
|
.map_err(|_| NymdError::SerializationError("MsgRevokeAllowance".to_owned()))?;
|
||||||
|
|
||||||
|
self.sign_and_broadcast(granter, vec![revoke_allowance_msg], fee, memo)
|
||||||
|
.await?
|
||||||
|
.check_response()
|
||||||
|
}
|
||||||
|
|
||||||
async fn delegate_tokens(
|
async fn delegate_tokens(
|
||||||
&self,
|
&self,
|
||||||
delegator_address: &AccountId,
|
delegator_address: &AccountId,
|
||||||
@@ -514,10 +574,10 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
|||||||
let fee = match fee {
|
let fee = match fee {
|
||||||
Fee::Manual(fee) => fee,
|
Fee::Manual(fee) => fee,
|
||||||
Fee::Auto(multiplier) => auto_fee(multiplier).await?,
|
Fee::Auto(multiplier) => auto_fee(multiplier).await?,
|
||||||
Fee::PayerGranterAuto(multiplier, payer, granter) => {
|
Fee::PayerGranterAuto(auto_feegrant) => {
|
||||||
let mut fee = auto_fee(multiplier).await?;
|
let mut fee = auto_fee(auto_feegrant.gas_adjustment).await?;
|
||||||
fee.payer = payer;
|
fee.payer = auto_feegrant.payer;
|
||||||
fee.granter = granter;
|
fee.granter = auto_feegrant.granter;
|
||||||
fee
|
fee
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::nymd::Coin;
|
||||||
use crate::nymd::Gas;
|
use crate::nymd::Gas;
|
||||||
use cosmrs::{tx, AccountId};
|
use cosmrs::{tx, AccountId};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
pub mod gas_price;
|
pub mod gas_price;
|
||||||
|
|
||||||
@@ -11,11 +13,74 @@ pub type GasAdjustment = f32;
|
|||||||
|
|
||||||
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
|
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct AutoFeeGrant {
|
||||||
|
pub gas_adjustment: Option<GasAdjustment>,
|
||||||
|
pub payer: Option<AccountId>,
|
||||||
|
pub granter: Option<AccountId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AutoFeeGrant {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if let Some(gas_adjustment) = self.gas_adjustment {
|
||||||
|
write!(f, "Feegrant in auto mode with {gas_adjustment} simulated multiplier with {:?} payer and {:?} granter", self.payer, self.granter)
|
||||||
|
} else {
|
||||||
|
write!(f, "Feegrant in auto mode with no custom simulated multiplier with {:?} payer and {:?} granter", self.payer, self.granter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub enum Fee {
|
pub enum Fee {
|
||||||
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
|
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
|
||||||
Auto(Option<GasAdjustment>),
|
Auto(Option<GasAdjustment>),
|
||||||
PayerGranterAuto(Option<GasAdjustment>, Option<AccountId>, Option<AccountId>),
|
PayerGranterAuto(AutoFeeGrant),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Fee {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Fee::Manual(fee) => {
|
||||||
|
write!(f, "Fee in manual mode with ")?;
|
||||||
|
for fee in &fee.amount {
|
||||||
|
write!(f, "{}{} paid in fees, ", fee.amount, fee.denom)?;
|
||||||
|
}
|
||||||
|
write!(f, "{} set as gas limit, ", fee.gas_limit)?;
|
||||||
|
if let Some(payer) = &fee.payer {
|
||||||
|
write!(f, "{payer} set as payer, ")?;
|
||||||
|
}
|
||||||
|
if let Some(granter) = &fee.granter {
|
||||||
|
write!(f, "{granter} set as granter")?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Fee::Auto(Some(multiplier)) => {
|
||||||
|
write!(f, "Fee in auto mode with {multiplier} simulated multiplier")
|
||||||
|
}
|
||||||
|
Fee::Auto(None) => write!(f, "Fee in auto mode with no custom simulated multiplier"),
|
||||||
|
Fee::PayerGranterAuto(auto_feegrant) => write!(f, "{}", auto_feegrant),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fee {
|
||||||
|
pub fn new_payer_granter_auto(
|
||||||
|
gas_adjustment: Option<GasAdjustment>,
|
||||||
|
payer: Option<AccountId>,
|
||||||
|
granter: Option<AccountId>,
|
||||||
|
) -> Self {
|
||||||
|
Fee::PayerGranterAuto(AutoFeeGrant {
|
||||||
|
gas_adjustment,
|
||||||
|
payer,
|
||||||
|
granter,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
pub fn try_get_manual_amount(&self) -> Option<Vec<Coin>> {
|
||||||
|
match self {
|
||||||
|
Fee::Manual(tx_fee) => Some(tx_fee.amount.iter().cloned().map(Into::into).collect()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<tx::Fee> for Fee {
|
impl From<tx::Fee> for Fee {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ use mixnet_contract_common::{
|
|||||||
};
|
};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
use std::time::SystemTime;
|
||||||
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
|
use vesting_contract_common::ExecuteMsg as VestingExecuteMsg;
|
||||||
use vesting_contract_common::QueryMsg as VestingQueryMsg;
|
use vesting_contract_common::QueryMsg as VestingQueryMsg;
|
||||||
|
|
||||||
@@ -388,7 +389,7 @@ impl<C> NymdClient<C> {
|
|||||||
pub async fn get_balance(
|
pub async fn get_balance(
|
||||||
&self,
|
&self,
|
||||||
address: &AccountId,
|
address: &AccountId,
|
||||||
denom: Denom,
|
denom: String,
|
||||||
) -> Result<Option<Coin>, NymdError>
|
) -> Result<Option<Coin>, NymdError>
|
||||||
where
|
where
|
||||||
C: CosmWasmClient + Sync,
|
C: CosmWasmClient + Sync,
|
||||||
@@ -845,6 +846,49 @@ impl<C> NymdClient<C> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Grant a fee allowance from one address to another
|
||||||
|
pub async fn grant_allowance(
|
||||||
|
&self,
|
||||||
|
grantee: &AccountId,
|
||||||
|
spend_limit: Vec<Coin>,
|
||||||
|
expiration: Option<SystemTime>,
|
||||||
|
allowed_messages: Vec<String>,
|
||||||
|
memo: impl Into<String> + Send + 'static,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<TxResponse, NymdError>
|
||||||
|
where
|
||||||
|
C: SigningCosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
|
self.client
|
||||||
|
.grant_allowance(
|
||||||
|
self.address(),
|
||||||
|
grantee,
|
||||||
|
spend_limit,
|
||||||
|
expiration,
|
||||||
|
allowed_messages,
|
||||||
|
fee,
|
||||||
|
memo,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Revoke a fee allowance from one address to another
|
||||||
|
pub async fn revoke_allowance(
|
||||||
|
&self,
|
||||||
|
grantee: &AccountId,
|
||||||
|
memo: impl Into<String> + Send + 'static,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<TxResponse, NymdError>
|
||||||
|
where
|
||||||
|
C: SigningCosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
|
self.client
|
||||||
|
.revoke_allowance(self.address(), grantee, fee, memo)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn execute<M>(
|
pub async fn execute<M>(
|
||||||
&self,
|
&self,
|
||||||
contract_address: &AccountId,
|
contract_address: &AccountId,
|
||||||
@@ -962,6 +1006,29 @@ impl<C> NymdClient<C> {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[execute("mixnet")]
|
||||||
|
fn _compound_reward(
|
||||||
|
&self,
|
||||||
|
operator: Option<String>,
|
||||||
|
delegator: Option<String>,
|
||||||
|
mix_identity: Option<IdentityKey>,
|
||||||
|
proxy: Option<String>,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> (ExecuteMsg, Option<Fee>)
|
||||||
|
where
|
||||||
|
C: SigningCosmWasmClient + Sync,
|
||||||
|
{
|
||||||
|
(
|
||||||
|
ExecuteMsg::CompoundReward {
|
||||||
|
operator,
|
||||||
|
delegator,
|
||||||
|
mix_identity,
|
||||||
|
proxy,
|
||||||
|
},
|
||||||
|
fee,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
#[execute("mixnet")]
|
#[execute("mixnet")]
|
||||||
fn _compound_operator_reward(&self, fee: Option<Fee>) -> (ExecuteMsg, Option<Fee>)
|
fn _compound_operator_reward(&self, fee: Option<Fee>) -> (ExecuteMsg, Option<Fee>)
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::nymd::error::NymdError;
|
||||||
|
use crate::nymd::{CosmWasmClient, NymdClient};
|
||||||
|
|
||||||
|
use coconut_bandwidth_contract_common::msg::QueryMsg;
|
||||||
|
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait CoconutBandwidthQueryClient {
|
||||||
|
async fn get_spent_credential(
|
||||||
|
&self,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
) -> Result<SpendCredentialResponse, NymdError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<C: CosmWasmClient + Sync + Send> CoconutBandwidthQueryClient for NymdClient<C> {
|
||||||
|
async fn get_spent_credential(
|
||||||
|
&self,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
) -> Result<SpendCredentialResponse, NymdError> {
|
||||||
|
let request = QueryMsg::GetSpentCredential {
|
||||||
|
blinded_serial_number,
|
||||||
|
};
|
||||||
|
self.client
|
||||||
|
.query_contract_smart(self.coconut_bandwidth_contract_address(), &request)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -5,6 +5,7 @@ pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient;
|
|||||||
use crate::nymd::cosmwasm_client::types::ExecuteResult;
|
use crate::nymd::cosmwasm_client::types::ExecuteResult;
|
||||||
use crate::nymd::error::NymdError;
|
use crate::nymd::error::NymdError;
|
||||||
use crate::nymd::{Coin, Fee, NymdClient};
|
use crate::nymd::{Coin, Fee, NymdClient};
|
||||||
|
use coconut_bandwidth_contract_common::spend_credential::SpendCredentialData;
|
||||||
use coconut_bandwidth_contract_common::{deposit::DepositData, msg::ExecuteMsg};
|
use coconut_bandwidth_contract_common::{deposit::DepositData, msg::ExecuteMsg};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
@@ -19,6 +20,13 @@ pub trait CoconutBandwidthSigningClient {
|
|||||||
encryption_key: String,
|
encryption_key: String,
|
||||||
fee: Option<Fee>,
|
fee: Option<Fee>,
|
||||||
) -> Result<ExecuteResult, NymdError>;
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
|
async fn spend_credential(
|
||||||
|
&self,
|
||||||
|
funds: Coin,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
gateway_cosmos_address: String,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NymdError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@@ -46,4 +54,30 @@ impl<C: SigningCosmWasmClient + Sync + Send> CoconutBandwidthSigningClient for N
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
async fn spend_credential(
|
||||||
|
&self,
|
||||||
|
funds: Coin,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
gateway_cosmos_address: String,
|
||||||
|
fee: Option<Fee>,
|
||||||
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
|
let req = ExecuteMsg::SpendCredential {
|
||||||
|
data: SpendCredentialData::new(
|
||||||
|
funds.into(),
|
||||||
|
blinded_serial_number,
|
||||||
|
gateway_cosmos_address,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
self.client
|
||||||
|
.execute(
|
||||||
|
self.address(),
|
||||||
|
self.coconut_bandwidth_contract_address(),
|
||||||
|
&req,
|
||||||
|
fee,
|
||||||
|
"CoconutBandwidth::SpendCredential",
|
||||||
|
vec![],
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
mod coconut_bandwidth_query_client;
|
||||||
mod coconut_bandwidth_signing_client;
|
mod coconut_bandwidth_signing_client;
|
||||||
mod multisig_query_client;
|
mod multisig_query_client;
|
||||||
mod multisig_signing_client;
|
mod multisig_signing_client;
|
||||||
mod vesting_query_client;
|
mod vesting_query_client;
|
||||||
mod vesting_signing_client;
|
mod vesting_signing_client;
|
||||||
|
|
||||||
|
pub use coconut_bandwidth_query_client::CoconutBandwidthQueryClient;
|
||||||
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
|
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
|
||||||
pub use multisig_query_client::QueryClient;
|
pub use multisig_query_client::MultisigQueryClient;
|
||||||
pub use multisig_signing_client::MultisigSigningClient;
|
pub use multisig_signing_client::MultisigSigningClient;
|
||||||
pub use vesting_query_client::VestingQueryClient;
|
pub use vesting_query_client::VestingQueryClient;
|
||||||
pub use vesting_signing_client::VestingSigningClient;
|
pub use vesting_signing_client::VestingSigningClient;
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ use multisig_contract_common::msg::{ProposalResponse, QueryMsg};
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait QueryClient {
|
pub trait MultisigQueryClient {
|
||||||
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError>;
|
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<C: CosmWasmClient + Sync + Send> QueryClient for NymdClient<C> {
|
impl<C: CosmWasmClient + Sync + Send> MultisigQueryClient for NymdClient<C> {
|
||||||
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError> {
|
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NymdError> {
|
||||||
let request = QueryMsg::Proposal { proposal_id };
|
let request = QueryMsg::Proposal { proposal_id };
|
||||||
self.client
|
self.client
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ use multisig_contract_common::msg::ExecuteMsg;
|
|||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
|
use cosmwasm_std::{to_binary, Coin, CosmosMsg, WasmMsg};
|
||||||
use cw3::Vote;
|
use cw3::Vote;
|
||||||
use network_defaults::DEFAULT_NETWORK;
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait MultisigSigningClient {
|
pub trait MultisigSigningClient {
|
||||||
@@ -49,7 +48,10 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
|
|||||||
) -> Result<ExecuteResult, NymdError> {
|
) -> Result<ExecuteResult, NymdError> {
|
||||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||||
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
||||||
funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
|
funds: Coin::new(
|
||||||
|
voucher_value,
|
||||||
|
self.config.chain_details.mix_denom.base.clone(),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
|
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
|
||||||
|
|||||||
@@ -207,35 +207,20 @@ mod tests {
|
|||||||
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
|
"acquire rebel spot skin gun such erupt pull swear must define ill chief turtle today flower chunk truth battle claw rigid detail gym feel",
|
||||||
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
|
"step income throw wheat mobile ship wave drink pool sudden upset jaguar bar globe rifle spice frost bless glimpse size regular carry aspect ball"
|
||||||
];
|
];
|
||||||
let prefixes = vec![
|
let prefix = MAINNET.bech32_prefix();
|
||||||
MAINNET.bech32_prefix(),
|
|
||||||
SANDBOX.bech32_prefix(),
|
|
||||||
QA.bech32_prefix(),
|
|
||||||
];
|
|
||||||
|
|
||||||
for prefix in prefixes {
|
let addrs = vec![
|
||||||
let addrs = match prefix.as_ref() {
|
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
|
||||||
"nymt" => vec![
|
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
|
||||||
"nymt1jw6mp7d5xqc7w6xm79lha27glmd0vdt339me94",
|
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
|
||||||
"nymt1h5hgn94nsq4kh99rjj794hr5h5q6yfm23rjshv",
|
];
|
||||||
"nymt17n9flp6jflljg6fp05dsy07wcprf2uuufgn4d4",
|
for (idx, mnemonic) in mnemonics.iter().enumerate() {
|
||||||
],
|
let wallet =
|
||||||
"n" => vec![
|
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap()).unwrap();
|
||||||
"n1jw6mp7d5xqc7w6xm79lha27glmd0vdt3l9artf",
|
assert_eq!(
|
||||||
"n1h5hgn94nsq4kh99rjj794hr5h5q6yfm2lr52es",
|
wallet.try_derive_accounts().unwrap()[0].address,
|
||||||
"n17n9flp6jflljg6fp05dsy07wcprf2uuu8g40rf",
|
addrs[idx].parse().unwrap()
|
||||||
],
|
)
|
||||||
_ => panic!("Test needs to be updated with new bech32 prefix"),
|
|
||||||
};
|
|
||||||
for (idx, mnemonic) in mnemonics.iter().enumerate() {
|
|
||||||
let wallet =
|
|
||||||
DirectSecp256k1HdWallet::from_mnemonic(&prefix, mnemonic.parse().unwrap())
|
|
||||||
.unwrap();
|
|
||||||
assert_eq!(
|
|
||||||
wallet.try_derive_accounts().unwrap()[0].address,
|
|
||||||
addrs[idx].parse().unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use validator_api_requests::coconut::{
|
use validator_api_requests::coconut::{
|
||||||
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse,
|
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse, VerificationKeyResponse,
|
||||||
ExecuteReleaseFundsRequestBody, ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse,
|
VerifyCredentialBody, VerifyCredentialResponse,
|
||||||
VerificationKeyResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
|
||||||
};
|
};
|
||||||
use validator_api_requests::models::{
|
use validator_api_requests::models::{
|
||||||
CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
|
CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
|
||||||
@@ -405,40 +404,6 @@ impl Client {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn propose_release_funds(
|
|
||||||
&self,
|
|
||||||
request_body: &ProposeReleaseFundsRequestBody,
|
|
||||||
) -> Result<ProposeReleaseFundsResponse, ValidatorAPIError> {
|
|
||||||
self.post_validator_api(
|
|
||||||
&[
|
|
||||||
routes::API_VERSION,
|
|
||||||
routes::COCONUT_ROUTES,
|
|
||||||
routes::BANDWIDTH,
|
|
||||||
routes::COCONUT_PROPOSE_RELEASE_FUNDS,
|
|
||||||
],
|
|
||||||
NO_PARAMS,
|
|
||||||
request_body,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn execute_release_funds(
|
|
||||||
&self,
|
|
||||||
request_body: &ExecuteReleaseFundsRequestBody,
|
|
||||||
) -> Result<(), ValidatorAPIError> {
|
|
||||||
self.post_validator_api(
|
|
||||||
&[
|
|
||||||
routes::API_VERSION,
|
|
||||||
routes::COCONUT_ROUTES,
|
|
||||||
routes::BANDWIDTH,
|
|
||||||
routes::COCONUT_EXECUTE_RELEASE_FUNDS,
|
|
||||||
],
|
|
||||||
NO_PARAMS,
|
|
||||||
request_body,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// utility function that should solve the double slash problem in validator API forever.
|
// utility function that should solve the double slash problem in validator API forever.
|
||||||
|
|||||||
@@ -19,8 +19,6 @@ pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-creden
|
|||||||
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
|
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
|
||||||
pub const COCONUT_COSMOS_ADDRESS: &str = "cosmos-address";
|
pub const COCONUT_COSMOS_ADDRESS: &str = "cosmos-address";
|
||||||
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
|
pub const COCONUT_VERIFY_BANDWIDTH_CREDENTIAL: &str = "verify-bandwidth-credential";
|
||||||
pub const COCONUT_PROPOSE_RELEASE_FUNDS: &str = "propose-release-funds";
|
|
||||||
pub const COCONUT_EXECUTE_RELEASE_FUNDS: &str = "execute-release-funds";
|
|
||||||
|
|
||||||
pub const STATUS_ROUTES: &str = "status";
|
pub const STATUS_ROUTES: &str = "status";
|
||||||
pub const MIXNODE: &str = "mixnode";
|
pub const MIXNODE: &str = "mixnode";
|
||||||
|
|||||||
@@ -9,3 +9,4 @@ edition = "2021"
|
|||||||
cosmwasm-std = "1.0.0"
|
cosmwasm-std = "1.0.0"
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
serde = { version = "1.0.103", default-features = false, features = ["derive"] }
|
||||||
|
multisig-contract-common = { path = "../multisig-contract" }
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
pub mod deposit;
|
pub mod deposit;
|
||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod msg;
|
pub mod msg;
|
||||||
|
pub mod spend_credential;
|
||||||
|
|||||||
@@ -5,24 +5,34 @@ use cosmwasm_std::Coin;
|
|||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::deposit::DepositData;
|
use crate::{deposit::DepositData, spend_credential::SpendCredentialData};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
pub struct InstantiateMsg {
|
pub struct InstantiateMsg {
|
||||||
pub multisig_addr: String,
|
pub multisig_addr: String,
|
||||||
pub pool_addr: String,
|
pub pool_addr: String,
|
||||||
|
pub mix_denom: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ExecuteMsg {
|
pub enum ExecuteMsg {
|
||||||
DepositFunds { data: DepositData },
|
DepositFunds { data: DepositData },
|
||||||
|
SpendCredential { data: SpendCredentialData },
|
||||||
ReleaseFunds { funds: Coin },
|
ReleaseFunds { funds: Coin },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum QueryMsg {}
|
pub enum QueryMsg {
|
||||||
|
GetSpentCredential {
|
||||||
|
blinded_serial_number: String,
|
||||||
|
},
|
||||||
|
GetAllSpentCredentials {
|
||||||
|
limit: Option<u32>,
|
||||||
|
start_after: Option<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
|||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use cosmwasm_std::{from_binary, to_binary, Addr, Coin, CosmosMsg, StdResult, WasmMsg};
|
||||||
|
use multisig_contract_common::msg::ExecuteMsg as MultisigExecuteMsg;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::msg::ExecuteMsg;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
|
pub struct SpendCredentialData {
|
||||||
|
funds: Coin,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
gateway_cosmos_address: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpendCredentialData {
|
||||||
|
pub fn new(funds: Coin, blinded_serial_number: String, gateway_cosmos_address: String) -> Self {
|
||||||
|
SpendCredentialData {
|
||||||
|
funds,
|
||||||
|
blinded_serial_number,
|
||||||
|
gateway_cosmos_address,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn funds(&self) -> &Coin {
|
||||||
|
&self.funds
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blinded_serial_number(&self) -> &str {
|
||||||
|
&self.blinded_serial_number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gateway_cosmos_address(&self) -> &str {
|
||||||
|
&self.gateway_cosmos_address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
|
pub enum SpendCredentialStatus {
|
||||||
|
InProgress,
|
||||||
|
Spent,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
|
pub struct SpendCredential {
|
||||||
|
funds: Coin,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
gateway_cosmos_address: Addr,
|
||||||
|
status: SpendCredentialStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpendCredential {
|
||||||
|
pub fn new(funds: Coin, blinded_serial_number: String, gateway_cosmos_address: Addr) -> Self {
|
||||||
|
SpendCredential {
|
||||||
|
funds,
|
||||||
|
blinded_serial_number,
|
||||||
|
gateway_cosmos_address,
|
||||||
|
status: SpendCredentialStatus::InProgress,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn blinded_serial_number(&self) -> &str {
|
||||||
|
&self.blinded_serial_number
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn status(&self) -> SpendCredentialStatus {
|
||||||
|
self.status
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mark_as_spent(&mut self) {
|
||||||
|
self.status = SpendCredentialStatus::Spent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
|
pub struct PagedSpendCredentialResponse {
|
||||||
|
pub spend_credentials: Vec<SpendCredential>,
|
||||||
|
pub per_page: usize,
|
||||||
|
pub start_next_after: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PagedSpendCredentialResponse {
|
||||||
|
pub fn new(
|
||||||
|
spend_credentials: Vec<SpendCredential>,
|
||||||
|
per_page: usize,
|
||||||
|
start_next_after: Option<String>,
|
||||||
|
) -> Self {
|
||||||
|
PagedSpendCredentialResponse {
|
||||||
|
spend_credentials,
|
||||||
|
per_page,
|
||||||
|
start_next_after,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)]
|
||||||
|
pub struct SpendCredentialResponse {
|
||||||
|
pub spend_credential: Option<SpendCredential>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SpendCredentialResponse {
|
||||||
|
pub fn new(spend_credential: Option<SpendCredential>) -> Self {
|
||||||
|
SpendCredentialResponse { spend_credential }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_cosmos_msg(
|
||||||
|
funds: Coin,
|
||||||
|
blinded_serial_number: String,
|
||||||
|
coconut_bandwidth_addr: String,
|
||||||
|
multisig_addr: String,
|
||||||
|
) -> StdResult<CosmosMsg> {
|
||||||
|
let release_funds_req = ExecuteMsg::ReleaseFunds { funds };
|
||||||
|
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
|
contract_addr: coconut_bandwidth_addr,
|
||||||
|
msg: to_binary(&release_funds_req)?,
|
||||||
|
funds: vec![],
|
||||||
|
});
|
||||||
|
let req = MultisigExecuteMsg::Propose {
|
||||||
|
title: String::from("Release funds, as ordered by Coconut Bandwidth Contract"),
|
||||||
|
description: blinded_serial_number,
|
||||||
|
msgs: vec![release_funds_msg],
|
||||||
|
latest: None,
|
||||||
|
};
|
||||||
|
let msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
|
contract_addr: multisig_addr,
|
||||||
|
msg: to_binary(&req)?,
|
||||||
|
funds: vec![],
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn funds_from_cosmos_msgs(msgs: Vec<CosmosMsg>) -> Option<Coin> {
|
||||||
|
if let Some(CosmosMsg::Wasm(WasmMsg::Execute {
|
||||||
|
contract_addr: _,
|
||||||
|
msg,
|
||||||
|
funds: _,
|
||||||
|
})) = msgs.get(0)
|
||||||
|
{
|
||||||
|
if let Ok(ExecuteMsg::ReleaseFunds { funds }) = from_binary::<ExecuteMsg>(msg) {
|
||||||
|
return Some(funds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ name = "mixnet-contract-common"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
authors = ["Jędrzej Stuczyński <andrew@nymtech.net>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
rust-version = "1.62"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
@@ -13,7 +14,6 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
serde_repr = "0.1"
|
serde_repr = "0.1"
|
||||||
schemars = "0.8"
|
schemars = "0.8"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
network-defaults = { path = "../../network-defaults" }
|
|
||||||
fixed = { version = "1.1", features = ["serde"] }
|
fixed = { version = "1.1", features = ["serde"] }
|
||||||
az = "1.1"
|
az = "1.1"
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ pub struct Delegation {
|
|||||||
pub node_identity: IdentityKey,
|
pub node_identity: IdentityKey,
|
||||||
pub amount: Coin,
|
pub amount: Coin,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub proxy: Option<Addr>, // proxy address used to delegate the funds on behalf of anouther address
|
pub proxy: Option<Addr>, // proxy address used to delegate the funds on behalf of another address
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Delegation {}
|
impl Eq for Delegation {}
|
||||||
|
|||||||
@@ -37,6 +37,16 @@ pub enum DelegationEvent {
|
|||||||
Undelegate(PendingUndelegate),
|
Undelegate(PendingUndelegate),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DelegationEvent {
|
||||||
|
pub fn delegation_amount(&self) -> Option<Coin> {
|
||||||
|
match self {
|
||||||
|
DelegationEvent::Delegate(delegation) => Some(delegation.amount.clone()),
|
||||||
|
// I think it would be nice to also expose an amount here to know how much we're undelegating
|
||||||
|
DelegationEvent::Undelegate(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema)]
|
||||||
pub struct PendingUndelegate {
|
pub struct PendingUndelegate {
|
||||||
mix_identity: IdentityKey,
|
mix_identity: IdentityKey,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
pub struct InstantiateMsg {
|
pub struct InstantiateMsg {
|
||||||
pub rewarding_validator_address: String,
|
pub rewarding_validator_address: String,
|
||||||
|
pub mixnet_denom: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
@@ -32,6 +33,12 @@ pub enum ExecuteMsg {
|
|||||||
CompoundDelegatorReward {
|
CompoundDelegatorReward {
|
||||||
mix_identity: IdentityKey,
|
mix_identity: IdentityKey,
|
||||||
},
|
},
|
||||||
|
CompoundReward {
|
||||||
|
operator: Option<String>,
|
||||||
|
delegator: Option<String>,
|
||||||
|
mix_identity: Option<IdentityKey>,
|
||||||
|
proxy: Option<String>,
|
||||||
|
},
|
||||||
BondMixnode {
|
BondMixnode {
|
||||||
mix_node: MixNode,
|
mix_node: MixNode,
|
||||||
owner_signature: String,
|
owner_signature: String,
|
||||||
@@ -115,6 +122,7 @@ pub enum ExecuteMsg {
|
|||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum QueryMsg {
|
pub enum QueryMsg {
|
||||||
|
GetBlacklistedNodes {},
|
||||||
GetCurrentOperatorCost {},
|
GetCurrentOperatorCost {},
|
||||||
GetRewardingValidatorAddress {},
|
GetRewardingValidatorAddress {},
|
||||||
GetAllDelegationKeys {},
|
GetAllDelegationKeys {},
|
||||||
@@ -205,6 +213,31 @@ pub enum QueryMsg {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct MigrateMsg {}
|
pub struct MigrateMsg {
|
||||||
|
pub mixnet_denom: String,
|
||||||
|
nodes_to_remove: Option<Vec<NodeToRemove>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MigrateMsg {
|
||||||
|
pub fn nodes_to_remove(&self) -> Vec<NodeToRemove> {
|
||||||
|
self.nodes_to_remove.clone().unwrap_or_default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
|
pub struct NodeToRemove {
|
||||||
|
owner: String,
|
||||||
|
proxy: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeToRemove {
|
||||||
|
pub fn owner(&self) -> &str {
|
||||||
|
&self.owner
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn proxy(&self) -> Option<&String> {
|
||||||
|
self.proxy.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use cw_utils::{Duration, Expiration, Threshold};
|
|||||||
pub struct InstantiateMsg {
|
pub struct InstantiateMsg {
|
||||||
// this is the group contract that contains the member list
|
// this is the group contract that contains the member list
|
||||||
pub group_addr: String,
|
pub group_addr: String,
|
||||||
|
pub coconut_bandwidth_contract_address: String,
|
||||||
pub threshold: Threshold,
|
pub threshold: Threshold,
|
||||||
pub max_voting_period: Duration,
|
pub max_voting_period: Duration,
|
||||||
}
|
}
|
||||||
@@ -77,3 +78,8 @@ pub enum QueryMsg {
|
|||||||
limit: Option<u32>,
|
limit: Option<u32>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub struct MigrateMsg {
|
||||||
|
pub coconut_bandwidth_address: String,
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
use config::defaults::MIX_DENOM;
|
|
||||||
use cosmwasm_std::{Coin, Timestamp};
|
use cosmwasm_std::{Coin, Timestamp};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -10,8 +9,8 @@ pub use messages::{ExecuteMsg, InitMsg, MigrateMsg, QueryMsg};
|
|||||||
pub mod events;
|
pub mod events;
|
||||||
pub mod messages;
|
pub mod messages;
|
||||||
|
|
||||||
pub fn one_ucoin() -> Coin {
|
pub fn one_ucoin(denom: String) -> Coin {
|
||||||
Coin::new(1, MIX_DENOM.base)
|
Coin::new(1, denom)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
@@ -28,8 +27,8 @@ pub enum Period {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
pub struct PledgeData {
|
pub struct PledgeData {
|
||||||
amount: Coin,
|
pub amount: Coin,
|
||||||
block_time: Timestamp,
|
pub block_time: Timestamp,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PledgeData {
|
impl PledgeData {
|
||||||
@@ -48,9 +47,9 @@ impl PledgeData {
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
||||||
pub struct OriginalVestingResponse {
|
pub struct OriginalVestingResponse {
|
||||||
amount: Coin,
|
pub amount: Coin,
|
||||||
number_of_periods: usize,
|
pub number_of_periods: usize,
|
||||||
period_duration: u64,
|
pub period_duration: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OriginalVestingResponse {
|
impl OriginalVestingResponse {
|
||||||
|
|||||||
@@ -7,11 +7,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct InitMsg {
|
pub struct InitMsg {
|
||||||
pub mixnet_contract_address: String,
|
pub mixnet_contract_address: String,
|
||||||
|
pub mix_denom: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct MigrateMsg {}
|
pub struct MigrateMsg {
|
||||||
|
pub mix_denom: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
|
||||||
pub struct VestingSpecification {
|
pub struct VestingSpecification {
|
||||||
|
|||||||
@@ -7,14 +7,13 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||||
cosmrs = { version = "0.7.0", optional = true }
|
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support", optional = true }
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
|
||||||
# I guess temporarily until we get serde support in coconut up and running
|
# I guess temporarily until we get serde support in coconut up and running
|
||||||
coconut-interface = { path = "../coconut-interface" }
|
coconut-interface = { path = "../coconut-interface" }
|
||||||
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
||||||
network-defaults = { path = "../network-defaults" }
|
|
||||||
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
|
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
|
||||||
validator-client = { path = "../client-libs/validator-client" }
|
validator-client = { path = "../client-libs/validator-client" }
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use std::ops::Neg;
|
|||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(Clone, PartialEq))]
|
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
|
||||||
pub struct Ciphertexts {
|
pub struct Ciphertexts {
|
||||||
pub rr: [G1Projective; NUM_CHUNKS],
|
pub rr: [G1Projective; NUM_CHUNKS],
|
||||||
pub ss: [G1Projective; NUM_CHUNKS],
|
pub ss: [G1Projective; NUM_CHUNKS],
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ impl PublicKey {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct PublicKeyWithProof {
|
pub struct PublicKeyWithProof {
|
||||||
pub(crate) key: PublicKey,
|
pub(crate) key: PublicKey,
|
||||||
pub(crate) proof: ProofOfDiscreteLog,
|
pub(crate) proof: ProofOfDiscreteLog,
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ impl<'a> Instance<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(Clone, PartialEq))]
|
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
|
||||||
pub struct ProofOfChunking {
|
pub struct ProofOfChunking {
|
||||||
y0: G1Projective,
|
y0: G1Projective,
|
||||||
bb: Vec<G1Projective>,
|
bb: Vec<G1Projective>,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const DISCRETE_LOG_DOMAIN: &[u8] =
|
|||||||
b"NYM_COCONUT_NIDKG_V01_CS01_WITH_BLS12381_XMD:SHA-256_SSWU_RO_PROOF_DISCRETE_LOG";
|
b"NYM_COCONUT_NIDKG_V01_CS01_WITH_BLS12381_XMD:SHA-256_SSWU_RO_PROOF_DISCRETE_LOG";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct ProofOfDiscreteLog {
|
pub struct ProofOfDiscreteLog {
|
||||||
pub(crate) rand_commitment: G1Projective,
|
pub(crate) rand_commitment: G1Projective,
|
||||||
pub(crate) response: Scalar,
|
pub(crate) response: Scalar,
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ impl<'a> Instance<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(Clone, PartialEq))]
|
#[cfg_attr(test, derive(Clone, PartialEq, Eq))]
|
||||||
pub struct ProofOfSecretSharing {
|
pub struct ProofOfSecretSharing {
|
||||||
ff: G1Projective,
|
ff: G1Projective,
|
||||||
aa: G2Projective,
|
aa: G2Projective,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ use std::collections::BTreeMap;
|
|||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct Dealing {
|
pub struct Dealing {
|
||||||
pub public_coefficients: PublicCoefficients,
|
pub public_coefficients: PublicCoefficients,
|
||||||
pub ciphertexts: Ciphertexts,
|
pub ciphertexts: Ciphertexts,
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use config::defaults::DEFAULT_NETWORK;
|
|
||||||
use subtle_encoding::bech32;
|
use subtle_encoding::bech32;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
@@ -15,16 +14,15 @@ pub fn try_bech32_decode(address: &str) -> Result<String, Bech32Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
|
pub fn validate_bech32_prefix(bech32_prefix: &str, address: &str) -> Result<(), Bech32Error> {
|
||||||
let prefix = try_bech32_decode(address)?;
|
let prefix = try_bech32_decode(address)?;
|
||||||
|
|
||||||
if prefix == DEFAULT_NETWORK.bech32_prefix() {
|
if prefix == bech32_prefix {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Bech32Error::WrongPrefix(format!(
|
Err(Bech32Error::WrongPrefix(format!(
|
||||||
"your bech32 address prefix should be {}, not {}",
|
"your bech32 address prefix should be {}, not {}",
|
||||||
DEFAULT_NETWORK.bech32_prefix(),
|
bech32_prefix, prefix
|
||||||
prefix
|
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,6 +31,8 @@ pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
const TEST_BECH32_PREFIX: &str = "n";
|
||||||
|
|
||||||
mod decoding_bech32_addresses {
|
mod decoding_bech32_addresses {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -71,9 +71,12 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
Err(Bech32Error::WrongPrefix(format!(
|
Err(Bech32Error::WrongPrefix(format!(
|
||||||
"your bech32 address prefix should be {}, not punk",
|
"your bech32 address prefix should be {}, not punk",
|
||||||
DEFAULT_NETWORK.bech32_prefix()
|
TEST_BECH32_PREFIX
|
||||||
))),
|
))),
|
||||||
validate_bech32_prefix("punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0")
|
validate_bech32_prefix(
|
||||||
|
TEST_BECH32_PREFIX,
|
||||||
|
"punk1h3w4nj7kny5dfyjw2le4vm74z03v9vd4dstpu0"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,6 +85,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
Ok(()),
|
Ok(()),
|
||||||
validate_bech32_prefix(
|
validate_bech32_prefix(
|
||||||
|
TEST_BECH32_PREFIX,
|
||||||
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g"
|
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cfg-if = "1.0.0"
|
cfg-if = "1.0.0"
|
||||||
|
dotenv = "0.15.0"
|
||||||
hex-literal = "0.3.3"
|
hex-literal = "0.3.3"
|
||||||
once_cell = "1.7.2"
|
once_cell = "1.7.2"
|
||||||
serde = {version = "1.0", features = ["derive"]}
|
serde = {version = "1.0", features = ["derive"]}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
match option_env!("NETWORK") {
|
|
||||||
None | Some("mainnet") => println!("cargo:rustc-cfg=network=\"mainnet\"",),
|
|
||||||
Some("sandbox") => println!("cargo:rustc-cfg=network=\"sandbox\"",),
|
|
||||||
Some("sandbox2") => println!("cargo:rustc-cfg=network=\"sandbox2\"",),
|
|
||||||
Some("qa") => println!("cargo:rustc-cfg=network=\"qa\""),
|
|
||||||
_ => panic!("No such network"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DefaultNetworkDetails, DenomDetailsOwned, NymNetworkDetails, ValidatorDetails,
|
DefaultNetworkDetails, DenomDetailsOwned, NymNetworkDetails, ValidatorDetails,
|
||||||
MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS, SANDBOX2_DEFAULTS
|
MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{collections::HashMap, fmt, str::FromStr};
|
use std::{collections::HashMap, fmt, str::FromStr};
|
||||||
@@ -21,7 +21,6 @@ pub enum NetworkDefaultsError {
|
|||||||
pub enum Network {
|
pub enum Network {
|
||||||
QA,
|
QA,
|
||||||
SANDBOX,
|
SANDBOX,
|
||||||
SANDBOX2,
|
|
||||||
MAINNET,
|
MAINNET,
|
||||||
CUSTOM { details: NymNetworkDetails },
|
CUSTOM { details: NymNetworkDetails },
|
||||||
}
|
}
|
||||||
@@ -35,7 +34,6 @@ impl Network {
|
|||||||
match self {
|
match self {
|
||||||
Self::QA => (&*QA_DEFAULTS).into(),
|
Self::QA => (&*QA_DEFAULTS).into(),
|
||||||
Self::SANDBOX => (&*SANDBOX_DEFAULTS).into(),
|
Self::SANDBOX => (&*SANDBOX_DEFAULTS).into(),
|
||||||
Self::SANDBOX2 => (&*SANDBOX2_DEFAULTS).into(),
|
|
||||||
Self::MAINNET => (&*MAINNET_DEFAULTS).into(),
|
Self::MAINNET => (&*MAINNET_DEFAULTS).into(),
|
||||||
// I dislike the clone here, but for compatibility reasons we cannot define other networks with `NymNetworkDetails` directly yet
|
// I dislike the clone here, but for compatibility reasons we cannot define other networks with `NymNetworkDetails` directly yet
|
||||||
Self::CUSTOM { details } => details.clone(),
|
Self::CUSTOM { details } => details.clone(),
|
||||||
@@ -91,7 +89,6 @@ impl Network {
|
|||||||
match self {
|
match self {
|
||||||
Network::QA => crate::qa::REWARDING_VALIDATOR_ADDRESS,
|
Network::QA => crate::qa::REWARDING_VALIDATOR_ADDRESS,
|
||||||
Network::SANDBOX => crate::sandbox::REWARDING_VALIDATOR_ADDRESS,
|
Network::SANDBOX => crate::sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||||
Network::SANDBOX2 => crate::sandbox2::REWARDING_VALIDATOR_ADDRESS,
|
|
||||||
Network::MAINNET => crate::mainnet::REWARDING_VALIDATOR_ADDRESS,
|
Network::MAINNET => crate::mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||||
Network::CUSTOM { .. } => {
|
Network::CUSTOM { .. } => {
|
||||||
panic!("rewarding validator address is unavailable for a custom network")
|
panic!("rewarding validator address is unavailable for a custom network")
|
||||||
@@ -103,8 +100,10 @@ impl Network {
|
|||||||
pub fn statistics_service_url(&self) -> &str {
|
pub fn statistics_service_url(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Network::MAINNET => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
Network::MAINNET => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||||
_ => {
|
Network::SANDBOX => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||||
panic!("statistics service url is only available for mainnet!")
|
Network::QA => crate::mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||||
|
Network::CUSTOM { .. } => {
|
||||||
|
panic!("statistics service url is unavailable for a custom network")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +116,6 @@ impl FromStr for Network {
|
|||||||
match s.to_lowercase().as_str() {
|
match s.to_lowercase().as_str() {
|
||||||
"qa" => Ok(Network::QA),
|
"qa" => Ok(Network::QA),
|
||||||
"sandbox" => Ok(Network::SANDBOX),
|
"sandbox" => Ok(Network::SANDBOX),
|
||||||
"sandbox2" => Ok(Network::SANDBOX2),
|
|
||||||
"mainnet" => Ok(Network::MAINNET),
|
"mainnet" => Ok(Network::MAINNET),
|
||||||
_ => Err(NetworkDefaultsError::MalformedNetworkProvided(
|
_ => Err(NetworkDefaultsError::MalformedNetworkProvided(
|
||||||
s.to_string(),
|
s.to_string(),
|
||||||
@@ -131,7 +129,6 @@ impl fmt::Display for Network {
|
|||||||
match *self {
|
match *self {
|
||||||
Network::QA => f.write_str("QA"),
|
Network::QA => f.write_str("QA"),
|
||||||
Network::SANDBOX => f.write_str("Sandbox"),
|
Network::SANDBOX => f.write_str("Sandbox"),
|
||||||
Network::SANDBOX2 => f.write_str("Sandbox2"),
|
|
||||||
Network::MAINNET => f.write_str("Mainnet"),
|
Network::MAINNET => f.write_str("Mainnet"),
|
||||||
Network::CUSTOM { .. } => f.write_str("Custom"),
|
Network::CUSTOM { .. } => f.write_str("Custom"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::{env::var, path::PathBuf};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub mod all;
|
pub mod all;
|
||||||
@@ -10,44 +11,10 @@ pub mod eth_contract;
|
|||||||
pub mod mainnet;
|
pub mod mainnet;
|
||||||
pub mod qa;
|
pub mod qa;
|
||||||
pub mod sandbox;
|
pub mod sandbox;
|
||||||
pub mod sandbox2;
|
pub mod var_names;
|
||||||
|
|
||||||
// The set of defaults that are decided at compile time. Ideally we want to reduce these to a
|
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
|
||||||
// minimum.
|
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||||
// Keep DENOM around mostly for use in contracts. (TODO: consider moving it there, or renaming?)
|
|
||||||
cfg_if::cfg_if! {
|
|
||||||
if #[cfg(network = "mainnet")] {
|
|
||||||
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
|
|
||||||
pub const MIX_DENOM: DenomDetails = mainnet::MIX_DENOM;
|
|
||||||
pub const STAKE_DENOM: DenomDetails = mainnet::STAKE_DENOM;
|
|
||||||
|
|
||||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
|
|
||||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
|
|
||||||
|
|
||||||
} else if #[cfg(network = "qa")] {
|
|
||||||
pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
|
|
||||||
pub const MIX_DENOM: DenomDetails = qa::MIX_DENOM;
|
|
||||||
pub const STAKE_DENOM: DenomDetails = qa::STAKE_DENOM;
|
|
||||||
|
|
||||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
|
|
||||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
|
|
||||||
|
|
||||||
} else if #[cfg(network = "sandbox")] {
|
|
||||||
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
|
|
||||||
pub const MIX_DENOM: DenomDetails = sandbox::MIX_DENOM;
|
|
||||||
pub const STAKE_DENOM: DenomDetails = sandbox::STAKE_DENOM;
|
|
||||||
|
|
||||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
|
|
||||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
|
|
||||||
} else if #[cfg(network = "sandbox2")] {
|
|
||||||
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX2;
|
|
||||||
pub const MIX_DENOM: DenomDetails = sandbox2::MIX_DENOM;
|
|
||||||
pub const STAKE_DENOM: DenomDetails = sandbox2::STAKE_DENOM;
|
|
||||||
|
|
||||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox2::_ETH_CONTRACT_ADDRESS;
|
|
||||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox2::_ETH_ERC20_CONTRACT_ADDRESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
pub struct ChainDetails {
|
pub struct ChainDetails {
|
||||||
@@ -90,23 +57,56 @@ impl NymNetworkDetails {
|
|||||||
NymNetworkDetails::default()
|
NymNetworkDetails::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_qa() -> Self {
|
pub fn new_from_env() -> Self {
|
||||||
(&*QA_DEFAULTS).into()
|
NymNetworkDetails::new()
|
||||||
}
|
.with_bech32_account_prefix(
|
||||||
|
var(var_names::BECH32_PREFIX).expect("bech32 prefix not set"),
|
||||||
pub fn new_sandbox() -> Self {
|
)
|
||||||
(&*SANDBOX_DEFAULTS).into()
|
.with_mix_denom(DenomDetailsOwned {
|
||||||
|
base: var(var_names::MIX_DENOM).expect("mix denomination base not set"),
|
||||||
|
display: var(var_names::MIX_DENOM_DISPLAY)
|
||||||
|
.expect("mix denomination display not set"),
|
||||||
|
display_exponent: var(var_names::DENOMS_EXPONENT)
|
||||||
|
.expect("denomination exponent not set")
|
||||||
|
.parse()
|
||||||
|
.expect("denomination exponent is not u32"),
|
||||||
|
})
|
||||||
|
.with_stake_denom(DenomDetailsOwned {
|
||||||
|
base: var(var_names::STAKE_DENOM).expect("stake denomination base not set"),
|
||||||
|
display: var(var_names::STAKE_DENOM_DISPLAY)
|
||||||
|
.expect("stake denomination display not set"),
|
||||||
|
display_exponent: var(var_names::DENOMS_EXPONENT)
|
||||||
|
.expect("denomination exponent not set")
|
||||||
|
.parse()
|
||||||
|
.expect("denomination exponent is not u32"),
|
||||||
|
})
|
||||||
|
.with_validator_endpoint(ValidatorDetails::new(
|
||||||
|
var(var_names::NYMD_VALIDATOR).expect("nymd validator not set"),
|
||||||
|
Some(var(var_names::API_VALIDATOR).expect("api validator not set")),
|
||||||
|
))
|
||||||
|
.with_mixnet_contract(Some(
|
||||||
|
var(var_names::MIXNET_CONTRACT_ADDRESS).expect("mixnet contract not set"),
|
||||||
|
))
|
||||||
|
.with_vesting_contract(Some(
|
||||||
|
var(var_names::VESTING_CONTRACT_ADDRESS).expect("vesting contract not set"),
|
||||||
|
))
|
||||||
|
.with_bandwidth_claim_contract(Some(
|
||||||
|
var(var_names::BANDWIDTH_CLAIM_CONTRACT_ADDRESS)
|
||||||
|
.expect("bandwidth claim contract not set"),
|
||||||
|
))
|
||||||
|
.with_coconut_bandwidth_contract(Some(
|
||||||
|
var(var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS)
|
||||||
|
.expect("coconut bandwidth contract not set"),
|
||||||
|
))
|
||||||
|
.with_multisig_contract(Some(
|
||||||
|
var(var_names::MULTISIG_CONTRACT_ADDRESS).expect("multisig contract not set"),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_mainnet() -> Self {
|
pub fn new_mainnet() -> Self {
|
||||||
(&*MAINNET_DEFAULTS).into()
|
(&*MAINNET_DEFAULTS).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn current_default() -> Self {
|
|
||||||
// backwards compatibility reasons
|
|
||||||
DEFAULT_NETWORK.details()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
|
pub fn with_bech32_account_prefix<S: Into<String>>(mut self, prefix: S) -> Self {
|
||||||
self.chain_details.bech32_account_prefix = prefix.into();
|
self.chain_details.bech32_account_prefix = prefix.into();
|
||||||
self
|
self
|
||||||
@@ -243,20 +243,6 @@ static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetwo
|
|||||||
validators: sandbox::validators(),
|
validators: sandbox::validators(),
|
||||||
});
|
});
|
||||||
|
|
||||||
static SANDBOX2_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
|
||||||
bech32_prefix: sandbox2::BECH32_PREFIX,
|
|
||||||
mix_denom: sandbox2::MIX_DENOM,
|
|
||||||
stake_denom: sandbox2::STAKE_DENOM,
|
|
||||||
mixnet_contract_address: sandbox2::MIXNET_CONTRACT_ADDRESS,
|
|
||||||
vesting_contract_address: sandbox2::VESTING_CONTRACT_ADDRESS,
|
|
||||||
bandwidth_claim_contract_address: sandbox2::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
|
||||||
coconut_bandwidth_contract_address: sandbox2::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
|
||||||
multisig_contract_address: sandbox2::MULTISIG_CONTRACT_ADDRESS,
|
|
||||||
rewarding_validator_address: sandbox2::REWARDING_VALIDATOR_ADDRESS,
|
|
||||||
statistics_service_url: sandbox2::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
|
||||||
validators: sandbox2::validators(),
|
|
||||||
});
|
|
||||||
|
|
||||||
static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||||
bech32_prefix: qa::BECH32_PREFIX,
|
bech32_prefix: qa::BECH32_PREFIX,
|
||||||
mix_denom: qa::MIX_DENOM,
|
mix_denom: qa::MIX_DENOM,
|
||||||
@@ -289,7 +275,7 @@ impl DenomDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Debug, Serialize, Deserialize, Hash, Clone, PartialEq, Eq)]
|
||||||
pub struct DenomDetailsOwned {
|
pub struct DenomDetailsOwned {
|
||||||
pub base: String,
|
pub base: String,
|
||||||
pub display: String,
|
pub display: String,
|
||||||
@@ -355,27 +341,21 @@ impl ValidatorDetails {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_statistics_service_url() -> Url {
|
pub fn setup_env(config_env_file: Option<PathBuf>) {
|
||||||
DEFAULT_NETWORK
|
match std::env::var(var_names::CONFIGURED) {
|
||||||
.statistics_service_url()
|
// if the configuration is not already set in the env vars
|
||||||
.parse()
|
Err(std::env::VarError::NotPresent) => {
|
||||||
.expect("the provided statistics service url is invalid!")
|
if let Some(config_env_file) = config_env_file {
|
||||||
}
|
dotenv::from_path(config_env_file)
|
||||||
|
.expect("Invalid path to environment configuration file");
|
||||||
pub fn default_nymd_endpoints() -> Vec<Url> {
|
} else {
|
||||||
DEFAULT_NETWORK
|
// if nothing is set, the use mainnet defaults
|
||||||
.validators()
|
crate::mainnet::export_to_env();
|
||||||
.iter()
|
}
|
||||||
.map(ValidatorDetails::nymd_url)
|
}
|
||||||
.collect()
|
Err(_) => crate::mainnet::export_to_env(),
|
||||||
}
|
_ => {}
|
||||||
|
}
|
||||||
pub fn default_api_endpoints() -> Vec<Url> {
|
|
||||||
DEFAULT_NETWORK
|
|
||||||
.validators()
|
|
||||||
.iter()
|
|
||||||
.filter_map(ValidatorDetails::api_url)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name of the event triggered by the eth contract. If the event name is changed,
|
// Name of the event triggered by the eth contract. If the event name is changed,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::var_names;
|
||||||
use crate::{DenomDetails, ValidatorDetails};
|
use crate::{DenomDetails, ValidatorDetails};
|
||||||
|
|
||||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||||
@@ -24,9 +25,48 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
|||||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
|
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n10yyd98e2tuwu0f7ypz9dy3hhjw7v772q6287gy";
|
||||||
|
|
||||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://127.0.0.1:8090";
|
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://127.0.0.1:8090";
|
||||||
|
pub const NYMD_VALIDATOR: &str = "https://rpc.nyx.nodes.guru/";
|
||||||
|
pub const API_VALIDATOR: &str = "https://validator.nymtech.net/api/";
|
||||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||||
vec![ValidatorDetails::new(
|
vec![ValidatorDetails::new(NYMD_VALIDATOR, Some(API_VALIDATOR))]
|
||||||
"https://rpc.nyx.nodes.guru/",
|
}
|
||||||
Some("https://validator.nymtech.net/api/"),
|
|
||||||
)]
|
pub fn export_to_env() {
|
||||||
|
std::env::set_var(var_names::CONFIGURED, "true");
|
||||||
|
std::env::set_var(var_names::BECH32_PREFIX, BECH32_PREFIX);
|
||||||
|
std::env::set_var(var_names::MIX_DENOM, MIX_DENOM.base);
|
||||||
|
std::env::set_var(var_names::MIX_DENOM_DISPLAY, MIX_DENOM.display);
|
||||||
|
std::env::set_var(var_names::STAKE_DENOM, STAKE_DENOM.base);
|
||||||
|
std::env::set_var(var_names::STAKE_DENOM_DISPLAY, STAKE_DENOM.display);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::DENOMS_EXPONENT,
|
||||||
|
STAKE_DENOM.display_exponent.to_string(),
|
||||||
|
);
|
||||||
|
std::env::set_var(var_names::MIXNET_CONTRACT_ADDRESS, MIXNET_CONTRACT_ADDRESS);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::VESTING_CONTRACT_ADDRESS,
|
||||||
|
VESTING_CONTRACT_ADDRESS,
|
||||||
|
);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||||
|
BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||||
|
);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||||
|
COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||||
|
);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::MULTISIG_CONTRACT_ADDRESS,
|
||||||
|
MULTISIG_CONTRACT_ADDRESS,
|
||||||
|
);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::REWARDING_VALIDATOR_ADDRESS,
|
||||||
|
REWARDING_VALIDATOR_ADDRESS,
|
||||||
|
);
|
||||||
|
std::env::set_var(
|
||||||
|
var_names::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||||
|
STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||||
|
);
|
||||||
|
std::env::set_var(var_names::NYMD_VALIDATOR, NYMD_VALIDATOR);
|
||||||
|
std::env::set_var(var_names::API_VALIDATOR, API_VALIDATOR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
|||||||
hex_literal::hex!("0000000000000000000000000000000000000000");
|
hex_literal::hex!("0000000000000000000000000000000000000000");
|
||||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq";
|
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "n1tfzd4qz3a45u8p4mr5zmzv66457uwjgcl05jdq";
|
||||||
|
|
||||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
|
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://0.0.0.0";
|
||||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||||
vec![ValidatorDetails::new(
|
vec![ValidatorDetails::new(
|
||||||
"https://qa-validator.nymtech.net",
|
"https://qa-validator.nymtech.net",
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
|||||||
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
|
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
|
||||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
|
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "nymt1jh0s6qu6tuw9ut438836mmn7f3f2wencrnmdj4";
|
||||||
|
|
||||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
|
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "http://0.0.0.0";
|
||||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
||||||
vec![ValidatorDetails::new(
|
vec![ValidatorDetails::new(
|
||||||
"https://sandbox-validator.nymtech.net",
|
"https://sandbox-validator.nymtech.net",
|
||||||
|
|||||||
@@ -1,30 +0,0 @@
|
|||||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
use crate::{DenomDetails, ValidatorDetails};
|
|
||||||
|
|
||||||
pub(crate) const BECH32_PREFIX: &str = "ns";
|
|
||||||
|
|
||||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unymt", "nymt", 6);
|
|
||||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyxt", "nyxt", 6);
|
|
||||||
|
|
||||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "ns17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9jfksztgw5uh69wac2pgsrtzqqx";
|
|
||||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "ns1aakfpghcanxtc45gpqlx8j3rq0zcpyf49qmhm9mdjrfx036h4z5sptexdf";
|
|
||||||
pub(crate) const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str =
|
|
||||||
"";
|
|
||||||
pub(crate) const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str =
|
|
||||||
"";
|
|
||||||
pub(crate) const MULTISIG_CONTRACT_ADDRESS: &str = "";
|
|
||||||
pub(crate) const _ETH_CONTRACT_ADDRESS: [u8; 20] =
|
|
||||||
hex_literal::hex!("8e0DcFF7F3085235C32E845f3667aEB3f1e83133");
|
|
||||||
pub(crate) const _ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] =
|
|
||||||
hex_literal::hex!("E8883BAeF3869e14E4823F46662e81D4F7d2A81F");
|
|
||||||
pub(crate) const REWARDING_VALIDATOR_ADDRESS: &str = "ns1a4542dv9tvsa95zyztqsev6erjd2l3ywxhxnpg";
|
|
||||||
|
|
||||||
pub(crate) const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "";
|
|
||||||
pub(crate) fn validators() -> Vec<ValidatorDetails> {
|
|
||||||
vec![ValidatorDetails::new(
|
|
||||||
"https://sandbox2-validator1.nymtech.net",
|
|
||||||
Some("https://sandbox2-validator-api1.nymte.ch/api"),
|
|
||||||
)]
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Environment variable that, if set, shows the environment is currently configured
|
||||||
|
pub const CONFIGURED: &str = "CONFIGURED";
|
||||||
|
|
||||||
|
pub const BECH32_PREFIX: &str = "BECH32_PREFIX";
|
||||||
|
pub const MIX_DENOM: &str = "MIX_DENOM";
|
||||||
|
pub const MIX_DENOM_DISPLAY: &str = "MIX_DENOM_DISPLAY";
|
||||||
|
pub const STAKE_DENOM: &str = "STAKE_DENOM";
|
||||||
|
pub const STAKE_DENOM_DISPLAY: &str = "STAKE_DENOM_DISPLAY";
|
||||||
|
pub const DENOMS_EXPONENT: &str = "DENOMS_EXPONENT";
|
||||||
|
pub const MIXNET_CONTRACT_ADDRESS: &str = "MIXNET_CONTRACT_ADDRESS";
|
||||||
|
pub const VESTING_CONTRACT_ADDRESS: &str = "VESTING_CONTRACT_ADDRESS";
|
||||||
|
pub const BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = "BANDWIDTH_CLAIM_CONTRACT_ADDRESS";
|
||||||
|
pub const COCONUT_BANDWIDTH_CONTRACT_ADDRESS: &str = "COCONUT_BANDWIDTH_CONTRACT_ADDRESS";
|
||||||
|
pub const MULTISIG_CONTRACT_ADDRESS: &str = "MULTISIG_CONTRACT_ADDRESS";
|
||||||
|
pub const REWARDING_VALIDATOR_ADDRESS: &str = "REWARDING_VALIDATOR_ADDRESS";
|
||||||
|
pub const STATISTICS_SERVICE_DOMAIN_ADDRESS: &str = "STATISTICS_SERVICE_DOMAIN_ADDRESS";
|
||||||
|
pub const NYMD_VALIDATOR: &str = "NYMD_VALIDATOR";
|
||||||
|
pub const API_VALIDATOR: &str = "API_VALIDATOR";
|
||||||
@@ -20,7 +20,7 @@ pub type EphemeralKey = Scalar;
|
|||||||
|
|
||||||
/// Two G1 points representing ElGamal ciphertext
|
/// Two G1 points representing ElGamal ciphertext
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct Ciphertext(pub(crate) G1Projective, pub(crate) G1Projective);
|
pub struct Ciphertext(pub(crate) G1Projective, pub(crate) G1Projective);
|
||||||
|
|
||||||
impl TryFrom<&[u8]> for Ciphertext {
|
impl TryFrom<&[u8]> for Ciphertext {
|
||||||
@@ -73,7 +73,7 @@ impl Ciphertext {
|
|||||||
|
|
||||||
/// PrivateKey used in the ElGamal encryption scheme to recover the plaintext
|
/// PrivateKey used in the ElGamal encryption scheme to recover the plaintext
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct PrivateKey(pub(crate) Scalar);
|
pub struct PrivateKey(pub(crate) Scalar);
|
||||||
|
|
||||||
impl PrivateKey {
|
impl PrivateKey {
|
||||||
@@ -121,7 +121,7 @@ impl Base58 for PrivateKey {}
|
|||||||
// TODO: perhaps be more explicit and apart from gamma also store generator and group order?
|
// TODO: perhaps be more explicit and apart from gamma also store generator and group order?
|
||||||
/// PublicKey used in the ElGamal encryption scheme to produce the ciphertext
|
/// PublicKey used in the ElGamal encryption scheme to produce the ciphertext
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct PublicKey(G1Projective);
|
pub struct PublicKey(G1Projective);
|
||||||
|
|
||||||
impl PublicKey {
|
impl PublicKey {
|
||||||
|
|||||||
@@ -34,8 +34,7 @@ mod error;
|
|||||||
mod impls;
|
mod impls;
|
||||||
mod proofs;
|
mod proofs;
|
||||||
mod scheme;
|
mod scheme;
|
||||||
#[cfg(test)]
|
pub mod tests;
|
||||||
mod tests;
|
|
||||||
mod traits;
|
mod traits;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use crate::Attribute;
|
|||||||
type ChallengeDigest = Sha256;
|
type ChallengeDigest = Sha256;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct ProofCmCs {
|
pub struct ProofCmCs {
|
||||||
challenge: Scalar,
|
challenge: Scalar,
|
||||||
response_opening: Scalar,
|
response_opening: Scalar,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ use crate::utils::{hash_g1, try_deserialize_g1_projective};
|
|||||||
// TODO NAMING: double check this one
|
// TODO NAMING: double check this one
|
||||||
// Lambda
|
// Lambda
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct BlindSignRequest {
|
pub struct BlindSignRequest {
|
||||||
// cm
|
// cm
|
||||||
commitment: G1Projective,
|
commitment: G1Projective,
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use crate::utils::{
|
|||||||
use crate::Base58;
|
use crate::Base58;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct SecretKey {
|
pub struct SecretKey {
|
||||||
pub(crate) x: Scalar,
|
pub(crate) x: Scalar,
|
||||||
pub(crate) ys: Vec<Scalar>,
|
pub(crate) ys: Vec<Scalar>,
|
||||||
@@ -351,7 +351,7 @@ impl Bytable for VerificationKey {
|
|||||||
impl Base58 for VerificationKey {}
|
impl Base58 for VerificationKey {}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct KeyPair {
|
pub struct KeyPair {
|
||||||
secret_key: SecretKey,
|
secret_key: SecretKey,
|
||||||
verification_key: VerificationKey,
|
verification_key: VerificationKey,
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ impl Bytable for Signature {
|
|||||||
impl Base58 for Signature {}
|
impl Base58 for Signature {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(test, derive(PartialEq))]
|
#[cfg_attr(test, derive(PartialEq, Eq))]
|
||||||
pub struct BlindedSignature(G1Projective, G1Projective);
|
pub struct BlindedSignature(G1Projective, G1Projective);
|
||||||
|
|
||||||
impl Bytable for BlindedSignature {
|
impl Bytable for BlindedSignature {
|
||||||
|
|||||||
@@ -1,23 +1,13 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign,
|
aggregate_verification_keys, setup, tests::helpers::theta_from_keys_and_attributes, ttp_keygen,
|
||||||
prove_bandwidth_credential, setup, ttp_keygen, verify_credential, CoconutError, Signature,
|
verify_credential, CoconutError, VerificationKey,
|
||||||
SignatureShare, VerificationKey,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use itertools::izip;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn main() -> Result<(), CoconutError> {
|
fn main() -> Result<(), CoconutError> {
|
||||||
let params = setup(5)?;
|
let params = setup(5)?;
|
||||||
|
|
||||||
let public_attributes = params.n_random_scalars(2);
|
let public_attributes = params.n_random_scalars(2);
|
||||||
let serial_number = params.random_scalar();
|
|
||||||
let binding_number = params.random_scalar();
|
|
||||||
let private_attributes = vec![serial_number, binding_number];
|
|
||||||
|
|
||||||
// generate commitment
|
|
||||||
let (commitments_openings, blind_sign_request) =
|
|
||||||
prepare_blind_sign(¶ms, &private_attributes, &public_attributes)?;
|
|
||||||
|
|
||||||
// generate_keys
|
// generate_keys
|
||||||
let coconut_keypairs = ttp_keygen(¶ms, 2, 3)?;
|
let coconut_keypairs = ttp_keygen(¶ms, 2, 3)?;
|
||||||
@@ -30,58 +20,8 @@ fn main() -> Result<(), CoconutError> {
|
|||||||
// aggregate verification keys
|
// aggregate verification keys
|
||||||
let verification_key = aggregate_verification_keys(&verification_keys, Some(&[1, 2, 3]))?;
|
let verification_key = aggregate_verification_keys(&verification_keys, Some(&[1, 2, 3]))?;
|
||||||
|
|
||||||
// generate blinded signatures
|
|
||||||
let mut blinded_signatures = Vec::new();
|
|
||||||
|
|
||||||
for keypair in coconut_keypairs {
|
|
||||||
let blinded_signature = blind_sign(
|
|
||||||
¶ms,
|
|
||||||
&keypair.secret_key(),
|
|
||||||
&blind_sign_request,
|
|
||||||
&public_attributes,
|
|
||||||
)?;
|
|
||||||
blinded_signatures.push(blinded_signature)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unblind
|
|
||||||
let unblinded_signatures: Vec<Signature> =
|
|
||||||
izip!(blinded_signatures.iter(), verification_keys.iter())
|
|
||||||
.map(|(s, vk)| {
|
|
||||||
s.unblind(
|
|
||||||
¶ms,
|
|
||||||
vk,
|
|
||||||
&private_attributes,
|
|
||||||
&public_attributes,
|
|
||||||
&blind_sign_request.get_commitment_hash(),
|
|
||||||
&commitments_openings,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Aggregate signatures
|
|
||||||
let signature_shares: Vec<SignatureShare> = unblinded_signatures
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, signature)| SignatureShare::new(*signature, (idx + 1) as u64))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
|
|
||||||
attributes.extend_from_slice(&private_attributes);
|
|
||||||
attributes.extend_from_slice(&public_attributes);
|
|
||||||
|
|
||||||
// Randomize credentials and generate any cryptographic material to verify them
|
|
||||||
let signature =
|
|
||||||
aggregate_signature_shares(¶ms, &verification_key, &attributes, &signature_shares)?;
|
|
||||||
|
|
||||||
// Generate cryptographic material to verify them
|
// Generate cryptographic material to verify them
|
||||||
let theta = prove_bandwidth_credential(
|
let theta = theta_from_keys_and_attributes(¶ms, &coconut_keypairs, &public_attributes)?;
|
||||||
¶ms,
|
|
||||||
&verification_key,
|
|
||||||
&signature,
|
|
||||||
serial_number,
|
|
||||||
binding_number,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Verify credentials
|
// Verify credentials
|
||||||
assert!(verify_credential(
|
assert!(verify_credential(
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::*;
|
||||||
|
use itertools::izip;
|
||||||
|
|
||||||
|
pub fn theta_from_keys_and_attributes(
|
||||||
|
params: &Parameters,
|
||||||
|
coconut_keypairs: &Vec<KeyPair>,
|
||||||
|
public_attributes: &Vec<PublicAttribute>,
|
||||||
|
) -> Result<Theta, CoconutError> {
|
||||||
|
let serial_number = params.random_scalar();
|
||||||
|
let binding_number = params.random_scalar();
|
||||||
|
let private_attributes = vec![serial_number, binding_number];
|
||||||
|
|
||||||
|
// generate commitment
|
||||||
|
let (commitments_openings, blind_sign_request) =
|
||||||
|
prepare_blind_sign(params, &private_attributes, public_attributes)?;
|
||||||
|
|
||||||
|
let verification_keys: Vec<VerificationKey> = coconut_keypairs
|
||||||
|
.iter()
|
||||||
|
.map(|keypair| keypair.verification_key())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// aggregate verification keys
|
||||||
|
let indices: Vec<u64> = coconut_keypairs
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, _)| (idx + 1) as u64)
|
||||||
|
.collect();
|
||||||
|
let verification_key = aggregate_verification_keys(&verification_keys, Some(&indices))?;
|
||||||
|
|
||||||
|
// generate blinded signatures
|
||||||
|
let mut blinded_signatures = Vec::new();
|
||||||
|
|
||||||
|
for keypair in coconut_keypairs {
|
||||||
|
let blinded_signature = blind_sign(
|
||||||
|
params,
|
||||||
|
&keypair.secret_key(),
|
||||||
|
&blind_sign_request,
|
||||||
|
public_attributes,
|
||||||
|
)?;
|
||||||
|
blinded_signatures.push(blinded_signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unblind
|
||||||
|
let unblinded_signatures: Vec<Signature> =
|
||||||
|
izip!(blinded_signatures.iter(), verification_keys.iter())
|
||||||
|
.map(|(s, vk)| {
|
||||||
|
s.unblind(
|
||||||
|
params,
|
||||||
|
vk,
|
||||||
|
&private_attributes,
|
||||||
|
public_attributes,
|
||||||
|
&blind_sign_request.get_commitment_hash(),
|
||||||
|
&commitments_openings,
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Aggregate signatures
|
||||||
|
let signature_shares: Vec<SignatureShare> = unblinded_signatures
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, signature)| SignatureShare::new(*signature, (idx + 1) as u64))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut attributes = Vec::with_capacity(private_attributes.len() + public_attributes.len());
|
||||||
|
attributes.extend_from_slice(&private_attributes);
|
||||||
|
attributes.extend_from_slice(public_attributes);
|
||||||
|
|
||||||
|
// Randomize credentials and generate any cryptographic material to verify them
|
||||||
|
let signature =
|
||||||
|
aggregate_signature_shares(params, &verification_key, &attributes, &signature_shares)?;
|
||||||
|
|
||||||
|
// Generate cryptographic material to verify them
|
||||||
|
let theta = prove_bandwidth_credential(
|
||||||
|
params,
|
||||||
|
&verification_key,
|
||||||
|
&signature,
|
||||||
|
serial_number,
|
||||||
|
binding_number,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(theta)
|
||||||
|
}
|
||||||
@@ -1 +1,3 @@
|
|||||||
|
#[cfg(test)]
|
||||||
mod e2e;
|
mod e2e;
|
||||||
|
pub mod helpers;
|
||||||
|
|||||||
@@ -17,5 +17,3 @@ serde_json = "1"
|
|||||||
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
|
sqlx = { version = "0.5", features = ["runtime-tokio-rustls", "chrono"]}
|
||||||
thiserror = "1"
|
thiserror = "1"
|
||||||
tokio = { version = "1.19.1", features = [ "time" ] }
|
tokio = { version = "1.19.1", features = [ "time" ] }
|
||||||
|
|
||||||
network-defaults = { path = "../network-defaults" }
|
|
||||||
|
|||||||
@@ -34,12 +34,16 @@ pub enum StatsData {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct StatsGatewayData {
|
pub struct StatsGatewayData {
|
||||||
|
pub gateway_id: String,
|
||||||
pub inbox_count: u32,
|
pub inbox_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatsGatewayData {
|
impl StatsGatewayData {
|
||||||
pub fn new(inbox_count: u32) -> Self {
|
pub fn new(gateway_id: String, inbox_count: u32) -> Self {
|
||||||
StatsGatewayData { inbox_count }
|
StatsGatewayData {
|
||||||
|
gateway_id,
|
||||||
|
inbox_count,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ url = "2.2"
|
|||||||
ts-rs = "6.1.2"
|
ts-rs = "6.1.2"
|
||||||
|
|
||||||
cosmwasm-std = "1.0.0-beta8"
|
cosmwasm-std = "1.0.0-beta8"
|
||||||
cosmrs = "0.7.0"
|
cosmrs = { git = "https://github.com/neacsu/cosmos-rust", branch = "neacsu/feegrant_support" }
|
||||||
|
|
||||||
validator-client = { path = "../../common/client-libs/validator-client", features = [
|
validator-client = { path = "../../common/client-libs/validator-client", features = [
|
||||||
"nymd-client",
|
"nymd-client",
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::currency::{CurrencyDenom, MajorCurrencyAmount};
|
use crate::currency::{CurrencyDenom, DecCoin};
|
||||||
|
use config::defaults::DenomDetails;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
@@ -9,17 +10,20 @@ use serde::{Deserialize, Serialize};
|
|||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct Account {
|
pub struct Account {
|
||||||
pub contract_address: String,
|
|
||||||
pub client_address: String,
|
pub client_address: String,
|
||||||
pub denom: CurrencyDenom,
|
pub base_mix_denom: String,
|
||||||
|
|
||||||
|
// this should get refactored to just use a String, but for now it's fine as it reduces headache
|
||||||
|
// for others
|
||||||
|
pub display_mix_denom: CurrencyDenom,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Account {
|
impl Account {
|
||||||
pub fn new(contract_address: String, client_address: String, denom: CurrencyDenom) -> Self {
|
pub fn new(client_address: String, mix_denom: DenomDetails) -> Self {
|
||||||
Account {
|
Account {
|
||||||
contract_address,
|
|
||||||
client_address,
|
client_address,
|
||||||
denom,
|
base_mix_denom: mix_denom.base.to_owned(),
|
||||||
|
display_mix_denom: mix_denom.display.parse().unwrap_or_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,6 +57,15 @@ pub struct AccountEntry {
|
|||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct Balance {
|
pub struct Balance {
|
||||||
pub amount: MajorCurrencyAmount,
|
pub amount: DecCoin,
|
||||||
pub printable_balance: String,
|
pub printable_balance: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Balance {
|
||||||
|
pub fn new(amount: DecCoin) -> Self {
|
||||||
|
Balance {
|
||||||
|
printable_balance: amount.to_string(),
|
||||||
|
amount,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+412
-384
@@ -1,24 +1,29 @@
|
|||||||
use crate::error::TypesError;
|
use crate::error::TypesError;
|
||||||
use cosmrs::Denom as CosmosDenom;
|
use config::defaults::all::Network;
|
||||||
use cosmwasm_std::Coin as CosmWasmCoin;
|
use config::defaults::{DenomDetails, DenomDetailsOwned};
|
||||||
|
use cosmwasm_std::Fraction;
|
||||||
use cosmwasm_std::{Decimal, Uint128};
|
use cosmwasm_std::{Decimal, Uint128};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::ops::{Add, Mul};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use strum::{Display, EnumString, EnumVariantNames};
|
use strum::{Display, EnumString, EnumVariantNames};
|
||||||
use validator_client::nymd::{Coin, CosmosCoin};
|
use validator_client::nymd::Coin;
|
||||||
|
|
||||||
|
#[cfg(feature = "generate-ts")]
|
||||||
|
use ts_rs::{Dependency, TS};
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "generate-ts",
|
feature = "generate-ts",
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/CurrencyDenom.ts")
|
ts(export_to = "ts-packages/types/src/types/rust/CurrencyDenom.ts")
|
||||||
)]
|
)]
|
||||||
#[cfg_attr(feature = "generate-ts", ts(rename_all = "UPPERCASE"))]
|
#[cfg_attr(feature = "generate-ts", ts(rename_all = "lowercase"))]
|
||||||
#[derive(
|
#[derive(
|
||||||
Display,
|
Display,
|
||||||
|
Default,
|
||||||
Serialize,
|
Serialize,
|
||||||
Deserialize,
|
Deserialize,
|
||||||
Clone,
|
Clone,
|
||||||
@@ -29,10 +34,12 @@ use validator_client::nymd::{Coin, CosmosCoin};
|
|||||||
Eq,
|
Eq,
|
||||||
JsonSchema,
|
JsonSchema,
|
||||||
)]
|
)]
|
||||||
#[serde(rename_all = "UPPERCASE")]
|
#[serde(rename_all = "lowercase")]
|
||||||
#[strum(serialize_all = "UPPERCASE")]
|
#[strum(serialize_all = "lowercase")]
|
||||||
// TODO: this shouldn't be an enum...
|
|
||||||
pub enum CurrencyDenom {
|
pub enum CurrencyDenom {
|
||||||
|
#[strum(ascii_case_insensitive)]
|
||||||
|
#[default]
|
||||||
|
Unknown,
|
||||||
#[strum(ascii_case_insensitive)]
|
#[strum(ascii_case_insensitive)]
|
||||||
Nym,
|
Nym,
|
||||||
#[strum(ascii_case_insensitive)]
|
#[strum(ascii_case_insensitive)]
|
||||||
@@ -43,448 +50,469 @@ pub enum CurrencyDenom {
|
|||||||
Nyxt,
|
Nyxt,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CurrencyDenom {
|
pub type Denom = String;
|
||||||
pub fn parse(value: &str) -> Result<CurrencyDenom, TypesError> {
|
|
||||||
let mut denom = value.to_string();
|
#[derive(Debug, Default)]
|
||||||
if denom.starts_with('u') {
|
pub struct RegisteredCoins(HashMap<Denom, CoinMetadata>);
|
||||||
denom = denom[1..].to_string();
|
|
||||||
|
impl RegisteredCoins {
|
||||||
|
pub fn default_denoms(network: Network) -> Self {
|
||||||
|
let mut network_coins = HashMap::new();
|
||||||
|
network_coins.insert(network.mix_denom().base, network.mix_denom().into());
|
||||||
|
network_coins.insert(network.stake_denom().base, network.stake_denom().into());
|
||||||
|
RegisteredCoins(network_coins)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, denom: Denom, metadata: CoinMetadata) -> Option<CoinMetadata> {
|
||||||
|
self.0.insert(denom, metadata)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, denom: &Denom) -> Option<CoinMetadata> {
|
||||||
|
self.0.remove(denom)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn attempt_convert_to_base_coin(&self, coin: DecCoin) -> Result<Coin, TypesError> {
|
||||||
|
// check if this is already in the base denom
|
||||||
|
if self.0.contains_key(&coin.denom) {
|
||||||
|
// if we're converting a base DecCoin it CANNOT fail, unless somebody is providing
|
||||||
|
// bullshit data on purpose : )
|
||||||
|
return coin.try_into();
|
||||||
|
} else {
|
||||||
|
// TODO: this kinda suggests we may need a better data structure
|
||||||
|
for registered_coin in self.0.values() {
|
||||||
|
if let Some(exponent) = registered_coin.get_exponent(&coin.denom) {
|
||||||
|
let amount = try_convert_decimal_to_u128(coin.try_scale_up_value(exponent)?)?;
|
||||||
|
return Ok(Coin::new(amount, ®istered_coin.base));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
match CurrencyDenom::from_str(&denom) {
|
Err(TypesError::UnknownCoinDenom(coin.denom))
|
||||||
Ok(res) => Ok(res),
|
}
|
||||||
Err(_e) => Err(TypesError::InvalidDenom(value.to_string())),
|
|
||||||
|
pub fn attempt_convert_to_display_dec_coin(&self, coin: Coin) -> Result<DecCoin, TypesError> {
|
||||||
|
for registered_coin in self.0.values() {
|
||||||
|
if let Some(exponent) = registered_coin.get_exponent(&coin.denom) {
|
||||||
|
// if this fails it means we haven't registered our display denom which honestly should never be the case
|
||||||
|
// unless somebody is rocking their own custom network
|
||||||
|
let display_exponent = registered_coin
|
||||||
|
.get_exponent(®istered_coin.display)
|
||||||
|
.ok_or_else(|| TypesError::UnknownCoinDenom(coin.denom.clone()))?;
|
||||||
|
|
||||||
|
return match exponent.cmp(&display_exponent) {
|
||||||
|
Ordering::Greater => {
|
||||||
|
// we need to scale up, unlikely to ever be needed but included for completion sake,
|
||||||
|
// for example if we decided to created knym with exponent 9 and wanted to convert to nym with exponent 6
|
||||||
|
Ok(DecCoin::new_scaled_up(
|
||||||
|
coin.amount,
|
||||||
|
®istered_coin.display,
|
||||||
|
exponent - display_exponent,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
// we're already in the display denom
|
||||||
|
Ordering::Equal => Ok(coin.into()),
|
||||||
|
Ordering::Less => {
|
||||||
|
// we need to scale down, the most common case, for example we're in base unym with exponent 0 and want to convert to nym with exponent 6
|
||||||
|
Ok(DecCoin::new_scaled_down(
|
||||||
|
coin.amount,
|
||||||
|
®istered_coin.display,
|
||||||
|
display_exponent - exponent,
|
||||||
|
)?)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(TypesError::UnknownCoinDenom(coin.denom))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<CosmosDenom> for CurrencyDenom {
|
// TODO: should this live here?
|
||||||
type Error = TypesError;
|
// attempts to replicate cosmos-sdk's coin metadata
|
||||||
|
// https://docs.cosmos.network/master/architecture/adr-024-coin-metadata.html
|
||||||
|
// this way we could more easily handle multiple coin types simultaneously (like nym/nyx/nymt/nyx + local currencies)
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DenomUnit {
|
||||||
|
pub denom: Denom,
|
||||||
|
pub exponent: u32,
|
||||||
|
// pub aliases: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
fn try_from(value: CosmosDenom) -> Result<Self, Self::Error> {
|
impl DenomUnit {
|
||||||
CurrencyDenom::parse(value.as_ref())
|
pub fn new(denom: Denom, exponent: u32) -> Self {
|
||||||
|
DenomUnit { denom, exponent }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(
|
pub struct CoinMetadata {
|
||||||
feature = "generate-ts",
|
pub denom_units: Vec<DenomUnit>,
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/CurrencyStringMajorAmount.ts")
|
pub base: Denom,
|
||||||
)]
|
pub display: Denom,
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
||||||
pub struct MajorAmountString(String); // see https://github.com/Aleph-Alpha/ts-rs/issues/51 for exporting type aliases
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
|
||||||
#[cfg_attr(
|
|
||||||
feature = "generate-ts",
|
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/Currency.ts")
|
|
||||||
)]
|
|
||||||
// #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
|
|
||||||
pub struct MajorCurrencyAmount {
|
|
||||||
// temporarly going back to original impl to speed up merge
|
|
||||||
pub amount: MajorAmountString,
|
|
||||||
pub denom: CurrencyDenom,
|
|
||||||
// // temporary...
|
|
||||||
// #[cfg_attr(feature = "generate-ts", ts(skip))]
|
|
||||||
// pub coin: Coin,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl JsonSchema for MajorCurrencyAmount {
|
impl CoinMetadata {
|
||||||
// fn schema_name() -> String {
|
pub fn new(denom_units: Vec<DenomUnit>, base: Denom, display: Denom) -> Self {
|
||||||
// todo!()
|
CoinMetadata {
|
||||||
// }
|
denom_units,
|
||||||
//
|
base,
|
||||||
// fn json_schema(gen: &mut SchemaGenerator) -> Schema {
|
display,
|
||||||
// todo!()
|
}
|
||||||
// }
|
}
|
||||||
// }
|
|
||||||
|
pub fn get_exponent(&self, denom: &str) -> Option<u32> {
|
||||||
|
self.denom_units
|
||||||
|
.iter()
|
||||||
|
.find(|denom_unit| denom_unit.denom == denom)
|
||||||
|
.map(|denom_unit| denom_unit.exponent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DenomDetails> for CoinMetadata {
|
||||||
|
fn from(denom_details: DenomDetails) -> Self {
|
||||||
|
CoinMetadata::new(
|
||||||
|
vec![
|
||||||
|
DenomUnit::new(denom_details.base.into(), 0),
|
||||||
|
DenomUnit::new(denom_details.display.into(), denom_details.display_exponent),
|
||||||
|
],
|
||||||
|
denom_details.base.into(),
|
||||||
|
denom_details.display.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DenomDetailsOwned> for CoinMetadata {
|
||||||
|
fn from(denom_details: DenomDetailsOwned) -> Self {
|
||||||
|
CoinMetadata::new(
|
||||||
|
vec![
|
||||||
|
DenomUnit::new(denom_details.base.clone(), 0),
|
||||||
|
DenomUnit::new(
|
||||||
|
denom_details.display.clone(),
|
||||||
|
denom_details.display_exponent,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
denom_details.base,
|
||||||
|
denom_details.display,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// tries to semi-replicate cosmos-sdk's DecCoin for being able to handle tokens with decimal amounts
|
// tries to semi-replicate cosmos-sdk's DecCoin for being able to handle tokens with decimal amounts
|
||||||
// https://github.com/cosmos/cosmos-sdk/blob/v0.45.4/types/dec_coin.go
|
// https://github.com/cosmos/cosmos-sdk/blob/v0.45.4/types/dec_coin.go
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, JsonSchema)]
|
||||||
pub struct DecCoin {
|
pub struct DecCoin {
|
||||||
//
|
pub denom: Denom,
|
||||||
|
// Decimal is already serialized to string and using string in its schema, so lets also go straight to string for ts_rs
|
||||||
|
// todo: is `Decimal` the correct type to use? Do we want to depend on cosmwasm_std here?
|
||||||
|
pub amount: Decimal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MajorCurrencyAmount {
|
// I had to implement it manually to correctly set dependencies
|
||||||
pub fn new(amount: &str, denom: CurrencyDenom) -> MajorCurrencyAmount {
|
#[cfg(feature = "generate-ts")]
|
||||||
MajorCurrencyAmount {
|
impl TS for DecCoin {
|
||||||
amount: MajorAmountString(amount.to_string()),
|
const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/DecCoin.ts");
|
||||||
denom,
|
|
||||||
|
fn decl() -> String {
|
||||||
|
format!("type {} = {};", Self::name(), Self::inline())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name() -> String {
|
||||||
|
"DecCoin".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inline() -> String {
|
||||||
|
"{ denom: CurrencyDenom, amount: string }".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dependencies() -> Vec<Dependency> {
|
||||||
|
vec![Dependency::from_ty::<CurrencyDenom>()
|
||||||
|
.expect("TS was incorrectly defined on `CurrencyDenom`")]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transparent() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DecCoin {
|
||||||
|
pub fn new_base<S: Into<String>>(amount: impl Into<Uint128>, denom: S) -> Self {
|
||||||
|
DecCoin {
|
||||||
|
denom: denom.into(),
|
||||||
|
amount: Decimal::from_atomics(amount, 0).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zero(denom: &CurrencyDenom) -> MajorCurrencyAmount {
|
pub fn zero<S: Into<String>>(denom: S) -> Self {
|
||||||
MajorCurrencyAmount::new("0", denom.clone())
|
DecCoin {
|
||||||
|
denom: denom.into(),
|
||||||
|
amount: Decimal::zero(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// pub fn from_cosmrs_coin(coin: &CosmosCoin) -> Result<MajorCurrencyAmount, TypesError> {
|
|
||||||
// MajorCurrencyAmount::from_cosmrs_decimal_and_denom(coin.amount, coin.denom.to_string())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn from_minor_uint128_and_denom(
|
|
||||||
// amount_minor: Uint128,
|
|
||||||
// denom_minor: &str,
|
|
||||||
// ) -> Result<MajorCurrencyAmount, TypesError> {
|
|
||||||
// MajorCurrencyAmount::from_minor_decimal_and_denom(
|
|
||||||
// Decimal::from_atomics(amount_minor, 0)?,
|
|
||||||
// denom_minor,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn from_minor_decimal_and_denom(
|
|
||||||
// amount_minor: Decimal,
|
|
||||||
// denom_minor: &str,
|
|
||||||
// ) -> Result<MajorCurrencyAmount, TypesError> {
|
|
||||||
// if !(denom_minor.starts_with('u') || denom_minor.starts_with('U')) {
|
|
||||||
// return Err(TypesError::InvalidDenom(denom_minor.to_string()));
|
|
||||||
// }
|
|
||||||
// let major = amount_minor / Uint128::from(1_000_000u64);
|
|
||||||
// if let Ok(denom) = CurrencyDenom::from_str(&denom_minor[1..].to_string()) {
|
|
||||||
// return Ok(MajorCurrencyAmount {
|
|
||||||
// amount: MajorAmountString(major.to_string()),
|
|
||||||
// denom,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Err(TypesError::InvalidDenom(denom_minor.to_string()))
|
|
||||||
// }
|
|
||||||
// pub fn from_decimal_and_denom(
|
|
||||||
// amount: Decimal,
|
|
||||||
// denom: String,
|
|
||||||
// ) -> Result<MajorCurrencyAmount, TypesError> {
|
|
||||||
// if denom.starts_with('u') || denom.starts_with('U') {
|
|
||||||
// return MajorCurrencyAmount::from_minor_decimal_and_denom(amount, &denom);
|
|
||||||
// }
|
|
||||||
// if let Ok(denom) = CurrencyDenom::from_str(denom.as_str()) {
|
|
||||||
// return Ok(MajorCurrencyAmount {
|
|
||||||
// amount: MajorAmountString(amount.to_string()),
|
|
||||||
// denom,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Err(TypesError::InvalidDenom(denom))
|
|
||||||
// }
|
|
||||||
// pub fn from_cosmrs_decimal_and_denom(
|
|
||||||
// amount: CosmosDecimal,
|
|
||||||
// denom: String,
|
|
||||||
// ) -> Result<MajorCurrencyAmount, TypesError> {
|
|
||||||
// if denom.starts_with('u') || denom.starts_with('U') {
|
|
||||||
// return match Decimal::from_str(&amount.to_string()) {
|
|
||||||
// Ok(amount) => MajorCurrencyAmount::from_minor_decimal_and_denom(amount, &denom),
|
|
||||||
// Err(_e) => Err(TypesError::InvalidAmount(amount.to_string())),
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if let Ok(denom) = CurrencyDenom::from_str(denom.as_str()) {
|
|
||||||
// return Ok(MajorCurrencyAmount {
|
|
||||||
// amount: MajorAmountString(amount.to_string()),
|
|
||||||
// denom,
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// Err(TypesError::InvalidDenom(denom))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn into_cosmos_coin(self) -> CosmosCoin {
|
|
||||||
// self.coin.into()
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// pub fn to_minor_uint128(&self) -> Result<Uint128, TypesError> {
|
|
||||||
// if self.amount.0.contains('.') {
|
|
||||||
// // has a decimal point (Cosmos assumes "." is the decimal separator)
|
|
||||||
// let parts = self.amount.0.split('.');
|
|
||||||
// let str = parts.collect_vec();
|
|
||||||
// if str.is_empty() || str.len() > 2 {
|
|
||||||
// return Err(TypesError::InvalidAmount("Amount is invalid".to_string()));
|
|
||||||
// }
|
|
||||||
// if str.len() == 2 {
|
|
||||||
// // has a decimal, so check decimal places first
|
|
||||||
// if str[1].len() > 6 {
|
|
||||||
// return Err(TypesError::InvalidDenom(
|
|
||||||
// "Amount is invalid, only 6 decimal places of precision are allowed"
|
|
||||||
// .to_string(),
|
|
||||||
// ));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // so multiple whole part by 1e6 and add decimal part
|
|
||||||
// let whole_part = Uint128::from_str(str[0])? * Uint128::from(1_000_000u64);
|
|
||||||
//
|
|
||||||
// // TODO: has Rust got anything that deals with fixed point values, or parsing from format strings? Leading zeroes are causing issues
|
|
||||||
// return match format!("0.{}", str[1]).parse::<f64>() {
|
|
||||||
// Ok(decimal_part_float) => {
|
|
||||||
// // this makes an assumption that 6 decimal places of f64 can never lose precision
|
|
||||||
// let truncated = (decimal_part_float * 1_000_000.).trunc() as u32;
|
|
||||||
// let decimal_part = Uint128::from(truncated);
|
|
||||||
// let sum = whole_part + decimal_part;
|
|
||||||
// Ok(sum)
|
|
||||||
// }
|
|
||||||
// Err(_e) => Err(TypesError::InvalidAmount(
|
|
||||||
// "Amount decimal part is invalid".to_string(),
|
|
||||||
// )),
|
|
||||||
// };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// let major = Uint128::from_str(&self.amount.0)?;
|
|
||||||
// let scaled = major * Uint128::new(1_000_000u128);
|
|
||||||
// Ok(scaled)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn denom_to_string(&self) -> String {
|
pub fn new_scaled_up<S: Into<String>>(
|
||||||
// self.denom.to_string()
|
base_amount: impl Into<Uint128>,
|
||||||
// }
|
denom: S,
|
||||||
|
exponent: u32,
|
||||||
|
) -> Result<Self, TypesError> {
|
||||||
|
let base_amount = Decimal::from_atomics(base_amount, 0).unwrap();
|
||||||
|
Ok(DecCoin {
|
||||||
|
denom: denom.into(),
|
||||||
|
amount: try_scale_up_decimal(base_amount, exponent)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_scaled_down<S: Into<String>>(
|
||||||
|
base_amount: impl Into<Uint128>,
|
||||||
|
denom: S,
|
||||||
|
exponent: u32,
|
||||||
|
) -> Result<Self, TypesError> {
|
||||||
|
let base_amount = Decimal::from_atomics(base_amount, 0).unwrap();
|
||||||
|
Ok(DecCoin {
|
||||||
|
denom: denom.into(),
|
||||||
|
amount: try_scale_down_decimal(base_amount, exponent)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_scale_down_value(&self, exponent: u32) -> Result<Decimal, TypesError> {
|
||||||
|
try_scale_down_decimal(self.amount, exponent)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_scale_up_value(&self, exponent: u32) -> Result<Decimal, TypesError> {
|
||||||
|
try_scale_up_decimal(self.amount, exponent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for MajorCurrencyAmount {
|
// TODO: should thoese live here?
|
||||||
|
pub fn try_scale_down_decimal(dec: Decimal, exponent: u32) -> Result<Decimal, TypesError> {
|
||||||
|
let rhs = 10u128
|
||||||
|
.checked_pow(exponent)
|
||||||
|
.ok_or(TypesError::UnsupportedExponent(exponent))?;
|
||||||
|
let denominator = dec
|
||||||
|
.denominator()
|
||||||
|
.checked_mul(rhs.into())
|
||||||
|
.map_err(|_| TypesError::UnsupportedExponent(exponent))?;
|
||||||
|
|
||||||
|
Ok(Decimal::from_ratio(dec.numerator(), denominator))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_scale_up_decimal(dec: Decimal, exponent: u32) -> Result<Decimal, TypesError> {
|
||||||
|
let rhs = 10u128
|
||||||
|
.checked_pow(exponent)
|
||||||
|
.ok_or(TypesError::UnsupportedExponent(exponent))?;
|
||||||
|
let denominator = dec
|
||||||
|
.denominator()
|
||||||
|
.checked_div(rhs.into())
|
||||||
|
.map_err(|_| TypesError::UnsupportedExponent(exponent))?;
|
||||||
|
|
||||||
|
Ok(Decimal::from_ratio(dec.numerator(), denominator))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_convert_decimal_to_u128(dec: Decimal) -> Result<u128, TypesError> {
|
||||||
|
let whole = dec.numerator() / dec.denominator();
|
||||||
|
|
||||||
|
// unwrap is fine as we're not dividing by zero here
|
||||||
|
let fractional = (dec.numerator()).checked_rem(dec.denominator()).unwrap();
|
||||||
|
|
||||||
|
// we cannot convert as we'd lose our decimal places
|
||||||
|
// (for example if somebody attempted to represent our gas price (WHICH YOU SHOULDN'T DO) as DecCoin)
|
||||||
|
if fractional != Uint128::zero() {
|
||||||
|
return Err(TypesError::LossyCoinConversion);
|
||||||
|
}
|
||||||
|
Ok(whole.u128())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for DecCoin {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{} {}", self.amount.0, self.denom)
|
write!(f, "{} {}", self.amount, self.denom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cleanup after merge
|
impl From<Coin> for DecCoin {
|
||||||
impl From<CosmosCoin> for MajorCurrencyAmount {
|
|
||||||
fn from(c: CosmosCoin) -> Self {
|
|
||||||
MajorCurrencyAmount::from(Coin::from(c))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CosmWasmCoin> for MajorCurrencyAmount {
|
|
||||||
fn from(c: CosmWasmCoin) -> Self {
|
|
||||||
MajorCurrencyAmount::from(Coin::from(c))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Coin> for MajorCurrencyAmount {
|
|
||||||
fn from(coin: Coin) -> Self {
|
fn from(coin: Coin) -> Self {
|
||||||
// current assumption: MajorCurrencyAmount is represented as decimal with 6 decimal points
|
DecCoin::new_base(coin.amount, coin.denom)
|
||||||
// unwrap is fine as we haven't exceeded decimal range since our coins are at max 1B in value
|
|
||||||
// (this is a weak assumption, but for solving this merge conflict it's good enough temporary workaround)
|
|
||||||
let amount = Decimal::from_atomics(coin.amount, 6).unwrap();
|
|
||||||
MajorCurrencyAmount {
|
|
||||||
amount: MajorAmountString(amount.to_string()),
|
|
||||||
denom: CurrencyDenom::parse(&coin.denom).expect("this will go away after the merge..."),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// temporary...
|
// this conversion assumes same denomination
|
||||||
impl From<MajorCurrencyAmount> for CosmosCoin {
|
impl TryFrom<DecCoin> for Coin {
|
||||||
fn from(c: MajorCurrencyAmount) -> CosmosCoin {
|
type Error = TypesError;
|
||||||
let c: Coin = c.into();
|
|
||||||
c.into()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MajorCurrencyAmount> for CosmWasmCoin {
|
fn try_from(value: DecCoin) -> Result<Self, Self::Error> {
|
||||||
fn from(c: MajorCurrencyAmount) -> CosmWasmCoin {
|
Ok(Coin {
|
||||||
let c: Coin = c.into();
|
amount: try_convert_decimal_to_u128(value.try_scale_down_value(0)?)?,
|
||||||
c.into()
|
denom: value.denom,
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MajorCurrencyAmount> for Coin {
|
|
||||||
fn from(c: MajorCurrencyAmount) -> Coin {
|
|
||||||
let decimal: Decimal = c
|
|
||||||
.amount
|
|
||||||
.0
|
|
||||||
.parse()
|
|
||||||
.expect("stringified amount should have been a valid decimal");
|
|
||||||
|
|
||||||
// again, temporary
|
|
||||||
let exp = Uint128::new(1000000);
|
|
||||||
let val = decimal.mul(exp);
|
|
||||||
|
|
||||||
// again, terrible assumption for denom, but it works temporarily...
|
|
||||||
Coin {
|
|
||||||
amount: val.u128(),
|
|
||||||
denom: format!("u{}", c.denom).to_lowercase(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Add for MajorCurrencyAmount {
|
|
||||||
type Output = Self;
|
|
||||||
|
|
||||||
fn add(self, rhs: Self) -> Self::Output {
|
|
||||||
// again, temporary workaround to help with merge
|
|
||||||
(Coin::from(self).try_add(&Coin::from(rhs)))
|
|
||||||
.expect("provided coins had different denoms")
|
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use cosmrs::Coin as CosmosCoin;
|
use std::convert::TryFrom;
|
||||||
use cosmrs::Decimal as CosmosDecimal;
|
|
||||||
use cosmrs::Denom as CosmosDenom;
|
|
||||||
use cosmwasm_std::Coin as CosmWasmCoin;
|
|
||||||
use cosmwasm_std::Decimal as CosmWasmDecimal;
|
|
||||||
use serde_json::json;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn json_to_major_currency_amount() {
|
fn dec_value_scale_down() {
|
||||||
let nym = json!({
|
let dec = DecCoin {
|
||||||
"amount": "1",
|
denom: "foo".to_string(),
|
||||||
"denom": "NYM"
|
amount: "1234007000".parse().unwrap(),
|
||||||
});
|
};
|
||||||
let nymt = json!({
|
|
||||||
"amount": "1",
|
|
||||||
"denom": "NYMT"
|
|
||||||
});
|
|
||||||
|
|
||||||
let test_nym_amount = MajorCurrencyAmount::new("1", CurrencyDenom::Nym);
|
|
||||||
let test_nymt_amount = MajorCurrencyAmount::new("1", CurrencyDenom::Nymt);
|
|
||||||
|
|
||||||
let nym_amount = serde_json::from_value::<MajorCurrencyAmount>(nym).unwrap();
|
|
||||||
let nymt_amount = serde_json::from_value::<MajorCurrencyAmount>(nymt).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(nym_amount, test_nym_amount);
|
|
||||||
assert_eq!(nymt_amount, test_nymt_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn minor_amount_json_to_major_currency_amount() {
|
|
||||||
let one_micro_nym = json!({
|
|
||||||
"amount": "0.000001",
|
|
||||||
"denom": "NYM"
|
|
||||||
});
|
|
||||||
|
|
||||||
let expected_nym_amount = MajorCurrencyAmount::new("0.000001", CurrencyDenom::Nym);
|
|
||||||
let actual_nym_amount =
|
|
||||||
serde_json::from_value::<MajorCurrencyAmount>(one_micro_nym).unwrap();
|
|
||||||
|
|
||||||
assert_eq!(expected_nym_amount, actual_nym_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn denom_from_str() {
|
|
||||||
assert_eq!(CurrencyDenom::from_str("nym").unwrap(), CurrencyDenom::Nym);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
CurrencyDenom::from_str("nymt").unwrap(),
|
"1234007000".parse::<Decimal>().unwrap(),
|
||||||
CurrencyDenom::Nymt
|
dec.try_scale_down_value(0).unwrap()
|
||||||
);
|
|
||||||
assert_eq!(CurrencyDenom::from_str("NYM").unwrap(), CurrencyDenom::Nym);
|
|
||||||
assert_eq!(
|
|
||||||
CurrencyDenom::from_str("NYMT").unwrap(),
|
|
||||||
CurrencyDenom::Nymt
|
|
||||||
);
|
|
||||||
assert_eq!(CurrencyDenom::from_str("NyM").unwrap(), CurrencyDenom::Nym);
|
|
||||||
assert_eq!(
|
|
||||||
CurrencyDenom::from_str("NYmt").unwrap(),
|
|
||||||
CurrencyDenom::Nymt
|
|
||||||
);
|
|
||||||
|
|
||||||
assert!(matches!(
|
|
||||||
CurrencyDenom::from_str("foo").unwrap_err(),
|
|
||||||
strum::ParseError::VariantNotFound,
|
|
||||||
));
|
|
||||||
|
|
||||||
// denominations must all be major
|
|
||||||
assert!(matches!(
|
|
||||||
CurrencyDenom::from_str("unym").unwrap_err(),
|
|
||||||
strum::ParseError::VariantNotFound,
|
|
||||||
));
|
|
||||||
assert!(matches!(
|
|
||||||
CurrencyDenom::from_str("unymt").unwrap_err(),
|
|
||||||
strum::ParseError::VariantNotFound,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn to_string() {
|
|
||||||
assert_eq!(
|
|
||||||
MajorCurrencyAmount::new("1", CurrencyDenom::Nym).to_string(),
|
|
||||||
"1 NYM"
|
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MajorCurrencyAmount::new("1", CurrencyDenom::Nymt).to_string(),
|
"123400700".parse::<Decimal>().unwrap(),
|
||||||
"1 NYMT"
|
dec.try_scale_down_value(1).unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
MajorCurrencyAmount::new("1000000000000", CurrencyDenom::Nym).to_string(),
|
"12340070".parse::<Decimal>().unwrap(),
|
||||||
"1000000000000 NYM"
|
dec.try_scale_down_value(2).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"123400.7".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_down_value(4).unwrap()
|
||||||
|
);
|
||||||
|
|
||||||
|
let dec = DecCoin {
|
||||||
|
denom: "foo".to_string(),
|
||||||
|
amount: "10000000000".parse().unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
"100".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_down_value(8).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"1".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_down_value(10).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"0.01".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_down_value(12).unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn minor_coin_to_major_currency() {
|
fn dec_value_scale_up() {
|
||||||
let cosmos_coin = CosmosCoin {
|
let dec = DecCoin {
|
||||||
amount: CosmosDecimal::from(1u64),
|
denom: "foo".to_string(),
|
||||||
denom: CosmosDenom::from_str("unym").unwrap(),
|
amount: "1234.56".parse().unwrap(),
|
||||||
};
|
};
|
||||||
let c = MajorCurrencyAmount::from(cosmos_coin);
|
|
||||||
assert_eq!(c, MajorCurrencyAmount::new("0.000001", CurrencyDenom::Nym));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
assert_eq!(
|
||||||
fn minor_cosmwasm_coin_to_major_currency() {
|
"1234.56".parse::<Decimal>().unwrap(),
|
||||||
let coin = CosmWasmCoin {
|
dec.try_scale_up_value(0).unwrap()
|
||||||
amount: Uint128::from(1u64),
|
|
||||||
denom: "unym".to_string(),
|
|
||||||
};
|
|
||||||
println!(
|
|
||||||
"from_atomics = {}",
|
|
||||||
CosmWasmDecimal::from_atomics(coin.amount, 6).unwrap()
|
|
||||||
);
|
);
|
||||||
let c: MajorCurrencyAmount = coin.into();
|
assert_eq!(
|
||||||
assert_eq!(c, MajorCurrencyAmount::new("0.000001", CurrencyDenom::Nym));
|
"12345.6".parse::<Decimal>().unwrap(),
|
||||||
}
|
dec.try_scale_up_value(1).unwrap()
|
||||||
|
);
|
||||||
#[test]
|
assert_eq!(
|
||||||
fn minor_cosmwasm_coin_to_major_currency_2() {
|
"123456".parse::<Decimal>().unwrap(),
|
||||||
let coin = CosmWasmCoin {
|
dec.try_scale_up_value(2).unwrap()
|
||||||
amount: Uint128::from(1_000_000u64),
|
);
|
||||||
denom: "unym".to_string(),
|
assert_eq!(
|
||||||
};
|
"1234560".parse::<Decimal>().unwrap(),
|
||||||
println!(
|
dec.try_scale_up_value(3).unwrap()
|
||||||
"from_atomics = {:?}",
|
);
|
||||||
CosmWasmDecimal::from_atomics(coin.amount, 6)
|
assert_eq!(
|
||||||
.unwrap()
|
"12345600".parse::<Decimal>().unwrap(),
|
||||||
.to_string()
|
dec.try_scale_up_value(4).unwrap()
|
||||||
);
|
);
|
||||||
let c: MajorCurrencyAmount = coin.into();
|
|
||||||
assert_eq!(c, MajorCurrencyAmount::new("1", CurrencyDenom::Nym));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
let dec = DecCoin {
|
||||||
fn major_currency_to_minor_cosmos_coin() {
|
denom: "foo".to_string(),
|
||||||
let expected_cosmos_coin = CosmosCoin {
|
amount: "0.00000123".parse().unwrap(),
|
||||||
amount: CosmosDecimal::from(1u64),
|
|
||||||
denom: CosmosDenom::from_str("unym").unwrap(),
|
|
||||||
};
|
};
|
||||||
let c = MajorCurrencyAmount::new("0.000001", CurrencyDenom::Nym);
|
|
||||||
let minor_cosmos_coin = c.into();
|
assert_eq!(
|
||||||
assert_eq!(expected_cosmos_coin, minor_cosmos_coin);
|
"0.0000123".parse::<Decimal>().unwrap(),
|
||||||
assert_eq!("unym", minor_cosmos_coin.denom.to_string());
|
dec.try_scale_up_value(1).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"0.000123".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_up_value(2).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"123".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_up_value(8).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"1230".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_up_value(9).unwrap()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
"12300".parse::<Decimal>().unwrap(),
|
||||||
|
dec.try_scale_up_value(10).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn major_currency_to_minor_cosmos_coin_2() {
|
fn coin_to_dec_coin() {
|
||||||
let expected_cosmos_coin = CosmosCoin {
|
let coin = Coin::new(123, "foo");
|
||||||
amount: CosmosDecimal::from(1000000u64),
|
let dec = DecCoin::from(coin.clone());
|
||||||
denom: CosmosDenom::from_str("unym").unwrap(),
|
assert_eq!(coin.denom, dec.denom);
|
||||||
|
assert_eq!(dec.amount, Decimal::from_atomics(coin.amount, 0).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn dec_coin_to_coin() {
|
||||||
|
let dec = DecCoin {
|
||||||
|
denom: "foo".to_string(),
|
||||||
|
amount: "123".parse().unwrap(),
|
||||||
};
|
};
|
||||||
let c = MajorCurrencyAmount::new("1", CurrencyDenom::Nym);
|
let coin = Coin::try_from(dec.clone()).unwrap();
|
||||||
let minor_cosmos_coin = c.into();
|
assert_eq!(dec.denom, coin.denom);
|
||||||
assert_eq!(expected_cosmos_coin, minor_cosmos_coin);
|
assert_eq!(coin.amount, 123u128);
|
||||||
assert_eq!("unym", minor_cosmos_coin.denom.to_string());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn minor_cosmos_coin_to_major_currency_string() {
|
fn converting_to_display() {
|
||||||
// check minor cosmos coin is converted to major value
|
let reg = RegisteredCoins::default_denoms(Network::MAINNET);
|
||||||
let cosmos_coin = CosmosCoin {
|
let values = vec![
|
||||||
amount: CosmosDecimal::from(1u64),
|
(1u128, "0.000001"),
|
||||||
denom: CosmosDenom::from_str("unym").unwrap(),
|
(10u128, "0.00001"),
|
||||||
};
|
(100u128, "0.0001"),
|
||||||
let c = MajorCurrencyAmount::from(cosmos_coin);
|
(1000u128, "0.001"),
|
||||||
assert_eq!(c.to_string(), "0.000001 NYM");
|
(10000u128, "0.01"),
|
||||||
|
(100000u128, "0.1"),
|
||||||
|
(1000000u128, "1"),
|
||||||
|
(1234567u128, "1.234567"),
|
||||||
|
(123456700u128, "123.4567"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (raw, expected) in values {
|
||||||
|
let coin = Coin::new(raw, Network::MAINNET.mix_denom().base);
|
||||||
|
let display = reg.attempt_convert_to_display_dec_coin(coin).unwrap();
|
||||||
|
assert_eq!(Network::MAINNET.mix_denom().display, display.denom);
|
||||||
|
assert_eq!(expected, display.amount.to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn denom_to_string() {
|
fn converting_to_base() {
|
||||||
let c = MajorCurrencyAmount::new("1", CurrencyDenom::Nym);
|
let reg = RegisteredCoins::default_denoms(Network::MAINNET);
|
||||||
let denom = c.denom.to_string();
|
let values = vec![
|
||||||
assert_eq!(denom, "NYM".to_string());
|
(1u128, "0.000001"),
|
||||||
|
(10u128, "0.00001"),
|
||||||
|
(100u128, "0.0001"),
|
||||||
|
(1000u128, "0.001"),
|
||||||
|
(10000u128, "0.01"),
|
||||||
|
(100000u128, "0.1"),
|
||||||
|
(1000000u128, "1"),
|
||||||
|
(1234567u128, "1.234567"),
|
||||||
|
(123456700u128, "123.4567"),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (expected, raw_display) in values {
|
||||||
|
let coin = DecCoin {
|
||||||
|
denom: Network::MAINNET.mix_denom().display.into(),
|
||||||
|
amount: raw_display.parse().unwrap(),
|
||||||
|
};
|
||||||
|
let base = reg.attempt_convert_to_base_coin(coin).unwrap();
|
||||||
|
assert_eq!(Network::MAINNET.mix_denom().base, base.denom);
|
||||||
|
assert_eq!(expected, base.amount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+41
-106
@@ -1,13 +1,10 @@
|
|||||||
use schemars::JsonSchema;
|
use crate::currency::{DecCoin, RegisteredCoins};
|
||||||
use serde::{Deserialize, Serialize};
|
use crate::error::TypesError;
|
||||||
|
|
||||||
use log::error;
|
|
||||||
use mixnet_contract_common::mixnode::DelegationEvent as ContractDelegationEvent;
|
use mixnet_contract_common::mixnode::DelegationEvent as ContractDelegationEvent;
|
||||||
use mixnet_contract_common::mixnode::PendingUndelegate as ContractPendingUndelegate;
|
use mixnet_contract_common::mixnode::PendingUndelegate as ContractPendingUndelegate;
|
||||||
use mixnet_contract_common::Delegation as MixnetContractDelegation;
|
use mixnet_contract_common::Delegation as MixnetContractDelegation;
|
||||||
|
use schemars::JsonSchema;
|
||||||
use crate::currency::MajorCurrencyAmount;
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::error::TypesError;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
@@ -18,31 +15,22 @@ use crate::error::TypesError;
|
|||||||
pub struct Delegation {
|
pub struct Delegation {
|
||||||
pub owner: String,
|
pub owner: String,
|
||||||
pub node_identity: String,
|
pub node_identity: String,
|
||||||
pub amount: MajorCurrencyAmount,
|
pub amount: DecCoin,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub proxy: Option<String>, // proxy address used to delegate the funds on behalf of another address
|
pub proxy: Option<String>, // proxy address used to delegate the funds on behalf of another address
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<MixnetContractDelegation> for Delegation {
|
impl Delegation {
|
||||||
type Error = TypesError;
|
pub fn from_mixnet_contract(
|
||||||
|
delegation: MixnetContractDelegation,
|
||||||
fn try_from(value: MixnetContractDelegation) -> Result<Self, Self::Error> {
|
reg: &RegisteredCoins,
|
||||||
let MixnetContractDelegation {
|
) -> Result<Self, TypesError> {
|
||||||
owner,
|
|
||||||
node_identity,
|
|
||||||
amount,
|
|
||||||
block_height,
|
|
||||||
proxy,
|
|
||||||
} = value;
|
|
||||||
|
|
||||||
let amount: MajorCurrencyAmount = amount.into();
|
|
||||||
|
|
||||||
Ok(Delegation {
|
Ok(Delegation {
|
||||||
owner: owner.into_string(),
|
owner: delegation.owner.to_string(),
|
||||||
node_identity,
|
node_identity: delegation.node_identity,
|
||||||
amount,
|
amount: reg.attempt_convert_to_display_dec_coin(delegation.amount.into())?,
|
||||||
block_height,
|
block_height: delegation.block_height,
|
||||||
proxy: proxy.map(|p| p.into_string()),
|
proxy: delegation.proxy.map(|d| d.to_string()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,7 +42,7 @@ impl TryFrom<MixnetContractDelegation> for Delegation {
|
|||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq, JsonSchema)]
|
||||||
pub struct DelegationRecord {
|
pub struct DelegationRecord {
|
||||||
pub amount: MajorCurrencyAmount,
|
pub amount: DecCoin,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub delegated_on_iso_datetime: String,
|
pub delegated_on_iso_datetime: String,
|
||||||
pub uses_vesting_contract_tokens: bool,
|
pub uses_vesting_contract_tokens: bool,
|
||||||
@@ -69,16 +57,16 @@ pub struct DelegationRecord {
|
|||||||
pub struct DelegationWithEverything {
|
pub struct DelegationWithEverything {
|
||||||
pub owner: String,
|
pub owner: String,
|
||||||
pub node_identity: String,
|
pub node_identity: String,
|
||||||
pub amount: MajorCurrencyAmount,
|
pub amount: DecCoin,
|
||||||
pub total_delegation: Option<MajorCurrencyAmount>,
|
pub total_delegation: Option<DecCoin>,
|
||||||
pub pledge_amount: Option<MajorCurrencyAmount>,
|
pub pledge_amount: Option<DecCoin>,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub delegated_on_iso_datetime: String,
|
pub delegated_on_iso_datetime: String,
|
||||||
pub profit_margin_percent: Option<u8>,
|
pub profit_margin_percent: Option<u8>,
|
||||||
pub avg_uptime_percent: Option<u8>,
|
pub avg_uptime_percent: Option<u8>,
|
||||||
pub stake_saturation: Option<f32>,
|
pub stake_saturation: Option<f32>,
|
||||||
pub uses_vesting_contract_tokens: bool,
|
pub uses_vesting_contract_tokens: bool,
|
||||||
pub accumulated_rewards: Option<MajorCurrencyAmount>,
|
pub accumulated_rewards: Option<DecCoin>,
|
||||||
pub pending_events: Vec<DelegationEvent>,
|
pub pending_events: Vec<DelegationEvent>,
|
||||||
pub history: Vec<DelegationRecord>,
|
pub history: Vec<DelegationRecord>,
|
||||||
}
|
}
|
||||||
@@ -92,34 +80,7 @@ pub struct DelegationWithEverything {
|
|||||||
pub struct DelegationResult {
|
pub struct DelegationResult {
|
||||||
source_address: String,
|
source_address: String,
|
||||||
target_address: String,
|
target_address: String,
|
||||||
amount: Option<MajorCurrencyAmount>,
|
amount: Option<DecCoin>,
|
||||||
}
|
|
||||||
|
|
||||||
impl DelegationResult {
|
|
||||||
pub fn new(
|
|
||||||
source_address: &str,
|
|
||||||
target_address: &str,
|
|
||||||
amount: Option<MajorCurrencyAmount>,
|
|
||||||
) -> DelegationResult {
|
|
||||||
DelegationResult {
|
|
||||||
source_address: source_address.to_string(),
|
|
||||||
target_address: target_address.to_string(),
|
|
||||||
amount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<MixnetContractDelegation> for DelegationResult {
|
|
||||||
type Error = TypesError;
|
|
||||||
|
|
||||||
fn try_from(delegation: MixnetContractDelegation) -> Result<Self, Self::Error> {
|
|
||||||
let amount: MajorCurrencyAmount = delegation.amount.clone().into();
|
|
||||||
Ok(DelegationResult {
|
|
||||||
source_address: delegation.owner().to_string(),
|
|
||||||
target_address: delegation.node_identity(),
|
|
||||||
amount: Some(amount),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
@@ -143,36 +104,34 @@ pub struct DelegationEvent {
|
|||||||
pub kind: DelegationEventKind,
|
pub kind: DelegationEventKind,
|
||||||
pub node_identity: String,
|
pub node_identity: String,
|
||||||
pub address: String,
|
pub address: String,
|
||||||
pub amount: Option<MajorCurrencyAmount>,
|
pub amount: Option<DecCoin>,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<ContractDelegationEvent> for DelegationEvent {
|
impl DelegationEvent {
|
||||||
type Error = TypesError;
|
pub fn from_mixnet_contract(
|
||||||
|
event: ContractDelegationEvent,
|
||||||
fn try_from(event: ContractDelegationEvent) -> Result<Self, Self::Error> {
|
reg: &RegisteredCoins,
|
||||||
match event {
|
) -> Result<Self, TypesError> {
|
||||||
ContractDelegationEvent::Delegate(delegation) => {
|
Ok(match event {
|
||||||
let amount: MajorCurrencyAmount = delegation.amount.into();
|
ContractDelegationEvent::Delegate(delegation) => DelegationEvent {
|
||||||
Ok(DelegationEvent {
|
kind: DelegationEventKind::Delegate,
|
||||||
kind: DelegationEventKind::Delegate,
|
block_height: delegation.block_height,
|
||||||
block_height: delegation.block_height,
|
address: delegation.owner.into_string(),
|
||||||
address: delegation.owner.into_string(),
|
node_identity: delegation.node_identity,
|
||||||
node_identity: delegation.node_identity,
|
amount: Some(reg.attempt_convert_to_display_dec_coin(delegation.amount.into())?),
|
||||||
amount: Some(amount),
|
proxy: delegation.proxy.map(|p| p.into_string()),
|
||||||
proxy: delegation.proxy.map(|p| p.into_string()),
|
},
|
||||||
})
|
ContractDelegationEvent::Undelegate(pending_undelegate) => DelegationEvent {
|
||||||
}
|
|
||||||
ContractDelegationEvent::Undelegate(pending_undelegate) => Ok(DelegationEvent {
|
|
||||||
kind: DelegationEventKind::Undelegate,
|
kind: DelegationEventKind::Undelegate,
|
||||||
block_height: pending_undelegate.block_height(),
|
block_height: pending_undelegate.block_height(),
|
||||||
address: pending_undelegate.delegate().into_string(),
|
address: pending_undelegate.delegate().into_string(),
|
||||||
node_identity: pending_undelegate.mix_identity(),
|
node_identity: pending_undelegate.mix_identity(),
|
||||||
amount: None,
|
amount: None,
|
||||||
proxy: pending_undelegate.proxy().map(|p| p.into_string()),
|
proxy: pending_undelegate.proxy().map(|p| p.into_string()),
|
||||||
}),
|
},
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,30 +159,6 @@ impl From<ContractPendingUndelegate> for PendingUndelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_contract_delegation_events(
|
|
||||||
events: Vec<ContractDelegationEvent>,
|
|
||||||
) -> Result<Vec<DelegationEvent>, TypesError> {
|
|
||||||
let (events, errors): (Vec<_>, Vec<_>) = events
|
|
||||||
.into_iter()
|
|
||||||
.map(|delegation_event| delegation_event.try_into())
|
|
||||||
.partition(Result::is_ok);
|
|
||||||
|
|
||||||
if errors.is_empty() {
|
|
||||||
let events = events
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|e| e.ok())
|
|
||||||
.collect::<Vec<DelegationEvent>>();
|
|
||||||
return Ok(events);
|
|
||||||
}
|
|
||||||
let errors = errors
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|e| e.err())
|
|
||||||
.collect::<Vec<TypesError>>();
|
|
||||||
|
|
||||||
error!("Failed to convert delegations: {:?}", errors);
|
|
||||||
Err(TypesError::DelegationsInvalid)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "generate-ts",
|
feature = "generate-ts",
|
||||||
@@ -232,6 +167,6 @@ pub fn from_contract_delegation_events(
|
|||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub struct DelegationsSummaryResponse {
|
pub struct DelegationsSummaryResponse {
|
||||||
pub delegations: Vec<DelegationWithEverything>,
|
pub delegations: Vec<DelegationWithEverything>,
|
||||||
pub total_delegations: MajorCurrencyAmount,
|
pub total_delegations: DecCoin,
|
||||||
pub total_rewards: MajorCurrencyAmount,
|
pub total_rewards: DecCoin,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use thiserror::Error;
|
|||||||
use validator_client::validator_api::error::ValidatorAPIError;
|
use validator_client::validator_api::error::ValidatorAPIError;
|
||||||
use validator_client::{nymd::error::NymdError, ValidatorClientError};
|
use validator_client::{nymd::error::NymdError, ValidatorClientError};
|
||||||
|
|
||||||
|
// TODO: ask @MS why this even exists
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum TypesError {
|
pub enum TypesError {
|
||||||
#[error("{source}")]
|
#[error("{source}")]
|
||||||
@@ -63,6 +64,12 @@ pub enum TypesError {
|
|||||||
InvalidGatewayBond(),
|
InvalidGatewayBond(),
|
||||||
#[error("Invalid delegations")]
|
#[error("Invalid delegations")]
|
||||||
DelegationsInvalid,
|
DelegationsInvalid,
|
||||||
|
#[error("Attempted to use too huge currency exponent ({0})")]
|
||||||
|
UnsupportedExponent(u32),
|
||||||
|
#[error("Attempted to convert coin that would have resulted in loss of precision")]
|
||||||
|
LossyCoinConversion,
|
||||||
|
#[error("The provided coin has an unknown denomination - {0}")]
|
||||||
|
UnknownCoinDenom(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for TypesError {
|
impl Serialize for TypesError {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::currency::MajorCurrencyAmount;
|
use crate::currency::DecCoin;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use validator_client::nymd::Fee;
|
use validator_client::nymd::Fee;
|
||||||
|
|
||||||
@@ -8,10 +8,16 @@ use ts_rs::{Dependency, TS};
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct FeeDetails {
|
pub struct FeeDetails {
|
||||||
// expected to be used by the wallet in order to display detailed fee information to the user
|
// expected to be used by the wallet in order to display detailed fee information to the user
|
||||||
pub amount: Option<MajorCurrencyAmount>,
|
pub amount: Option<DecCoin>,
|
||||||
pub fee: Fee,
|
pub fee: Fee,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FeeDetails {
|
||||||
|
pub fn new(amount: Option<DecCoin>, fee: Fee) -> Self {
|
||||||
|
FeeDetails { amount, fee }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "generate-ts")]
|
#[cfg(feature = "generate-ts")]
|
||||||
impl TS for FeeDetails {
|
impl TS for FeeDetails {
|
||||||
const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/FeeDetails.ts");
|
const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/FeeDetails.ts");
|
||||||
@@ -25,13 +31,12 @@ impl TS for FeeDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn inline() -> String {
|
fn inline() -> String {
|
||||||
"{ amount: MajorCurrencyAmount | null, fee: Fee }".into()
|
"{ amount: DecCoin | null, fee: Fee }".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dependencies() -> Vec<Dependency> {
|
fn dependencies() -> Vec<Dependency> {
|
||||||
vec![
|
vec![
|
||||||
Dependency::from_ty::<MajorCurrencyAmount>()
|
Dependency::from_ty::<DecCoin>().expect("TS was incorrectly defined on `DecCoin`"),
|
||||||
.expect("TS was incorrectly defined on `CurrencyDenom`"),
|
|
||||||
Dependency::from_ty::<ts_type_helpers::Fee>()
|
Dependency::from_ty::<ts_type_helpers::Fee>()
|
||||||
.expect("TS was incorrectly defined on `ts_type_helpers::Fee`"),
|
.expect("TS was incorrectly defined on `ts_type_helpers::Fee`"),
|
||||||
]
|
]
|
||||||
|
|||||||
+26
-60
@@ -1,48 +1,29 @@
|
|||||||
use crate::currency::MajorCurrencyAmount;
|
|
||||||
use crate::error::TypesError;
|
|
||||||
use cosmrs::tx::Gas as CosmrsGas;
|
use cosmrs::tx::Gas as CosmrsGas;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use validator_client::nymd::cosmwasm_client::types::GasInfo as ValidatorClientGasInfo;
|
use validator_client::nymd::cosmwasm_client::types::GasInfo as ValidatorClientGasInfo;
|
||||||
use validator_client::nymd::GasPrice;
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "generate-ts",
|
feature = "generate-ts",
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/Gas.ts")
|
ts(export_to = "ts-packages/types/src/types/rust/Gas.ts")
|
||||||
)]
|
)]
|
||||||
#[derive(Deserialize, Serialize, Clone)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug)]
|
||||||
pub struct Gas {
|
pub struct Gas {
|
||||||
/// units of gas used
|
/// units of gas used
|
||||||
pub gas_units: u64,
|
pub gas_units: u64,
|
||||||
//
|
|
||||||
// /// gas units converted to fee as major coin amount
|
|
||||||
// pub amount: MajorCurrencyAmount,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gas {
|
impl Gas {
|
||||||
pub fn from_cosmrs_gas(value: CosmrsGas, _denom_minor: &str) -> Result<Gas, TypesError> {
|
pub fn from_u64(value: u64) -> Gas {
|
||||||
Ok(Gas {
|
Gas { gas_units: value }
|
||||||
gas_units: value.value(),
|
|
||||||
})
|
|
||||||
|
|
||||||
// // TODO: use simulator struct to do conversion to fee
|
|
||||||
// let value_u128 = Uint128::from(value.value());
|
|
||||||
// let amount = Decimal::new(value_u128) * Decimal::from_str("0.0025")?;
|
|
||||||
// Ok(Gas {
|
|
||||||
// gas_units: value.value(),
|
|
||||||
// amount: MajorCurrencyAmount::from_minor_decimal_and_denom(amount, denom_minor)?,
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
pub fn from_u64(value: u64, _denom_minor: &str) -> Result<Gas, TypesError> {
|
}
|
||||||
Ok(Gas { gas_units: value })
|
|
||||||
// todo!()
|
impl From<CosmrsGas> for Gas {
|
||||||
// // TODO: use simulator struct to do conversion to fee
|
fn from(gas: CosmrsGas) -> Self {
|
||||||
// let value_u128 = Uint128::from(value);
|
Gas {
|
||||||
// let amount = Decimal::new(value_u128) * Decimal::from_str("0.0025")?;
|
gas_units: gas.value(),
|
||||||
// Ok(Gas {
|
}
|
||||||
// gas_units: value,
|
|
||||||
// amount: MajorCurrencyAmount::from_minor_decimal_and_denom(amount, denom_minor)?,
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,44 +32,29 @@ impl Gas {
|
|||||||
feature = "generate-ts",
|
feature = "generate-ts",
|
||||||
ts(export_to = "ts-packages/types/src/types/rust/GasInfo.ts")
|
ts(export_to = "ts-packages/types/src/types/rust/GasInfo.ts")
|
||||||
)]
|
)]
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Copy, Clone, Debug)]
|
||||||
pub struct GasInfo {
|
pub struct GasInfo {
|
||||||
/// GasWanted is the maximum units of work we allow this tx to perform.
|
/// GasWanted is the maximum units of work we allow this tx to perform.
|
||||||
pub gas_wanted: u64,
|
pub gas_wanted: Gas,
|
||||||
|
|
||||||
/// GasUsed is the amount of gas actually consumed.
|
/// GasUsed is the amount of gas actually consumed.
|
||||||
pub gas_used: u64,
|
pub gas_used: Gas,
|
||||||
|
}
|
||||||
|
|
||||||
/// gas units converted to fee as major coin amount
|
impl From<ValidatorClientGasInfo> for GasInfo {
|
||||||
pub fee: MajorCurrencyAmount,
|
fn from(info: ValidatorClientGasInfo) -> Self {
|
||||||
|
GasInfo {
|
||||||
|
gas_wanted: info.gas_wanted.into(),
|
||||||
|
gas_used: info.gas_used.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GasInfo {
|
impl GasInfo {
|
||||||
pub fn from_validator_client_gas_info(
|
pub fn from_u64(gas_wanted: u64, gas_used: u64) -> GasInfo {
|
||||||
value: ValidatorClientGasInfo,
|
GasInfo {
|
||||||
denom_minor: &str,
|
gas_wanted: Gas::from_u64(gas_wanted),
|
||||||
) -> Result<GasInfo, TypesError> {
|
gas_used: Gas::from_u64(gas_used),
|
||||||
// terrible workaround, but I don't want to break the current flow (just yet)
|
}
|
||||||
let gas_price = GasPrice::new_with_default_price(denom_minor)?;
|
|
||||||
let fee = (&gas_price) * value.gas_used;
|
|
||||||
Ok(GasInfo {
|
|
||||||
gas_wanted: value.gas_wanted.value(),
|
|
||||||
gas_used: value.gas_used.value(),
|
|
||||||
fee: fee.into(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
pub fn from_u64(
|
|
||||||
gas_wanted: u64,
|
|
||||||
gas_used: u64,
|
|
||||||
denom_minor: &str,
|
|
||||||
) -> Result<GasInfo, TypesError> {
|
|
||||||
// terrible workaround, but I don't want to break the current flow (just yet)
|
|
||||||
let gas_price = GasPrice::new_with_default_price(denom_minor)?;
|
|
||||||
let fee = (&gas_price) * CosmrsGas::from(gas_used);
|
|
||||||
Ok(GasInfo {
|
|
||||||
gas_wanted,
|
|
||||||
gas_used,
|
|
||||||
fee: fee.into(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-33
@@ -1,4 +1,4 @@
|
|||||||
use crate::currency::MajorCurrencyAmount;
|
use crate::currency::{DecCoin, RegisteredCoins};
|
||||||
use crate::error::TypesError;
|
use crate::error::TypesError;
|
||||||
use mixnet_contract_common::{
|
use mixnet_contract_common::{
|
||||||
Gateway as MixnetContractGateway, GatewayBond as MixnetContractGatewayBond,
|
Gateway as MixnetContractGateway, GatewayBond as MixnetContractGatewayBond,
|
||||||
@@ -54,7 +54,7 @@ impl From<MixnetContractGateway> for Gateway {
|
|||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||||
pub struct GatewayBond {
|
pub struct GatewayBond {
|
||||||
pub pledge_amount: MajorCurrencyAmount,
|
pub pledge_amount: DecCoin,
|
||||||
pub owner: String,
|
pub owner: String,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub gateway: Gateway,
|
pub gateway: Gateway,
|
||||||
@@ -63,38 +63,15 @@ pub struct GatewayBond {
|
|||||||
|
|
||||||
impl GatewayBond {
|
impl GatewayBond {
|
||||||
pub fn from_mixnet_contract_gateway_bond(
|
pub fn from_mixnet_contract_gateway_bond(
|
||||||
bond: Option<MixnetContractGatewayBond>,
|
bond: MixnetContractGatewayBond,
|
||||||
) -> Result<Option<GatewayBond>, TypesError> {
|
reg: &RegisteredCoins,
|
||||||
match bond {
|
) -> Result<GatewayBond, TypesError> {
|
||||||
Some(bond) => {
|
|
||||||
let bond: GatewayBond = bond.try_into()?;
|
|
||||||
Ok(Some(bond))
|
|
||||||
}
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<MixnetContractGatewayBond> for GatewayBond {
|
|
||||||
type Error = TypesError;
|
|
||||||
|
|
||||||
fn try_from(value: MixnetContractGatewayBond) -> Result<Self, Self::Error> {
|
|
||||||
let MixnetContractGatewayBond {
|
|
||||||
pledge_amount,
|
|
||||||
owner,
|
|
||||||
block_height,
|
|
||||||
gateway,
|
|
||||||
proxy,
|
|
||||||
} = value;
|
|
||||||
|
|
||||||
let pledge_amount: MajorCurrencyAmount = pledge_amount.into();
|
|
||||||
|
|
||||||
Ok(GatewayBond {
|
Ok(GatewayBond {
|
||||||
pledge_amount,
|
pledge_amount: reg.attempt_convert_to_display_dec_coin(bond.pledge_amount.into())?,
|
||||||
owner: owner.into_string(),
|
owner: bond.owner.to_string(),
|
||||||
block_height,
|
block_height: bond.block_height,
|
||||||
gateway: gateway.into(),
|
gateway: bond.gateway.into(),
|
||||||
proxy: proxy.map(|p| p.into_string()),
|
proxy: bond.proxy.map(|p| p.into_string()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-54
@@ -1,11 +1,11 @@
|
|||||||
use crate::currency::MajorCurrencyAmount;
|
use crate::currency::{DecCoin, RegisteredCoins};
|
||||||
use crate::error::TypesError;
|
use crate::error::TypesError;
|
||||||
use mixnet_contract_common::{
|
use mixnet_contract_common::{
|
||||||
Coin as CosmWasmCoin, MixNode as MixnetContractMixNode,
|
MixNode as MixnetContractMixNode, MixNodeBond as MixnetContractMixNodeBond,
|
||||||
MixNodeBond as MixnetContractMixNodeBond,
|
|
||||||
};
|
};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use validator_client::nymd::Coin;
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
@@ -58,67 +58,39 @@ impl From<MixnetContractMixNode> for MixNode {
|
|||||||
)]
|
)]
|
||||||
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Eq, Serialize, JsonSchema)]
|
||||||
pub struct MixNodeBond {
|
pub struct MixNodeBond {
|
||||||
pub pledge_amount: MajorCurrencyAmount,
|
pub pledge_amount: DecCoin,
|
||||||
pub total_delegation: MajorCurrencyAmount,
|
pub total_delegation: DecCoin,
|
||||||
pub owner: String,
|
pub owner: String,
|
||||||
pub layer: String,
|
pub layer: String,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub mix_node: MixNode,
|
pub mix_node: MixNode,
|
||||||
pub proxy: Option<String>,
|
pub proxy: Option<String>,
|
||||||
pub accumulated_rewards: Option<MajorCurrencyAmount>,
|
pub accumulated_rewards: Option<DecCoin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MixNodeBond {
|
impl MixNodeBond {
|
||||||
pub fn from_mixnet_contract_mixnode_bond(
|
pub fn from_mixnet_contract_mixnode_bond(
|
||||||
bond: Option<MixnetContractMixNodeBond>,
|
bond: MixnetContractMixNodeBond,
|
||||||
) -> Result<Option<MixNodeBond>, TypesError> {
|
reg: &RegisteredCoins,
|
||||||
match bond {
|
) -> Result<MixNodeBond, TypesError> {
|
||||||
Some(bond) => {
|
let denom = bond.pledge_amount.denom.clone();
|
||||||
let bond: MixNodeBond = bond.try_into()?;
|
|
||||||
Ok(Some(bond))
|
|
||||||
}
|
|
||||||
None => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<MixnetContractMixNodeBond> for MixNodeBond {
|
|
||||||
type Error = TypesError;
|
|
||||||
|
|
||||||
fn try_from(value: MixnetContractMixNodeBond) -> Result<Self, Self::Error> {
|
|
||||||
let MixnetContractMixNodeBond {
|
|
||||||
pledge_amount,
|
|
||||||
total_delegation,
|
|
||||||
owner,
|
|
||||||
layer,
|
|
||||||
block_height,
|
|
||||||
mix_node,
|
|
||||||
proxy,
|
|
||||||
accumulated_rewards,
|
|
||||||
} = value;
|
|
||||||
|
|
||||||
if pledge_amount.denom != total_delegation.denom {
|
|
||||||
return Err(TypesError::InvalidDenom(
|
|
||||||
"The pledge and delegation denominations do not match".to_string(),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let denom = total_delegation.denom.clone();
|
|
||||||
|
|
||||||
let pledge_amount: MajorCurrencyAmount = pledge_amount.into();
|
|
||||||
let total_delegation: MajorCurrencyAmount = total_delegation.into();
|
|
||||||
let accumulated_rewards: Option<MajorCurrencyAmount> =
|
|
||||||
accumulated_rewards.map(|r| CosmWasmCoin::new(r.u128(), denom).into());
|
|
||||||
|
|
||||||
Ok(MixNodeBond {
|
Ok(MixNodeBond {
|
||||||
pledge_amount,
|
pledge_amount: reg.attempt_convert_to_display_dec_coin(bond.pledge_amount.into())?,
|
||||||
total_delegation,
|
total_delegation: reg
|
||||||
owner: owner.into_string(),
|
.attempt_convert_to_display_dec_coin(bond.total_delegation.into())?,
|
||||||
layer: layer.into(),
|
owner: bond.owner.into_string(),
|
||||||
block_height,
|
layer: bond.layer.into(),
|
||||||
mix_node: mix_node.into(),
|
block_height: bond.block_height,
|
||||||
proxy: proxy.map(|p| p.into_string()),
|
mix_node: bond.mix_node.into(),
|
||||||
accumulated_rewards,
|
proxy: bond.proxy.map(|p| p.to_string()),
|
||||||
|
accumulated_rewards: bond
|
||||||
|
.accumulated_rewards
|
||||||
|
.map(|reward| {
|
||||||
|
// here we're making an assumption that rewards always use the same denom as the pledge
|
||||||
|
// (which I think is a reasonable assumption)
|
||||||
|
reg.attempt_convert_to_display_dec_coin(Coin::new(reward.u128(), denom))
|
||||||
|
})
|
||||||
|
.transpose()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::currency::MajorCurrencyAmount;
|
use crate::currency::DecCoin;
|
||||||
use crate::error::TypesError;
|
use crate::error::TypesError;
|
||||||
use crate::gas::GasInfo;
|
use crate::gas::{Gas, GasInfo};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use validator_client::nymd::cosmwasm_client::types::ExecuteResult;
|
use validator_client::nymd::cosmwasm_client::types::ExecuteResult;
|
||||||
use validator_client::nymd::TxResponse;
|
use validator_client::nymd::TxResponse;
|
||||||
@@ -15,31 +15,23 @@ pub struct SendTxResult {
|
|||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub code: u32,
|
pub code: u32,
|
||||||
pub details: TransactionDetails,
|
pub details: TransactionDetails,
|
||||||
pub gas_used: u64,
|
pub gas_used: Gas,
|
||||||
pub gas_wanted: u64,
|
pub gas_wanted: Gas,
|
||||||
pub tx_hash: String,
|
pub tx_hash: String,
|
||||||
// pub fee: MajorCurrencyAmount,
|
pub fee: Option<DecCoin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SendTxResult {
|
impl SendTxResult {
|
||||||
pub fn new(
|
pub fn new(t: TxResponse, details: TransactionDetails, fee: Option<DecCoin>) -> SendTxResult {
|
||||||
t: TxResponse,
|
SendTxResult {
|
||||||
details: TransactionDetails,
|
|
||||||
_denom_minor: &str,
|
|
||||||
) -> Result<SendTxResult, TypesError> {
|
|
||||||
Ok(SendTxResult {
|
|
||||||
block_height: t.height.value(),
|
block_height: t.height.value(),
|
||||||
code: t.tx_result.code.value(),
|
code: t.tx_result.code.value(),
|
||||||
details,
|
details,
|
||||||
gas_used: t.tx_result.gas_used.value(),
|
gas_used: t.tx_result.gas_used.into(),
|
||||||
gas_wanted: t.tx_result.gas_wanted.value(),
|
gas_wanted: t.tx_result.gas_wanted.into(),
|
||||||
tx_hash: t.hash.to_string(),
|
tx_hash: t.hash.to_string(),
|
||||||
// that is completely wrong: fee is what you told the validator to use beforehand
|
fee,
|
||||||
// fee: MajorCurrencyAmount::from_decimal_and_denom(
|
}
|
||||||
// Decimal::new(Uint128::from(t.tx_result.gas_used.value())),
|
|
||||||
// denom_minor.to_string(),
|
|
||||||
// )?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,11 +42,21 @@ impl SendTxResult {
|
|||||||
)]
|
)]
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
pub struct TransactionDetails {
|
pub struct TransactionDetails {
|
||||||
pub amount: MajorCurrencyAmount,
|
pub amount: DecCoin,
|
||||||
pub from_address: String,
|
pub from_address: String,
|
||||||
pub to_address: String,
|
pub to_address: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TransactionDetails {
|
||||||
|
pub fn new(amount: DecCoin, from_address: String, to_address: String) -> Self {
|
||||||
|
TransactionDetails {
|
||||||
|
amount,
|
||||||
|
from_address,
|
||||||
|
to_address,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "generate-ts",
|
feature = "generate-ts",
|
||||||
@@ -66,18 +68,16 @@ pub struct TransactionExecuteResult {
|
|||||||
pub data_json: String,
|
pub data_json: String,
|
||||||
pub transaction_hash: String,
|
pub transaction_hash: String,
|
||||||
pub gas_info: GasInfo,
|
pub gas_info: GasInfo,
|
||||||
pub fee: MajorCurrencyAmount,
|
pub fee: Option<DecCoin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransactionExecuteResult {
|
impl TransactionExecuteResult {
|
||||||
pub fn from_execute_result(
|
pub fn from_execute_result(
|
||||||
value: ExecuteResult,
|
value: ExecuteResult,
|
||||||
denom_minor: &str,
|
fee: Option<DecCoin>,
|
||||||
) -> Result<TransactionExecuteResult, TypesError> {
|
) -> Result<TransactionExecuteResult, TypesError> {
|
||||||
let gas_info = GasInfo::from_validator_client_gas_info(value.gas_info, denom_minor)?;
|
|
||||||
let fee = gas_info.fee.clone();
|
|
||||||
Ok(TransactionExecuteResult {
|
Ok(TransactionExecuteResult {
|
||||||
gas_info,
|
gas_info: value.gas_info.into(),
|
||||||
transaction_hash: value.transaction_hash.to_string(),
|
transaction_hash: value.transaction_hash.to_string(),
|
||||||
data_json: ::serde_json::to_string_pretty(&value.data)?,
|
data_json: ::serde_json::to_string_pretty(&value.data)?,
|
||||||
logs_json: ::serde_json::to_string_pretty(&value.logs)?,
|
logs_json: ::serde_json::to_string_pretty(&value.logs)?,
|
||||||
@@ -97,30 +97,24 @@ pub struct RpcTransactionResponse {
|
|||||||
pub tx_result_json: String,
|
pub tx_result_json: String,
|
||||||
pub block_height: u64,
|
pub block_height: u64,
|
||||||
pub transaction_hash: String,
|
pub transaction_hash: String,
|
||||||
pub gas_info: GasInfo,
|
pub gas_used: Gas,
|
||||||
// pub fee: MajorCurrencyAmount,
|
pub gas_wanted: Gas,
|
||||||
|
pub fee: Option<DecCoin>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RpcTransactionResponse {
|
impl RpcTransactionResponse {
|
||||||
pub fn from_tx_response(
|
pub fn from_tx_response(
|
||||||
value: &TxResponse,
|
t: &TxResponse,
|
||||||
denom_minor: &str,
|
fee: Option<DecCoin>,
|
||||||
) -> Result<RpcTransactionResponse, TypesError> {
|
) -> Result<RpcTransactionResponse, TypesError> {
|
||||||
Ok(RpcTransactionResponse {
|
Ok(RpcTransactionResponse {
|
||||||
index: value.index,
|
index: t.index,
|
||||||
gas_info: GasInfo::from_u64(
|
gas_used: t.tx_result.gas_used.into(),
|
||||||
value.tx_result.gas_wanted.value(),
|
gas_wanted: t.tx_result.gas_wanted.into(),
|
||||||
value.tx_result.gas_used.value(),
|
transaction_hash: t.hash.to_string(),
|
||||||
denom_minor,
|
tx_result_json: ::serde_json::to_string_pretty(&t.tx_result)?,
|
||||||
)?,
|
block_height: t.height.value(),
|
||||||
transaction_hash: value.hash.to_string(),
|
fee,
|
||||||
tx_result_json: ::serde_json::to_string_pretty(&value.tx_result)?,
|
|
||||||
block_height: value.height.value(),
|
|
||||||
// wrong
|
|
||||||
// fee: MajorCurrencyAmount::from_decimal_and_denom(
|
|
||||||
// Decimal::new(Uint128::from(value.tx_result.gas_used.value())),
|
|
||||||
// denom_minor.to_string(),
|
|
||||||
// )?,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-45
@@ -1,10 +1,10 @@
|
|||||||
use crate::currency::MajorCurrencyAmount;
|
use crate::currency::{DecCoin, RegisteredCoins};
|
||||||
use crate::error::TypesError;
|
use crate::error::TypesError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use vesting_contract::vesting::Account as VestingAccount;
|
use vesting_contract::vesting::Account as ContractVestingAccount;
|
||||||
use vesting_contract::vesting::VestingPeriod as VestingVestingPeriod;
|
use vesting_contract::vesting::VestingPeriod as ContractVestingPeriod;
|
||||||
use vesting_contract_common::OriginalVestingResponse as VestingOriginalVestingResponse;
|
use vesting_contract_common::OriginalVestingResponse as ContractOriginalVestingResponse;
|
||||||
use vesting_contract_common::PledgeData as VestingPledgeData;
|
use vesting_contract_common::PledgeData as ContractPledgeData;
|
||||||
|
|
||||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
@@ -13,25 +13,19 @@ use vesting_contract_common::PledgeData as VestingPledgeData;
|
|||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct PledgeData {
|
pub struct PledgeData {
|
||||||
pub amount: MajorCurrencyAmount,
|
pub amount: DecCoin,
|
||||||
pub block_time: u64,
|
pub block_time: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<VestingPledgeData> for PledgeData {
|
|
||||||
type Error = TypesError;
|
|
||||||
|
|
||||||
fn try_from(data: VestingPledgeData) -> Result<Self, Self::Error> {
|
|
||||||
let amount: MajorCurrencyAmount = data.amount().into();
|
|
||||||
Ok(Self {
|
|
||||||
amount,
|
|
||||||
block_time: data.block_time().seconds(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PledgeData {
|
impl PledgeData {
|
||||||
pub fn and_then(data: VestingPledgeData) -> Option<Self> {
|
pub fn from_vesting_contract(
|
||||||
data.try_into().ok()
|
pledge: ContractPledgeData,
|
||||||
|
reg: &RegisteredCoins,
|
||||||
|
) -> Result<Self, TypesError> {
|
||||||
|
Ok(PledgeData {
|
||||||
|
amount: reg.attempt_convert_to_display_dec_coin(pledge.amount.into())?,
|
||||||
|
block_time: pledge.block_time.seconds(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,20 +36,20 @@ impl PledgeData {
|
|||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct OriginalVestingResponse {
|
pub struct OriginalVestingResponse {
|
||||||
amount: MajorCurrencyAmount,
|
amount: DecCoin,
|
||||||
number_of_periods: usize,
|
number_of_periods: usize,
|
||||||
period_duration: u64,
|
period_duration: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<VestingOriginalVestingResponse> for OriginalVestingResponse {
|
impl OriginalVestingResponse {
|
||||||
type Error = TypesError;
|
pub fn from_vesting_contract(
|
||||||
|
res: ContractOriginalVestingResponse,
|
||||||
fn try_from(data: VestingOriginalVestingResponse) -> Result<Self, Self::Error> {
|
reg: &RegisteredCoins,
|
||||||
let amount = data.amount().into();
|
) -> Result<Self, TypesError> {
|
||||||
Ok(Self {
|
Ok(OriginalVestingResponse {
|
||||||
amount,
|
amount: reg.attempt_convert_to_display_dec_coin(res.amount.into())?,
|
||||||
number_of_periods: data.number_of_periods(),
|
number_of_periods: res.number_of_periods,
|
||||||
period_duration: data.period_duration(),
|
period_duration: res.period_duration,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,24 +65,20 @@ pub struct VestingAccountInfo {
|
|||||||
staking_address: Option<String>,
|
staking_address: Option<String>,
|
||||||
start_time: u64,
|
start_time: u64,
|
||||||
periods: Vec<VestingPeriod>,
|
periods: Vec<VestingPeriod>,
|
||||||
amount: MajorCurrencyAmount,
|
amount: DecCoin,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<VestingAccount> for VestingAccountInfo {
|
impl VestingAccountInfo {
|
||||||
type Error = TypesError;
|
pub fn from_vesting_contract(
|
||||||
|
account: ContractVestingAccount,
|
||||||
fn try_from(account: VestingAccount) -> Result<Self, Self::Error> {
|
reg: &RegisteredCoins,
|
||||||
let mut periods = Vec::new();
|
) -> Result<Self, TypesError> {
|
||||||
for period in account.periods() {
|
Ok(VestingAccountInfo {
|
||||||
periods.push(period.into());
|
|
||||||
}
|
|
||||||
let amount: MajorCurrencyAmount = account.coin().into();
|
|
||||||
Ok(Self {
|
|
||||||
owner_address: account.owner_address().to_string(),
|
owner_address: account.owner_address().to_string(),
|
||||||
staking_address: account.staking_address().map(|a| a.to_string()),
|
staking_address: account.staking_address().map(|a| a.to_string()),
|
||||||
start_time: account.start_time().seconds(),
|
start_time: account.start_time().seconds(),
|
||||||
periods,
|
periods: account.periods().into_iter().map(Into::into).collect(),
|
||||||
amount,
|
amount: reg.attempt_convert_to_display_dec_coin(account.coin.into())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,8 +94,8 @@ pub struct VestingPeriod {
|
|||||||
period_seconds: u64,
|
period_seconds: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<VestingVestingPeriod> for VestingPeriod {
|
impl From<ContractVestingPeriod> for VestingPeriod {
|
||||||
fn from(period: VestingVestingPeriod) -> Self {
|
fn from(period: ContractVestingPeriod) -> Self {
|
||||||
Self {
|
Self {
|
||||||
start_time: period.start_time,
|
start_time: period.start_time,
|
||||||
period_seconds: period.period_seconds,
|
period_seconds: period.period_seconds,
|
||||||
|
|||||||
Generated
+34
-9
@@ -50,7 +50,6 @@ name = "bandwidth-claim"
|
|||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bandwidth-claim-contract",
|
"bandwidth-claim-contract",
|
||||||
"config",
|
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cosmwasm-storage",
|
"cosmwasm-storage",
|
||||||
"schemars",
|
"schemars",
|
||||||
@@ -221,12 +220,11 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bandwidth-claim-contract",
|
"bandwidth-claim-contract",
|
||||||
"coconut-bandwidth-contract-common",
|
"coconut-bandwidth-contract-common",
|
||||||
"config",
|
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cosmwasm-storage",
|
"cosmwasm-storage",
|
||||||
"cw-controllers",
|
"cw-controllers",
|
||||||
"cw-multi-test",
|
|
||||||
"cw-storage-plus",
|
"cw-storage-plus",
|
||||||
|
"multisig-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -237,10 +235,32 @@ name = "coconut-bandwidth-contract-common"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
|
"multisig-contract-common",
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "coconut-test"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bandwidth-claim-contract",
|
||||||
|
"coconut-bandwidth",
|
||||||
|
"coconut-bandwidth-contract-common",
|
||||||
|
"cosmwasm-std",
|
||||||
|
"cosmwasm-storage",
|
||||||
|
"cw-controllers",
|
||||||
|
"cw-multi-test",
|
||||||
|
"cw-storage-plus",
|
||||||
|
"cw-utils",
|
||||||
|
"cw3-flex-multisig",
|
||||||
|
"cw4-group",
|
||||||
|
"multisig-contract-common",
|
||||||
|
"schemars",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "config"
|
name = "config"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -592,6 +612,12 @@ dependencies = [
|
|||||||
"generic-array 0.14.5",
|
"generic-array 0.14.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dotenv"
|
||||||
|
version = "0.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@@ -1056,7 +1082,6 @@ dependencies = [
|
|||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"fixed",
|
"fixed",
|
||||||
"log",
|
"log",
|
||||||
"network-defaults",
|
|
||||||
"schemars",
|
"schemars",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
@@ -1082,6 +1107,7 @@ name = "network-defaults"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"dotenv",
|
||||||
"hex-literal",
|
"hex-literal",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1366,18 +1392,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.4"
|
version = "1.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.25"
|
version = "0.6.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rfc6979"
|
name = "rfc6979"
|
||||||
@@ -1828,7 +1854,6 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
|||||||
name = "vesting-contract"
|
name = "vesting-contract"
|
||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"config",
|
|
||||||
"cosmwasm-std",
|
"cosmwasm-std",
|
||||||
"cw-storage-plus",
|
"cw-storage-plus",
|
||||||
"mixnet-contract-common",
|
"mixnet-contract-common",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[workspace]
|
[workspace]
|
||||||
members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group"]
|
members = ["bandwidth-claim", "coconut-bandwidth", "mixnet", "vesting", "multisig/cw3-flex-multisig", "multisig/cw4-group", "coconut-test"]
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user