Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa63549a9c |
@@ -1,38 +0,0 @@
|
||||
name: Build release of Nym smart contracts
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: contracts
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: wasm32-unknown-unknown
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
- name: Build release contracts
|
||||
run: RUSTFLAGS='-C link-arg=-s' cargo build --release --target wasm32-unknown-unknown
|
||||
|
||||
- name: Upload Mixnet Contract Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mixnet_contract.wasm
|
||||
path: contracts/target/wasm32-unknown-unknown/release/mixnet_contract.wasm
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload Vesting Contract Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: vesting_contract.wasm
|
||||
path: contracts/target/wasm32-unknown-unknown/release/vesting_contract.wasm
|
||||
retention-days: 5
|
||||
@@ -2,7 +2,7 @@ name: Nightly builds
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '14 1 * * *'
|
||||
- cron: '14 4 * * *'
|
||||
jobs:
|
||||
matrix_prep:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
name: Publish Nym Connect (MacOS)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [macos-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Check the release tag starts with `nym-connect-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-connect-...')
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install the Apple developer certificate for code signing
|
||||
env:
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
||||
run: |
|
||||
# create variables
|
||||
CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12
|
||||
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
# import certificate and provisioning profile from secrets
|
||||
echo -n "$APPLE_CERTIFICATE" | base64 --decode --output $CERTIFICATE_PATH
|
||||
|
||||
# create temporary keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
|
||||
|
||||
# import certificate to keychain
|
||||
security import $CERTIFICATE_PATH -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH
|
||||
security list-keychain -d user -s $KEYCHAIN_PATH
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install app dependencies and build it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
||||
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_IDENTITY_ID }}
|
||||
APPLE_ID: ${{ secrets.APPLE_ID }}
|
||||
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
run: yarn && yarn build
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect_1.0.0_x64.dmg
|
||||
path: nym-connect/target/release/bundle/dmg/nym-connect_1.0.0_x64.dmg
|
||||
retention-days: 5
|
||||
|
||||
- name: Clean up keychain
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/dmg/*.dmg
|
||||
nym-connect/target/release/bundle/macos/*.app.tar.gz*
|
||||
@@ -1,67 +0,0 @@
|
||||
name: Publish Nym Connect (Ubuntu)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [ubuntu-latest]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Tauri dependencies
|
||||
run: >
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install -y webkit2gtk-4.0 libayatana-appindicator3-dev
|
||||
- name: Check the release tag starts with `nym-connect-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-connect-...')
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect.AppImage.tar.gz
|
||||
path: nym-connect/target/release/bundle/macos/nym-connect.AppImage.tar.gz
|
||||
retention-days: 5
|
||||
|
||||
- name: Build app
|
||||
run: yarn build
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/appimage/*.AppImage
|
||||
nym-connect/target/release/bundle/appimage/*.AppImage.tar.gz*
|
||||
@@ -1,90 +0,0 @@
|
||||
name: Publish Nym Connect (Windows 10)
|
||||
on:
|
||||
workflow_dispatch:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: nym-connect
|
||||
|
||||
jobs:
|
||||
publish-tauri:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [windows10]
|
||||
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- name: Clean up first
|
||||
continue-on-error: true
|
||||
working-directory: .
|
||||
run: |
|
||||
cd ..
|
||||
del /s /q /A:H nym
|
||||
rmdir /s /q nym
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Check the release tag starts with `nym-connect-`
|
||||
if: startsWith(github.ref, 'refs/tags/nym-connect-') == false && github.event_name != 'workflow_dispatch'
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
script: |
|
||||
core.setFailed('Release tag did not start with nym-connect-...')
|
||||
|
||||
- name: Import signing certificate
|
||||
env:
|
||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
run: |
|
||||
New-Item -ItemType directory -Path certificate
|
||||
Set-Content -Path certificate/tempCert.txt -Value $env:WINDOWS_CERTIFICATE
|
||||
certutil -decode certificate/tempCert.txt certificate/certificate.pfx
|
||||
Remove-Item -path certificate -include tempCert.txt
|
||||
Import-PfxCertificate -FilePath certificate/certificate.pfx -CertStoreLocation Cert:\CurrentUser\My -Password (ConvertTo-SecureString -String $env:WINDOWS_CERTIFICATE_PASSWORD -Force -AsPlainText)
|
||||
|
||||
- name: Node v16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Install Rust stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
|
||||
- name: Create env file
|
||||
uses: timheuer/base64-to-file@v1.1
|
||||
with:
|
||||
fileName: '.env'
|
||||
encodedString: ${{ secrets.WALLET_ADMIN_ADDRESS }}
|
||||
|
||||
- name: Install app dependencies
|
||||
run: yarn
|
||||
|
||||
- name: Build and sign it
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ENABLE_CODE_SIGNING: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }}
|
||||
WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
run: yarn build
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: nym-connect.AppImage.tar.gz
|
||||
path: nym-connect/target/release/bundle/macos/nym-connect.msi.zip
|
||||
retention-days: 5
|
||||
|
||||
- name: Upload to release based on tag name
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: github.event_name == 'release'
|
||||
with:
|
||||
files: |
|
||||
nym-connect/target/release/bundle/msi/*.msi
|
||||
nym-connect/target/release/bundle/msi/*.msi.zip*
|
||||
+19
-41
@@ -2,7 +2,6 @@
|
||||
|
||||
Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
@@ -11,28 +10,36 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
- 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]).
|
||||
- explorer-api: learned how to sum the delegations by owner in a new endpoint.
|
||||
- explorer-api: add apy values to `mix_nodes` endpoint
|
||||
- gateway: Added gateway coconut verifications and validator-api communication for double spending protection ([#1261])
|
||||
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||
- mixnet-contract: Added staking_supply field to ContractStateParams.
|
||||
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
|
||||
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
|
||||
- network-explorer-ui: Upgrade to React Router 6
|
||||
- rewarding: replace circulating supply with staking supply in reward calculations ([#1324])
|
||||
- validator-api: add `estimated_node_profit` and `estimated_operator_cost` to `reward-estimate` endpoint ([#1284])
|
||||
- validator-api: add detailed mixnode bond endpoints, and explorer-api makes use of that data to append stake saturation
|
||||
- validator-api: add Swagger to document the REST API ([#1249]).
|
||||
- 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])
|
||||
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- 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]).
|
||||
- validator-api: endpoint, in coconut mode, for returning the validator-api cosmos address ([#1404]).
|
||||
|
||||
### Fixed
|
||||
|
||||
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
|
||||
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
|
||||
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
|
||||
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
|
||||
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
|
||||
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
|
||||
- mixnode, gateway: attempting to determine reconnection backoff to persistently failing mixnode could result in a crash ([#1260])
|
||||
- mixnode: the mixnode learned how to shutdown gracefully
|
||||
- native & socks5 clients: fail early when clients try to re-init with a different gateway, which is not supported yet ([#1322])
|
||||
- native & socks5 clients: rerun init will now reuse previous gateway configuration instead of failing ([#1353])
|
||||
- native & socks5 clients: deduplicate big chunks of init logic
|
||||
- validator: fixed local docker-compose setup to work on Apple M1 ([#1329])
|
||||
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -44,10 +51,15 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
|
||||
[#1249]: https://github.com/nymtech/nym/pull/1249
|
||||
[#1256]: https://github.com/nymtech/nym/pull/1256
|
||||
[#1257]: https://github.com/nymtech/nym/pull/1257
|
||||
[#1258]: https://github.com/nymtech/nym/pull/1258
|
||||
[#1260]: https://github.com/nymtech/nym/pull/1260
|
||||
[#1261]: https://github.com/nymtech/nym/pull/1261
|
||||
[#1267]: https://github.com/nymtech/nym/pull/1267
|
||||
[#1275]: https://github.com/nymtech/nym/pull/1275
|
||||
[#1278]: https://github.com/nymtech/nym/pull/1278
|
||||
[#1284]: https://github.com/nymtech/nym/pull/1284
|
||||
[#1292]: https://github.com/nymtech/nym/pull/1292
|
||||
[#1295]: https://github.com/nymtech/nym/pull/1295
|
||||
[#1302]: https://github.com/nymtech/nym/pull/1302
|
||||
[#1308]: https://github.com/nymtech/nym/pull/1308
|
||||
@@ -57,43 +69,9 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https://
|
||||
[#1328]: https://github.com/nymtech/nym/pull/1328
|
||||
[#1329]: https://github.com/nymtech/nym/pull/1329
|
||||
[#1353]: https://github.com/nymtech/nym/pull/1353
|
||||
[#1376]: https://github.com/nymtech/nym/pull/1376
|
||||
[#1388]: https://github.com/nymtech/nym/pull/1388
|
||||
[#1393]: https://github.com/nymtech/nym/pull/1393
|
||||
[#1404]: https://github.com/nymtech/nym/pull/1404
|
||||
|
||||
## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22)
|
||||
|
||||
### Added
|
||||
|
||||
- mixnet-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- mixnet-contract: Replace all naked `-` with `saturating_sub`.
|
||||
- mixnet-contract: Added staking_supply field to ContractStateParams.
|
||||
- mixnet-contract: Added a query to get MixnodeBond by identity key ([#1369]).
|
||||
- mixnet-contract: Added a query to get GatewayBond by identity key ([#1369]).
|
||||
- vesting-contract: Added ClaimOperatorReward and ClaimDelegatorReward messages ([#1292])
|
||||
- vesting-contract: Added limit to the amount of tokens one can pledge ([#1331])
|
||||
|
||||
### Fixed
|
||||
|
||||
- mixnet-contract: `estimated_delegator_reward` calculation ([#1284])
|
||||
- mixnet-contract: delegator and operator rewards use lambda and sigma instead of lambda_ticked and sigma_ticked ([#1284])
|
||||
- mixnet-contract: removed `expect` in `query_delegator_reward` and queries containing invalid proxy address should now return a more human-readable error ([#1257])
|
||||
- mixnet-contract: replaced integer division with fixed for performance calculations ([#1284])
|
||||
- mixnet-contract: Under certain circumstances nodes could not be unbonded ([#1255](https://github.com/nymtech/nym/issues/1255)) ([#1258])
|
||||
- mixnet-contract: Using correct staking supply when distributing rewards. ([#1373])
|
||||
- vesting-contract: replaced `checked_sub` with `saturating_sub` to fix the underflow in `get_vesting_tokens` ([#1275])
|
||||
|
||||
|
||||
[#1255]: https://github.com/nymtech/nym/pull/1255
|
||||
[#1257]: https://github.com/nymtech/nym/pull/1257
|
||||
[#1258]: https://github.com/nymtech/nym/pull/1258
|
||||
[#1275]: https://github.com/nymtech/nym/pull/1275
|
||||
[#1284]: https://github.com/nymtech/nym/pull/1284
|
||||
[#1292]: https://github.com/nymtech/nym/pull/1292
|
||||
[#1331]: https://github.com/nymtech/nym/pull/1331
|
||||
[#1369]: https://github.com/nymtech/nym/pull/1369
|
||||
[#1373]: https://github.com/nymtech/nym/pull/1373
|
||||
[#1376]: https://github.com/nymtech/nym/pull/1376
|
||||
|
||||
## [nym-wallet-v1.0.6](https://github.com/nymtech/nym/tree/nym-wallet-v1.0.6) (2022-06-21)
|
||||
|
||||
|
||||
Generated
+3
-9
@@ -924,7 +924,6 @@ dependencies = [
|
||||
"rand 0.7.3",
|
||||
"thiserror",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
]
|
||||
|
||||
@@ -1664,9 +1663,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "fixed"
|
||||
version = "1.15.0"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36a65312835c1097a0c926ff3702df965285fadc33d948b87397ff8961bad881"
|
||||
checksum = "86d3f4dd10ddfcb0bd2b2efe9f18aff37ed48265fda3e20e5d53f046aba9d50a"
|
||||
dependencies = [
|
||||
"az",
|
||||
"bytemuck",
|
||||
@@ -3121,7 +3120,6 @@ dependencies = [
|
||||
"tokio-tungstenite",
|
||||
"tokio-util 0.7.3",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
"vergen",
|
||||
"version-checker",
|
||||
@@ -6256,10 +6254,6 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
name = "validator-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"coconut-interface",
|
||||
"cosmrs",
|
||||
"getset",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -6352,7 +6346,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vesting-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Collection of initialization steps used by client implementations
|
||||
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
use crate::{
|
||||
client::key_manager::KeyManager,
|
||||
config::{persistence::key_pathfinder::ClientKeyPathfinder, Config},
|
||||
};
|
||||
|
||||
pub async fn query_gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn register_with_gateway_and_store_keys<T>(
|
||||
gateway_details: gateway::Node,
|
||||
config: &Config<T>,
|
||||
) where
|
||||
T: NymConfig,
|
||||
{
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
}
|
||||
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
pub fn show_address<T>(config: &Config<T>)
|
||||
where
|
||||
T: config::NymConfig,
|
||||
{
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config);
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod client;
|
||||
pub mod config;
|
||||
pub mod init;
|
||||
|
||||
@@ -8,7 +8,7 @@ use url::Url;
|
||||
use crate::error::Result;
|
||||
use crate::{MNEMONIC, NYMD_URL};
|
||||
|
||||
use network_defaults::{DEFAULT_NETWORK, MIX_DENOM, VOUCHER_INFO};
|
||||
use network_defaults::{DEFAULT_NETWORK, DENOM, VOUCHER_INFO};
|
||||
use validator_client::nymd::traits::CoconutBandwidthSigningClient;
|
||||
use validator_client::nymd::{Coin, Fee, NymdClient, SigningNymdClient};
|
||||
|
||||
@@ -34,7 +34,7 @@ impl Client {
|
||||
encryption_key: String,
|
||||
fee: Option<Fee>,
|
||||
) -> Result<String> {
|
||||
let amount = Coin::new(amount as u128, MIX_DENOM.base.to_string());
|
||||
let amount = Coin::new(amount as u128, DENOM.to_string());
|
||||
Ok(self
|
||||
.nymd_client
|
||||
.deposit(
|
||||
|
||||
@@ -2,8 +2,22 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::config::GatewayEndpoint;
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
@@ -79,6 +93,133 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
app
|
||||
}
|
||||
|
||||
async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
async fn gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn show_address(config: &Config) {
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
|
||||
async fn set_gateway_config(config: &mut Config, chosen_gateway_id: Option<&str>) -> gateway::Node {
|
||||
println!("Setting gateway config");
|
||||
log::trace!("Chosen gateway: {:?}", chosen_gateway_id);
|
||||
|
||||
// Get the gateway details by querying the validator-api, and using the chosen one if it's
|
||||
// among the available ones.
|
||||
let gateway_details = gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::trace!("Used gateway: {}", gateway_details);
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(gateway_details.clone().into());
|
||||
gateway_details
|
||||
}
|
||||
|
||||
async fn register_and_store_gateway_keys(gateway_details: gateway::Node, config: &Config) {
|
||||
println!("Registering gateway");
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
}
|
||||
|
||||
pub async fn execute(matches: ArgMatches<'static>) {
|
||||
println!("Initialising client...");
|
||||
|
||||
@@ -95,31 +236,51 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
let user_wants_force_register = matches.is_present("force-register-gateway");
|
||||
let should_force_register = matches.is_present("force-register-gateway");
|
||||
|
||||
// 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).
|
||||
// Unless the user really wants to.
|
||||
let register_gateway = !already_init || user_wants_force_register;
|
||||
let will_register_gateway = !already_init || should_force_register;
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = matches.value_of("gateway");
|
||||
let is_gateway_provided = matches.value_of("gateway").is_some();
|
||||
|
||||
let mut config = Config::new(id);
|
||||
|
||||
// TODO: ideally that should be the last thing that's being done to config.
|
||||
// However, we are later further overriding it with gateway id
|
||||
config = override_config(config, &matches);
|
||||
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;
|
||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||
if will_register_gateway {
|
||||
// Create identity, encryption and ack keys.
|
||||
let gateway_details = set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
register_and_store_gateway_keys(gateway_details, &config).await;
|
||||
} else if is_gateway_provided {
|
||||
// Just set the config, don't register or create any keys
|
||||
set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
} else {
|
||||
// Read the existing config to reuse the gateway configuration
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
if let Ok(existing_config) = Config::load_from_file(Some(id)) {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(existing_config.get_base().get_gateway_endpoint().clone());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Existing configuration found, but enable to load gateway details. \
|
||||
Proceeding anyway."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
@@ -130,58 +291,5 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
);
|
||||
println!("Client configuration completed.");
|
||||
|
||||
client_core::init::show_address(config.get_base());
|
||||
}
|
||||
|
||||
async fn setup_gateway(
|
||||
id: &str,
|
||||
register: bool,
|
||||
user_chosen_gateway_id: Option<&str>,
|
||||
config: &Config,
|
||||
) -> GatewayEndpoint {
|
||||
if register {
|
||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||
// the chosen one if it's among the available ones.
|
||||
println!("Configuring gateway");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// Registering with gateway by setting up and writing shared keys to disk
|
||||
log::trace!("Registering gateway");
|
||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||
.await;
|
||||
println!("Saved all generated keys");
|
||||
|
||||
gateway.into()
|
||||
} else if user_chosen_gateway_id.is_some() {
|
||||
// Just set the config, don't register or create any keys
|
||||
// This assumes that the user knows what they are doing, and that the existing keys are
|
||||
// valid for the gateway being used
|
||||
println!("Using gateway provided by user, keeping existing keys");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
gateway.into()
|
||||
} else {
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
match Config::load_from_file(Some(id)) {
|
||||
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Unable to configure gateway: {err}. \n
|
||||
Seems like the client was already initialized but it was not possible to read \
|
||||
the existing configuration file. \n
|
||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||
removing the existing configuration and starting over."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
show_address(&config);
|
||||
}
|
||||
|
||||
@@ -2,8 +2,20 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use clap::{App, Arg, ArgMatches};
|
||||
use client_core::config::GatewayEndpoint;
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use gateway_client::GatewayClient;
|
||||
use gateway_requests::registration::handshake::SharedKeys;
|
||||
use nymsphinx::addressing::clients::Recipient;
|
||||
use nymsphinx::addressing::nodes::NodeIdentity;
|
||||
use rand::{prelude::SliceRandom, rngs::OsRng, thread_rng};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use topology::{filter::VersionFilterable, gateway};
|
||||
use url::Url;
|
||||
|
||||
use crate::client::config::Config;
|
||||
use crate::commands::override_config;
|
||||
@@ -81,6 +93,137 @@ pub fn command_args<'a, 'b>() -> clap::App<'a, 'b> {
|
||||
app
|
||||
}
|
||||
|
||||
// TODO: make this private again after refactoring the config setup
|
||||
pub async fn register_with_gateway(
|
||||
gateway: &gateway::Node,
|
||||
our_identity: Arc<identity::KeyPair>,
|
||||
) -> Arc<SharedKeys> {
|
||||
let timeout = Duration::from_millis(1500);
|
||||
let mut gateway_client = GatewayClient::new_init(
|
||||
gateway.clients_address(),
|
||||
gateway.identity_key,
|
||||
gateway.owner.clone(),
|
||||
our_identity.clone(),
|
||||
timeout,
|
||||
);
|
||||
gateway_client
|
||||
.establish_connection()
|
||||
.await
|
||||
.expect("failed to establish connection with the gateway!");
|
||||
gateway_client
|
||||
.perform_initial_authentication()
|
||||
.await
|
||||
.expect("failed to register with the gateway!")
|
||||
}
|
||||
|
||||
// TODO: make this private again after refactoring the config setup
|
||||
pub async fn gateway_details(
|
||||
validator_servers: Vec<Url>,
|
||||
chosen_gateway_id: Option<&str>,
|
||||
) -> gateway::Node {
|
||||
let validator_api = validator_servers
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validator apis is empty");
|
||||
let validator_client = validator_client::ApiClient::new(validator_api.clone());
|
||||
|
||||
log::trace!("Fetching list of gateways from: {}", validator_api);
|
||||
let gateways = validator_client.get_cached_gateways().await.unwrap();
|
||||
let valid_gateways = gateways
|
||||
.into_iter()
|
||||
.filter_map(|gateway| gateway.try_into().ok())
|
||||
.collect::<Vec<gateway::Node>>();
|
||||
|
||||
let filtered_gateways = valid_gateways.filter_by_version(env!("CARGO_PKG_VERSION"));
|
||||
|
||||
// if we have chosen particular gateway - use it, otherwise choose a random one.
|
||||
// (remember that in active topology all gateways have at least 100 reputation so should
|
||||
// be working correctly)
|
||||
if let Some(gateway_id) = chosen_gateway_id {
|
||||
filtered_gateways
|
||||
.iter()
|
||||
.find(|gateway| gateway.identity_key.to_base58_string() == gateway_id)
|
||||
.expect(&*format!("no gateway with id {} exists!", gateway_id))
|
||||
.clone()
|
||||
} else {
|
||||
filtered_gateways
|
||||
.choose(&mut rand::thread_rng())
|
||||
.expect("there are no gateways on the network!")
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make this private again after refactoring the config setup
|
||||
pub fn show_address(config: &Config) {
|
||||
fn load_identity_keys(pathfinder: &ClientKeyPathfinder) -> identity::KeyPair {
|
||||
let identity_keypair: identity::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_identity_key().to_owned(),
|
||||
pathfinder.public_identity_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored identity key files");
|
||||
identity_keypair
|
||||
}
|
||||
|
||||
fn load_sphinx_keys(pathfinder: &ClientKeyPathfinder) -> encryption::KeyPair {
|
||||
let sphinx_keypair: encryption::KeyPair =
|
||||
pemstore::load_keypair(&pemstore::KeyPairPath::new(
|
||||
pathfinder.private_encryption_key().to_owned(),
|
||||
pathfinder.public_encryption_key().to_owned(),
|
||||
))
|
||||
.expect("Failed to read stored sphinx key files");
|
||||
sphinx_keypair
|
||||
}
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
let identity_keypair = load_identity_keys(&pathfinder);
|
||||
let sphinx_keypair = load_sphinx_keys(&pathfinder);
|
||||
|
||||
let client_recipient = Recipient::new(
|
||||
*identity_keypair.public_key(),
|
||||
*sphinx_keypair.public_key(),
|
||||
// TODO: below only works under assumption that gateway address == gateway id
|
||||
// (which currently is true)
|
||||
NodeIdentity::from_base58_string(config.get_base().get_gateway_id()).unwrap(),
|
||||
);
|
||||
|
||||
println!("\nThe address of this client is: {}", client_recipient);
|
||||
}
|
||||
|
||||
async fn set_gateway_config(config: &mut Config, chosen_gateway_id: Option<&str>) -> gateway::Node {
|
||||
println!("Setting gateway config");
|
||||
log::trace!("Chosen gateway: {:?}", chosen_gateway_id);
|
||||
|
||||
// Get the gateway details by querying the validator-api, and using the chosen one if it's
|
||||
// among the available ones.
|
||||
let gateway_details = gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
log::trace!("Used gateway: {}", gateway_details);
|
||||
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(gateway_details.clone().into());
|
||||
gateway_details
|
||||
}
|
||||
|
||||
async fn register_and_store_gateway_keys(gateway_details: gateway::Node, config: &Config) {
|
||||
println!("Registering gateway");
|
||||
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
let shared_keys = register_with_gateway(&gateway_details, key_manager.identity_keypair()).await;
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
println!("Saved all generated keys");
|
||||
}
|
||||
|
||||
pub async fn execute(matches: ArgMatches<'static>) {
|
||||
println!("Initialising client...");
|
||||
|
||||
@@ -98,31 +241,51 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
|
||||
// Usually you only register with the gateway on the first init, however you can force
|
||||
// re-registering if wanted.
|
||||
let user_wants_force_register = matches.is_present("force-register-gateway");
|
||||
let should_force_register = matches.is_present("force-register-gateway");
|
||||
|
||||
// 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).
|
||||
// Unless the user really wants to.
|
||||
let register_gateway = !already_init || user_wants_force_register;
|
||||
let will_register_gateway = !already_init || should_force_register;
|
||||
|
||||
// Attempt to use a user-provided gateway, if possible
|
||||
let user_chosen_gateway_id = matches.value_of("gateway");
|
||||
let is_gateway_provided = matches.value_of("gateway").is_some();
|
||||
|
||||
let mut config = Config::new(id, provider_address);
|
||||
|
||||
// TODO: ideally that should be the last thing that's being done to config.
|
||||
// However, we are later further overriding it with gateway id
|
||||
config = override_config(config, &matches);
|
||||
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;
|
||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||
if will_register_gateway {
|
||||
// Create identity, encryption and ack keys.
|
||||
let gateway_details = set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
register_and_store_gateway_keys(gateway_details, &config).await;
|
||||
} else if is_gateway_provided {
|
||||
// Just set the config, don't register or create any keys
|
||||
set_gateway_config(&mut config, matches.value_of("gateway")).await;
|
||||
} else {
|
||||
// Read the existing config to reuse the gateway configuration
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
if let Ok(existing_config) = Config::load_from_file(Some(id)) {
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(existing_config.get_base().get_gateway_endpoint().clone());
|
||||
} else {
|
||||
log::warn!(
|
||||
"Existing configuration found, but enable to load gateway details. \
|
||||
Proceeding anyway."
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
|
||||
println!("Saved configuration file to {:?}", config_save_location);
|
||||
println!("Using gateway: {}", config.get_base().get_gateway_id());
|
||||
log::debug!("Gateway id: {}", config.get_base().get_gateway_id());
|
||||
@@ -133,58 +296,5 @@ pub async fn execute(matches: ArgMatches<'static>) {
|
||||
);
|
||||
println!("Client configuration completed.");
|
||||
|
||||
client_core::init::show_address(config.get_base());
|
||||
}
|
||||
|
||||
async fn setup_gateway(
|
||||
id: &str,
|
||||
register: bool,
|
||||
user_chosen_gateway_id: Option<&str>,
|
||||
config: &Config,
|
||||
) -> GatewayEndpoint {
|
||||
if register {
|
||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||
// the chosen one if it's among the available ones.
|
||||
println!("Configuring gateway");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// Registering with gateway by setting up and writing shared keys to disk
|
||||
log::trace!("Registering gateway");
|
||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||
.await;
|
||||
println!("Saved all generated keys");
|
||||
|
||||
gateway.into()
|
||||
} else if user_chosen_gateway_id.is_some() {
|
||||
// Just set the config, don't register or create any keys
|
||||
// This assumes that the user knows what they are doing, and that the existing keys are
|
||||
// valid for the gateway being used
|
||||
println!("Using gateway provided by user, keeping existing keys");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
gateway.into()
|
||||
} else {
|
||||
println!("Not registering gateway, will reuse existing config and keys");
|
||||
match Config::load_from_file(Some(id)) {
|
||||
Ok(existing_config) => existing_config.get_base().get_gateway_endpoint().clone(),
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Unable to configure gateway: {err}. \n
|
||||
Seems like the client was already initialized but it was not possible to read \
|
||||
the existing configuration file. \n
|
||||
CAUTION: Consider backing up your gateway keys and try force gateway registration, or \
|
||||
removing the existing configuration and starting over."
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
show_address(&config);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ futures = "0.3"
|
||||
|
||||
coconut-interface = { path = "../../coconut-interface" }
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests", features = ["coconut"] }
|
||||
validator-api-requests = { path = "../../../validator-api/validator-api-requests" }
|
||||
|
||||
# required for nymd-client
|
||||
# at some point it might be possible to make it wasm-compatible
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use url::Url;
|
||||
use validator_api_requests::coconut::{
|
||||
use coconut_interface::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
||||
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
||||
VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use url::Url;
|
||||
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::nymd::cosmwasm_client::types::*;
|
||||
use crate::nymd::error::NymdError;
|
||||
use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
|
||||
use crate::nymd::wallet::DirectSecp256k1HdWallet;
|
||||
use crate::nymd::{Coin, GasAdjustable, GasPrice, TxResponse};
|
||||
use crate::nymd::{Coin, GasPrice, TxResponse};
|
||||
use async_trait::async_trait;
|
||||
use cosmrs::bank::MsgSend;
|
||||
use cosmrs::distribution::MsgWithdrawDelegatorReward;
|
||||
@@ -504,7 +504,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
|
||||
.gas_used;
|
||||
|
||||
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
|
||||
let gas = gas_estimation.adjust_gas(multiplier);
|
||||
let gas = ((gas_estimation.value() as f32 * multiplier) as u64).into();
|
||||
|
||||
debug!("Gas estimation: {}", gas_estimation);
|
||||
debug!("Multiplying the estimation by {}", multiplier);
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::nymd::Gas;
|
||||
use cosmrs::tx;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod gas_price;
|
||||
|
||||
pub type GasAdjustment = f32;
|
||||
|
||||
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3;
|
||||
pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: f32 = 1.3;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum Fee {
|
||||
Manual(#[serde(with = "sealed::TxFee")] tx::Fee),
|
||||
Auto(Option<GasAdjustment>),
|
||||
Auto(Option<f32>),
|
||||
}
|
||||
|
||||
impl From<tx::Fee> for Fee {
|
||||
@@ -23,8 +20,8 @@ impl From<tx::Fee> for Fee {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<GasAdjustment> for Fee {
|
||||
fn from(multiplier: GasAdjustment) -> Self {
|
||||
impl From<f32> for Fee {
|
||||
fn from(multiplier: f32) -> Self {
|
||||
Fee::Auto(Some(multiplier))
|
||||
}
|
||||
}
|
||||
@@ -35,21 +32,6 @@ impl Default for Fee {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GasAdjustable {
|
||||
fn adjust_gas(&self, adjustment: GasAdjustment) -> Self;
|
||||
}
|
||||
|
||||
impl GasAdjustable for Gas {
|
||||
fn adjust_gas(&self, adjustment: GasAdjustment) -> Self {
|
||||
if adjustment == 1.0 {
|
||||
*self
|
||||
} else {
|
||||
let adjusted = (self.value() as f32 * adjustment).ceil();
|
||||
(adjusted as u64).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a workaround to provide serde implementation for tx::Fee. We don't want to ever expose any of those
|
||||
// types to the public and ideally they will get replaced by proper implementation inside comrs
|
||||
mod sealed {
|
||||
|
||||
@@ -15,6 +15,7 @@ use cosmrs::rpc::HttpClientUrl;
|
||||
use cosmrs::tx::Msg;
|
||||
use cosmwasm_std::Uint128;
|
||||
use execute::execute;
|
||||
pub use fee::gas_price::GasPrice;
|
||||
use mixnet_contract_common::mixnode::DelegationEvent;
|
||||
use mixnet_contract_common::{
|
||||
ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse,
|
||||
@@ -49,7 +50,6 @@ pub use cosmrs::tx::{self, Gas};
|
||||
pub use cosmrs::Coin as CosmosCoin;
|
||||
pub use cosmrs::{bip32, AccountId, Decimal, Denom};
|
||||
pub use cosmwasm_std::Coin as CosmWasmCoin;
|
||||
pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment};
|
||||
pub use signing_client::Client as SigningNymdClient;
|
||||
pub use traits::{VestingQueryClient, VestingSigningClient};
|
||||
|
||||
@@ -136,7 +136,7 @@ impl NymdClient<SigningNymdClient> {
|
||||
where
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
let denom = network.mix_denom().base;
|
||||
let denom = network.denom();
|
||||
let client_address = signer
|
||||
.try_derive_accounts()?
|
||||
.into_iter()
|
||||
@@ -178,7 +178,7 @@ impl NymdClient<SigningNymdClient> {
|
||||
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
|
||||
{
|
||||
let prefix = network.bech32_prefix();
|
||||
let denom = network.mix_denom().base;
|
||||
let denom = network.denom();
|
||||
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic)?;
|
||||
let client_address = wallet
|
||||
.try_derive_accounts()?
|
||||
@@ -270,10 +270,6 @@ impl<C> NymdClient<C> {
|
||||
self.client.gas_price()
|
||||
}
|
||||
|
||||
pub fn gas_adjustment(&self) -> GasAdjustment {
|
||||
self.simulated_gas_multiplier
|
||||
}
|
||||
|
||||
pub async fn account_sequence(&self) -> Result<SequenceResponse, NymdError>
|
||||
where
|
||||
C: SigningCosmWasmClient + Sync,
|
||||
|
||||
@@ -49,7 +49,7 @@ impl<C: SigningCosmWasmClient + Sync + Send> MultisigSigningClient for NymdClien
|
||||
) -> Result<ExecuteResult, NymdError> {
|
||||
let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier)));
|
||||
let release_funds_req = CoconutBandwidthExecuteMsg::ReleaseFunds {
|
||||
funds: Coin::new(voucher_value, DEFAULT_NETWORK.mix_denom().base),
|
||||
funds: Coin::new(voucher_value, DEFAULT_NETWORK.denom()),
|
||||
};
|
||||
let release_funds_msg = CosmosMsg::Wasm(WasmMsg::Execute {
|
||||
contract_addr: self.coconut_bandwidth_contract_address().to_string(),
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
use crate::validator_api::error::ValidatorAPIError;
|
||||
use crate::validator_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
|
||||
use coconut_interface::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, ExecuteReleaseFundsRequestBody,
|
||||
ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse, VerificationKeyResponse,
|
||||
VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use url::Url;
|
||||
use validator_api_requests::coconut::{
|
||||
BlindSignRequestBody, BlindedSignatureResponse, CosmosAddressResponse,
|
||||
ExecuteReleaseFundsRequestBody, ProposeReleaseFundsRequestBody, ProposeReleaseFundsResponse,
|
||||
VerificationKeyResponse, VerifyCredentialBody, VerifyCredentialResponse,
|
||||
};
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, InclusionProbabilityResponse, MixNodeBondAnnotated,
|
||||
MixnodeStatusResponse, RewardEstimationResponse, StakeSaturationResponse, UptimeResponse,
|
||||
@@ -376,19 +376,6 @@ impl Client {
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn get_cosmos_address(&self) -> Result<CosmosAddressResponse, ValidatorAPIError> {
|
||||
self.query_validator_api(
|
||||
&[
|
||||
routes::API_VERSION,
|
||||
routes::COCONUT_ROUTES,
|
||||
routes::BANDWIDTH,
|
||||
routes::COCONUT_COSMOS_ADDRESS,
|
||||
],
|
||||
NO_PARAMS,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn verify_bandwidth_credential(
|
||||
&self,
|
||||
request_body: &VerifyCredentialBody,
|
||||
|
||||
@@ -17,7 +17,6 @@ pub const BANDWIDTH: &str = "bandwidth";
|
||||
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
|
||||
pub const COCONUT_PARTIAL_BANDWIDTH_CREDENTIAL: &str = "partial-bandwidth-credential";
|
||||
pub const COCONUT_VERIFICATION_KEY: &str = "verification-key";
|
||||
pub const COCONUT_COSMOS_ADDRESS: &str = "cosmos-address";
|
||||
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";
|
||||
|
||||
@@ -127,6 +127,171 @@ impl Bytable for Credential {
|
||||
|
||||
impl Base58 for Credential {}
|
||||
|
||||
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
|
||||
pub struct VerifyCredentialBody {
|
||||
#[getset(get = "pub")]
|
||||
credential: Credential,
|
||||
#[getset(get = "pub")]
|
||||
proposal_id: u64,
|
||||
}
|
||||
|
||||
impl VerifyCredentialBody {
|
||||
pub fn new(credential: Credential, proposal_id: u64) -> VerifyCredentialBody {
|
||||
VerifyCredentialBody {
|
||||
credential,
|
||||
proposal_id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct VerifyCredentialResponse {
|
||||
pub verification_result: bool,
|
||||
}
|
||||
|
||||
impl VerifyCredentialResponse {
|
||||
pub fn new(verification_result: bool) -> Self {
|
||||
VerifyCredentialResponse {
|
||||
verification_result,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All strings are base58 encoded representations of structs
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, Getters, CopyGetters)]
|
||||
pub struct BlindSignRequestBody {
|
||||
#[getset(get = "pub")]
|
||||
blind_sign_request: BlindSignRequest,
|
||||
#[getset(get = "pub")]
|
||||
tx_hash: String,
|
||||
#[getset(get = "pub")]
|
||||
signature: String,
|
||||
public_attributes: Vec<String>,
|
||||
#[getset(get = "pub")]
|
||||
public_attributes_plain: Vec<String>,
|
||||
#[getset(get = "pub")]
|
||||
total_params: u32,
|
||||
}
|
||||
|
||||
impl BlindSignRequestBody {
|
||||
pub fn new(
|
||||
blind_sign_request: &BlindSignRequest,
|
||||
tx_hash: String,
|
||||
signature: String,
|
||||
public_attributes: &[Attribute],
|
||||
public_attributes_plain: Vec<String>,
|
||||
total_params: u32,
|
||||
) -> BlindSignRequestBody {
|
||||
BlindSignRequestBody {
|
||||
blind_sign_request: blind_sign_request.clone(),
|
||||
tx_hash,
|
||||
signature,
|
||||
public_attributes: public_attributes
|
||||
.iter()
|
||||
.map(|attr| attr.to_bs58())
|
||||
.collect(),
|
||||
public_attributes_plain,
|
||||
total_params,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public_attributes(&self) -> Vec<Attribute> {
|
||||
self.public_attributes
|
||||
.iter()
|
||||
.map(|x| Attribute::try_from_bs58(x).unwrap())
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct BlindedSignatureResponse {
|
||||
pub remote_key: [u8; 32],
|
||||
pub encrypted_signature: Vec<u8>,
|
||||
}
|
||||
|
||||
impl BlindedSignatureResponse {
|
||||
pub fn new(encrypted_signature: Vec<u8>, remote_key: [u8; 32]) -> BlindedSignatureResponse {
|
||||
BlindedSignatureResponse {
|
||||
encrypted_signature,
|
||||
remote_key,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_base58_string(&self) -> String {
|
||||
bs58::encode(&self.to_bytes()).into_string()
|
||||
}
|
||||
|
||||
pub fn from_base58_string<I: AsRef<[u8]>>(val: I) -> Result<Self, CoconutInterfaceError> {
|
||||
let bytes = bs58::decode(val).into_vec()?;
|
||||
Self::from_bytes(&bytes)
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let mut bytes = self.remote_key.to_vec();
|
||||
bytes.extend_from_slice(&self.encrypted_signature);
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, CoconutInterfaceError> {
|
||||
if bytes.len() < 32 {
|
||||
return Err(CoconutInterfaceError::InvalidByteLength(bytes.len(), 32));
|
||||
}
|
||||
let mut remote_key = [0u8; 32];
|
||||
remote_key.copy_from_slice(&bytes[..32]);
|
||||
let encrypted_signature = bytes[32..].to_vec();
|
||||
Ok(BlindedSignatureResponse {
|
||||
remote_key,
|
||||
encrypted_signature,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct VerificationKeyResponse {
|
||||
pub key: VerificationKey,
|
||||
}
|
||||
|
||||
impl VerificationKeyResponse {
|
||||
pub fn new(key: VerificationKey) -> VerificationKeyResponse {
|
||||
VerificationKeyResponse { key }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Getters, CopyGetters)]
|
||||
pub struct ProposeReleaseFundsRequestBody {
|
||||
#[getset(get = "pub")]
|
||||
credential: Credential,
|
||||
}
|
||||
|
||||
impl ProposeReleaseFundsRequestBody {
|
||||
pub fn new(credential: Credential) -> Self {
|
||||
ProposeReleaseFundsRequestBody { credential }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ProposeReleaseFundsResponse {
|
||||
pub proposal_id: u64,
|
||||
}
|
||||
|
||||
impl ProposeReleaseFundsResponse {
|
||||
pub fn new(proposal_id: u64) -> Self {
|
||||
ProposeReleaseFundsResponse { proposal_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Getters, CopyGetters)]
|
||||
pub struct ExecuteReleaseFundsRequestBody {
|
||||
#[getset(get = "pub")]
|
||||
proposal_id: u64,
|
||||
}
|
||||
|
||||
impl ExecuteReleaseFundsRequestBody {
|
||||
pub fn new(proposal_id: u64) -> Self {
|
||||
ExecuteReleaseFundsRequestBody { proposal_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Coin, Timestamp};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -11,7 +11,7 @@ pub mod events;
|
||||
pub mod messages;
|
||||
|
||||
pub fn one_ucoin() -> Coin {
|
||||
Coin::new(1, MIX_DENOM.base)
|
||||
Coin::new(1, DENOM)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
|
||||
@@ -15,7 +15,6 @@ url = "2.2"
|
||||
coconut-interface = { path = "../coconut-interface" }
|
||||
crypto = { path = "../crypto", features = ["rand", "asymmetric", "symmetric", "hashing"] }
|
||||
network-defaults = { path = "../network-defaults" }
|
||||
validator-api-requests = { path = "../../validator-api/validator-api-requests" }
|
||||
validator-client = { path = "../client-libs/validator-client" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
|
||||
use coconut_interface::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, prove_bandwidth_credential, Attribute,
|
||||
BlindedSignature, Credential, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
BlindSignRequestBody, BlindedSignature, Credential, Parameters, Signature, SignatureShare,
|
||||
VerificationKey,
|
||||
};
|
||||
use crypto::asymmetric::encryption::PublicKey;
|
||||
use crypto::shared_key::recompute_shared_key;
|
||||
use crypto::symmetric::stream_cipher;
|
||||
use url::Url;
|
||||
use validator_api_requests::coconut::BlindSignRequestBody;
|
||||
|
||||
use crate::coconut::bandwidth::{BandwidthVoucher, PRIVATE_ATTRIBUTES, PUBLIC_ATTRIBUTES};
|
||||
use crate::coconut::params::{
|
||||
|
||||
@@ -5,8 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fmt, str::FromStr};
|
||||
|
||||
use crate::{
|
||||
DefaultNetworkDetails, DenomDetails, DenomDetailsOwned, ValidatorDetails, MAINNET_DEFAULTS,
|
||||
QA_DEFAULTS, SANDBOX_DEFAULTS,
|
||||
DefaultNetworkDetails, ValidatorDetails, MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
@@ -25,7 +24,7 @@ pub enum Network {
|
||||
}
|
||||
|
||||
impl Network {
|
||||
fn details(&self) -> &DefaultNetworkDetails {
|
||||
fn details(&self) -> &DefaultNetworkDetails<'_> {
|
||||
match self {
|
||||
Self::QA => &QA_DEFAULTS,
|
||||
Self::SANDBOX => &SANDBOX_DEFAULTS,
|
||||
@@ -37,12 +36,8 @@ impl Network {
|
||||
self.details().bech32_prefix
|
||||
}
|
||||
|
||||
pub fn mix_denom(&self) -> &DenomDetails {
|
||||
&self.details().mix_denom
|
||||
}
|
||||
|
||||
pub fn stake_denom(&self) -> &DenomDetails {
|
||||
&self.details().stake_denom
|
||||
pub fn denom(&self) -> &str {
|
||||
self.details().denom
|
||||
}
|
||||
|
||||
pub fn mixnet_contract_address(&self) -> &str {
|
||||
@@ -106,8 +101,7 @@ impl fmt::Display for Network {
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct NetworkDetails {
|
||||
bech32_prefix: String,
|
||||
mix_denom: DenomDetailsOwned,
|
||||
stake_denom: DenomDetailsOwned,
|
||||
denom: String,
|
||||
mixnet_contract_address: String,
|
||||
vesting_contract_address: String,
|
||||
bandwidth_claim_contract_address: String,
|
||||
@@ -115,12 +109,11 @@ pub struct NetworkDetails {
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
impl From<&DefaultNetworkDetails> for NetworkDetails {
|
||||
fn from(details: &DefaultNetworkDetails) -> Self {
|
||||
impl From<&DefaultNetworkDetails<'_>> for NetworkDetails {
|
||||
fn from(details: &DefaultNetworkDetails<'_>) -> Self {
|
||||
NetworkDetails {
|
||||
bech32_prefix: details.bech32_prefix.into(),
|
||||
mix_denom: details.mix_denom.into(),
|
||||
stake_denom: details.stake_denom.into(),
|
||||
denom: details.denom.into(),
|
||||
mixnet_contract_address: details.mixnet_contract_address.into(),
|
||||
vesting_contract_address: details.vesting_contract_address.into(),
|
||||
bandwidth_claim_contract_address: details.bandwidth_claim_contract_address.into(),
|
||||
@@ -130,12 +123,6 @@ impl From<&DefaultNetworkDetails> for NetworkDetails {
|
||||
}
|
||||
}
|
||||
|
||||
impl NetworkDetails {
|
||||
pub fn base_mix_denom(&self) -> &str {
|
||||
&self.mix_denom.base
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct SupportedNetworks {
|
||||
networks: HashMap<Network, NetworkDetails>,
|
||||
@@ -157,10 +144,10 @@ impl SupportedNetworks {
|
||||
.map(|network_details| network_details.bech32_prefix.as_str())
|
||||
}
|
||||
|
||||
pub fn base_mix_denom(&self, network: Network) -> Option<&str> {
|
||||
pub fn denom(&self, network: Network) -> Option<&str> {
|
||||
self.networks
|
||||
.get(&network)
|
||||
.map(|network_details| network_details.base_mix_denom())
|
||||
.map(|network_details| network_details.denom.as_str())
|
||||
}
|
||||
|
||||
pub fn mixnet_contract_address(&self, network: Network) -> Option<&str> {
|
||||
|
||||
@@ -17,24 +17,24 @@ pub mod sandbox;
|
||||
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 DENOM: &str = mainnet::DENOM;
|
||||
pub const STAKE_DENOM: &str = 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 DENOM: &str = qa::DENOM;
|
||||
pub const STAKE_DENOM: &str = 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 DENOM: &str = sandbox::DENOM;
|
||||
pub const STAKE_DENOM: &str = 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;
|
||||
@@ -45,52 +45,50 @@ cfg_if::cfg_if! {
|
||||
// future. If we do this, and also get rid of the references we could potentially unify with
|
||||
// `NetworkDetails`.
|
||||
#[derive(Debug)]
|
||||
pub struct DefaultNetworkDetails {
|
||||
bech32_prefix: &'static str,
|
||||
mix_denom: DenomDetails,
|
||||
stake_denom: DenomDetails,
|
||||
mixnet_contract_address: &'static str,
|
||||
vesting_contract_address: &'static str,
|
||||
bandwidth_claim_contract_address: &'static str,
|
||||
coconut_bandwidth_contract_address: &'static str,
|
||||
multisig_contract_address: &'static str,
|
||||
rewarding_validator_address: &'static str,
|
||||
statistics_service_url: &'static str,
|
||||
pub struct DefaultNetworkDetails<'a> {
|
||||
bech32_prefix: &'a str,
|
||||
denom: &'a str,
|
||||
mixnet_contract_address: &'a str,
|
||||
vesting_contract_address: &'a str,
|
||||
bandwidth_claim_contract_address: &'a str,
|
||||
coconut_bandwidth_contract_address: &'a str,
|
||||
multisig_contract_address: &'a str,
|
||||
rewarding_validator_address: &'a str,
|
||||
statistics_service_url: &'a str,
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: mainnet::BECH32_PREFIX,
|
||||
mix_denom: mainnet::MIX_DENOM,
|
||||
stake_denom: mainnet::STAKE_DENOM,
|
||||
mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: mainnet::validators(),
|
||||
});
|
||||
static MAINNET_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
|
||||
Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: mainnet::BECH32_PREFIX,
|
||||
denom: mainnet::DENOM,
|
||||
mixnet_contract_address: mainnet::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: mainnet::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: mainnet::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: mainnet::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: mainnet::validators(),
|
||||
});
|
||||
|
||||
static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: sandbox::BECH32_PREFIX,
|
||||
mix_denom: sandbox::MIX_DENOM,
|
||||
stake_denom: sandbox::STAKE_DENOM,
|
||||
mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: sandbox::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: sandbox::validators(),
|
||||
});
|
||||
static SANDBOX_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> =
|
||||
Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: sandbox::BECH32_PREFIX,
|
||||
denom: sandbox::DENOM,
|
||||
mixnet_contract_address: sandbox::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: sandbox::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
coconut_bandwidth_contract_address: sandbox::COCONUT_BANDWIDTH_CONTRACT_ADDRESS,
|
||||
multisig_contract_address: sandbox::MULTISIG_CONTRACT_ADDRESS,
|
||||
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
statistics_service_url: sandbox::STATISTICS_SERVICE_DOMAIN_ADDRESS,
|
||||
validators: sandbox::validators(),
|
||||
});
|
||||
|
||||
static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDetails {
|
||||
static QA_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: qa::BECH32_PREFIX,
|
||||
mix_denom: qa::MIX_DENOM,
|
||||
stake_denom: qa::STAKE_DENOM,
|
||||
denom: qa::DENOM,
|
||||
mixnet_contract_address: qa::MIXNET_CONTRACT_ADDRESS,
|
||||
vesting_contract_address: qa::VESTING_CONTRACT_ADDRESS,
|
||||
bandwidth_claim_contract_address: qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
@@ -101,42 +99,6 @@ static QA_DEFAULTS: Lazy<DefaultNetworkDetails> = Lazy::new(|| DefaultNetworkDet
|
||||
validators: qa::validators(),
|
||||
});
|
||||
|
||||
#[derive(Debug, Copy, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct DenomDetails {
|
||||
pub base: &'static str,
|
||||
pub display: &'static str,
|
||||
// i.e. display_amount * 10^display_exponent = base_amount
|
||||
pub display_exponent: u32,
|
||||
}
|
||||
|
||||
impl DenomDetails {
|
||||
pub const fn new(base: &'static str, display: &'static str, display_exponent: u32) -> Self {
|
||||
DenomDetails {
|
||||
base,
|
||||
display,
|
||||
display_exponent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct DenomDetailsOwned {
|
||||
pub base: String,
|
||||
pub display: String,
|
||||
// i.e. display_amount * 10^display_exponent = base_amount
|
||||
pub display_exponent: u32,
|
||||
}
|
||||
|
||||
impl From<DenomDetails> for DenomDetailsOwned {
|
||||
fn from(details: DenomDetails) -> Self {
|
||||
DenomDetailsOwned {
|
||||
base: details.base.to_owned(),
|
||||
display: details.display.to_owned(),
|
||||
display_exponent: details.display_exponent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]
|
||||
pub struct ValidatorDetails {
|
||||
// it is assumed those values are always valid since they're being provided in our defaults file
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{DenomDetails, ValidatorDetails};
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||
|
||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unym", "nym", 6);
|
||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6);
|
||||
pub const DENOM: &str = "unym";
|
||||
pub const STAKE_DENOM: &str = "unyx";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9sjyvg3g";
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{DenomDetails, ValidatorDetails};
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "n";
|
||||
|
||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unym", "nym", 6);
|
||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyx", "nyx", 6);
|
||||
pub const DENOM: &str = "unym";
|
||||
pub const STAKE_DENOM: &str = "unyx";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str =
|
||||
"n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep";
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::{DenomDetails, ValidatorDetails};
|
||||
use crate::ValidatorDetails;
|
||||
|
||||
pub(crate) const BECH32_PREFIX: &str = "nymt";
|
||||
|
||||
pub const MIX_DENOM: DenomDetails = DenomDetails::new("unymt", "nymt", 6);
|
||||
pub const STAKE_DENOM: DenomDetails = DenomDetails::new("unyxt", "nyxt", 6);
|
||||
pub const DENOM: &str = "unymt";
|
||||
pub const STAKE_DENOM: &str = "unyxt";
|
||||
|
||||
pub(crate) const MIXNET_CONTRACT_ADDRESS: &str = "nymt1ghd753shjuwexxywmgs4xz7x2q732vcnstz02j";
|
||||
pub(crate) const VESTING_CONTRACT_ADDRESS: &str = "nymt14ejqjyq8um4p3xfqj74yld5waqljf88fn549lh";
|
||||
|
||||
@@ -1,84 +1,18 @@
|
||||
use crate::currency::MajorCurrencyAmount;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use validator_client::nymd::Fee;
|
||||
|
||||
#[cfg(feature = "generate-ts")]
|
||||
use ts_rs::{Dependency, TS};
|
||||
use crate::currency::MajorCurrencyAmount;
|
||||
|
||||
#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
feature = "generate-ts",
|
||||
ts(export_to = "ts-packages/types/src/types/rust/FeeDetails.ts")
|
||||
)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FeeDetails {
|
||||
// expected to be used by the wallet in order to display detailed fee information to the user
|
||||
pub amount: Option<MajorCurrencyAmount>,
|
||||
#[cfg_attr(feature = "generate-ts", ts(skip))]
|
||||
pub fee: Fee,
|
||||
}
|
||||
|
||||
#[cfg(feature = "generate-ts")]
|
||||
impl TS for FeeDetails {
|
||||
const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/FeeDetails.ts");
|
||||
|
||||
fn decl() -> String {
|
||||
format!("type {} = {};", Self::name(), Self::inline())
|
||||
}
|
||||
|
||||
fn name() -> String {
|
||||
"FeeDetails".into()
|
||||
}
|
||||
|
||||
fn inline() -> String {
|
||||
"{ amount: MajorCurrencyAmount | null, fee: Fee }".into()
|
||||
}
|
||||
|
||||
fn dependencies() -> Vec<Dependency> {
|
||||
vec![
|
||||
Dependency::from_ty::<MajorCurrencyAmount>()
|
||||
.expect("TS was incorrectly defined on `CurrencyDenom`"),
|
||||
Dependency::from_ty::<ts_type_helpers::Fee>()
|
||||
.expect("TS was incorrectly defined on `ts_type_helpers::Fee`"),
|
||||
]
|
||||
}
|
||||
|
||||
fn transparent() -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// this should really be sealed and NEVER EVER used as "normal" types,
|
||||
// but due to our typescript requirements, we have to expose it to generate
|
||||
// the types...
|
||||
#[cfg(feature = "generate-ts")]
|
||||
pub mod ts_type_helpers {
|
||||
use serde::{Deserialize, Serialize};
|
||||
use validator_client::nymd::GasAdjustment;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export_to = "ts-packages/types/src/types/rust/Fee.ts")]
|
||||
pub enum Fee {
|
||||
Manual(CosmosFee),
|
||||
Auto(Option<GasAdjustment>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export_to = "ts-packages/types/src/types/rust/CosmosFee.ts")]
|
||||
// this should corresponds to cosmrs::tx::Fee
|
||||
// IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations
|
||||
// on the type. The below struct might have to get readjusted if we update cosmrs!!
|
||||
pub struct CosmosFee {
|
||||
amount: Vec<Coin>,
|
||||
gas_limit: u64,
|
||||
payer: Option<String>,
|
||||
granter: Option<String>,
|
||||
}
|
||||
|
||||
// Note: I've got a feeling this one will bite us hard at some point...
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)]
|
||||
#[ts(export_to = "ts-packages/types/src/types/rust/Coin.ts")]
|
||||
// this should corresponds to cosmrs::Coin
|
||||
// IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations
|
||||
// on the type. The below struct might have to get readjusted if we update cosmrs!!
|
||||
pub struct Coin {
|
||||
denom: String,
|
||||
// this is not entirely true, but for the purposes
|
||||
// of ts_rs, it's sufficient for the time being
|
||||
amount: u64,
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+2
-2
@@ -1024,7 +1024,7 @@ checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||
|
||||
[[package]]
|
||||
name = "mixnet-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"az",
|
||||
"bs58",
|
||||
@@ -1826,7 +1826,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vesting-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
|
||||
@@ -62,7 +62,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use bandwidth_claim_contract::payment::PagedPaymentResponse;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, from_binary};
|
||||
|
||||
@@ -91,11 +91,11 @@ pub mod tests {
|
||||
|
||||
// Contract balance should match what we initialized it as
|
||||
assert_eq!(
|
||||
coins(0, MIX_DENOM.base),
|
||||
coins(0, DENOM),
|
||||
vec![deps
|
||||
.as_ref()
|
||||
.querier
|
||||
.query_balance(env.contract.address, MIX_DENOM.base)
|
||||
.query_balance(env.contract.address, DENOM)
|
||||
.unwrap()]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -63,10 +63,11 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests::helpers::*;
|
||||
use coconut_bandwidth_contract_common::deposit::DepositData;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, Addr};
|
||||
use cw_multi_test::Executor;
|
||||
use serde::de::Unexpected::Str;
|
||||
|
||||
#[test]
|
||||
fn initialize_contract() {
|
||||
@@ -83,20 +84,20 @@ mod tests {
|
||||
|
||||
// Contract balance should be 0
|
||||
assert_eq!(
|
||||
coins(0, MIX_DENOM.base),
|
||||
coins(0, DENOM),
|
||||
vec![deps
|
||||
.as_ref()
|
||||
.querier
|
||||
.query_balance(env.contract.address, MIX_DENOM.base)
|
||||
.query_balance(env.contract.address, DENOM)
|
||||
.unwrap()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deposit_and_release() {
|
||||
let init_funds = coins(10, MIX_DENOM.base);
|
||||
let deposit_funds = coins(1, MIX_DENOM.base);
|
||||
let release_funds = coins(2, MIX_DENOM.base);
|
||||
let init_funds = coins(10, DENOM);
|
||||
let deposit_funds = coins(1, DENOM);
|
||||
let release_funds = coins(2, DENOM);
|
||||
let mut app = mock_app(&init_funds);
|
||||
let multisig_addr = String::from(MULTISIG_CONTRACT);
|
||||
let pool_addr = String::from(POOL_CONTRACT);
|
||||
@@ -156,7 +157,7 @@ mod tests {
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
let pool_bal = app.wrap().query_balance(pool_addr, MIX_DENOM.base).unwrap();
|
||||
let pool_bal = app.wrap().query_balance(pool_addr, DENOM).unwrap();
|
||||
assert_eq!(pool_bal, deposit_funds[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use cosmwasm_std::StdError;
|
||||
use cw_controllers::AdminError;
|
||||
use thiserror::Error;
|
||||
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
|
||||
/// Custom errors for contract failure conditions.
|
||||
///
|
||||
@@ -22,7 +22,7 @@ pub enum ContractError {
|
||||
#[error("No coin was sent for voucher")]
|
||||
NoCoin,
|
||||
|
||||
#[error("Wrong coin denomination, you must send {}", MIX_DENOM.base)]
|
||||
#[error("Wrong coin denomination, you must send {}", DENOM)]
|
||||
WrongDenom,
|
||||
|
||||
#[error("There aren't enough funds in the contract")]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#[cfg(test)]
|
||||
pub mod helpers {
|
||||
pub const OWNER: &str = "admin0001";
|
||||
pub const SOMEBODY: &str = "somebody";
|
||||
pub const MULTISIG_CONTRACT: &str = "multisig contract address";
|
||||
pub const POOL_CONTRACT: &str = "mix pool contract address";
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ use coconut_bandwidth_contract_common::events::{
|
||||
DEPOSITED_FUNDS_EVENT_TYPE, DEPOSIT_ENCRYPTION_KEY, DEPOSIT_IDENTITY_KEY, DEPOSIT_INFO,
|
||||
DEPOSIT_VALUE,
|
||||
};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
|
||||
pub(crate) fn deposit_funds(
|
||||
_deps: DepsMut<'_>,
|
||||
@@ -25,7 +25,7 @@ pub(crate) fn deposit_funds(
|
||||
if info.funds.len() > 1 {
|
||||
return Err(ContractError::MultipleDenoms);
|
||||
}
|
||||
if info.funds[0].denom != MIX_DENOM.base {
|
||||
if info.funds[0].denom != DENOM {
|
||||
return Err(ContractError::WrongDenom);
|
||||
}
|
||||
|
||||
@@ -45,12 +45,10 @@ pub(crate) fn release_funds(
|
||||
info: MessageInfo,
|
||||
funds: Coin,
|
||||
) -> Result<Response, ContractError> {
|
||||
if funds.denom != MIX_DENOM.base {
|
||||
if funds.denom != DENOM {
|
||||
return Err(ContractError::WrongDenom);
|
||||
}
|
||||
let current_balance = deps
|
||||
.querier
|
||||
.query_balance(env.contract.address, MIX_DENOM.base)?;
|
||||
let current_balance = deps.querier.query_balance(env.contract.address, DENOM)?;
|
||||
if funds.amount > current_balance.amount {
|
||||
return Err(ContractError::NotEnoughFunds);
|
||||
}
|
||||
@@ -92,7 +90,7 @@ mod tests {
|
||||
Err(ContractError::NoCoin)
|
||||
);
|
||||
|
||||
let coin = Coin::new(1000000, MIX_DENOM.base);
|
||||
let coin = Coin::new(1000000, DENOM);
|
||||
let second_coin = Coin::new(1000000, "some_denom");
|
||||
|
||||
let info = mock_info("requester", &[coin, second_coin.clone()]);
|
||||
@@ -122,7 +120,7 @@ mod tests {
|
||||
verification_key.clone(),
|
||||
encryption_key.clone(),
|
||||
);
|
||||
let coin = Coin::new(deposit_value, MIX_DENOM.base);
|
||||
let coin = Coin::new(deposit_value, DENOM);
|
||||
let info = mock_info("requester", &[coin]);
|
||||
|
||||
let tx = deposit_funds(deps.as_mut(), env.clone(), info, data).unwrap();
|
||||
@@ -171,7 +169,7 @@ mod tests {
|
||||
let mut deps = helpers::init_contract();
|
||||
let env = mock_env();
|
||||
let invalid_admin = "invalid admin";
|
||||
let funds = Coin::new(1, MIX_DENOM.base);
|
||||
let funds = Coin::new(1, DENOM);
|
||||
|
||||
let err = release_funds(
|
||||
deps.as_mut(),
|
||||
@@ -207,7 +205,7 @@ mod tests {
|
||||
fn valid_release() {
|
||||
let mut deps = helpers::init_contract();
|
||||
let env = mock_env();
|
||||
let coin = Coin::new(1, MIX_DENOM.base);
|
||||
let coin = Coin::new(1, DENOM);
|
||||
|
||||
deps.querier
|
||||
.update_balance(env.contract.address.clone(), vec![coin.clone()]);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "mixnet-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
authors = ["Dave Hrycyszyn <futurechimp@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
|
||||
|
||||
@@ -443,8 +443,62 @@ pub fn query(deps: Deps<'_>, env: Env, msg: QueryMsg) -> Result<QueryResponse, C
|
||||
Ok(query_res?)
|
||||
}
|
||||
|
||||
fn update_epoch_duration(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
let mut epoch = crate::interval::storage::current_epoch(deps.storage)?;
|
||||
epoch.update_duration(600);
|
||||
crate::interval::storage::save_epoch(deps.storage, &epoch)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _migrate_contract_state_params(deps: DepsMut<'_>) -> Result<(), ContractError> {
|
||||
use crate::mixnet_contract_settings::storage::CONTRACT_STATE;
|
||||
use cw_storage_plus::Item;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractState {
|
||||
pub owner: Addr,
|
||||
pub rewarding_validator_address: Addr,
|
||||
pub params: OldContractStateParams,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct OldContractStateParams {
|
||||
pub minimum_mixnode_pledge: Uint128,
|
||||
pub minimum_gateway_pledge: Uint128,
|
||||
pub mixnode_rewarded_set_size: u32,
|
||||
pub mixnode_active_set_size: u32,
|
||||
}
|
||||
|
||||
const OLD_CONTRACT_STATE: Item<'_, OldContractState> = Item::new("config");
|
||||
|
||||
let old_contract_state = OLD_CONTRACT_STATE.load(deps.storage)?;
|
||||
|
||||
let old_params = old_contract_state.params;
|
||||
|
||||
let new_params = ContractStateParams {
|
||||
minimum_mixnode_pledge: old_params.minimum_mixnode_pledge,
|
||||
minimum_gateway_pledge: old_params.minimum_gateway_pledge,
|
||||
mixnode_rewarded_set_size: old_params.mixnode_rewarded_set_size,
|
||||
mixnode_active_set_size: old_params.mixnode_active_set_size,
|
||||
staking_supply: INITIAL_STAKING_SUPPLY,
|
||||
};
|
||||
|
||||
let new_contract_state = ContractState {
|
||||
owner: old_contract_state.owner,
|
||||
rewarding_validator_address: old_contract_state.rewarding_validator_address,
|
||||
params: new_params,
|
||||
};
|
||||
|
||||
CONTRACT_STATE.save(deps.storage, &new_contract_state)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[entry_point]
|
||||
pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
pub fn migrate(deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
|
||||
update_epoch_duration(deps)?;
|
||||
Ok(Default::default())
|
||||
}
|
||||
|
||||
@@ -452,7 +506,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests;
|
||||
use config::defaults::{DEFAULT_NETWORK, MIX_DENOM};
|
||||
use config::defaults::{DEFAULT_NETWORK, DENOM};
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, from_binary};
|
||||
use mixnet_contract_common::PagedMixnodeResponse;
|
||||
@@ -484,7 +538,7 @@ pub mod tests {
|
||||
|
||||
// Contract balance should match what we initialized it as
|
||||
assert_eq!(
|
||||
coins(0, MIX_DENOM.base),
|
||||
coins(0, DENOM),
|
||||
tests::queries::query_contract_balance(env.contract.address, deps)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ pub(crate) fn query_mixnode_delegations_paged(
|
||||
pub(crate) mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{coin, Addr, Storage};
|
||||
use rand::Rng;
|
||||
|
||||
@@ -385,7 +385,7 @@ pub(crate) mod tests {
|
||||
let delegation = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
node_identity.clone(),
|
||||
coin(1234, MIX_DENOM.base),
|
||||
coin(1234, DENOM),
|
||||
1234,
|
||||
None,
|
||||
);
|
||||
@@ -433,7 +433,7 @@ pub(crate) mod tests {
|
||||
let delegation = Delegation::new(
|
||||
delegation_owner2,
|
||||
node_identity1.clone(),
|
||||
coin(1234, MIX_DENOM.base),
|
||||
coin(1234, DENOM),
|
||||
1234,
|
||||
None,
|
||||
);
|
||||
@@ -460,7 +460,7 @@ pub(crate) mod tests {
|
||||
let delegation = Delegation::new(
|
||||
delegation_owner1.clone(),
|
||||
node_identity2,
|
||||
coin(1234, MIX_DENOM.base),
|
||||
coin(1234, DENOM),
|
||||
1234,
|
||||
None,
|
||||
);
|
||||
|
||||
@@ -77,7 +77,7 @@ mod tests {
|
||||
mod reverse_mix_delegations {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::mock_env;
|
||||
use cosmwasm_std::{coin, Order};
|
||||
use mixnet_contract_common::Delegation;
|
||||
@@ -87,7 +87,7 @@ mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let node_identity: IdentityKey = "foo".into();
|
||||
let delegation_owner = Addr::unchecked("bar");
|
||||
let delegation = coin(12345, MIX_DENOM.base);
|
||||
let delegation = coin(12345, DENOM);
|
||||
|
||||
let dummy_data = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
@@ -125,7 +125,7 @@ mod tests {
|
||||
let node_identity2: IdentityKey = "foo2".into();
|
||||
let delegation_owner1 = Addr::unchecked("bar");
|
||||
let delegation_owner2 = Addr::unchecked("bar2");
|
||||
let delegation = coin(12345, MIX_DENOM.base);
|
||||
let delegation = coin(12345, DENOM);
|
||||
|
||||
assert!(test_helpers::read_delegation(
|
||||
deps.as_ref().storage,
|
||||
|
||||
@@ -6,7 +6,7 @@ use super::storage::{self, PENDING_DELEGATION_EVENTS};
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, Event, MessageInfo, Order,
|
||||
Response, Storage, Uint128, WasmMsg,
|
||||
@@ -85,7 +85,7 @@ fn validate_delegation_stake(mut delegation: Vec<Coin>) -> Result<Coin, Contract
|
||||
}
|
||||
|
||||
// check that the denomination is correct
|
||||
if delegation[0].denom != MIX_DENOM.base {
|
||||
if delegation[0].denom != DENOM {
|
||||
return Err(ContractError::WrongDenom {});
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
.as_ref()
|
||||
.unwrap_or(&pending_undelegate.delegate())
|
||||
.to_string(),
|
||||
amount: coins(total_funds.u128(), MIX_DENOM.base),
|
||||
amount: coins(total_funds.u128(), DENOM),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@@ -401,7 +401,7 @@ pub(crate) fn try_reconcile_undelegation(
|
||||
let msg = Some(VestingContractExecuteMsg::TrackUndelegation {
|
||||
owner: pending_undelegate.delegate().as_str().to_string(),
|
||||
mix_identity: pending_undelegate.mix_identity(),
|
||||
amount: Coin::new(total_funds.u128(), MIX_DENOM.base),
|
||||
amount: Coin::new(total_funds.u128(), DENOM),
|
||||
});
|
||||
|
||||
wasm_msg = Some(wasm_execute(proxy, &msg, vec![one_ucoin()])?);
|
||||
@@ -492,7 +492,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
Err(ContractError::MultipleDenoms),
|
||||
validate_delegation_stake(vec![
|
||||
coin(123, MIX_DENOM.base),
|
||||
coin(123, DENOM),
|
||||
coin(123, "BTC"),
|
||||
coin(123, "DOGE")
|
||||
])
|
||||
@@ -511,16 +511,16 @@ mod tests {
|
||||
fn stake_coin_must_have_value_greater_than_zero() {
|
||||
assert_eq!(
|
||||
Err(ContractError::EmptyDelegation),
|
||||
validate_delegation_stake(coins(0, MIX_DENOM.base))
|
||||
validate_delegation_stake(coins(0, DENOM))
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stake_can_have_any_positive_value() {
|
||||
// this might change in the future, but right now an arbitrary (positive) value can be delegated
|
||||
assert!(validate_delegation_stake(coins(1, MIX_DENOM.base)).is_ok());
|
||||
assert!(validate_delegation_stake(coins(123, MIX_DENOM.base)).is_ok());
|
||||
assert!(validate_delegation_stake(coins(10000000000, MIX_DENOM.base)).is_ok());
|
||||
assert!(validate_delegation_stake(coins(1, DENOM)).is_ok());
|
||||
assert!(validate_delegation_stake(coins(123, DENOM)).is_ok());
|
||||
assert!(validate_delegation_stake(coins(10000000000, DENOM)).is_ok());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -543,7 +543,7 @@ mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("sender", &coins(123, MIX_DENOM.base)),
|
||||
mock_info("sender", &coins(123, DENOM)),
|
||||
"non-existent-mix-identity".into(),
|
||||
)
|
||||
);
|
||||
@@ -559,7 +559,7 @@ mod tests {
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation = coin(123, MIX_DENOM.base);
|
||||
let delegation = coin(123, DENOM);
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
@@ -616,7 +616,7 @@ mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(123, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(123, DENOM)),
|
||||
identity,
|
||||
)
|
||||
);
|
||||
@@ -637,7 +637,7 @@ mod tests {
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation = coin(123, MIX_DENOM.base);
|
||||
let delegation = coin(123, DENOM);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
@@ -687,8 +687,8 @@ mod tests {
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation1 = coin(100, MIX_DENOM.base);
|
||||
let delegation2 = coin(50, MIX_DENOM.base);
|
||||
let delegation1 = coin(100, DENOM);
|
||||
let delegation2 = coin(50, DENOM);
|
||||
|
||||
let mut env = mock_env();
|
||||
|
||||
@@ -715,7 +715,7 @@ mod tests {
|
||||
// let expected = Delegation::new(
|
||||
// delegation_owner.clone(),
|
||||
// identity.clone(),
|
||||
// coin(delegation1.amount.u128() + delegation2.amount.u128(), MIX_DENOM.base),
|
||||
// coin(delegation1.amount.u128() + delegation2.amount.u128(), DENOM),
|
||||
// mock_env().block.height,
|
||||
// None,
|
||||
// );
|
||||
@@ -750,7 +750,7 @@ mod tests {
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation = coin(100, MIX_DENOM.base);
|
||||
let delegation = coin(100, DENOM);
|
||||
let env1 = mock_env();
|
||||
let mut env2 = mock_env();
|
||||
let initial_height = env1.block.height;
|
||||
@@ -815,8 +815,8 @@ mod tests {
|
||||
);
|
||||
let delegation_owner1 = Addr::unchecked("sender1");
|
||||
let delegation_owner2 = Addr::unchecked("sender2");
|
||||
let delegation1 = coin(100, MIX_DENOM.base);
|
||||
let delegation2 = coin(120, MIX_DENOM.base);
|
||||
let delegation1 = coin(100, DENOM);
|
||||
let delegation2 = coin(120, DENOM);
|
||||
let env1 = mock_env();
|
||||
let mut env2 = mock_env();
|
||||
let initial_height = env1.block.height;
|
||||
@@ -891,7 +891,7 @@ mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, DENOM)),
|
||||
identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -903,7 +903,7 @@ mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(50, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(50, DENOM)),
|
||||
identity,
|
||||
)
|
||||
);
|
||||
@@ -928,14 +928,14 @@ mod tests {
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(123, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(123, DENOM)),
|
||||
identity1.clone(),
|
||||
)
|
||||
.is_ok());
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(42, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(42, DENOM)),
|
||||
identity2.clone(),
|
||||
)
|
||||
.is_ok());
|
||||
@@ -945,7 +945,7 @@ mod tests {
|
||||
let expected1 = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
identity1.clone(),
|
||||
coin(123, MIX_DENOM.base),
|
||||
coin(123, DENOM),
|
||||
mock_env().block.height,
|
||||
None,
|
||||
);
|
||||
@@ -953,7 +953,7 @@ mod tests {
|
||||
let expected2 = Delegation::new(
|
||||
delegation_owner.clone(),
|
||||
identity2.clone(),
|
||||
coin(42, MIX_DENOM.base),
|
||||
coin(42, DENOM),
|
||||
mock_env().block.height,
|
||||
None,
|
||||
);
|
||||
@@ -989,8 +989,8 @@ mod tests {
|
||||
tests::fixtures::good_mixnode_pledge(),
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation1 = coin(123, MIX_DENOM.base);
|
||||
let delegation2 = coin(234, MIX_DENOM.base);
|
||||
let delegation1 = coin(123, DENOM);
|
||||
let delegation2 = coin(234, DENOM);
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
@@ -1026,7 +1026,7 @@ mod tests {
|
||||
deps.as_mut(),
|
||||
);
|
||||
let delegation_owner = Addr::unchecked("sender");
|
||||
let delegation_amount = coin(100, MIX_DENOM.base);
|
||||
let delegation_amount = coin(100, DENOM);
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
@@ -1118,7 +1118,7 @@ mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, DENOM)),
|
||||
identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1137,7 +1137,7 @@ mod tests {
|
||||
let expected_response = Response::new()
|
||||
.add_message(BankMsg::Send {
|
||||
to_address: delegation_owner.clone().into(),
|
||||
amount: coins(100, MIX_DENOM.base),
|
||||
amount: coins(100, DENOM),
|
||||
})
|
||||
.add_event(new_undelegation_event(
|
||||
&delegation_owner,
|
||||
@@ -1188,7 +1188,7 @@ mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, MIX_DENOM.base)),
|
||||
mock_info(delegation_owner.as_str(), &coins(100, DENOM)),
|
||||
identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1207,7 +1207,7 @@ mod tests {
|
||||
let expected_response = Response::new()
|
||||
.add_message(BankMsg::Send {
|
||||
to_address: delegation_owner.clone().into(),
|
||||
amount: coins(100, MIX_DENOM.base),
|
||||
amount: coins(100, DENOM),
|
||||
})
|
||||
.add_event(new_undelegation_event(
|
||||
&delegation_owner,
|
||||
@@ -1251,8 +1251,8 @@ mod tests {
|
||||
);
|
||||
let delegation_owner1 = Addr::unchecked("sender1");
|
||||
let delegation_owner2 = Addr::unchecked("sender2");
|
||||
let delegation1 = coin(123, MIX_DENOM.base);
|
||||
let delegation2 = coin(234, MIX_DENOM.base);
|
||||
let delegation1 = coin(123, DENOM);
|
||||
let delegation2 = coin(234, DENOM);
|
||||
assert!(try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Addr, StdError};
|
||||
use mixnet_contract_common::{error::MixnetContractError, IdentityKey};
|
||||
use thiserror::Error;
|
||||
@@ -33,13 +33,13 @@ pub enum ContractError {
|
||||
#[error("MIXNET ({}): Unauthorized", line!())]
|
||||
Unauthorized,
|
||||
|
||||
#[error("MIXNET ({}): Wrong coin denomination, you must send {}", line!(), MIX_DENOM.base)]
|
||||
#[error("MIXNET ({}): Wrong coin denomination, you must send {}", line!(), DENOM)]
|
||||
WrongDenom,
|
||||
|
||||
#[error("MIXNET ({}): Received multiple coin types during staking", line!())]
|
||||
MultipleDenoms,
|
||||
|
||||
#[error("MIXNET ({}): No coin was sent for the bonding, you must send {}", line!(), MIX_DENOM.base)]
|
||||
#[error("MIXNET ({}): No coin was sent for the bonding, you must send {}", line!(), DENOM)]
|
||||
NoBondFound,
|
||||
|
||||
#[error("MIXNET ({}): Provided active set size is bigger than the rewarded set", line!())]
|
||||
|
||||
@@ -36,7 +36,7 @@ pub(crate) fn gateways<'a>() -> IndexedMap<'a, IdentityKeyRef<'a>, GatewayBond,
|
||||
mod tests {
|
||||
use super::super::storage;
|
||||
use crate::support::tests;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::MockStorage;
|
||||
use cosmwasm_std::StdResult;
|
||||
use cosmwasm_std::Storage;
|
||||
@@ -84,7 +84,7 @@ mod tests {
|
||||
let pledge_amount = 1000;
|
||||
|
||||
let gateway_bond = GatewayBond {
|
||||
pledge_amount: coin(pledge_amount, MIX_DENOM.base),
|
||||
pledge_amount: coin(pledge_amount, DENOM),
|
||||
owner: node_owner,
|
||||
block_height: 12_345,
|
||||
gateway: Gateway {
|
||||
|
||||
@@ -5,7 +5,7 @@ use super::storage;
|
||||
use crate::error::ContractError;
|
||||
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::support::helpers::{ensure_no_existing_bond, validate_node_identity_signature};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
wasm_execute, Addr, BankMsg, Coin, DepsMut, Env, MessageInfo, Response, Uint128,
|
||||
};
|
||||
@@ -203,7 +203,7 @@ fn validate_gateway_pledge(
|
||||
}
|
||||
|
||||
// check that the denomination is correct
|
||||
if pledge[0].denom != MIX_DENOM.base {
|
||||
if pledge[0].denom != DENOM {
|
||||
return Err(ContractError::WrongDenom {});
|
||||
}
|
||||
|
||||
@@ -226,7 +226,7 @@ pub mod tests {
|
||||
use crate::gateways::transactions::validate_gateway_pledge;
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, BankMsg, Response};
|
||||
use cosmwasm_std::{from_binary, Addr, Uint128};
|
||||
@@ -238,7 +238,7 @@ pub mod tests {
|
||||
|
||||
// if we fail validation (by say not sending enough funds
|
||||
let insufficient_bond = Into::<u128>::into(INITIAL_GATEWAY_PLEDGE) - 1;
|
||||
let info = mock_info("anyone", &coins(insufficient_bond, MIX_DENOM.base));
|
||||
let info = mock_info("anyone", &coins(insufficient_bond, DENOM));
|
||||
let (msg, _) = tests::messages::valid_bond_gateway_msg("anyone");
|
||||
|
||||
// we are informed that we didn't send enough funds
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{StdResult, Storage, Uint128};
|
||||
use cw_storage_plus::{Index, IndexList, IndexedSnapshotMap, Map, Strategy, UniqueIndex};
|
||||
use mixnet_contract_common::{
|
||||
@@ -171,7 +171,7 @@ pub(crate) fn read_full_mixnode_bond(
|
||||
Ok(Some(MixNodeBond {
|
||||
pledge_amount: stored_bond.pledge_amount,
|
||||
total_delegation: Coin {
|
||||
denom: MIX_DENOM.base.to_owned(),
|
||||
denom: DENOM.to_owned(),
|
||||
amount: total_delegation.unwrap_or_default(),
|
||||
},
|
||||
owner: stored_bond.owner,
|
||||
@@ -190,7 +190,7 @@ mod tests {
|
||||
use super::super::storage;
|
||||
use super::*;
|
||||
use crate::support::tests;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::MockStorage;
|
||||
use cosmwasm_std::{coin, Addr, Uint128};
|
||||
use mixnet_contract_common::{IdentityKey, MixNode};
|
||||
@@ -223,7 +223,7 @@ mod tests {
|
||||
let pledge_value = 1000000000;
|
||||
|
||||
let mixnode_bond = StoredMixnodeBond {
|
||||
pledge_amount: coin(pledge_value, MIX_DENOM.base),
|
||||
pledge_amount: coin(pledge_value, DENOM),
|
||||
owner: node_owner,
|
||||
layer: Layer::One,
|
||||
block_height: 12_345,
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::mixnet_contract_settings::storage as mixnet_params_storage;
|
||||
use crate::mixnodes::layer_queries::query_layer_distribution;
|
||||
use crate::mixnodes::storage::StoredMixnodeBond;
|
||||
use crate::support::helpers::{ensure_no_existing_bond, validate_node_identity_signature};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
wasm_execute, Addr, BankMsg, Coin, DepsMut, Env, MessageInfo, Response, Storage, Uint128,
|
||||
};
|
||||
@@ -364,7 +364,7 @@ fn validate_mixnode_pledge(
|
||||
}
|
||||
|
||||
// check that the denomination is correct
|
||||
if pledge[0].denom != MIX_DENOM.base {
|
||||
if pledge[0].denom != DENOM {
|
||||
return Err(ContractError::WrongDenom {});
|
||||
}
|
||||
|
||||
@@ -387,7 +387,7 @@ pub mod tests {
|
||||
use crate::mixnodes::transactions::validate_mixnode_pledge;
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, BankMsg, Response};
|
||||
use cosmwasm_std::{from_binary, Addr, Uint128};
|
||||
@@ -402,7 +402,7 @@ pub mod tests {
|
||||
|
||||
// if we don't send enough funds
|
||||
let insufficient_bond = Into::<u128>::into(INITIAL_MIXNODE_PLEDGE) - 1;
|
||||
let info = mock_info("anyone", &coins(insufficient_bond, MIX_DENOM.base));
|
||||
let info = mock_info("anyone", &coins(insufficient_bond, DENOM));
|
||||
let (msg, _) = tests::messages::valid_bond_mixnode_msg("anyone");
|
||||
|
||||
// we are informed that we didn't send enough funds
|
||||
|
||||
@@ -83,7 +83,7 @@ pub(crate) mod tests {
|
||||
use crate::delegations::transactions::try_delegate_to_mixnode;
|
||||
use crate::interval::storage::{save_epoch, save_epoch_reward_params};
|
||||
use crate::rewards::transactions::try_reward_mixnode;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{coin, Addr};
|
||||
use mixnet_contract_common::{
|
||||
Interval, RewardingResult, RewardingStatus, MIXNODE_DELEGATORS_PAGE_LIMIT,
|
||||
@@ -185,10 +185,7 @@ pub(crate) mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
mock_info(
|
||||
&*format!("delegator{:04}", i),
|
||||
&[coin(200_000000, MIX_DENOM.base)],
|
||||
),
|
||||
mock_info(&*format!("delegator{:04}", i), &[coin(200_000000, DENOM)]),
|
||||
node_identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -14,7 +14,7 @@ use crate::mixnodes::storage::mixnodes;
|
||||
use crate::mixnodes::storage::{self as mixnodes_storage, StoredMixnodeBond};
|
||||
use crate::rewards::helpers;
|
||||
use crate::support::helpers::{is_authorized, operator_cost_at_epoch};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
coins, wasm_execute, Addr, Api, BankMsg, Coin, DepsMut, Env, MessageInfo, Order, Response,
|
||||
Storage, Uint128,
|
||||
@@ -105,7 +105,7 @@ fn _try_claim_operator_reward(
|
||||
|
||||
let return_tokens = BankMsg::Send {
|
||||
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
|
||||
amount: coins(reward.u128(), MIX_DENOM.base),
|
||||
amount: coins(reward.u128(), DENOM),
|
||||
};
|
||||
|
||||
let mut response = Response::default()
|
||||
@@ -115,7 +115,7 @@ fn _try_claim_operator_reward(
|
||||
if let Some(proxy) = proxy {
|
||||
let msg = Some(VestingContractExecuteMsg::TrackReward {
|
||||
address: owner.to_string(),
|
||||
amount: Coin::new(reward.u128(), MIX_DENOM.base),
|
||||
amount: Coin::new(reward.u128(), DENOM),
|
||||
});
|
||||
|
||||
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
@@ -153,7 +153,7 @@ pub fn _try_claim_delegator_reward(
|
||||
|
||||
let return_tokens = BankMsg::Send {
|
||||
to_address: proxy.as_ref().unwrap_or(&owner).to_string(),
|
||||
amount: coins(reward.u128(), MIX_DENOM.base),
|
||||
amount: coins(reward.u128(), DENOM),
|
||||
};
|
||||
|
||||
let mut response =
|
||||
@@ -169,7 +169,7 @@ pub fn _try_claim_delegator_reward(
|
||||
if let Some(proxy) = proxy {
|
||||
let msg = Some(VestingContractExecuteMsg::TrackReward {
|
||||
address: owner.to_string(),
|
||||
amount: Coin::new(reward.u128(), MIX_DENOM.base),
|
||||
amount: Coin::new(reward.u128(), DENOM),
|
||||
});
|
||||
|
||||
let wasm_msg = wasm_execute(proxy, &msg, vec![one_ucoin()])?;
|
||||
@@ -438,7 +438,7 @@ pub fn _try_compound_delegator_reward(
|
||||
owner_address,
|
||||
Coin {
|
||||
amount: compounded_delegation,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
proxy,
|
||||
)?;
|
||||
@@ -726,7 +726,7 @@ pub mod tests {
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::test_helpers;
|
||||
use az::CheckedCast;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
use cosmwasm_std::{coin, coins, Addr, StdError, Timestamp, Uint128};
|
||||
use mixnet_contract_common::events::{
|
||||
@@ -744,7 +744,7 @@ pub mod tests {
|
||||
let mut deps = test_helpers::init_contract();
|
||||
let mut env = mock_env();
|
||||
let sender = rewarding_validator_address(&deps.storage).unwrap();
|
||||
let info = mock_info(&sender, &coins(1000, MIX_DENOM.base));
|
||||
let info = mock_info(&sender, &coins(1000, DENOM));
|
||||
crate::interval::transactions::init_epoch(&mut deps.storage, env.clone()).unwrap();
|
||||
|
||||
// bond the node
|
||||
@@ -885,7 +885,7 @@ pub mod tests {
|
||||
let initial_bond = 10000_000000;
|
||||
let initial_delegation = 20000_000000;
|
||||
let mixnode_bond = StoredMixnodeBond {
|
||||
pledge_amount: coin(initial_bond, MIX_DENOM.base),
|
||||
pledge_amount: coin(initial_bond, DENOM),
|
||||
owner: node_owner,
|
||||
layer: Layer::One,
|
||||
block_height: env.block.height,
|
||||
@@ -925,7 +925,7 @@ pub mod tests {
|
||||
&Delegation::new(
|
||||
Addr::unchecked("delegator"),
|
||||
node_identity.clone(),
|
||||
coin(initial_delegation, MIX_DENOM.base),
|
||||
coin(initial_delegation, DENOM),
|
||||
env.block.height,
|
||||
None,
|
||||
),
|
||||
@@ -1109,7 +1109,7 @@ pub mod tests {
|
||||
assert_eq!(staking_supply, 100_000_000_000_000u128);
|
||||
|
||||
let sender = Addr::unchecked("alice");
|
||||
let stake = coins(10_000_000_000, MIX_DENOM.base);
|
||||
let stake = coins(10_000_000_000, DENOM);
|
||||
|
||||
let keypair = crypto::asymmetric::identity::KeyPair::new(&mut thread_rng());
|
||||
let owner_signature = keypair
|
||||
@@ -1160,14 +1160,14 @@ pub mod tests {
|
||||
let node_owner: Addr = Addr::unchecked("johnny");
|
||||
let node_identity_2 = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10_000_000_000, MIX_DENOM.base),
|
||||
coins(10_000_000_000, DENOM),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alice_d1", &[coin(8000_000000, MIX_DENOM.base)]),
|
||||
mock_info("alice_d1", &[coin(8000_000000, DENOM)]),
|
||||
node_identity_1.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1175,7 +1175,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alice_d2", &[coin(2000_000000, MIX_DENOM.base)]),
|
||||
mock_info("alice_d2", &[coin(2000_000000, DENOM)]),
|
||||
node_identity_1.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1183,7 +1183,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("bob_d1", &[coin(8000_000000, MIX_DENOM.base)]),
|
||||
mock_info("bob_d1", &[coin(8000_000000, DENOM)]),
|
||||
node_identity_2.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1191,7 +1191,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("bob_d2", &[coin(2000_000000, MIX_DENOM.base)]),
|
||||
mock_info("bob_d2", &[coin(2000_000000, DENOM)]),
|
||||
node_identity_2.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1199,14 +1199,14 @@ pub mod tests {
|
||||
let node_owner: Addr = Addr::unchecked("alicebob");
|
||||
let node_identity_3 = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10_000_000_000 * 2, MIX_DENOM.base),
|
||||
coins(10_000_000_000 * 2, DENOM),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alicebob_d1", &[coin(8000_000000 * 2, MIX_DENOM.base)]),
|
||||
mock_info("alicebob_d1", &[coin(8000_000000 * 2, DENOM)]),
|
||||
node_identity_3.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1214,7 +1214,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alicebob_d2", &[coin(2000_000000 * 2, MIX_DENOM.base)]),
|
||||
mock_info("alicebob_d2", &[coin(2000_000000 * 2, DENOM)]),
|
||||
node_identity_3.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1321,7 +1321,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
mock_info("alice_d1", &[coin(8000_000000, MIX_DENOM.base)]),
|
||||
mock_info("alice_d1", &[coin(8000_000000, DENOM)]),
|
||||
node_identity_1.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1560,14 +1560,14 @@ pub mod tests {
|
||||
let node_owner: Addr = Addr::unchecked("alice");
|
||||
let node_identity = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10_000_000_000, MIX_DENOM.base),
|
||||
coins(10_000_000_000, DENOM),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alice_d1", &[coin(8000_000000, MIX_DENOM.base)]),
|
||||
mock_info("alice_d1", &[coin(8000_000000, DENOM)]),
|
||||
node_identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1575,7 +1575,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
mock_env(),
|
||||
mock_info("alice_d2", &[coin(2000_000000, MIX_DENOM.base)]),
|
||||
mock_info("alice_d2", &[coin(2000_000000, DENOM)]),
|
||||
node_identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
@@ -1751,7 +1751,7 @@ pub mod tests {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
let node_identity = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10000_000_000, MIX_DENOM.base),
|
||||
coins(10000_000_000, DENOM),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
@@ -1778,7 +1778,7 @@ pub mod tests {
|
||||
#[allow(clippy::inconsistent_digit_grouping)]
|
||||
let node_identity = test_helpers::add_mixnode(
|
||||
node_owner.as_str(),
|
||||
coins(10000_000_000, MIX_DENOM.base),
|
||||
coins(10000_000_000, DENOM),
|
||||
deps.as_mut(),
|
||||
);
|
||||
|
||||
@@ -1786,10 +1786,7 @@ pub mod tests {
|
||||
try_delegate_to_mixnode(
|
||||
deps.as_mut(),
|
||||
env.clone(),
|
||||
mock_info(
|
||||
&*format!("delegator{:04}", i),
|
||||
&[coin(2000_000000, MIX_DENOM.base)],
|
||||
),
|
||||
mock_info(&*format!("delegator{:04}", i), &[coin(2000_000000, DENOM)]),
|
||||
node_identity.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::contract::INITIAL_MIXNODE_PLEDGE;
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use crate::{mixnodes::storage::StoredMixnodeBond, support::tests};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{coin, Addr, Coin};
|
||||
use mixnet_contract_common::reward_params::NodeRewardParams;
|
||||
use mixnet_contract_common::{Gateway, GatewayBond, Layer, MixNode};
|
||||
@@ -37,7 +37,7 @@ pub fn gateway_bond_fixture(owner: &str) -> GatewayBond {
|
||||
..tests::fixtures::gateway_fixture()
|
||||
};
|
||||
GatewayBond::new(
|
||||
coin(50, MIX_DENOM.base),
|
||||
coin(50, DENOM),
|
||||
Addr::unchecked(owner),
|
||||
12_345,
|
||||
gateway,
|
||||
@@ -47,7 +47,7 @@ pub fn gateway_bond_fixture(owner: &str) -> GatewayBond {
|
||||
|
||||
pub(crate) fn stored_mixnode_bond_fixture(owner: &str) -> mixnodes_storage::StoredMixnodeBond {
|
||||
StoredMixnodeBond::new(
|
||||
coin(50, MIX_DENOM.base),
|
||||
coin(50, DENOM),
|
||||
Addr::unchecked(owner),
|
||||
Layer::One,
|
||||
12_345,
|
||||
@@ -64,14 +64,14 @@ pub(crate) fn stored_mixnode_bond_fixture(owner: &str) -> mixnodes_storage::Stor
|
||||
|
||||
pub fn good_mixnode_pledge() -> Vec<Coin> {
|
||||
vec![Coin {
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
amount: INITIAL_MIXNODE_PLEDGE,
|
||||
}]
|
||||
}
|
||||
|
||||
pub fn good_gateway_pledge() -> Vec<Coin> {
|
||||
vec![Coin {
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
amount: INITIAL_MIXNODE_PLEDGE,
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ pub mod test_helpers {
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use crate::mixnodes::transactions::try_add_mixnode;
|
||||
use crate::support::tests;
|
||||
use config::defaults::{DEFAULT_NETWORK, MIX_DENOM};
|
||||
use config::defaults::{DEFAULT_NETWORK, DENOM};
|
||||
use cosmwasm_std::testing::mock_dependencies;
|
||||
use cosmwasm_std::testing::mock_env;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
@@ -111,7 +111,7 @@ pub mod test_helpers {
|
||||
let delegation = Delegation {
|
||||
owner: Addr::unchecked(owner.into()),
|
||||
node_identity: mix.into(),
|
||||
amount: coin(12345, MIX_DENOM.base),
|
||||
amount: coin(12345, DENOM),
|
||||
block_height: block_height,
|
||||
proxy: None,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
from_binary,
|
||||
testing::{mock_env, MockApi, MockQuerier, MockStorage},
|
||||
@@ -45,5 +45,5 @@ pub fn query_contract_balance(
|
||||
deps: OwnedDeps<MockStorage, MockApi, MockQuerier>,
|
||||
) -> Vec<Coin> {
|
||||
let querier = deps.as_ref().querier;
|
||||
vec![querier.query_balance(address, MIX_DENOM.base).unwrap()]
|
||||
vec![querier.query_balance(address, DENOM).unwrap()]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "vesting-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
authors = ["Drazen Urch <durch@users.noreply.github.com>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -23,4 +23,4 @@ cw-storage-plus = { version = "0.13.4", features = ["iterator"] }
|
||||
|
||||
schemars = "0.8"
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
thiserror = { version = "1.0" }
|
||||
thiserror = { version = "1.0" }
|
||||
@@ -7,7 +7,7 @@ use crate::traits::{
|
||||
DelegatingAccount, GatewayBondingAccount, MixnodeBondingAccount, VestingAccount,
|
||||
};
|
||||
use crate::vesting::{populate_vesting_periods, Account};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{
|
||||
coin, entry_point, to_binary, BankMsg, Coin, Deps, DepsMut, Env, MessageInfo, QueryResponse,
|
||||
Response, Timestamp, Uint128,
|
||||
@@ -167,11 +167,8 @@ pub fn try_withdraw_vested_coins(
|
||||
info: MessageInfo,
|
||||
deps: DepsMut<'_>,
|
||||
) -> Result<Response, ContractError> {
|
||||
if amount.denom != MIX_DENOM.base {
|
||||
return Err(ContractError::WrongDenom(
|
||||
amount.denom,
|
||||
MIX_DENOM.base.to_string(),
|
||||
));
|
||||
if amount.denom != DENOM {
|
||||
return Err(ContractError::WrongDenom(amount.denom, DENOM.to_string()));
|
||||
}
|
||||
|
||||
let address = info.sender.clone();
|
||||
@@ -639,10 +636,10 @@ fn validate_funds(funds: &[Coin]) -> Result<Coin, ContractError> {
|
||||
return Err(ContractError::MultipleDenoms);
|
||||
}
|
||||
|
||||
if funds[0].denom != MIX_DENOM.base {
|
||||
if funds[0].denom != DENOM {
|
||||
return Err(ContractError::WrongDenom(
|
||||
funds[0].denom.clone(),
|
||||
MIX_DENOM.base.to_string(),
|
||||
DENOM.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
pub mod helpers {
|
||||
use crate::contract::instantiate;
|
||||
use crate::vesting::{populate_vesting_periods, Account};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_dependencies, mock_env, mock_info, MockApi, MockQuerier};
|
||||
use cosmwasm_std::{Addr, Coin, Empty, Env, MemoryStorage, OwnedDeps, Storage, Uint128};
|
||||
use vesting_contract_common::messages::{InitMsg, VestingSpecification};
|
||||
@@ -31,7 +31,7 @@ pub mod helpers {
|
||||
Some(Addr::unchecked("staking")),
|
||||
Coin {
|
||||
amount: Uint128::new(1_000_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
start_time_ts,
|
||||
periods,
|
||||
@@ -50,7 +50,7 @@ pub mod helpers {
|
||||
Some(Addr::unchecked("staking")),
|
||||
Coin {
|
||||
amount: Uint128::new(1_000_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
start_time,
|
||||
periods,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::errors::ContractError;
|
||||
use crate::storage::{delete_account, save_account, DELEGATIONS};
|
||||
use crate::traits::VestingAccount;
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::{Addr, Coin, Env, Order, Storage, Timestamp, Uint128};
|
||||
use vesting_contract_common::{OriginalVestingResponse, Period};
|
||||
|
||||
@@ -47,7 +47,7 @@ impl VestingAccount for Account {
|
||||
.u128(),
|
||||
),
|
||||
),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ impl VestingAccount for Account {
|
||||
.u128()
|
||||
.saturating_sub(self.locked_coins(block_time, env, storage)?.amount.u128()),
|
||||
),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -78,15 +78,15 @@ impl VestingAccount for Account {
|
||||
let amount = match period {
|
||||
Period::Before => Coin {
|
||||
amount: Uint128::new(0),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
Period::In(idx) => Coin {
|
||||
amount: Uint128::new(self.tokens_per_period()? * idx as u128),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
Period::After => Coin {
|
||||
amount: self.coin.amount,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
};
|
||||
Ok(amount)
|
||||
@@ -100,7 +100,7 @@ impl VestingAccount for Account {
|
||||
Ok(Coin {
|
||||
amount: self.get_original_vesting().amount().amount
|
||||
- self.get_vested_coins(block_time, env)?.amount,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ impl VestingAccount for Account {
|
||||
|
||||
Ok(Coin {
|
||||
amount,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ impl VestingAccount for Account {
|
||||
|
||||
Ok(Coin {
|
||||
amount,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ impl VestingAccount for Account {
|
||||
|
||||
Ok(Coin {
|
||||
amount,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -226,12 +226,12 @@ impl VestingAccount for Account {
|
||||
let amount = bond.amount().amount - bonded_free.amount;
|
||||
Ok(Coin {
|
||||
amount,
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
} else {
|
||||
Ok(Coin {
|
||||
amount: Uint128::zero(),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ mod tests {
|
||||
use crate::traits::DelegatingAccount;
|
||||
use crate::traits::VestingAccount;
|
||||
use crate::traits::{GatewayBondingAccount, MixnodeBondingAccount};
|
||||
use config::defaults::MIX_DENOM;
|
||||
use config::defaults::DENOM;
|
||||
use cosmwasm_std::testing::{mock_env, mock_info};
|
||||
use cosmwasm_std::{coins, Addr, Coin, Timestamp, Uint128};
|
||||
use mixnet_contract_common::{Gateway, MixNode};
|
||||
@@ -55,7 +55,7 @@ mod tests {
|
||||
fn test_account_creation() {
|
||||
let mut deps = init_contract();
|
||||
let env = mock_env();
|
||||
let info = mock_info("not_admin", &coins(1_000_000_000_000, MIX_DENOM.base));
|
||||
let info = mock_info("not_admin", &coins(1_000_000_000_000, DENOM));
|
||||
let msg = ExecuteMsg::CreateAccount {
|
||||
owner_address: "owner".to_string(),
|
||||
staking_address: Some("staking".to_string()),
|
||||
@@ -65,7 +65,7 @@ mod tests {
|
||||
let response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
|
||||
assert!(response.is_err());
|
||||
|
||||
let info = mock_info("admin", &coins(1_000_000_000_000, MIX_DENOM.base));
|
||||
let info = mock_info("admin", &coins(1_000_000_000_000, DENOM));
|
||||
let _response = execute(deps.as_mut(), env.clone(), info.clone(), msg.clone());
|
||||
let created_account = load_account(&Addr::unchecked("owner"), &deps.storage)
|
||||
.unwrap()
|
||||
@@ -131,7 +131,7 @@ mod tests {
|
||||
let msg = ExecuteMsg::WithdrawVestedCoins {
|
||||
amount: Coin {
|
||||
amount: Uint128::new(1),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
};
|
||||
let info = mock_info("new_owner", &[]);
|
||||
@@ -262,7 +262,7 @@ mod tests {
|
||||
|
||||
let delegation = Coin {
|
||||
amount: Uint128::new(90_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
};
|
||||
|
||||
let ok = account.try_delegate_to_mixnode(
|
||||
@@ -388,7 +388,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(1_000_000_000_001),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -399,7 +399,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(90_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -411,7 +411,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(20_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -426,7 +426,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(500_000_000_001),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -522,7 +522,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(1_000_000_000_001),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -534,7 +534,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(90_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -550,7 +550,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(10_000_000_001),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -642,7 +642,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(1_000_000_000_001),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -654,7 +654,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(90_000_000_000),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
@@ -670,7 +670,7 @@ mod tests {
|
||||
"alice".to_string(),
|
||||
Coin {
|
||||
amount: Uint128::new(500_000_000_001),
|
||||
denom: MIX_DENOM.base.to_string(),
|
||||
denom: DENOM.to_string(),
|
||||
},
|
||||
&env,
|
||||
&mut deps.storage,
|
||||
|
||||
@@ -83,7 +83,7 @@ pub(crate) async fn get_description(
|
||||
Some(bond) => {
|
||||
match get_mix_node_description(
|
||||
&bond.mix_node().host,
|
||||
bond.mix_node().http_api_port,
|
||||
&bond.mix_node().http_api_port,
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -129,7 +129,7 @@ pub(crate) async fn get_stats(
|
||||
trace!("No valid cache value for {}", pubkey);
|
||||
match state.inner.get_mix_node(pubkey).await {
|
||||
Some(bond) => {
|
||||
match get_mix_node_stats(&bond.mix_node().host, bond.mix_node().http_api_port)
|
||||
match get_mix_node_stats(&bond.mix_node().host, &bond.mix_node().http_api_port)
|
||||
.await
|
||||
{
|
||||
Ok(response) => {
|
||||
@@ -188,14 +188,14 @@ pub(crate) async fn get_economic_dynamics_stats(
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_mix_node_description(host: &str, port: u16) -> Result<NodeDescription, ReqwestError> {
|
||||
async fn get_mix_node_description(host: &str, port: &u16) -> Result<NodeDescription, ReqwestError> {
|
||||
reqwest::get(format!("http://{}:{}/description", host, port))
|
||||
.await?
|
||||
.json::<NodeDescription>()
|
||||
.await
|
||||
}
|
||||
|
||||
async fn get_mix_node_stats(host: &str, port: u16) -> Result<NodeStats, ReqwestError> {
|
||||
async fn get_mix_node_stats(host: &str, port: &u16) -> Result<NodeStats, ReqwestError> {
|
||||
reqwest::get(format!("http://{}:{}/stats", host, port))
|
||||
.await?
|
||||
.json::<NodeStats>()
|
||||
|
||||
@@ -29,10 +29,8 @@ pub(crate) struct PrettyDetailedMixNodeBond {
|
||||
pub owner: Addr,
|
||||
pub layer: Layer,
|
||||
pub mix_node: MixNode,
|
||||
pub avg_uptime: Option<u8>,
|
||||
pub stake_saturation: f32,
|
||||
pub avg_uptime: u8,
|
||||
pub estimated_operator_apy: f64,
|
||||
pub estimated_delegators_apy: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, JsonSchema)]
|
||||
|
||||
@@ -32,7 +32,7 @@ pub(crate) async fn list_active_set(
|
||||
) -> Json<Vec<PrettyDetailedMixNodeBond>> {
|
||||
Json(get_mixnodes_by_status(
|
||||
state.inner.mixnodes.get_detailed_mixnodes().await,
|
||||
&MixnodeStatus::Active,
|
||||
MixnodeStatus::Active,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ pub(crate) async fn list_inactive_set(
|
||||
) -> Json<Vec<PrettyDetailedMixNodeBond>> {
|
||||
Json(get_mixnodes_by_status(
|
||||
state.inner.mixnodes.get_detailed_mixnodes().await,
|
||||
&MixnodeStatus::Inactive,
|
||||
MixnodeStatus::Inactive,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ pub(crate) async fn list_standby_set(
|
||||
) -> Json<Vec<PrettyDetailedMixNodeBond>> {
|
||||
Json(get_mixnodes_by_status(
|
||||
state.inner.mixnodes.get_detailed_mixnodes().await,
|
||||
&MixnodeStatus::Standby,
|
||||
MixnodeStatus::Standby,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -66,9 +66,9 @@ pub(crate) async fn summary(state: &State<ExplorerApiStateContext>) -> Json<MixN
|
||||
|
||||
pub(crate) async fn get_mixnode_summary(state: &State<ExplorerApiStateContext>) -> MixNodeSummary {
|
||||
let mixnodes = state.inner.mixnodes.get_detailed_mixnodes().await;
|
||||
let active = get_mixnodes_by_status(mixnodes.clone(), &MixnodeStatus::Active).len();
|
||||
let standby = get_mixnodes_by_status(mixnodes.clone(), &MixnodeStatus::Standby).len();
|
||||
let inactive = get_mixnodes_by_status(mixnodes.clone(), &MixnodeStatus::Inactive).len();
|
||||
let active = get_mixnodes_by_status(mixnodes.clone(), MixnodeStatus::Active).len();
|
||||
let standby = get_mixnodes_by_status(mixnodes.clone(), MixnodeStatus::Standby).len();
|
||||
let inactive = get_mixnodes_by_status(mixnodes.clone(), MixnodeStatus::Inactive).len();
|
||||
MixNodeSummary {
|
||||
count: mixnodes.len(),
|
||||
activeset: MixNodeActiveSetSummary {
|
||||
@@ -81,10 +81,10 @@ pub(crate) async fn get_mixnode_summary(state: &State<ExplorerApiStateContext>)
|
||||
|
||||
fn get_mixnodes_by_status(
|
||||
all_mixnodes: Vec<PrettyDetailedMixNodeBond>,
|
||||
status: &MixnodeStatus,
|
||||
status: MixnodeStatus,
|
||||
) -> Vec<PrettyDetailedMixNodeBond> {
|
||||
all_mixnodes
|
||||
.into_iter()
|
||||
.filter(|mixnode| &mixnode.status == status)
|
||||
.filter(|mixnode| mixnode.status == status)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -8,8 +8,9 @@ use std::time::{Duration, SystemTime};
|
||||
use serde::Serialize;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use validator_client::models::MixNodeBondAnnotated;
|
||||
use validator_client::models::{MixNodeBondAnnotated, UptimeResponse};
|
||||
|
||||
use crate::cache::Cache;
|
||||
use crate::mix_node::models::{MixnodeStatus, PrettyDetailedMixNodeBond};
|
||||
use crate::mix_nodes::location::{Location, LocationCache, LocationCacheItem};
|
||||
use crate::mix_nodes::CACHE_ENTRY_TTL;
|
||||
@@ -76,10 +77,16 @@ impl MixNodesResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct MixNodeHealth {
|
||||
avg_uptime: u8,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct ThreadsafeMixNodesCache {
|
||||
mixnodes: Arc<RwLock<MixNodesResult>>,
|
||||
locations: Arc<RwLock<LocationCache>>,
|
||||
mixnode_health: Arc<RwLock<Cache<MixNodeHealth>>>,
|
||||
}
|
||||
|
||||
impl ThreadsafeMixNodesCache {
|
||||
@@ -87,6 +94,7 @@ impl ThreadsafeMixNodesCache {
|
||||
ThreadsafeMixNodesCache {
|
||||
mixnodes: Arc::new(RwLock::new(MixNodesResult::new())),
|
||||
locations: Arc::new(RwLock::new(LocationCache::new())),
|
||||
mixnode_health: Arc::new(RwLock::new(Cache::new())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +102,7 @@ impl ThreadsafeMixNodesCache {
|
||||
ThreadsafeMixNodesCache {
|
||||
mixnodes: Arc::new(RwLock::new(MixNodesResult::new())),
|
||||
locations: Arc::new(RwLock::new(locations)),
|
||||
mixnode_health: Arc::new(RwLock::new(Cache::new())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,9 +111,8 @@ impl ThreadsafeMixNodesCache {
|
||||
.read()
|
||||
.await
|
||||
.get(identity_key)
|
||||
.map_or(false, |cache_item| {
|
||||
cache_item.valid_until > SystemTime::now()
|
||||
})
|
||||
.map(|cache_item| cache_item.valid_until > SystemTime::now())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub(crate) async fn get_locations(&self) -> LocationCache {
|
||||
@@ -133,9 +141,11 @@ impl ThreadsafeMixNodesCache {
|
||||
) -> Option<PrettyDetailedMixNodeBond> {
|
||||
let mixnodes_guard = self.mixnodes.read().await;
|
||||
let location_guard = self.locations.read().await;
|
||||
let mixnode_health_guard = self.mixnode_health.read().await;
|
||||
|
||||
let bond = mixnodes_guard.get_mixnode(identity_key);
|
||||
let location = location_guard.get(identity_key);
|
||||
let health = mixnode_health_guard.get(identity_key);
|
||||
|
||||
match bond {
|
||||
Some(bond) => Some(PrettyDetailedMixNodeBond {
|
||||
@@ -146,10 +156,8 @@ impl ThreadsafeMixNodesCache {
|
||||
owner: bond.mixnode_bond.owner,
|
||||
layer: bond.mixnode_bond.layer,
|
||||
mix_node: bond.mixnode_bond.mix_node,
|
||||
avg_uptime: bond.uptime,
|
||||
avg_uptime: health.map(|m| m.avg_uptime),
|
||||
stake_saturation: bond.stake_saturation,
|
||||
estimated_operator_apy: bond.estimated_operator_apy,
|
||||
estimated_delegators_apy: bond.estimated_delegators_apy,
|
||||
}),
|
||||
None => None,
|
||||
}
|
||||
@@ -158,6 +166,7 @@ impl ThreadsafeMixNodesCache {
|
||||
pub(crate) async fn get_detailed_mixnodes(&self) -> Vec<PrettyDetailedMixNodeBond> {
|
||||
let mixnodes_guard = self.mixnodes.read().await;
|
||||
let location_guard = self.locations.read().await;
|
||||
let mixnode_health_guard = self.mixnode_health.read().await;
|
||||
|
||||
mixnodes_guard
|
||||
.all_mixnodes
|
||||
@@ -165,6 +174,7 @@ impl ThreadsafeMixNodesCache {
|
||||
.map(|bond| {
|
||||
let location = location_guard.get(&bond.mix_node().identity_key);
|
||||
let copy = bond.mixnode_bond.clone();
|
||||
let health = mixnode_health_guard.get(&bond.mix_node().identity_key);
|
||||
PrettyDetailedMixNodeBond {
|
||||
location: location.and_then(|l| l.location.clone()),
|
||||
status: mixnodes_guard.determine_node_status(&bond.mix_node().identity_key),
|
||||
@@ -173,10 +183,8 @@ impl ThreadsafeMixNodesCache {
|
||||
owner: copy.owner,
|
||||
layer: copy.layer,
|
||||
mix_node: copy.mix_node,
|
||||
avg_uptime: bond.uptime,
|
||||
avg_uptime: health.map(|m| m.avg_uptime),
|
||||
stake_saturation: bond.stake_saturation,
|
||||
estimated_operator_apy: bond.estimated_operator_apy,
|
||||
estimated_delegators_apy: bond.estimated_delegators_apy,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
@@ -197,4 +205,14 @@ impl ThreadsafeMixNodesCache {
|
||||
guard.active_mixnodes = active_nodes;
|
||||
guard.valid_until = SystemTime::now() + CACHE_ENTRY_TTL;
|
||||
}
|
||||
|
||||
pub(crate) async fn update_health_cache(&self, all_uptimes: Vec<UptimeResponse>) {
|
||||
let mut mixnode_health = self.mixnode_health.write().await;
|
||||
for uptime in all_uptimes {
|
||||
let health = MixNodeHealth {
|
||||
avg_uptime: uptime.avg_uptime,
|
||||
};
|
||||
mixnode_health.set(&uptime.identity, health);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,14 +120,14 @@ async fn do_port_check(host: &str, port: u16) -> bool {
|
||||
trace!("Successfully pinged {}", addr);
|
||||
true
|
||||
}
|
||||
Ok(Err(stream_err)) => {
|
||||
warn!("{} ping failed {:}", addr, stream_err);
|
||||
Ok(Err(_stream_err)) => {
|
||||
warn!("{} ping failed {:}", addr, _stream_err);
|
||||
// didn't timeout but couldn't open tcp stream
|
||||
false
|
||||
}
|
||||
Err(timeout) => {
|
||||
Err(_timeout) => {
|
||||
// timed out
|
||||
warn!("{} timed out {:}", addr, timeout);
|
||||
warn!("{} timed out {:}", addr, _timeout);
|
||||
false
|
||||
}
|
||||
},
|
||||
|
||||
+30
-27
@@ -64,36 +64,39 @@ impl ExplorerApiStateContext {
|
||||
let json_file_path = Path::new(&json_file);
|
||||
info!("Loading state from file {:?}...", json_file);
|
||||
|
||||
if let Ok(Ok(state)) =
|
||||
File::open(json_file_path).map(serde_json::from_reader::<_, ExplorerApiStateOnDisk>)
|
||||
{
|
||||
info!("Loaded state from file {:?}: {:?}", json_file, state);
|
||||
ExplorerApiState {
|
||||
country_node_distribution:
|
||||
ThreadsafeCountryNodesDistribution::new_from_distribution(
|
||||
state.country_node_distribution,
|
||||
match File::open(json_file_path).map(serde_json::from_reader::<_, ExplorerApiStateOnDisk>) {
|
||||
Ok(Ok(state)) => {
|
||||
info!("Loaded state from file {:?}: {:?}", json_file, state);
|
||||
ExplorerApiState {
|
||||
country_node_distribution:
|
||||
ThreadsafeCountryNodesDistribution::new_from_distribution(
|
||||
state.country_node_distribution,
|
||||
),
|
||||
gateways: ThreadsafeGatewayCache::new(),
|
||||
mixnode: ThreadsafeMixNodeCache::new(),
|
||||
mixnodes: ThreadsafeMixNodesCache::new_with_location_cache(
|
||||
state.location_cache,
|
||||
),
|
||||
gateways: ThreadsafeGatewayCache::new(),
|
||||
mixnode: ThreadsafeMixNodeCache::new(),
|
||||
mixnodes: ThreadsafeMixNodesCache::new_with_location_cache(state.location_cache),
|
||||
ping: ThreadsafePingCache::new(),
|
||||
validators: ThreadsafeValidatorCache::new(),
|
||||
validator_client: ThreadsafeValidatorClient::new(),
|
||||
ping: ThreadsafePingCache::new(),
|
||||
validators: ThreadsafeValidatorCache::new(),
|
||||
validator_client: ThreadsafeValidatorClient::new(),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"Failed to load state from file {:?}, starting with empty state!",
|
||||
json_file
|
||||
);
|
||||
_ => {
|
||||
warn!(
|
||||
"Failed to load state from file {:?}, starting with empty state!",
|
||||
json_file
|
||||
);
|
||||
|
||||
ExplorerApiState {
|
||||
country_node_distribution: ThreadsafeCountryNodesDistribution::new(),
|
||||
gateways: ThreadsafeGatewayCache::new(),
|
||||
mixnode: ThreadsafeMixNodeCache::new(),
|
||||
mixnodes: ThreadsafeMixNodesCache::new(),
|
||||
ping: ThreadsafePingCache::new(),
|
||||
validators: ThreadsafeValidatorCache::new(),
|
||||
validator_client: ThreadsafeValidatorClient::new(),
|
||||
ExplorerApiState {
|
||||
country_node_distribution: ThreadsafeCountryNodesDistribution::new(),
|
||||
gateways: ThreadsafeGatewayCache::new(),
|
||||
mixnode: ThreadsafeMixNodeCache::new(),
|
||||
mixnodes: ThreadsafeMixNodesCache::new(),
|
||||
ping: ThreadsafePingCache::new(),
|
||||
validators: ThreadsafeValidatorCache::new(),
|
||||
validator_client: ThreadsafeValidatorClient::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use std::future::Future;
|
||||
|
||||
use mixnet_contract_common::GatewayBond;
|
||||
use validator_client::models::MixNodeBondAnnotated;
|
||||
use validator_client::models::{MixNodeBondAnnotated, UptimeResponse};
|
||||
use validator_client::nymd::error::NymdError;
|
||||
use validator_client::nymd::{Paging, QueryNymdClient, ValidatorResponse};
|
||||
use validator_client::ValidatorClientError;
|
||||
@@ -89,6 +89,17 @@ impl ExplorerApiTasks {
|
||||
.await
|
||||
}
|
||||
|
||||
async fn retrieve_all_mixnode_avg_uptimes(
|
||||
&self,
|
||||
) -> Result<Vec<UptimeResponse>, ValidatorClientError> {
|
||||
self.state
|
||||
.inner
|
||||
.validator_client
|
||||
.0
|
||||
.get_mixnode_avg_uptimes()
|
||||
.await
|
||||
}
|
||||
|
||||
async fn update_mixnode_cache(&self) {
|
||||
let all_bonds = self.retrieve_all_mixnodes().await;
|
||||
let rewarded_nodes = self
|
||||
@@ -110,6 +121,21 @@ impl ExplorerApiTasks {
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn update_mixnode_health_cache(&self) {
|
||||
match self.retrieve_all_mixnode_avg_uptimes().await {
|
||||
Ok(response) => {
|
||||
self.state
|
||||
.inner
|
||||
.mixnodes
|
||||
.update_health_cache(response)
|
||||
.await
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to get mixnode avg uptimes: {:?}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_validators_cache(&self) {
|
||||
match self.retrieve_all_validators().await {
|
||||
Ok(response) => self.state.inner.validators.update_cache(response).await,
|
||||
@@ -146,6 +172,10 @@ impl ExplorerApiTasks {
|
||||
|
||||
info!("Updating mix node cache...");
|
||||
self.update_mixnode_cache().await;
|
||||
|
||||
info!("Updating mix node health cache...");
|
||||
self.update_mixnode_health_cache().await;
|
||||
info!("Done");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+1
-2
@@ -52,12 +52,11 @@ network-defaults = { path = "../common/network-defaults" }
|
||||
nymsphinx = { path = "../common/nymsphinx" }
|
||||
pemstore = { path = "../common/pemstore" }
|
||||
statistics-common = { path = "../common/statistics" }
|
||||
validator-api-requests = { path = "../validator-api/validator-api-requests" }
|
||||
validator-client = { path = "../common/client-libs/validator-client", features = ["nymd-client"] }
|
||||
version-checker = { path = "../common/version-checker" }
|
||||
|
||||
[features]
|
||||
coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut", "validator-api-requests/coconut"]
|
||||
coconut = ["coconut-interface", "gateway-requests/coconut", "gateway-client/coconut", "credentials/coconut"]
|
||||
eth = []
|
||||
|
||||
[build-dependencies]
|
||||
|
||||
@@ -10,7 +10,7 @@ use thiserror::Error;
|
||||
|
||||
pub const ENCRYPTED_ADDRESS_SIZE: usize = DESTINATION_ADDRESS_LENGTH;
|
||||
|
||||
/// Replacement for what used to be an `AuthToken`. We used to be generating an `AuthToken` based on
|
||||
/// Replacement for what used to be an 'AuthToken'. We used to be generating an 'AuthToken' based on
|
||||
/// local secret and remote address in order to allow for authentication. Due to changes in registration
|
||||
/// and the fact we are deriving a shared key, we are encrypting remote's address with the previously
|
||||
/// derived shared key. If the value is as expected, then authentication is successful.
|
||||
|
||||
@@ -43,10 +43,6 @@ pub struct Init {
|
||||
#[clap(long)]
|
||||
validator_apis: Option<String>,
|
||||
|
||||
/// Comma separated list of endpoints of the validator
|
||||
#[clap(long)]
|
||||
validators: Option<String>,
|
||||
|
||||
/// Cosmos wallet mnemonic needed for double spending protection
|
||||
#[clap(long)]
|
||||
mnemonic: Option<String>,
|
||||
@@ -68,6 +64,11 @@ pub struct Init {
|
||||
/// URL where a statistics aggregator is running. The default value is a Nym aggregator server
|
||||
#[clap(long)]
|
||||
statistics_service_url: Option<String>,
|
||||
|
||||
/// Comma separated list of endpoints of the validator
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
#[clap(long)]
|
||||
validators: Option<String>,
|
||||
}
|
||||
|
||||
impl From<Init> for OverrideConfig {
|
||||
@@ -80,7 +81,6 @@ impl From<Init> for OverrideConfig {
|
||||
datastore: init_config.datastore,
|
||||
announce_host: init_config.announce_host,
|
||||
validator_apis: init_config.validator_apis,
|
||||
validators: init_config.validators,
|
||||
mnemonic: init_config.mnemonic,
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
@@ -91,6 +91,9 @@ impl From<Init> for OverrideConfig {
|
||||
|
||||
enabled_statistics: init_config.enabled_statistics,
|
||||
statistics_service_url: init_config.statistics_service_url,
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
validators: init_config.validators,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -171,14 +174,15 @@ mod tests {
|
||||
announce_host: Some("foo-announce-host".to_string()),
|
||||
datastore: Some("foo-datastore".to_string()),
|
||||
validator_apis: None,
|
||||
validators: None,
|
||||
mnemonic: None,
|
||||
mnemonic: Some("a b c".to_string()),
|
||||
statistics_service_url: None,
|
||||
enabled_statistics: None,
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
enabled_credentials_mode: None,
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
eth_endpoint: "".to_string(),
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
validators: None,
|
||||
};
|
||||
|
||||
let config = Config::new(&args.id);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::{process, str::FromStr};
|
||||
use std::process;
|
||||
|
||||
use crate::{config::Config, Cli};
|
||||
use clap::Subcommand;
|
||||
@@ -17,6 +17,9 @@ pub(crate) mod upgrade;
|
||||
|
||||
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||
const DEFAULT_ETH_ENDPOINT: &str = "https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||
const DEFAULT_VALIDATOR_ENDPOINT: &str = "http://localhost:26657";
|
||||
|
||||
#[derive(Subcommand)]
|
||||
pub(crate) enum Commands {
|
||||
/// Initialise the gateway
|
||||
@@ -46,7 +49,6 @@ pub(crate) struct OverrideConfig {
|
||||
enabled_statistics: Option<bool>,
|
||||
statistics_service_url: Option<String>,
|
||||
validator_apis: Option<String>,
|
||||
validators: Option<String>,
|
||||
mnemonic: Option<String>,
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
@@ -54,6 +56,9 @@ pub(crate) struct OverrideConfig {
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
eth_endpoint: Option<String>,
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
validators: Option<String>,
|
||||
}
|
||||
|
||||
pub(crate) async fn execute(args: Cli) {
|
||||
@@ -115,10 +120,6 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
|
||||
config = config.with_custom_validator_apis(parse_validators(&raw_validators));
|
||||
}
|
||||
|
||||
if let Some(raw_validators) = args.validators {
|
||||
config = config.with_custom_validator_nymd(parse_validators(&raw_validators));
|
||||
}
|
||||
|
||||
if let Some(wallet_address) = args.wallet_address {
|
||||
let trimmed = wallet_address.trim();
|
||||
validate_bech32_address_or_exit(trimmed);
|
||||
@@ -130,13 +131,12 @@ pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Confi
|
||||
}
|
||||
|
||||
if let Some(cosmos_mnemonic) = args.mnemonic {
|
||||
config = config.with_cosmos_mnemonic(
|
||||
bip39::Mnemonic::from_str(&cosmos_mnemonic).expect("Provided mnemonic is invalid"),
|
||||
);
|
||||
config = config.with_cosmos_mnemonic(cosmos_mnemonic);
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "eth"), not(feature = "coconut")))]
|
||||
{
|
||||
config = config.with_custom_validator_nymd(parse_validators(DEFAULT_VALIDATOR_ENDPOINT));
|
||||
config = config.with_eth_endpoint(String::from(DEFAULT_ETH_ENDPOINT));
|
||||
}
|
||||
|
||||
|
||||
@@ -43,10 +43,6 @@ pub struct Run {
|
||||
#[clap(long)]
|
||||
validator_apis: Option<String>,
|
||||
|
||||
/// Comma separated list of endpoints of the validator
|
||||
#[clap(long)]
|
||||
validators: Option<String>,
|
||||
|
||||
/// Cosmos wallet mnemonic
|
||||
#[clap(long)]
|
||||
mnemonic: Option<String>,
|
||||
@@ -68,6 +64,11 @@ pub struct Run {
|
||||
/// URL where a statistics aggregator is running. The default value is a Nym aggregator server
|
||||
#[clap(long)]
|
||||
statistics_service_url: Option<String>,
|
||||
|
||||
/// Comma separated list of endpoints of the validator
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
#[clap(long)]
|
||||
validators: Option<String>,
|
||||
}
|
||||
|
||||
impl From<Run> for OverrideConfig {
|
||||
@@ -80,7 +81,6 @@ impl From<Run> for OverrideConfig {
|
||||
datastore: run_config.datastore,
|
||||
announce_host: run_config.announce_host,
|
||||
validator_apis: run_config.validator_apis,
|
||||
validators: run_config.validators,
|
||||
mnemonic: run_config.mnemonic,
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
@@ -91,6 +91,9 @@ impl From<Run> for OverrideConfig {
|
||||
|
||||
enabled_statistics: run_config.enabled_statistics,
|
||||
statistics_service_url: run_config.statistics_service_url,
|
||||
|
||||
#[cfg(all(feature = "eth", not(feature = "coconut")))]
|
||||
validators: run_config.validators,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::IpAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use url::Url;
|
||||
|
||||
@@ -143,12 +142,13 @@ impl Config {
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub fn with_custom_validator_nymd(mut self, validator_nymd_urls: Vec<Url>) -> Self {
|
||||
self.gateway.validator_nymd_urls = validator_nymd_urls;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_cosmos_mnemonic(mut self, cosmos_mnemonic: bip39::Mnemonic) -> Self {
|
||||
pub fn with_cosmos_mnemonic(mut self, cosmos_mnemonic: String) -> Self {
|
||||
self.gateway.cosmos_mnemonic = cosmos_mnemonic;
|
||||
self
|
||||
}
|
||||
@@ -249,11 +249,12 @@ impl Config {
|
||||
self.gateway.validator_api_urls.clone()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
pub fn get_validator_nymd_endpoints(&self) -> Vec<Url> {
|
||||
self.gateway.validator_nymd_urls.clone()
|
||||
}
|
||||
|
||||
pub fn get_cosmos_mnemonic(&self) -> bip39::Mnemonic {
|
||||
pub fn _get_cosmos_mnemonic(&self) -> String {
|
||||
self.gateway.cosmos_mnemonic.clone()
|
||||
}
|
||||
|
||||
@@ -366,10 +367,11 @@ pub struct Gateway {
|
||||
validator_api_urls: Vec<Url>,
|
||||
|
||||
/// Addresses to validators which the node uses to check for double spending of ERC20 tokens.
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
validator_nymd_urls: Vec<Url>,
|
||||
|
||||
/// Mnemonic of a cosmos wallet used in checking for double spending.
|
||||
cosmos_mnemonic: bip39::Mnemonic,
|
||||
cosmos_mnemonic: String,
|
||||
|
||||
/// nym_home_directory specifies absolute path to the home nym gateways directory.
|
||||
/// It is expected to use default value and hence .toml file should not redefine this field.
|
||||
@@ -424,8 +426,9 @@ impl Default for Gateway {
|
||||
enabled_statistics: false,
|
||||
statistics_service_url: default_statistics_service_url(),
|
||||
validator_api_urls: default_api_endpoints(),
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
validator_nymd_urls: default_nymd_endpoints(),
|
||||
cosmos_mnemonic: bip39::Mnemonic::from_str("exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day").unwrap(),
|
||||
cosmos_mnemonic: "exact antique hybrid width raise anchor puzzle degree fee quit long crack net vague hip despair write put useless civil mechanic broom music day".to_string(),
|
||||
nym_root_directory: Config::default_root_directory(),
|
||||
persistent_storage: Default::default(),
|
||||
wallet_address: "nymXXXXXXXX".to_string(),
|
||||
|
||||
@@ -223,9 +223,7 @@ where
|
||||
));
|
||||
}
|
||||
|
||||
let req = validator_api_requests::coconut::ProposeReleaseFundsRequestBody::new(
|
||||
credential.clone(),
|
||||
);
|
||||
let req = coconut_interface::ProposeReleaseFundsRequestBody::new(credential.clone());
|
||||
let proposal_id = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
@@ -239,10 +237,7 @@ where
|
||||
.await?
|
||||
.proposal_id;
|
||||
|
||||
let req = validator_api_requests::coconut::VerifyCredentialBody::new(
|
||||
credential.clone(),
|
||||
proposal_id,
|
||||
);
|
||||
let req = coconut_interface::VerifyCredentialBody::new(credential.clone(), proposal_id);
|
||||
for client in self.inner.coconut_verifier.api_clients().iter().skip(1) {
|
||||
if !client
|
||||
.verify_bandwidth_credential(&req)
|
||||
@@ -253,7 +248,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
let req = validator_api_requests::coconut::ExecuteReleaseFundsRequestBody::new(proposal_id);
|
||||
let req = coconut_interface::ExecuteReleaseFundsRequestBody::new(proposal_id);
|
||||
self.inner
|
||||
.coconut_verifier
|
||||
.api_clients()
|
||||
|
||||
@@ -2,26 +2,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use coconut_interface::VerificationKey;
|
||||
use validator_client::{
|
||||
nymd::{NymdClient, SigningNymdClient},
|
||||
ApiClient,
|
||||
};
|
||||
use validator_client::ApiClient;
|
||||
|
||||
pub struct CoconutVerifier {
|
||||
api_clients: Vec<ApiClient>,
|
||||
_nymd_client: NymdClient<SigningNymdClient>,
|
||||
aggregated_verification_key: VerificationKey,
|
||||
}
|
||||
|
||||
impl CoconutVerifier {
|
||||
pub fn new(
|
||||
api_clients: Vec<ApiClient>,
|
||||
_nymd_client: NymdClient<SigningNymdClient>,
|
||||
aggregated_verification_key: VerificationKey,
|
||||
) -> Self {
|
||||
pub fn new(api_clients: Vec<ApiClient>, aggregated_verification_key: VerificationKey) -> Self {
|
||||
CoconutVerifier {
|
||||
api_clients,
|
||||
_nymd_client,
|
||||
aggregated_verification_key,
|
||||
}
|
||||
}
|
||||
@@ -30,10 +21,6 @@ impl CoconutVerifier {
|
||||
&self.api_clients
|
||||
}
|
||||
|
||||
pub fn _nymd_client(&self) -> &NymdClient<SigningNymdClient> {
|
||||
&self._nymd_client
|
||||
}
|
||||
|
||||
pub fn aggregated_verification_key(&self) -> &VerificationKey {
|
||||
&self.aggregated_verification_key
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::str::FromStr;
|
||||
use bip39::core::str::FromStr;
|
||||
use bip39::Mnemonic;
|
||||
use config::defaults::DEFAULT_NETWORK;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use url::Url;
|
||||
use web3::contract::tokens::Detokenize;
|
||||
use web3::contract::{Contract, Error};
|
||||
use web3::ethabi::Token;
|
||||
@@ -26,9 +31,17 @@ pub(crate) struct ERC20Bridge {
|
||||
}
|
||||
|
||||
impl ERC20Bridge {
|
||||
pub fn new(eth_endpoint: String, nymd_client: NymdClient<SigningNymdClient>) -> Self {
|
||||
pub fn new(eth_endpoint: String, nymd_urls: Vec<Url>, cosmos_mnemonic: String) -> Self {
|
||||
let transport = Http::new(ð_endpoint).expect("Invalid Ethereum endpoint");
|
||||
let web3 = Web3::new(transport);
|
||||
let nymd_url = nymd_urls
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validators is empty");
|
||||
let mnemonic =
|
||||
Mnemonic::from_str(&cosmos_mnemonic).expect("Invalid Cosmos mnemonic provided");
|
||||
let nymd_client =
|
||||
NymdClient::connect_with_mnemonic(DEFAULT_NETWORK, nymd_url.as_ref(), mnemonic, None)
|
||||
.expect("Could not create nymd client");
|
||||
|
||||
ERC20Bridge {
|
||||
contract: eth_contract(web3.clone()),
|
||||
|
||||
+7
-26
@@ -9,7 +9,6 @@ use crate::node::client_handling::websocket;
|
||||
use crate::node::mixnet_handling::receiver::connection_handler::ConnectionHandler;
|
||||
use crate::node::statistics::collector::GatewayStatisticsCollector;
|
||||
use crate::node::storage::Storage;
|
||||
use config::defaults::DEFAULT_NETWORK;
|
||||
use crypto::asymmetric::{encryption, identity};
|
||||
use log::*;
|
||||
use mixnet_client::forwarder::{MixForwardingSender, PacketForwarder};
|
||||
@@ -240,23 +239,6 @@ where
|
||||
validator_client::ApiClient::new(validator_api.clone())
|
||||
}
|
||||
|
||||
fn random_nymd_client(
|
||||
&self,
|
||||
) -> validator_client::nymd::NymdClient<validator_client::nymd::SigningNymdClient> {
|
||||
let endpoints = self.config.get_validator_nymd_endpoints();
|
||||
let validator_nymd = endpoints
|
||||
.choose(&mut thread_rng())
|
||||
.expect("The list of validators is empty");
|
||||
|
||||
validator_client::nymd::NymdClient::connect_with_mnemonic(
|
||||
DEFAULT_NETWORK,
|
||||
validator_nymd.as_ref(),
|
||||
self.config.get_cosmos_mnemonic(),
|
||||
None,
|
||||
)
|
||||
.expect("Could not connect with mnemonic")
|
||||
}
|
||||
|
||||
#[cfg(feature = "coconut")]
|
||||
fn all_api_clients(&self) -> Vec<validator_client::ApiClient> {
|
||||
self.config
|
||||
@@ -306,17 +288,16 @@ where
|
||||
obtain_aggregate_verification_key(&self.config.get_validator_api_endpoints())
|
||||
.await
|
||||
.expect("failed to contact validators to obtain their verification keys");
|
||||
|
||||
let nymd_client = self.random_nymd_client();
|
||||
#[cfg(feature = "coconut")]
|
||||
let coconut_verifier = CoconutVerifier::new(
|
||||
self.all_api_clients(),
|
||||
nymd_client,
|
||||
validators_verification_key,
|
||||
);
|
||||
let coconut_verifier =
|
||||
CoconutVerifier::new(self.all_api_clients(), validators_verification_key);
|
||||
|
||||
#[cfg(not(feature = "coconut"))]
|
||||
let erc20_bridge = ERC20Bridge::new(self.config.get_eth_endpoint(), nymd_client);
|
||||
let erc20_bridge = ERC20Bridge::new(
|
||||
self.config.get_eth_endpoint(),
|
||||
self.config.get_validator_nymd_endpoints(),
|
||||
self.config._get_cosmos_mnemonic(),
|
||||
);
|
||||
|
||||
let mix_forwarding_channel = self.start_packet_forwarder();
|
||||
|
||||
|
||||
Generated
+1
-7
@@ -897,7 +897,6 @@ dependencies = [
|
||||
"network-defaults",
|
||||
"thiserror",
|
||||
"url",
|
||||
"validator-api-requests",
|
||||
"validator-client",
|
||||
]
|
||||
|
||||
@@ -3405,7 +3404,6 @@ dependencies = [
|
||||
"tendermint-rpc",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"topology",
|
||||
"ts-rs",
|
||||
"url",
|
||||
]
|
||||
@@ -6299,10 +6297,6 @@ dependencies = [
|
||||
name = "validator-api-requests"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bs58",
|
||||
"coconut-interface",
|
||||
"cosmrs",
|
||||
"getset",
|
||||
"mixnet-contract-common",
|
||||
"schemars",
|
||||
"serde",
|
||||
@@ -6406,7 +6400,7 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "vesting-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
|
||||
@@ -38,9 +38,8 @@ pretty_env_logger = "0.4.0"
|
||||
fix-path-env = { git = "https://github.com/tauri-apps/fix-path-env-rs", branch = "release"}
|
||||
|
||||
client-core = { path = "../../clients/client-core" }
|
||||
config = { path = "../../common/config" }
|
||||
nym-socks5-client = { path = "../../clients/socks5" }
|
||||
topology = { path = "../../common/topology" }
|
||||
config = { path = "../../common/config" }
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 37 KiB |
@@ -1,11 +1,11 @@
|
||||
use client_core::config::GatewayEndpoint;
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
|
||||
use client_core::config::Config as BaseConfig;
|
||||
use client_core::client::key_manager::KeyManager;
|
||||
use client_core::config::persistence::key_pathfinder::ClientKeyPathfinder;
|
||||
use config::NymConfig;
|
||||
use nym_socks5::client::config::Config as Socks5Config;
|
||||
|
||||
// Generate a random id used for the config, since we need to init a new configuration each time
|
||||
// due to not being able to reuse gateway registration. This is probably something we should
|
||||
@@ -16,46 +16,18 @@ pub static SOCKS5_CONFIG_ID: Lazy<String> = Lazy::new(|| {
|
||||
});
|
||||
|
||||
// TODO: make this configurable from the UI
|
||||
// TODO: once we can set this is the UI, consider just removing it, and put in guards to halt if
|
||||
// user hasn't chosen the provider
|
||||
pub static PROVIDER_ADDRESS: &str = "EWa8DgePKfuWSjqPo6NEdavBK6gpnK4TKb2npi2HWuC2.6PGVT9y83UMGbFrPKDnCvTP2jJjpXYpD87ZpiRsLo1YR@CgQrYP8etksSBf4nALNqp93SHPpgFwEUyTsjBNNLj5WM";
|
||||
|
||||
const DEFAULT_ETH_ENDPOINT: &str = "https://rinkeby.infura.io/v3/00000000000000000000000000000000";
|
||||
const DEFAULT_ETH_PRIVATE_KEY: &str =
|
||||
"0000000000000000000000000000000000000000000000000000000000000001";
|
||||
|
||||
pub struct Config {
|
||||
socks5: Socks5Config,
|
||||
}
|
||||
pub struct Config {}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: Into<String>>(id: S, provider_mix_address: S) -> Self {
|
||||
Config {
|
||||
socks5: Socks5Config::new(id, provider_mix_address),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_socks5(&self) -> &Socks5Config {
|
||||
&self.socks5
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn get_socks5_mut(&mut self) -> &mut Socks5Config {
|
||||
&mut self.socks5
|
||||
}
|
||||
|
||||
pub fn get_base(&self) -> &BaseConfig<Socks5Config> {
|
||||
self.socks5.get_base()
|
||||
}
|
||||
|
||||
pub fn get_base_mut(&mut self) -> &mut BaseConfig<Socks5Config> {
|
||||
self.socks5.get_base_mut()
|
||||
}
|
||||
|
||||
pub async fn init(service_provider: Option<&String>) {
|
||||
let service_provider = service_provider.map_or(PROVIDER_ADDRESS, String::as_str);
|
||||
pub async fn init() {
|
||||
info!("Initialising...");
|
||||
init_socks5(service_provider, None).await;
|
||||
init_socks5(PROVIDER_ADDRESS, None).await;
|
||||
info!("Configuration saved 🚀");
|
||||
}
|
||||
}
|
||||
@@ -63,10 +35,40 @@ impl Config {
|
||||
pub async fn init_socks5(provider_address: &str, chosen_gateway_id: Option<&str>) {
|
||||
let id: &str = &SOCKS5_CONFIG_ID;
|
||||
log::trace!("Creating config for id: {}", id);
|
||||
let mut config = Config::new(id, provider_address);
|
||||
let mut config = nym_socks5::client::config::Config::new(id, provider_address);
|
||||
|
||||
let gateway = setup_gateway(chosen_gateway_id, config.get_socks5()).await;
|
||||
config.get_base_mut().with_gateway_endpoint(gateway);
|
||||
// create identity, encryption and ack keys.
|
||||
let mut rng = OsRng;
|
||||
let mut key_manager = KeyManager::new(&mut rng);
|
||||
|
||||
info!("Getting gateway details");
|
||||
let gateway_details = nym_socks5::commands::init::gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
|
||||
info!("Registering with gateway");
|
||||
let shared_keys = nym_socks5::commands::init::register_with_gateway(
|
||||
&gateway_details,
|
||||
key_manager.identity_keypair(),
|
||||
)
|
||||
.await;
|
||||
|
||||
info!("Setting gateway endpoint");
|
||||
config
|
||||
.get_base_mut()
|
||||
.with_gateway_endpoint(gateway_details.into());
|
||||
|
||||
info!("Insert gateway shared key");
|
||||
key_manager.insert_gateway_shared_key(shared_keys);
|
||||
|
||||
info!("Creating client key path finder");
|
||||
let pathfinder = ClientKeyPathfinder::new_from_config(config.get_base());
|
||||
key_manager
|
||||
.store_keys(&pathfinder)
|
||||
.expect("Failed to generated keys");
|
||||
info!("Saved all generated keys");
|
||||
|
||||
// As far as I'm aware, these two are not used, they are only set because the socks5 init code
|
||||
// requires them for initialising the bandwidth controller.
|
||||
@@ -77,40 +79,13 @@ pub async fn init_socks5(provider_address: &str, chosen_gateway_id: Option<&str>
|
||||
.get_base_mut()
|
||||
.with_eth_private_key(DEFAULT_ETH_PRIVATE_KEY);
|
||||
|
||||
let config_save_location = config.get_socks5().get_config_file_save_location();
|
||||
let config_save_location = config.get_config_file_save_location();
|
||||
config
|
||||
.get_socks5()
|
||||
.save_to_file(None)
|
||||
.expect("Failed to save the config file");
|
||||
info!("Saved configuration file to {:?}", config_save_location);
|
||||
info!(
|
||||
"Using gateway: {}",
|
||||
config.get_socks5().get_base().get_gateway_id(),
|
||||
);
|
||||
info!("Client configuration completed.");
|
||||
info!("Using gateway: {}", config.get_base().get_gateway_id(),);
|
||||
info!("Client configuration completed.\n\n\n");
|
||||
|
||||
client_core::init::show_address(config.get_base());
|
||||
}
|
||||
|
||||
async fn setup_gateway(
|
||||
user_chosen_gateway_id: Option<&str>,
|
||||
config: &nym_socks5::client::config::Config,
|
||||
) -> GatewayEndpoint {
|
||||
// Get the gateway details by querying the validator-api. Either pick one at random or use
|
||||
// the chosen one if it's among the available ones.
|
||||
log::info!("Configuring gateway");
|
||||
let gateway = client_core::init::query_gateway_details(
|
||||
config.get_base().get_validator_api_endpoints(),
|
||||
user_chosen_gateway_id,
|
||||
)
|
||||
.await;
|
||||
log::debug!("Querying gateway gives: {}", gateway);
|
||||
|
||||
// Registering with gateway by setting up and writing shared keys to disk
|
||||
log::trace!("Registering gateway");
|
||||
client_core::init::register_with_gateway_and_store_keys(gateway.clone(), config.get_base())
|
||||
.await;
|
||||
log::info!("Saved all generated keys");
|
||||
|
||||
gateway.into()
|
||||
nym_socks5::commands::init::show_address(&config);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ pub enum BackendError {
|
||||
CouldNotConnect,
|
||||
#[error("Could not disconnect")]
|
||||
CouldNotDisconnect,
|
||||
#[error("No serverice provider set")]
|
||||
NoServiceProviderSet,
|
||||
}
|
||||
|
||||
impl Serialize for BackendError {
|
||||
|
||||
@@ -34,8 +34,6 @@ fn main() {
|
||||
tauri::Builder::default()
|
||||
.manage(Arc::new(RwLock::new(State::new())))
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
crate::operations::connection::connect::get_service_provider,
|
||||
crate::operations::connection::connect::set_service_provider,
|
||||
crate::operations::connection::connect::start_connecting,
|
||||
crate::operations::connection::disconnect::start_disconnecting,
|
||||
crate::operations::window::hide_window,
|
||||
|
||||
@@ -18,24 +18,3 @@ pub async fn start_connecting(
|
||||
address: "Test".to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_service_provider(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<String, BackendError> {
|
||||
let guard = state.read().await;
|
||||
guard
|
||||
.get_service_provider()
|
||||
.clone()
|
||||
.ok_or(BackendError::NoServiceProviderSet)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn set_service_provider(
|
||||
service_provider: String,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<(), BackendError> {
|
||||
let mut guard = state.write().await;
|
||||
guard.set_service_provider(service_provider);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ use tauri::Manager;
|
||||
|
||||
pub struct State {
|
||||
status: ConnectionStatusKind,
|
||||
service_provider: Option<String>,
|
||||
socks5_client_sender: Option<Socks5ControlMessageSender>,
|
||||
}
|
||||
|
||||
@@ -24,7 +23,6 @@ impl State {
|
||||
pub fn new() -> Self {
|
||||
State {
|
||||
status: ConnectionStatusKind::Disconnected,
|
||||
service_provider: None,
|
||||
socks5_client_sender: None,
|
||||
}
|
||||
}
|
||||
@@ -44,16 +42,8 @@ impl State {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn get_service_provider(&self) -> &Option<String> {
|
||||
&self.service_provider
|
||||
}
|
||||
|
||||
pub fn set_service_provider(&mut self, provider: String) {
|
||||
self.service_provider = Some(provider);
|
||||
}
|
||||
|
||||
pub async fn init_config(&self) {
|
||||
crate::config::Config::init(self.service_provider.as_ref()).await;
|
||||
pub async fn init_config() {
|
||||
crate::config::Config::init().await;
|
||||
}
|
||||
|
||||
pub async fn start_connecting(&mut self, window: &tauri::Window<tauri::Wry>) {
|
||||
@@ -62,7 +52,7 @@ impl State {
|
||||
self.status = ConnectionStatusKind::Connecting;
|
||||
|
||||
// Setup configuration by writing to file
|
||||
self.init_config().await;
|
||||
Self::init_config().await;
|
||||
|
||||
// Kick of the main task and get the channel for controlling it
|
||||
let sender = start_nym_socks5_client();
|
||||
|
||||
@@ -42,9 +42,9 @@
|
||||
"entitlements": null
|
||||
},
|
||||
"windows": {
|
||||
"certificateThumbprint": "6DB77B1F529A0804FE0E6843A3EB8A8CECFFD408",
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": "http://timestamp.comodoca.com"
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"updater": {
|
||||
|
||||
Generated
+1
-1
@@ -5581,7 +5581,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "vesting-contract"
|
||||
version = "1.0.1"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"config",
|
||||
"cosmwasm-std",
|
||||
|
||||
@@ -28,21 +28,12 @@ impl Network {
|
||||
self.to_string().to_lowercase()
|
||||
}
|
||||
|
||||
// this should be returning just a `&str`, but don't want to cause too many conflicts just yet...
|
||||
pub fn base_mix_denom(&self) -> Denom {
|
||||
pub fn denom(&self) -> Denom {
|
||||
match self {
|
||||
// network defaults should be correctly formatted
|
||||
Network::QA => Denom::from_str(qa::MIX_DENOM.base).unwrap(),
|
||||
Network::SANDBOX => Denom::from_str(sandbox::MIX_DENOM.base).unwrap(),
|
||||
Network::MAINNET => Denom::from_str(mainnet::MIX_DENOM.base).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn display_mix_denom(&self) -> &str {
|
||||
match self {
|
||||
Network::QA => qa::MIX_DENOM.display,
|
||||
Network::SANDBOX => sandbox::MIX_DENOM.display,
|
||||
Network::MAINNET => mainnet::MIX_DENOM.display,
|
||||
Network::QA => Denom::from_str(qa::DENOM).unwrap(),
|
||||
Network::SANDBOX => Denom::from_str(sandbox::DENOM).unwrap(),
|
||||
Network::MAINNET => Denom::from_str(mainnet::DENOM).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ pub async fn connect_with_mnemonic(
|
||||
pub async fn get_balance(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Balance, BackendError> {
|
||||
let denom = state.read().await.current_network().base_mix_denom();
|
||||
let denom = state.read().await.current_network().denom();
|
||||
match nymd_client!(state)
|
||||
.get_balance(nymd_client!(state).address(), denom)
|
||||
.await
|
||||
@@ -74,7 +74,7 @@ pub async fn switch_network(
|
||||
let account = {
|
||||
let r_state = state.read().await;
|
||||
let client = r_state.client(network)?;
|
||||
let denom = network.base_mix_denom();
|
||||
let denom = network.denom();
|
||||
|
||||
Account::new(
|
||||
client.nymd.mixnet_contract_address().to_string(),
|
||||
@@ -162,7 +162,7 @@ async fn _connect_with_mnemonic(
|
||||
Some(client) => Ok(Account::new(
|
||||
client.nymd.mixnet_contract_address().to_string(),
|
||||
client.nymd.address().to_string(),
|
||||
default_network.base_mix_denom().try_into()?,
|
||||
default_network.denom().try_into()?,
|
||||
)),
|
||||
None => Err(BackendError::NetworkNotSupported(
|
||||
config::defaults::DEFAULT_NETWORK,
|
||||
|
||||
@@ -18,7 +18,7 @@ pub async fn bond_gateway(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let pledge_minor = pledge.clone().into();
|
||||
log::info!(
|
||||
">>> Bond gateway: identity_key = {}, pledge = {}, pledge_minor = {}, fee = {:?}",
|
||||
@@ -43,7 +43,7 @@ pub async fn unbond_gateway(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(">>> Unbond gateway, fee = {:?}", fee);
|
||||
let res = nymd_client!(state).unbond_gateway(fee).await?;
|
||||
log::info!("<<< tx hash = {}", res.transaction_hash);
|
||||
@@ -62,7 +62,7 @@ pub async fn bond_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let pledge_minor = pledge.clone().into();
|
||||
log::info!(
|
||||
">>> Bond mixnode: identity_key = {}, pledge = {}, pledge_minor = {}, fee = {:?}",
|
||||
@@ -87,7 +87,7 @@ pub async fn unbond_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(">>> Unbond mixnode, fee = {:?}", fee);
|
||||
let res = nymd_client!(state).unbond_mixnode(fee).await?;
|
||||
log::info!("<<< tx hash = {}", res.transaction_hash);
|
||||
@@ -104,7 +104,7 @@ pub async fn update_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Update mixnode: profit_margin_percent = {}, fee {:?}",
|
||||
profit_margin_percent,
|
||||
@@ -161,7 +161,7 @@ pub async fn get_operator_rewards(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<MajorCurrencyAmount, BackendError> {
|
||||
log::info!(">>> Get operator rewards for {}", address);
|
||||
let denom = state.read().await.current_network().base_mix_denom();
|
||||
let denom = state.read().await.current_network().denom();
|
||||
let rewards_as_minor = nymd_client!(state).get_operator_rewards(address).await?;
|
||||
let coin = CosmWasmCoin::new(rewards_as_minor.u128(), denom.as_ref());
|
||||
let amount: MajorCurrencyAmount = coin.into();
|
||||
|
||||
@@ -41,7 +41,7 @@ pub async fn delegate_to_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let delegation = amount.clone().into();
|
||||
log::info!(
|
||||
">>> Delegate to mixnode: identity_key = {}, amount = {}, minor_amount = {}, fee = {:?}",
|
||||
@@ -67,7 +67,7 @@ pub async fn undelegate_from_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Undelegate from mixnode: identity_key = {}, fee = {:?}",
|
||||
identity,
|
||||
@@ -126,7 +126,7 @@ pub async fn get_all_mix_delegations(
|
||||
|
||||
let address = nymd_client!(state).address().to_string();
|
||||
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let denom: CurrencyDenom = denom_minor.clone().try_into()?;
|
||||
|
||||
log::info!(" >>> Get delegations");
|
||||
@@ -340,7 +340,7 @@ pub async fn get_delegator_rewards(
|
||||
proxy: Option<String>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<MajorCurrencyAmount, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Get delegator rewards: mix_identity = {}, proxy = {:?}",
|
||||
mix_identity,
|
||||
@@ -361,7 +361,7 @@ pub async fn get_delegation_summary(
|
||||
) -> Result<DelegationsSummaryResponse, BackendError> {
|
||||
log::info!(">>> Get delegation summary");
|
||||
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let denom: CurrencyDenom = denom_minor.clone().try_into()?;
|
||||
|
||||
let delegations = get_all_mix_delegations(state.clone()).await?;
|
||||
|
||||
@@ -15,7 +15,7 @@ pub async fn claim_operator_reward(
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
// TODO: handle operator bonding with vesting contract
|
||||
log::info!(">>> Claim operator reward");
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_claim_operator_reward(fee)
|
||||
.await?;
|
||||
@@ -34,7 +34,7 @@ pub async fn compound_operator_reward(
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
// TODO: handle operator bonding with vesting contract
|
||||
log::info!(">>> Compound operator reward");
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_compound_operator_reward(fee)
|
||||
.await?;
|
||||
@@ -56,7 +56,7 @@ pub async fn claim_delegator_reward(
|
||||
">>> Claim delegator reward: identity_key = {}",
|
||||
mix_identity
|
||||
);
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_claim_delegator_reward(mix_identity, fee)
|
||||
.await?;
|
||||
@@ -78,7 +78,7 @@ pub async fn compound_delegator_reward(
|
||||
">>> Compound delegator reward: identity_key = {}",
|
||||
mix_identity
|
||||
);
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_compound_delegator_reward(mix_identity, fee)
|
||||
.await?;
|
||||
|
||||
@@ -16,7 +16,7 @@ pub async fn send(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<SendTxResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let address = AccountId::from_str(address)?;
|
||||
let from_address = nymd_client!(state).address().to_string();
|
||||
let amount2 = amount.clone().into();
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BackendError;
|
||||
use crate::operations::simulate::FeeDetails;
|
||||
use crate::simulate::detailed_fee;
|
||||
use crate::operations::simulate::{FeeDetails, SimulateResult};
|
||||
use crate::State;
|
||||
use mixnet_contract_common::{ContractStateParams, ExecuteMsg};
|
||||
use nym_wallet_types::admin::TauriContractStateParams;
|
||||
@@ -20,6 +19,7 @@ pub async fn simulate_update_contract_settings(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -28,5 +28,5 @@ pub async fn simulate_update_contract_settings(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BackendError;
|
||||
use crate::operations::simulate::FeeDetails;
|
||||
use crate::simulate::detailed_fee;
|
||||
use crate::operations::simulate::{FeeDetails, SimulateResult};
|
||||
use crate::state::State;
|
||||
use nym_types::currency::MajorCurrencyAmount;
|
||||
use std::str::FromStr;
|
||||
@@ -24,6 +23,7 @@ pub async fn simulate_send(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let from_address = client.nymd.address().clone();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
// TODO: I'm still not 100% convinced whether this should be exposed here or handled somewhere else in the client code
|
||||
let msg = MsgSend {
|
||||
@@ -33,5 +33,5 @@ pub async fn simulate_send(
|
||||
};
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BackendError;
|
||||
use crate::operations::simulate::FeeDetails;
|
||||
use crate::simulate::detailed_fee;
|
||||
use crate::nymd_client;
|
||||
use crate::operations::simulate::{FeeDetails, SimulateResult};
|
||||
use crate::State;
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
use mixnet_contract_common::{ExecuteMsg, Gateway, MixNode};
|
||||
@@ -23,6 +23,7 @@ pub async fn simulate_bond_gateway(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
// TODO: I'm still not 100% convinced whether this should be exposed here or handled somewhere else in the client code
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
@@ -35,7 +36,7 @@ pub async fn simulate_bond_gateway(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -43,8 +44,10 @@ pub async fn simulate_unbond_gateway(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -53,7 +56,7 @@ pub async fn simulate_unbond_gateway(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -68,6 +71,7 @@ pub async fn simulate_bond_mixnode(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -79,7 +83,7 @@ pub async fn simulate_bond_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -87,8 +91,10 @@ pub async fn simulate_unbond_mixnode(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -97,7 +103,7 @@ pub async fn simulate_unbond_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -106,8 +112,10 @@ pub async fn simulate_update_mixnode(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -118,7 +126,7 @@ pub async fn simulate_update_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -132,6 +140,7 @@ pub async fn simulate_delegate_to_mixnode(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -142,7 +151,7 @@ pub async fn simulate_delegate_to_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -151,8 +160,10 @@ pub async fn simulate_undelegate_from_mixnode(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let mixnet_contract = client.nymd.mixnet_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
mixnet_contract,
|
||||
@@ -163,27 +174,29 @@ pub async fn simulate_undelegate_from_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn simulate_claim_operator_reward(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client.nymd.simulate_claim_operator_reward(None).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let result = nymd_client!(state)
|
||||
.simulate_claim_operator_reward(None)
|
||||
.await?;
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn simulate_compound_operator_reward(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client.nymd.simulate_compound_operator_reward(None).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let result = nymd_client!(state)
|
||||
.simulate_compound_operator_reward(None)
|
||||
.await?;
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -191,13 +204,11 @@ pub async fn simulate_claim_delegator_reward(
|
||||
mix_identity: IdentityKey,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client
|
||||
.nymd
|
||||
let result = nymd_client!(state)
|
||||
.simulate_claim_delegator_reward(mix_identity, None)
|
||||
.await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -205,11 +216,9 @@ pub async fn simulate_compound_delegator_reward(
|
||||
mix_identity: IdentityKey,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client
|
||||
.nymd
|
||||
let result = nymd_client!(state)
|
||||
.simulate_compound_delegator_reward(mix_identity, None)
|
||||
.await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
@@ -1,31 +1,16 @@
|
||||
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cosmrs::tx;
|
||||
use cosmrs::tx::Gas;
|
||||
use nym_types::currency::MajorCurrencyAmount;
|
||||
use nym_types::fees::FeeDetails;
|
||||
use validator_client::nymd::cosmwasm_client::types::{GasInfo, SimulateResponse};
|
||||
use validator_client::nymd::{
|
||||
CosmosCoin, Fee, GasAdjustable, GasAdjustment, GasPrice, SigningNymdClient,
|
||||
};
|
||||
use validator_client::Client;
|
||||
use validator_client::nymd::cosmwasm_client::types::GasInfo;
|
||||
use validator_client::nymd::{tx, CosmosCoin, Fee, GasPrice};
|
||||
|
||||
pub mod admin;
|
||||
pub mod cosmos;
|
||||
pub mod mixnet;
|
||||
pub mod vesting;
|
||||
|
||||
pub(crate) fn detailed_fee(
|
||||
client: &Client<SigningNymdClient>,
|
||||
simulate_response: SimulateResponse,
|
||||
) -> FeeDetails {
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
let gas_adjustment = client.nymd.gas_adjustment();
|
||||
|
||||
SimulateResult::new(simulate_response.gas_info, gas_price, gas_adjustment).detailed_fee()
|
||||
}
|
||||
|
||||
// technically we could have also exposed a result: Option<AbciResult> field from the SimulateResponse,
|
||||
// but in the context of the wallet it's really irrelevant and useless for the time being
|
||||
pub(crate) struct SimulateResult {
|
||||
@@ -34,19 +19,13 @@ pub(crate) struct SimulateResult {
|
||||
// for example if you attempt to send a 'BondMixnode' with invalid signature
|
||||
pub gas_info: Option<GasInfo>,
|
||||
pub gas_price: GasPrice,
|
||||
pub gas_adjustment: GasAdjustment,
|
||||
}
|
||||
|
||||
impl SimulateResult {
|
||||
pub fn new(
|
||||
gas_info: Option<GasInfo>,
|
||||
gas_price: GasPrice,
|
||||
gas_adjustment: GasAdjustment,
|
||||
) -> Self {
|
||||
pub fn new(gas_info: Option<GasInfo>, gas_price: GasPrice) -> Self {
|
||||
SimulateResult {
|
||||
gas_info,
|
||||
gas_price,
|
||||
gas_adjustment,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,20 +37,18 @@ impl SimulateResult {
|
||||
}
|
||||
}
|
||||
|
||||
fn adjusted_gas(&self) -> Option<Gas> {
|
||||
self.gas_info
|
||||
.map(|gas_info| gas_info.gas_used.adjust_gas(self.gas_adjustment))
|
||||
}
|
||||
|
||||
fn to_fee_amount(&self) -> Option<CosmosCoin> {
|
||||
self.adjusted_gas().map(|gas| &self.gas_price * gas)
|
||||
self.gas_info
|
||||
.map(|gas_info| &self.gas_price * gas_info.gas_used)
|
||||
}
|
||||
|
||||
fn to_fee(&self) -> Fee {
|
||||
self.adjusted_gas()
|
||||
.map(|gas| {
|
||||
let fee_amount = &self.gas_price * gas;
|
||||
tx::Fee::from_amount_and_gas(fee_amount, gas).into()
|
||||
self.to_fee_amount()
|
||||
.and_then(|fee_amount| {
|
||||
self.gas_info.map(|gas_info| {
|
||||
let gas_limit = gas_info.gas_used;
|
||||
tx::Fee::from_amount_and_gas(fee_amount, gas_limit).into()
|
||||
})
|
||||
})
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::error::BackendError;
|
||||
use crate::operations::simulate::FeeDetails;
|
||||
use crate::simulate::detailed_fee;
|
||||
use crate::nymd_client;
|
||||
use crate::operations::simulate::{FeeDetails, SimulateResult};
|
||||
use crate::State;
|
||||
use mixnet_contract_common::IdentityKey;
|
||||
use mixnet_contract_common::{Gateway, MixNode};
|
||||
@@ -24,6 +24,7 @@ pub async fn simulate_vesting_bond_gateway(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let vesting_contract = client.nymd.vesting_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
vesting_contract,
|
||||
@@ -36,7 +37,7 @@ pub async fn simulate_vesting_bond_gateway(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -47,6 +48,7 @@ pub async fn simulate_vesting_unbond_gateway(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let vesting_contract = client.nymd.vesting_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
vesting_contract,
|
||||
@@ -55,7 +57,7 @@ pub async fn simulate_vesting_unbond_gateway(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -70,6 +72,7 @@ pub async fn simulate_vesting_bond_mixnode(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let vesting_contract = client.nymd.vesting_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
vesting_contract,
|
||||
@@ -82,7 +85,7 @@ pub async fn simulate_vesting_bond_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -93,6 +96,7 @@ pub async fn simulate_vesting_unbond_mixnode(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let vesting_contract = client.nymd.vesting_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
vesting_contract,
|
||||
@@ -101,7 +105,7 @@ pub async fn simulate_vesting_unbond_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -113,6 +117,7 @@ pub async fn simulate_vesting_update_mixnode(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let vesting_contract = client.nymd.vesting_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
vesting_contract,
|
||||
@@ -123,7 +128,7 @@ pub async fn simulate_vesting_update_mixnode(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -136,6 +141,7 @@ pub async fn simulate_withdraw_vested_coins(
|
||||
|
||||
let client = guard.current_client()?;
|
||||
let vesting_contract = client.nymd.vesting_contract_address();
|
||||
let gas_price = client.nymd.gas_price().clone();
|
||||
|
||||
let msg = client.nymd.wrap_contract_execute_message(
|
||||
vesting_contract,
|
||||
@@ -144,33 +150,29 @@ pub async fn simulate_withdraw_vested_coins(
|
||||
)?;
|
||||
|
||||
let result = client.nymd.simulate(vec![msg]).await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn simulate_vesting_claim_operator_reward(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client
|
||||
.nymd
|
||||
let result = nymd_client!(state)
|
||||
.simulate_vesting_claim_operator_reward(None)
|
||||
.await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn simulate_vesting_compound_operator_reward(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client
|
||||
.nymd
|
||||
let result = nymd_client!(state)
|
||||
.simulate_vesting_compound_operator_reward(None)
|
||||
.await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -178,13 +180,11 @@ pub async fn simulate_vesting_claim_delegator_reward(
|
||||
mix_identity: IdentityKey,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client
|
||||
.nymd
|
||||
let result = nymd_client!(state)
|
||||
.simulate_vesting_claim_delegator_reward(mix_identity, None)
|
||||
.await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -192,11 +192,9 @@ pub async fn simulate_vesting_compound_delegator_reward(
|
||||
mix_identity: IdentityKey,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<FeeDetails, BackendError> {
|
||||
let guard = state.read().await;
|
||||
let client = guard.current_client()?;
|
||||
let result = client
|
||||
.nymd
|
||||
let result = nymd_client!(state)
|
||||
.simulate_vesting_compound_delegator_reward(mix_identity, None)
|
||||
.await?;
|
||||
Ok(detailed_fee(client, result))
|
||||
let gas_price = nymd_client!(state).gas_price().clone();
|
||||
Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee())
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ pub async fn vesting_bond_gateway(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let pledge_minor = pledge.clone().into();
|
||||
log::info!(
|
||||
">>> Bond gateway with locked tokens: identity_key = {}, pledge = {}, pledge_minor = {}, fee = {:?}",
|
||||
@@ -42,7 +42,7 @@ pub async fn vesting_unbond_gateway(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Unbond gateway bonded with locked tokens, fee = {:?}",
|
||||
fee
|
||||
@@ -64,7 +64,7 @@ pub async fn vesting_bond_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let pledge_minor = pledge.clone().into();
|
||||
log::info!(
|
||||
">>> Bond mixnode with locked tokens: identity_key = {}, pledge = {}, pledge_minor = {}, fee = {:?}",
|
||||
@@ -89,7 +89,7 @@ pub async fn vesting_unbond_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Unbond mixnode bonded with locked tokens, fee = {:?}",
|
||||
fee
|
||||
@@ -109,7 +109,7 @@ pub async fn withdraw_vested_coins(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let amount_minor = amount.clone().into();
|
||||
log::info!(
|
||||
">>> Withdraw vested liquid coins: amount = {}, amount_minor = {}, fee = {:?}",
|
||||
@@ -134,7 +134,7 @@ pub async fn vesting_update_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Update mixnode bonded with locked tokens: profit_margin_percent = {}, fee = {:?}",
|
||||
profit_margin_percent,
|
||||
|
||||
@@ -44,7 +44,7 @@ pub async fn vesting_delegate_to_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let delegation = amount.clone().into();
|
||||
log::info!(
|
||||
">>> Delegate to mixnode with locked tokens: identity_key = {}, amount = {}, minor_amount = {}, fee = {:?}",
|
||||
@@ -70,7 +70,7 @@ pub async fn vesting_undelegate_from_mixnode(
|
||||
fee: Option<Fee>,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
log::info!(
|
||||
">>> Undelegate from mixnode delegated with locked tokens: identity_key = {}, fee = {:?}",
|
||||
identity,
|
||||
|
||||
@@ -12,7 +12,7 @@ pub async fn vesting_claim_operator_reward(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
log::info!(">>> Vesting account: claim operator reward");
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_vesting_claim_operator_reward(None)
|
||||
.await?;
|
||||
@@ -30,7 +30,7 @@ pub async fn vesting_compound_operator_reward(
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<TransactionExecuteResult, BackendError> {
|
||||
log::info!(">>> Vesting account: compound operator reward");
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_vesting_compound_operator_reward(fee)
|
||||
.await?;
|
||||
@@ -52,7 +52,7 @@ pub async fn vesting_claim_delegator_reward(
|
||||
">>> Vesting account: claim delegator reward: identity_key = {}",
|
||||
mix_identity
|
||||
);
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_vesting_claim_delegator_reward(mix_identity, fee)
|
||||
.await?;
|
||||
@@ -74,7 +74,7 @@ pub async fn vesting_compound_delegator_reward(
|
||||
">>> Vesting account: compound delegator reward: identity_key = {}",
|
||||
mix_identity
|
||||
);
|
||||
let denom_minor = state.read().await.current_network().base_mix_denom();
|
||||
let denom_minor = state.read().await.current_network().denom();
|
||||
let res = nymd_client!(state)
|
||||
.execute_vesting_compound_delegator_reward(mix_identity, fee)
|
||||
.await?;
|
||||
|
||||
@@ -4,7 +4,27 @@
|
||||
// Specify filenames and other platform specific constants to respect platform conventions, or at
|
||||
// least, something popular on each respective platform.
|
||||
|
||||
pub const CONFIG_DIR_NAME: &str = "nym-wallet";
|
||||
pub const CONFIG_FILENAME: &str = "config.toml";
|
||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
pub const CONFIG_DIR_NAME: &str = "nym-wallet";
|
||||
pub const CONFIG_FILENAME: &str = "config.toml";
|
||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
||||
} else if #[cfg(taret_os = "macos")] {
|
||||
pub const CONFIG_DIR_NAME: &str = "nym-wallet";
|
||||
pub const CONFIG_FILENAME: &str = "config.toml";
|
||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
||||
} else if #[cfg(taret_os = "windows")] {
|
||||
pub const CONFIG_DIR_NAME: &str = "NymWallet";
|
||||
pub const CONFIG_FILENAME: &str = "Config.toml";
|
||||
pub const STORAGE_DIR_NAME: &str = "NymWallet";
|
||||
pub const WALLET_INFO_FILENAME: &str = "saved_wallet.json";
|
||||
} else {
|
||||
// This case is likely to be a unix-y system
|
||||
pub const CONFIG_DIR_NAME: &str = "nym-wallet";
|
||||
pub const CONFIG_FILENAME: &str = "config.toml";
|
||||
pub const STORAGE_DIR_NAME: &str = "nym-wallet";
|
||||
pub const WALLET_INFO_FILENAME: &str = "saved-wallet.json";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1620,7 +1620,6 @@ mod tests {
|
||||
fn append_filename() {
|
||||
let wallet_file = PathBuf::from("/tmp/saved-wallet.json");
|
||||
let timestamp = OsString::from("42");
|
||||
#[cfg(target_family = "unix")]
|
||||
assert_eq!(
|
||||
append_timestamp_to_filename(wallet_file.clone(), timestamp.clone(), None)
|
||||
.unwrap()
|
||||
@@ -1629,17 +1628,6 @@ mod tests {
|
||||
.unwrap(),
|
||||
"/tmp/saved-wallet-42.json".to_string(),
|
||||
);
|
||||
#[cfg(not(target_family = "unix"))]
|
||||
assert_eq!(
|
||||
append_timestamp_to_filename(wallet_file.clone(), timestamp.clone(), None)
|
||||
.unwrap()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap(),
|
||||
r"/tmp\saved-wallet-42.json".to_string(),
|
||||
);
|
||||
|
||||
#[cfg(target_family = "unix")]
|
||||
assert_eq!(
|
||||
append_timestamp_to_filename(wallet_file, timestamp, Some(3))
|
||||
.unwrap()
|
||||
@@ -1648,14 +1636,5 @@ mod tests {
|
||||
.unwrap(),
|
||||
"/tmp/saved-wallet-42-3.json".to_string(),
|
||||
);
|
||||
#[cfg(not(target_family = "unix"))]
|
||||
assert_eq!(
|
||||
append_timestamp_to_filename(wallet_file, timestamp, Some(3))
|
||||
.unwrap()
|
||||
.into_os_string()
|
||||
.into_string()
|
||||
.unwrap(),
|
||||
r"/tmp\saved-wallet-42-3.json".to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export const ConnectPassword = () => {
|
||||
return (
|
||||
<Stack spacing={3} alignItems="center" minWidth="50%">
|
||||
<Title title="Create optional password" />
|
||||
<Subtitle subtitle="Password should be min 8 characters, at least one number and one symbol" />
|
||||
<Subtitle subtitle="Password should be min 8 characters, at least one uppercase character, one number and one symbol" />
|
||||
<FormControl fullWidth>
|
||||
<Stack spacing={2}>
|
||||
<>
|
||||
@@ -59,7 +59,7 @@ export const ConnectPassword = () => {
|
||||
<Button
|
||||
size="large"
|
||||
variant="contained"
|
||||
disabled={password !== confirmedPassword || password.length === 0 || !isStrongPassword || isLoading}
|
||||
disabled={password !== confirmedPassword || password.length === 0 || isLoading}
|
||||
onClick={storePassword}
|
||||
>
|
||||
{isLoading ? <CircularProgress size={25} /> : 'Create password'}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user