Compare commits

..

1 Commits

Author SHA1 Message Date
fmtabbara fa63549a9c update wording for password strength and allow 2022-06-22 10:04:52 +01:00
124 changed files with 1339 additions and 2055 deletions
-38
View File
@@ -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
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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",
-137
View File
@@ -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
View File
@@ -1,3 +1,2 @@
pub mod client;
pub mod config;
pub mod init;
+2 -2
View File
@@ -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(
+169 -61
View File
@@ -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);
}
+171 -61
View File
@@ -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";
+165
View File
@@ -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))]
-1
View File
@@ -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]
+2 -2
View File
@@ -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::{
+10 -23
View File
@@ -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> {
+44 -82
View File
@@ -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
+3 -4
View 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";
+3 -4
View 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 =
"n1suhgf5svhu4usrurvxzlgn54ksxmn8gljarjtxqnapv8kjnp4nrsd3qaep";
+3 -4
View 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 = "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";
+8 -74
View File
@@ -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,
}
}
+2 -2
View File
@@ -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",
+3 -3
View File
@@ -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()]
);
}
+8 -7
View File
@@ -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]);
}
}
+2 -2
View File
@@ -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 -1
View File
@@ -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"
+57 -3
View File
@@ -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)
);
}
+4 -4
View File
@@ -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,
);
+3 -3
View File
@@ -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(),
+3 -3
View File
@@ -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!())]
+2 -2
View File
@@ -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
+4 -4
View File
@@ -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
+2 -5
View File
@@ -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();
+26 -29
View File
@@ -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,
}]
}
+2 -2
View File
@@ -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()]
}
+2 -2
View File
@@ -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" }
+5 -8
View File
@@ -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(),
));
}
+3 -3
View File
@@ -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(),
})
}
}
+15 -15
View File
@@ -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,
+4 -4
View File
@@ -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>()
+1 -3
View File
@@ -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)]
+8 -8
View File
@@ -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()
}
+28 -10
View File
@@ -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);
}
}
}
+4 -4
View File
@@ -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
View File
@@ -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(),
}
}
}
}
+31 -1
View File
@@ -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
View File
@@ -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.
+11 -7
View File
@@ -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);
+9 -9
View File
@@ -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));
}
+8 -5
View File
@@ -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 -5
View File
@@ -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(&eth_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
View File
@@ -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();
+1 -7
View File
@@ -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",
+1 -2
View File
@@ -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

+43 -68
View File
@@ -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);
}
-2
View File
@@ -10,8 +10,6 @@ pub enum BackendError {
CouldNotConnect,
#[error("Could not disconnect")]
CouldNotDisconnect,
#[error("No serverice provider set")]
NoServiceProviderSet,
}
impl Serialize for BackendError {
-2
View File
@@ -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(())
}
+3 -13
View File
@@ -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();
+2 -2
View File
@@ -42,9 +42,9 @@
"entitlements": null
},
"windows": {
"certificateThumbprint": "6DB77B1F529A0804FE0E6843A3EB8A8CECFFD408",
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.comodoca.com"
"timestampUrl": ""
}
},
"updater": {
+1 -1
View File
@@ -5581,7 +5581,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "vesting-contract"
version = "1.0.1"
version = "1.0.0"
dependencies = [
"config",
"cosmwasm-std",
+4 -13
View File
@@ -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?;
+24 -4
View File
@@ -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