Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c2a6eb4d39 | |||
| 835a915f25 | |||
| 9c16e5ebfa | |||
| 5dc57d2a3e | |||
| fd619cad51 | |||
| 953c0915d1 | |||
| acb1aa8df0 | |||
| b9ef848523 | |||
| b7bc713cd4 | |||
| b966f962c8 | |||
| 698cdc524d | |||
| 448aba0917 | |||
| b813e1fee0 | |||
| 23de430f93 | |||
| 9462bc726d | |||
| 3d2eaeeabb | |||
| a732a676e0 | |||
| d6a8fcda9c | |||
| 3628cd92c9 | |||
| 8d26acbc7e | |||
| 07b971fe92 | |||
| 2a539dc3cc | |||
| 3fb9737db4 |
@@ -39,7 +39,7 @@ jobs:
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: --all
|
||||
args: --all --all-features
|
||||
|
||||
- name: Check formatting
|
||||
uses: actions-rs/cargo@v1
|
||||
|
||||
@@ -56,6 +56,12 @@ jobs:
|
||||
command: fmt
|
||||
args: --all -- --check
|
||||
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
- uses: actions-rs/clippy-check@v1
|
||||
name: Clippy checks
|
||||
with:
|
||||
@@ -69,13 +75,8 @@ jobs:
|
||||
command: clippy
|
||||
args: -- -D warnings
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Reclaim some disk space (because Windows is being annoying)
|
||||
uses: actions-rs/cargo@v1
|
||||
if: ${{ matrix.os == 'windows-latest' }}
|
||||
with:
|
||||
command: clean
|
||||
|
||||
# COCONUT stuff
|
||||
- name: Build all binaries with coconut enabled
|
||||
uses: actions-rs/cargo@v1
|
||||
with:
|
||||
|
||||
Generated
+722
-2560
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -17,7 +17,7 @@ members = [
|
||||
"clients/native",
|
||||
"clients/native/websocket-requests",
|
||||
"clients/socks5",
|
||||
"clients/tauri-client/src-tauri",
|
||||
# "clients/tauri-client/src-tauri",
|
||||
"common/client-libs/gateway-client",
|
||||
"common/client-libs/mixnet-client",
|
||||
"common/client-libs/validator-client",
|
||||
|
||||
@@ -3,7 +3,7 @@ happy: fmt clippy-happy test
|
||||
clippy-all: clippy-all-main clippy-all-contracts clippy-all-wallet
|
||||
clippy-happy: clippy-happy-main clippy-happy-contracts clippy-happy-wallet
|
||||
cargo-test: test-main test-contracts test-wallet
|
||||
build: build-main build-contracts build-wallet
|
||||
build: build-contracts build-wallet build-main
|
||||
fmt: fmt-main fmt-contracts fmt-wallet
|
||||
|
||||
clippy-happy-main:
|
||||
@@ -25,7 +25,7 @@ clippy-all-wallet:
|
||||
cargo clippy --manifest-path nym-wallet/Cargo.toml --all-features -- -D warnings
|
||||
|
||||
test-main:
|
||||
cargo test --all-features
|
||||
cargo test --all-features --all
|
||||
|
||||
test-contracts:
|
||||
cargo test --manifest-path contracts/Cargo.toml --all-features
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use log::*;
|
||||
use nymsphinx::anonymous_replies::{
|
||||
encryption_key::EncryptionKeyDigest, encryption_key::Unsigned, SurbEncryptionKey,
|
||||
SurbEncryptionKeySize,
|
||||
encryption_key::EncryptionKeyDigest, SurbEncryptionKey, SurbEncryptionKeySize,
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
@@ -43,7 +43,7 @@ impl ReplyKeyStorage {
|
||||
// if this fails it means we have some database corruption and we
|
||||
// absolutely can't continue
|
||||
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::to_usize() {
|
||||
if key_bytes_ref.len() != SurbEncryptionKeySize::USIZE {
|
||||
error!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
panic!("REPLY KEY STORAGE DATA CORRUPTION - ENCRYPTION KEY HAS INVALID LENGTH");
|
||||
}
|
||||
|
||||
Generated
-14885
File diff suppressed because it is too large
Load Diff
@@ -26,7 +26,7 @@
|
||||
"@rollup/plugin-node-resolve": "^8.0.0",
|
||||
"@rollup/plugin-replace": "^2.4.0",
|
||||
"@rollup/plugin-url": "^5.0.0",
|
||||
"@tauri-apps/cli": "^1.0.0-beta.5",
|
||||
"@tauri-apps/cli": "^1.0.0-rc.5",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
|
||||
@@ -12,15 +12,19 @@ build = "src/build.rs"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.0.0-beta.2" }
|
||||
tauri-build = { version = "=1.0.0-rc.2" }
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
tauri = { version = "1.0.0-beta.4", features = [] }
|
||||
tauri = { version = "=1.0.0-rc.2", features = [] }
|
||||
tokio = "1.4"
|
||||
url = "2.2"
|
||||
|
||||
tauri-codegen = "=1.0.0-rc.1"
|
||||
tauri-macros = "=1.0.0-rc.1"
|
||||
core-graphics = "=0.22.2"
|
||||
|
||||
coconut-interface = { path = "../../../common/coconut-interface" }
|
||||
credentials = { path = "../../../common/credentials" }
|
||||
validator-client = {path = "../../../common/client-libs/validator-client"}
|
||||
|
||||
+66
-2790
File diff suppressed because it is too large
Load Diff
@@ -64,15 +64,23 @@ export default class ValidatorClient implements INymClient {
|
||||
|
||||
readonly vestingContract: string;
|
||||
|
||||
readonly mainnetDenom = "unym";
|
||||
|
||||
readonly mainnetPrefix = "n";
|
||||
|
||||
private constructor(
|
||||
client: SigningClient | QueryClient,
|
||||
prefix: string,
|
||||
mixnetContract: string,
|
||||
vestingContract: string,
|
||||
vestingContract: string
|
||||
) {
|
||||
this.client = client;
|
||||
this.prefix = prefix;
|
||||
this.denom = `u${prefix}`;
|
||||
if (prefix == this.mainnetPrefix) {
|
||||
this.denom = this.mainnetDenom;
|
||||
} else {
|
||||
this.denom = `u${prefix}`;
|
||||
}
|
||||
|
||||
this.mixnetContract = mixnetContract;
|
||||
this.vestingContract = vestingContract;
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
import axios from 'axios';
|
||||
import { GasPrice } from '@cosmjs/stargate';
|
||||
|
||||
const mainnetPrefix = 'n';
|
||||
const mainnetDenom = 'nym';
|
||||
|
||||
export function nymGasPrice(prefix: string): GasPrice {
|
||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||
if (typeof prefix === 'string') {
|
||||
if (prefix === mainnetPrefix) {
|
||||
prefix = mainnetDenom;
|
||||
}
|
||||
return GasPrice.fromString(`0.025u${prefix}`); // TODO: ideally this ugly conversion shouldn't be hardcoded here.
|
||||
}
|
||||
else {
|
||||
throw new Error(`${prefix} is not of type string`);
|
||||
}
|
||||
}
|
||||
|
||||
export const downloadWasm = async (url: string): Promise<Uint8Array> => {
|
||||
|
||||
@@ -39,8 +39,9 @@ flate2 = { version = "1.0.20", optional = true }
|
||||
sha2 = { version = "0.9.5", optional = true }
|
||||
itertools = { version = "0.10", optional = true }
|
||||
cosmwasm-std = { version = "1.0.0-beta3", optional = true }
|
||||
# Leaving it as * so that it inherits whatever the wallet is using
|
||||
ts-rs = { version = "*", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
[features]
|
||||
nymd-client = [
|
||||
@@ -54,4 +55,3 @@ nymd-client = [
|
||||
"itertools",
|
||||
"cosmwasm-std",
|
||||
]
|
||||
typescript-types = ["ts-rs", "validator-api-requests/ts-rs"]
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use crate::{validator_api, ValidatorClientError};
|
||||
use coconut_interface::{BlindSignRequestBody, BlindedSignatureResponse, VerificationKeyResponse};
|
||||
use mixnet_contract_common::{GatewayBond, IdentityKeyRef, MixNodeBond};
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
use url::Url;
|
||||
use validator_api_requests::models::{
|
||||
CoreNodeStatusResponse, MixnodeStatusResponse, RewardEstimationResponse,
|
||||
@@ -29,6 +30,7 @@ use std::str::FromStr;
|
||||
|
||||
#[cfg(feature = "nymd-client")]
|
||||
#[must_use]
|
||||
#[derive(Debug)]
|
||||
pub struct Config {
|
||||
network: network_defaults::all::Network,
|
||||
api_url: Url,
|
||||
@@ -159,12 +161,10 @@ impl Client<QueryNymdClient> {
|
||||
let nymd_client = NymdClient::connect(
|
||||
config.nymd_url.as_str(),
|
||||
Some(config.mixnet_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_MIXNET_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
cosmrs::AccountId::from_str(DEFAULT_NETWORK.mixnet_contract_address()).unwrap()
|
||||
})),
|
||||
Some(config.vesting_contract_address.clone().unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(network_defaults::DEFAULT_VESTING_CONTRACT_ADDRESS)
|
||||
.unwrap()
|
||||
cosmrs::AccountId::from_str(DEFAULT_NETWORK.vesting_contract_address()).unwrap()
|
||||
})),
|
||||
Some(
|
||||
config
|
||||
@@ -172,7 +172,7 @@ impl Client<QueryNymdClient> {
|
||||
.clone()
|
||||
.unwrap_or_else(|| {
|
||||
cosmrs::AccountId::from_str(
|
||||
network_defaults::DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
DEFAULT_NETWORK.bandwidth_claim_contract_address(),
|
||||
)
|
||||
.unwrap()
|
||||
}),
|
||||
|
||||
@@ -72,7 +72,7 @@ impl FromStr for GasPrice {
|
||||
}
|
||||
|
||||
impl GasPrice {
|
||||
pub fn new_with_default_price(denom: String) -> Result<Self, NymdError> {
|
||||
pub fn new_with_default_price(denom: &str) -> Result<Self, NymdError> {
|
||||
format!("{}{}", defaults::GAS_PRICE_AMOUNT, denom).parse()
|
||||
}
|
||||
}
|
||||
@@ -83,8 +83,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn default_gas_price_is_valid() {
|
||||
let denom = "unym".parse().unwrap();
|
||||
let _ = GasPrice::new_with_default_price(denom);
|
||||
let denom = "unym";
|
||||
GasPrice::new_with_default_price(denom).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -7,7 +7,11 @@ use cosmrs::Coin;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::fmt;
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../../../nym-wallet/src/types/rust/operation.ts")
|
||||
)]
|
||||
#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
pub enum Operation {
|
||||
Upload,
|
||||
|
||||
@@ -57,16 +57,16 @@ pub struct DirectSecp256k1HdWallet {
|
||||
}
|
||||
|
||||
impl DirectSecp256k1HdWallet {
|
||||
pub fn builder(prefix: String) -> DirectSecp256k1HdWalletBuilder {
|
||||
pub fn builder(prefix: &str) -> DirectSecp256k1HdWalletBuilder {
|
||||
DirectSecp256k1HdWalletBuilder::new(prefix)
|
||||
}
|
||||
|
||||
/// Restores a wallet from the given BIP39 mnemonic using default options.
|
||||
pub fn from_mnemonic(prefix: String, mnemonic: bip39::Mnemonic) -> Result<Self, NymdError> {
|
||||
pub fn from_mnemonic(prefix: &str, mnemonic: bip39::Mnemonic) -> Result<Self, NymdError> {
|
||||
DirectSecp256k1HdWalletBuilder::new(prefix).build(mnemonic)
|
||||
}
|
||||
|
||||
pub fn generate(prefix: String, word_count: usize) -> Result<Self, NymdError> {
|
||||
pub fn generate(prefix: &str, word_count: usize) -> Result<Self, NymdError> {
|
||||
let mneomonic = bip39::Mnemonic::generate(word_count)?;
|
||||
Self::from_mnemonic(prefix, mneomonic)
|
||||
}
|
||||
@@ -146,11 +146,11 @@ pub struct DirectSecp256k1HdWalletBuilder {
|
||||
}
|
||||
|
||||
impl DirectSecp256k1HdWalletBuilder {
|
||||
pub fn new(prefix: String) -> Self {
|
||||
pub fn new(prefix: &str) -> Self {
|
||||
DirectSecp256k1HdWalletBuilder {
|
||||
bip39_password: String::new(),
|
||||
hd_paths: vec![defaults::COSMOS_DERIVATION_PATH.parse().unwrap()],
|
||||
prefix,
|
||||
prefix: prefix.into(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,11 +197,11 @@ impl DirectSecp256k1HdWalletBuilder {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use network_defaults::{default_network, BECH32_PREFIX};
|
||||
use network_defaults::DEFAULT_NETWORK;
|
||||
|
||||
#[test]
|
||||
fn generating_account_addresses() {
|
||||
let (addr1, addr2, addr3) = match BECH32_PREFIX {
|
||||
let (addr1, addr2, addr3) = match DEFAULT_NETWORK.bech32_prefix() {
|
||||
"punk" => (
|
||||
"punk1jw6mp7d5xqc7w6xm79lha27glmd0vdt32a3fj2",
|
||||
"punk1h5hgn94nsq4kh99rjj794hr5h5q6yfm22mcqqn",
|
||||
@@ -222,7 +222,7 @@ mod tests {
|
||||
];
|
||||
|
||||
for (mnemonic, address) in mnemonic_address.into_iter() {
|
||||
let prefix = default_network().bech32_prefix();
|
||||
let prefix = DEFAULT_NETWORK.bech32_prefix();
|
||||
let wallet =
|
||||
DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic.parse().unwrap()).unwrap();
|
||||
assert_eq!(
|
||||
|
||||
@@ -12,8 +12,6 @@ cosmwasm-std = "1.0.0-beta3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
schemars = "0.8"
|
||||
# Leaving it as * so that it inherits whatever the wallet is using
|
||||
ts-rs = { version = "*", optional = true }
|
||||
thiserror = "1.0"
|
||||
network-defaults = { path = "../../network-defaults" }
|
||||
fixed = { version = "1.1", features = ["serde"] }
|
||||
@@ -25,7 +23,7 @@ contracts-common = { path = "../contracts-common" }
|
||||
|
||||
[dev-dependencies]
|
||||
time = { version = "0.3.5", features = ["serde", "macros"] }
|
||||
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
||||
@@ -8,7 +8,11 @@ use serde::{Deserialize, Serialize};
|
||||
use std::cmp::Ordering;
|
||||
use std::fmt::Display;
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../../../nym-wallet/src/types/rust/gateway.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub struct Gateway {
|
||||
pub host: String,
|
||||
|
||||
@@ -18,7 +18,14 @@ fixed::const_fixed_from_int! {
|
||||
const ONE: U128 = 1;
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(
|
||||
export,
|
||||
export_to = "../../../nym-wallet/src/types/rust/rewardedsetnodestatus.ts"
|
||||
)
|
||||
)]
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub enum RewardedSetNodeStatus {
|
||||
Active,
|
||||
@@ -31,7 +38,11 @@ impl RewardedSetNodeStatus {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../../../nym-wallet/src/types/rust/mixnode.ts")
|
||||
)]
|
||||
#[derive(Clone, Debug, Deserialize, PartialEq, PartialOrd, Serialize, JsonSchema)]
|
||||
pub struct MixNode {
|
||||
pub host: String,
|
||||
|
||||
@@ -12,4 +12,6 @@ serde = { version = "1.0", features = ["derive"] }
|
||||
schemars = "0.8"
|
||||
cw-storage-plus = "0.11.1"
|
||||
config = { path = "../../config" }
|
||||
ts-rs = { version = "*", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "6.1.2"
|
||||
|
||||
@@ -12,7 +12,11 @@ pub fn one_ucoin() -> Coin {
|
||||
Coin::new(1, DENOM)
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "ts-rs", derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../../../nym-wallet/src/types/rust/period.ts")
|
||||
)]
|
||||
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone, JsonSchema)]
|
||||
pub enum Period {
|
||||
Before,
|
||||
|
||||
@@ -11,6 +11,6 @@ url = "2.2"
|
||||
|
||||
# I guess temporarily until we get serde support in coconut up and running
|
||||
coconut-interface = { path = "../coconut-interface" }
|
||||
crypto = { path = "../crypto" }
|
||||
crypto = { path = "../crypto", features = ["asymmetric"] }
|
||||
network-defaults = { path = "../network-defaults" }
|
||||
validator-client = { path = "../client-libs/validator-client" }
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
use coconut_interface::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, prepare_blind_sign,
|
||||
prove_bandwidth_credential, Attribute, BlindSignRequestBody, Credential, Parameters, Signature,
|
||||
SignatureShare, VerificationKey,
|
||||
prove_bandwidth_credential, Attribute, BlindSignRequest, BlindSignRequestBody, Credential,
|
||||
ElGamalKeyPair, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
};
|
||||
use url::Url;
|
||||
|
||||
@@ -47,13 +47,13 @@ pub async fn obtain_aggregate_verification_key(
|
||||
let mut client = validator_client::ApiClient::new(validators[0].clone());
|
||||
let response = client.get_coconut_verification_key().await?;
|
||||
|
||||
indices.push(0);
|
||||
indices.push(1);
|
||||
shares.push(response.key);
|
||||
|
||||
for (id, validator_url) in validators.iter().enumerate().skip(1) {
|
||||
client.change_validator_api(validator_url.clone());
|
||||
let response = client.get_coconut_verification_key().await?;
|
||||
indices.push(id as u64);
|
||||
indices.push((id + 1) as u64);
|
||||
shares.push(response.key);
|
||||
}
|
||||
|
||||
@@ -66,17 +66,11 @@ async fn obtain_partial_credential(
|
||||
private_attributes: &[Attribute],
|
||||
client: &validator_client::ApiClient,
|
||||
validator_vk: &VerificationKey,
|
||||
blind_sign_request: &BlindSignRequest,
|
||||
elgamal_keypair: &ElGamalKeyPair,
|
||||
) -> Result<Signature, Error> {
|
||||
let elgamal_keypair = coconut_interface::elgamal_keygen(params);
|
||||
let blind_sign_request = prepare_blind_sign(
|
||||
params,
|
||||
&elgamal_keypair,
|
||||
private_attributes,
|
||||
public_attributes,
|
||||
)?;
|
||||
|
||||
let blind_sign_request_body = BlindSignRequestBody::new(
|
||||
&blind_sign_request,
|
||||
blind_sign_request,
|
||||
elgamal_keypair.public_key(),
|
||||
public_attributes,
|
||||
(public_attributes.len() + private_attributes.len()) as u32,
|
||||
@@ -116,15 +110,25 @@ pub async fn obtain_aggregate_signature(
|
||||
let validator_partial_vk = client.get_coconut_verification_key().await?;
|
||||
validators_partial_vks.push(validator_partial_vk.key.clone());
|
||||
|
||||
let elgamal_keypair = coconut_interface::elgamal_keygen(params);
|
||||
let blind_sign_request = prepare_blind_sign(
|
||||
params,
|
||||
&elgamal_keypair,
|
||||
private_attributes,
|
||||
public_attributes,
|
||||
)?;
|
||||
|
||||
let first = obtain_partial_credential(
|
||||
params,
|
||||
public_attributes,
|
||||
private_attributes,
|
||||
&client,
|
||||
&validator_partial_vk.key,
|
||||
&blind_sign_request,
|
||||
&elgamal_keypair,
|
||||
)
|
||||
.await?;
|
||||
shares.push(SignatureShare::new(first, 0));
|
||||
shares.push(SignatureShare::new(first, 1));
|
||||
|
||||
for (id, validator_url) in validators.iter().enumerate().skip(1) {
|
||||
client.change_validator_api(validator_url.clone());
|
||||
@@ -136,9 +140,11 @@ pub async fn obtain_aggregate_signature(
|
||||
private_attributes,
|
||||
&client,
|
||||
&validator_partial_vk.key,
|
||||
&blind_sign_request,
|
||||
&elgamal_keypair,
|
||||
)
|
||||
.await?;
|
||||
let share = SignatureShare::new(signature, id as u64);
|
||||
let share = SignatureShare::new(signature, (id + 1) as u64);
|
||||
shares.push(share)
|
||||
}
|
||||
|
||||
@@ -148,7 +154,7 @@ pub async fn obtain_aggregate_signature(
|
||||
|
||||
let mut indices: Vec<u64> = Vec::with_capacity(validators_partial_vks.len());
|
||||
for i in 0..validators_partial_vks.len() {
|
||||
indices.push(i as u64);
|
||||
indices.push((i + 1) as u64);
|
||||
}
|
||||
let verification_key =
|
||||
aggregate_verification_keys(&validators_partial_vks, Some(indices.as_ref()))?;
|
||||
|
||||
+19
-11
@@ -7,21 +7,29 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
aes = { version = "0.7.4", features = ["ctr"] }
|
||||
aes = { version = "0.8.1", optional = true }
|
||||
bs58 = "0.4.0"
|
||||
blake3 = { version = "~1.2.0", features = ["traits-preview"] }
|
||||
digest = "0.9.0"
|
||||
generic-array = "0.14"
|
||||
hkdf = "0.11.0"
|
||||
hmac = "0.11.0"
|
||||
cipher = "0.3.0"
|
||||
x25519-dalek = "1.1"
|
||||
ed25519-dalek = "1.0"
|
||||
log = "0.4"
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
blake3 = { version = "1.3.1", features = ["traits-preview"], optional = true }
|
||||
ctr = { version = "0.9.1", optional = true }
|
||||
digest = { version = "0.10.3", optional = true }
|
||||
generic-array = { version = "0.14", optional = true }
|
||||
hkdf = { version = "0.12.3", optional = true }
|
||||
hmac = { version = "0.12.1", optional = true }
|
||||
cipher = { version = "0.4.3", optional = true }
|
||||
x25519-dalek = { version = "1.1", optional = true }
|
||||
ed25519-dalek = { version = "1.0", optional = true }
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"], optional = true }
|
||||
subtle-encoding = { version = "0.5", features = ["bech32-preview"]}
|
||||
|
||||
# internal
|
||||
nymsphinx-types = { path = "../nymsphinx/types" }
|
||||
pemstore = { path = "../../common/pemstore" }
|
||||
config = { path="../../common/config" }
|
||||
|
||||
[dev-dependencies]
|
||||
rand_chacha = "0.2"
|
||||
|
||||
[features]
|
||||
asymmetric = ["x25519-dalek", "ed25519-dalek"]
|
||||
hashing = ["blake3", "digest", "hkdf", "hmac", "generic-array"]
|
||||
symmetric = ["aes", "ctr", "cipher", "generic-array"]
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
@@ -46,6 +47,7 @@ pub struct KeyPair {
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let private_key = x25519_dalek::StaticSecret::new(rng);
|
||||
let public_key = (&private_key).into();
|
||||
|
||||
@@ -6,6 +6,7 @@ pub use ed25519_dalek::SignatureError;
|
||||
pub use ed25519_dalek::{Verifier, PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, SIGNATURE_LENGTH};
|
||||
use nymsphinx_types::{DestinationAddressBytes, DESTINATION_ADDRESS_LENGTH};
|
||||
use pemstore::traits::{PemStorableKey, PemStorableKeyPair};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
@@ -45,6 +46,7 @@ pub struct KeyPair {
|
||||
}
|
||||
|
||||
impl KeyPair {
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
|
||||
let ed25519_keypair = ed25519_dalek::Keypair::generate(rng);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use config::defaults;
|
||||
use config::defaults::DEFAULT_NETWORK;
|
||||
use subtle_encoding::bech32;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
@@ -18,12 +18,12 @@ pub fn try_bech32_decode(address: &str) -> Result<String, Bech32Error> {
|
||||
pub fn validate_bech32_prefix(address: &str) -> Result<(), Bech32Error> {
|
||||
let prefix = try_bech32_decode(address)?;
|
||||
|
||||
if prefix == defaults::BECH32_PREFIX {
|
||||
if prefix == DEFAULT_NETWORK.bech32_prefix() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Bech32Error::WrongPrefix(format!(
|
||||
"your bech32 address prefix should be {}, not {}",
|
||||
defaults::BECH32_PREFIX,
|
||||
DEFAULT_NETWORK.bech32_prefix(),
|
||||
prefix
|
||||
)))
|
||||
}
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use digest::{BlockInput, Digest, FixedOutput, Reset, Update};
|
||||
use generic_array::{ArrayLength, GenericArray};
|
||||
use digest::{Digest, Output};
|
||||
|
||||
pub fn compute_digest<D>(data: &[u8]) -> GenericArray<u8, <D as Digest>::OutputSize>
|
||||
pub fn compute_digest<D>(data: &[u8]) -> Output<D>
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest,
|
||||
{
|
||||
D::digest(data)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::ArrayLength;
|
||||
use hkdf::Hkdf;
|
||||
use hkdf::{
|
||||
hmac::{
|
||||
digest::{crypto_common::BlockSizeUser, Digest},
|
||||
SimpleHmac,
|
||||
},
|
||||
Hkdf,
|
||||
};
|
||||
|
||||
/// Perform HKDF `extract` then `expand` as a single step.
|
||||
pub fn extract_then_expand<D>(
|
||||
@@ -13,14 +17,12 @@ pub fn extract_then_expand<D>(
|
||||
okm_length: usize,
|
||||
) -> Result<Vec<u8>, hkdf::InvalidLength>
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
{
|
||||
// TODO: this would need to change if we ever needed the generated pseudorandom key, but
|
||||
// realistically I don't see any reasons why we might need it
|
||||
|
||||
let hkdf = Hkdf::<D>::new(salt, ikm);
|
||||
let hkdf = Hkdf::<D, SimpleHmac<D>>::new(salt, ikm);
|
||||
let mut okm = vec![0u8; okm_length];
|
||||
hkdf.expand(info.unwrap_or(&[]), &mut okm)?;
|
||||
|
||||
|
||||
+19
-24
@@ -1,24 +1,23 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
|
||||
use hmac::{crypto_mac, Hmac, Mac, NewMac};
|
||||
use hmac::{
|
||||
digest::{crypto_common::BlockSizeUser, CtOutput, Digest, Output},
|
||||
Mac, SimpleHmac,
|
||||
};
|
||||
|
||||
pub use hmac;
|
||||
|
||||
// Type alias for ease of use so that it would not require explicit import of crypto_mac or Hmac
|
||||
pub type HmacOutput<D> = crypto_mac::Output<Hmac<D>>;
|
||||
// TODO: We should probably change it to use some sealed trait to allow for both `Hmac` and `SimpleHmac`
|
||||
pub type HmacOutput<D> = CtOutput<SimpleHmac<D>>;
|
||||
|
||||
/// Compute keyed hmac
|
||||
pub fn compute_keyed_hmac<D>(key: &[u8], data: &[u8]) -> HmacOutput<D>
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser,
|
||||
{
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
|
||||
let mut hmac = SimpleHmac::<D>::new_from_slice(key)
|
||||
.expect("HMAC was instantiated with a key of an invalid size!");
|
||||
hmac.update(data);
|
||||
hmac.finalize()
|
||||
}
|
||||
@@ -26,32 +25,28 @@ where
|
||||
/// Compute keyed hmac and performs constant time equality check with the provided tag value.
|
||||
pub fn recompute_keyed_hmac_and_verify_tag<D>(key: &[u8], data: &[u8], tag: &[u8]) -> bool
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser,
|
||||
{
|
||||
let mut hmac =
|
||||
Hmac::<D>::new_from_slice(key).expect("HMAC should be able to take key of any size!");
|
||||
let mut hmac = SimpleHmac::<D>::new_from_slice(key)
|
||||
.expect("HMAC was instantiated with a key of an invalid size!");
|
||||
hmac.update(data);
|
||||
|
||||
let tag_arr = Output::<D>::from_slice(tag);
|
||||
// note, under the hood ct_eq is called
|
||||
hmac.verify(tag).is_ok()
|
||||
hmac.verify(tag_arr).is_ok()
|
||||
}
|
||||
|
||||
/// Verifies tag of an hmac output.
|
||||
pub fn verify_tag<D>(tag: &[u8], out: HmacOutput<D>) -> bool
|
||||
where
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
D: Digest + BlockSizeUser,
|
||||
{
|
||||
if tag.len() != D::OutputSize::to_usize() {
|
||||
if tag.len() != <D as Digest>::output_size() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let tag_bytes = GenericArray::clone_from_slice(tag);
|
||||
let tag_out = HmacOutput::new(tag_bytes);
|
||||
// note, under the hood ct_eq is called
|
||||
out == tag_out
|
||||
let tag_arr = Output::<D>::from_slice(tag);
|
||||
out == tag_arr.into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(feature = "asymmetric")]
|
||||
pub mod asymmetric;
|
||||
pub mod bech32_address_validation;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub mod crypto_hash;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub mod hkdf;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub mod hmac;
|
||||
#[cfg(all(feature = "asymmetric", feature = "hashing", feature = "symmetric"))]
|
||||
pub mod shared_key;
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub mod symmetric;
|
||||
|
||||
pub use digest::Digest;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub use digest::{Digest, OutputSizeUser};
|
||||
#[cfg(any(feature = "hashing", feature = "symmetric"))]
|
||||
pub use generic_array;
|
||||
|
||||
// with the below my idea was to try to introduce having a single place of importing all hashing, encryption,
|
||||
// etc. algorithms and import them elsewhere as needed via common/crypto
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub use aes;
|
||||
#[cfg(feature = "hashing")]
|
||||
pub use blake3;
|
||||
#[cfg(feature = "symmetric")]
|
||||
pub use ctr;
|
||||
|
||||
// TODO: this function uses all three modules: asymmetric crypto, symmetric crypto and derives key...,
|
||||
// so I don't know where to put it...
|
||||
|
||||
@@ -3,22 +3,22 @@
|
||||
|
||||
use crate::asymmetric::encryption;
|
||||
use crate::hkdf;
|
||||
use cipher::{CipherKey, NewCipher, StreamCipher};
|
||||
use digest::{BlockInput, FixedOutput, Reset, Update};
|
||||
use generic_array::{typenum::Unsigned, ArrayLength};
|
||||
use cipher::{Key, KeyIvInit, StreamCipher};
|
||||
use digest::crypto_common::BlockSizeUser;
|
||||
use digest::Digest;
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
/// Generate an ephemeral encryption keypair and perform diffie-hellman to establish
|
||||
/// shared key with the remote.
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn new_ephemeral_shared_key<C, D, R>(
|
||||
rng: &mut R,
|
||||
remote_key: &encryption::PublicKey,
|
||||
) -> (encryption::KeyPair, CipherKey<C>)
|
||||
) -> (encryption::KeyPair, Key<C>)
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let ephemeral_keypair = encryption::KeyPair::new(rng);
|
||||
@@ -27,11 +27,11 @@ where
|
||||
let dh_result = ephemeral_keypair.private_key().diffie_hellman(remote_key);
|
||||
|
||||
// there is no reason for this to fail as our okm is expected to be only C::KeySize bytes
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::KeySize::to_usize())
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::key_size())
|
||||
.expect("somehow too long okm was provided");
|
||||
|
||||
let derived_shared_key =
|
||||
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
|
||||
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!");
|
||||
|
||||
(ephemeral_keypair, derived_shared_key)
|
||||
}
|
||||
@@ -40,18 +40,16 @@ where
|
||||
pub fn recompute_shared_key<C, D>(
|
||||
remote_key: &encryption::PublicKey,
|
||||
local_key: &encryption::PrivateKey,
|
||||
) -> CipherKey<C>
|
||||
) -> Key<C>
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
D: Update + BlockInput + FixedOutput + Reset + Default + Clone,
|
||||
D::BlockSize: ArrayLength<u8>,
|
||||
D::OutputSize: ArrayLength<u8>,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
D: Digest + BlockSizeUser + Clone,
|
||||
{
|
||||
let dh_result = local_key.diffie_hellman(remote_key);
|
||||
|
||||
// there is no reason for this to fail as our okm is expected to be only C::KeySize bytes
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::KeySize::to_usize())
|
||||
let okm = hkdf::extract_then_expand::<D>(None, &dh_result, None, C::key_size())
|
||||
.expect("somehow too long okm was provided");
|
||||
|
||||
CipherKey::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
|
||||
Key::<C>::from_exact_iter(okm).expect("okm was expanded to incorrect length!")
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use cipher::{Nonce, StreamCipher};
|
||||
use generic_array::{typenum::Unsigned, GenericArray};
|
||||
use cipher::{Iv, StreamCipher};
|
||||
pub use cipher::{IvSizeUser, KeyIvInit, KeySizeUser};
|
||||
#[cfg(feature = "rand")]
|
||||
use rand::{CryptoRng, RngCore};
|
||||
|
||||
// re-export this for ease of use
|
||||
pub use cipher::{CipherKey, NewCipher};
|
||||
pub use cipher::Key as CipherKey;
|
||||
|
||||
// SECURITY:
|
||||
// TODO: note that this is not the most secure approach here
|
||||
@@ -19,49 +20,51 @@ pub use cipher::{CipherKey, NewCipher};
|
||||
|
||||
// I think 'IV' looks better than 'Iv', feel free to change that.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub type IV<C> = Nonce<C>;
|
||||
pub type IV<C> = Iv<C>;
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn generate_key<C, R>(rng: &mut R) -> CipherKey<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut key = GenericArray::default();
|
||||
let mut key = CipherKey::<C>::default();
|
||||
rng.fill_bytes(&mut key);
|
||||
key
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
pub fn random_iv<C, R>(rng: &mut R) -> IV<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut iv = GenericArray::default();
|
||||
let mut iv = IV::<C>::default();
|
||||
rng.fill_bytes(&mut iv);
|
||||
iv
|
||||
}
|
||||
|
||||
pub fn zero_iv<C>() -> IV<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
{
|
||||
GenericArray::default()
|
||||
Iv::<C>::default()
|
||||
}
|
||||
|
||||
pub fn iv_from_slice<C>(b: &[u8]) -> &IV<C>
|
||||
where
|
||||
C: NewCipher,
|
||||
C: KeyIvInit,
|
||||
{
|
||||
if b.len() != C::NonceSize::to_usize() {
|
||||
if b.len() != C::iv_size() {
|
||||
// `from_slice` would have caused a panic about this issue anyway.
|
||||
// Now we at least have slightly more information
|
||||
panic!(
|
||||
"Tried to convert {} bytes to IV. Expected {}",
|
||||
b.len(),
|
||||
C::NonceSize::to_usize()
|
||||
C::iv_size()
|
||||
)
|
||||
}
|
||||
GenericArray::from_slice(b)
|
||||
IV::<C>::from_slice(b)
|
||||
}
|
||||
|
||||
// TODO: there's really no way to use more parts of the keystream if it was required at some point.
|
||||
@@ -70,7 +73,7 @@ where
|
||||
#[inline]
|
||||
pub fn encrypt<C>(key: &CipherKey<C>, iv: &IV<C>, data: &[u8]) -> Vec<u8>
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut ciphertext = data.to_vec();
|
||||
encrypt_in_place::<C>(key, iv, &mut ciphertext);
|
||||
@@ -80,7 +83,7 @@ where
|
||||
#[inline]
|
||||
pub fn encrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut cipher = C::new(key, iv);
|
||||
cipher.apply_keystream(data)
|
||||
@@ -89,7 +92,7 @@ where
|
||||
#[inline]
|
||||
pub fn decrypt<C>(key: &CipherKey<C>, iv: &IV<C>, ciphertext: &[u8]) -> Vec<u8>
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut data = ciphertext.to_vec();
|
||||
decrypt_in_place::<C>(key, iv, &mut data);
|
||||
@@ -99,7 +102,7 @@ where
|
||||
#[inline]
|
||||
pub fn decrypt_in_place<C>(key: &CipherKey<C>, iv: &IV<C>, data: &mut [u8])
|
||||
where
|
||||
C: StreamCipher + NewCipher,
|
||||
C: StreamCipher + KeyIvInit,
|
||||
{
|
||||
let mut cipher = C::new(key, iv);
|
||||
cipher.apply_keystream(data)
|
||||
@@ -108,12 +111,12 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use rand::rngs::OsRng;
|
||||
use rand_chacha::rand_core::SeedableRng;
|
||||
|
||||
#[cfg(test)]
|
||||
mod aes_ctr128 {
|
||||
use super::*;
|
||||
use aes::Aes128Ctr;
|
||||
type Aes128Ctr = ctr::Ctr64LE<aes::Aes128>;
|
||||
|
||||
#[test]
|
||||
fn zero_iv_is_actually_zero() {
|
||||
@@ -125,7 +128,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn decryption_is_reciprocal_to_encryption() {
|
||||
let mut rng = OsRng;
|
||||
let dummy_seed = [1u8; 32];
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||
|
||||
let arr_input = [42; 200];
|
||||
let vec_input = vec![123, 200];
|
||||
@@ -148,7 +152,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn in_place_variants_work_same_way() {
|
||||
let mut rng = OsRng;
|
||||
let dummy_seed = [1u8; 32];
|
||||
let mut rng = rand_chacha::ChaCha20Rng::from_seed(dummy_seed);
|
||||
|
||||
let mut data = [42; 200];
|
||||
let original_data = data;
|
||||
|
||||
@@ -9,6 +9,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
cfg-if = "1.0.0"
|
||||
hex-literal = "0.3.3"
|
||||
once_cell = "1.7.2"
|
||||
serde = {version = "1.0", features = ["derive"]}
|
||||
thiserror = "1.0"
|
||||
url = "2.2"
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, fmt, str::FromStr};
|
||||
use std::{collections::HashMap, fmt, ops::Deref, str::FromStr};
|
||||
|
||||
use crate::{mainnet, qa, sandbox, ValidatorDetails};
|
||||
use crate::{
|
||||
DefaultNetworkDetails, ValidatorDetails, MAINNET_DEFAULTS, QA_DEFAULTS, SANDBOX_DEFAULTS,
|
||||
};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -22,20 +24,40 @@ pub enum Network {
|
||||
}
|
||||
|
||||
impl Network {
|
||||
pub fn bech32_prefix(&self) -> String {
|
||||
fn details(&self) -> &DefaultNetworkDetails<'_> {
|
||||
match self {
|
||||
Self::QA => String::from(qa::BECH32_PREFIX),
|
||||
Self::SANDBOX => String::from(sandbox::BECH32_PREFIX),
|
||||
Self::MAINNET => String::from(mainnet::BECH32_PREFIX),
|
||||
Self::QA => &QA_DEFAULTS,
|
||||
Self::SANDBOX => &SANDBOX_DEFAULTS,
|
||||
Self::MAINNET => &MAINNET_DEFAULTS,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn denom(&self) -> String {
|
||||
match self {
|
||||
Self::QA => String::from(qa::DENOM),
|
||||
Self::SANDBOX => String::from(sandbox::DENOM),
|
||||
Self::MAINNET => String::from(mainnet::DENOM),
|
||||
}
|
||||
pub fn bech32_prefix(&self) -> &str {
|
||||
self.details().bech32_prefix
|
||||
}
|
||||
|
||||
pub fn denom(&self) -> &str {
|
||||
self.details().denom
|
||||
}
|
||||
|
||||
pub fn mixnet_contract_address(&self) -> &str {
|
||||
self.details().mixnet_contract_address
|
||||
}
|
||||
|
||||
pub fn vesting_contract_address(&self) -> &str {
|
||||
self.details().vesting_contract_address
|
||||
}
|
||||
|
||||
pub fn bandwidth_claim_contract_address(&self) -> &str {
|
||||
self.details().bandwidth_claim_contract_address
|
||||
}
|
||||
|
||||
pub fn rewarding_validator_address(&self) -> &str {
|
||||
self.details().rewarding_validator_address
|
||||
}
|
||||
|
||||
pub fn validators(&self) -> impl Iterator<Item = &ValidatorDetails> {
|
||||
self.details().validators.iter()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +86,7 @@ impl fmt::Display for Network {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct NetworkDetails {
|
||||
bech32_prefix: String,
|
||||
denom: String,
|
||||
@@ -75,7 +97,21 @@ pub struct NetworkDetails {
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
impl From<&DefaultNetworkDetails<'_>> for NetworkDetails {
|
||||
fn from(details: &DefaultNetworkDetails) -> Self {
|
||||
NetworkDetails {
|
||||
bech32_prefix: details.bech32_prefix.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(),
|
||||
rewarding_validator_address: details.rewarding_validator_address.into(),
|
||||
validators: details.validators.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq, Eq)]
|
||||
pub struct SupportedNetworks {
|
||||
networks: HashMap<Network, NetworkDetails>,
|
||||
}
|
||||
@@ -86,53 +122,13 @@ impl SupportedNetworks {
|
||||
|
||||
for network in support {
|
||||
match network {
|
||||
Network::MAINNET => networks.insert(
|
||||
Network::MAINNET,
|
||||
NetworkDetails {
|
||||
bech32_prefix: String::from(mainnet::BECH32_PREFIX),
|
||||
denom: String::from(mainnet::DENOM),
|
||||
mixnet_contract_address: String::from(mainnet::MIXNET_CONTRACT_ADDRESS),
|
||||
vesting_contract_address: String::from(mainnet::VESTING_CONTRACT_ADDRESS),
|
||||
bandwidth_claim_contract_address: String::from(
|
||||
mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
),
|
||||
rewarding_validator_address: String::from(
|
||||
mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
),
|
||||
validators: mainnet::validators(),
|
||||
},
|
||||
),
|
||||
|
||||
Network::SANDBOX => networks.insert(
|
||||
Network::SANDBOX,
|
||||
NetworkDetails {
|
||||
bech32_prefix: String::from(sandbox::BECH32_PREFIX),
|
||||
denom: String::from(sandbox::DENOM),
|
||||
mixnet_contract_address: String::from(sandbox::MIXNET_CONTRACT_ADDRESS),
|
||||
vesting_contract_address: String::from(sandbox::VESTING_CONTRACT_ADDRESS),
|
||||
bandwidth_claim_contract_address: String::from(
|
||||
sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
),
|
||||
rewarding_validator_address: String::from(
|
||||
sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
),
|
||||
validators: sandbox::validators(),
|
||||
},
|
||||
),
|
||||
Network::QA => networks.insert(
|
||||
Network::QA,
|
||||
NetworkDetails {
|
||||
bech32_prefix: String::from(qa::BECH32_PREFIX),
|
||||
denom: String::from(qa::DENOM),
|
||||
mixnet_contract_address: String::from(qa::MIXNET_CONTRACT_ADDRESS),
|
||||
vesting_contract_address: String::from(qa::VESTING_CONTRACT_ADDRESS),
|
||||
bandwidth_claim_contract_address: String::from(
|
||||
qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS,
|
||||
),
|
||||
rewarding_validator_address: String::from(qa::REWARDING_VALIDATOR_ADDRESS),
|
||||
validators: qa::validators(),
|
||||
},
|
||||
),
|
||||
Network::MAINNET => {
|
||||
networks.insert(Network::MAINNET, MAINNET_DEFAULTS.deref().into())
|
||||
}
|
||||
Network::SANDBOX => {
|
||||
networks.insert(Network::SANDBOX, SANDBOX_DEFAULTS.deref().into())
|
||||
}
|
||||
Network::QA => networks.insert(Network::QA, QA_DEFAULTS.deref().into()),
|
||||
};
|
||||
}
|
||||
SupportedNetworks { networks }
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
||||
@@ -9,65 +11,80 @@ pub mod mainnet;
|
||||
pub mod qa;
|
||||
pub mod sandbox;
|
||||
|
||||
// The set of defaults that are decided at compile time. Ideally we want to reduce these to a
|
||||
// minimum.
|
||||
// Keep DENOM around mostly for use in contracts. (TODO: consider moving it there, or renaming?)
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(network = "mainnet")] {
|
||||
pub const BECH32_PREFIX: &str = mainnet::BECH32_PREFIX;
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::MAINNET;
|
||||
pub const DENOM: &str = mainnet::DENOM;
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = mainnet::MIXNET_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = mainnet::VESTING_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = mainnet::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = mainnet::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_REWARDING_VALIDATOR_ADDRESS: &str = mainnet::REWARDING_VALIDATOR_ADDRESS;
|
||||
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
mainnet::validators()
|
||||
}
|
||||
|
||||
pub fn default_network() -> all::Network {
|
||||
all::Network::MAINNET
|
||||
}
|
||||
} else if #[cfg(network = "qa")] {
|
||||
pub const BECH32_PREFIX: &str = qa::BECH32_PREFIX;
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::QA;
|
||||
pub const DENOM: &str = qa::DENOM;
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = qa::MIXNET_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = qa::VESTING_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = qa::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = qa::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_REWARDING_VALIDATOR: &str = qa::REWARDING_VALIDATOR_ADDRESS;
|
||||
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
qa::validators()
|
||||
}
|
||||
|
||||
pub fn default_network() -> all::Network {
|
||||
all::Network::QA
|
||||
}
|
||||
} else if #[cfg(network = "sandbox")] {
|
||||
pub const BECH32_PREFIX: &str = sandbox::BECH32_PREFIX;
|
||||
pub const DEFAULT_NETWORK: all::Network = all::Network::SANDBOX;
|
||||
pub const DENOM: &str = sandbox::DENOM;
|
||||
|
||||
pub const DEFAULT_MIXNET_CONTRACT_ADDRESS: &str = sandbox::MIXNET_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_VESTING_CONTRACT_ADDRESS: &str = sandbox::VESTING_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS: &str = sandbox::BANDWIDTH_CLAIM_CONTRACT_ADDRESS;
|
||||
pub const ETH_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_CONTRACT_ADDRESS;
|
||||
pub const ETH_ERC20_CONTRACT_ADDRESS: [u8; 20] = sandbox::_ETH_ERC20_CONTRACT_ADDRESS;
|
||||
pub const DEFAULT_REWARDING_VALIDATOR: &str = sandbox::REWARDING_VALIDATOR_ADDRESS;
|
||||
|
||||
pub fn default_validators() -> Vec<ValidatorDetails> {
|
||||
sandbox::validators()
|
||||
}
|
||||
|
||||
pub fn default_network() -> all::Network {
|
||||
all::Network::SANDBOX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
// Since these are lazily constructed, we can afford to switch some of them to stronger types in the
|
||||
// future. If we do this, and also get rid of the references we could potentially unify with
|
||||
// `NetworkDetails`.
|
||||
#[derive(Debug)]
|
||||
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,
|
||||
rewarding_validator_address: &'a str,
|
||||
validators: Vec<ValidatorDetails>,
|
||||
}
|
||||
|
||||
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,
|
||||
rewarding_validator_address: mainnet::REWARDING_VALIDATOR_ADDRESS,
|
||||
validators: mainnet::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,
|
||||
rewarding_validator_address: sandbox::REWARDING_VALIDATOR_ADDRESS,
|
||||
validators: sandbox::validators(),
|
||||
});
|
||||
|
||||
static QA_DEFAULTS: Lazy<DefaultNetworkDetails<'static>> = Lazy::new(|| DefaultNetworkDetails {
|
||||
bech32_prefix: qa::BECH32_PREFIX,
|
||||
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,
|
||||
rewarding_validator_address: qa::REWARDING_VALIDATOR_ADDRESS,
|
||||
validators: qa::validators(),
|
||||
});
|
||||
|
||||
#[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
|
||||
pub nymd_url: String,
|
||||
@@ -99,15 +116,15 @@ impl ValidatorDetails {
|
||||
}
|
||||
|
||||
pub fn default_nymd_endpoints() -> Vec<Url> {
|
||||
default_validators()
|
||||
.iter()
|
||||
DEFAULT_NETWORK
|
||||
.validators()
|
||||
.map(|validator| validator.nymd_url())
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn default_api_endpoints() -> Vec<Url> {
|
||||
default_validators()
|
||||
.iter()
|
||||
DEFAULT_NETWORK
|
||||
.validators()
|
||||
.filter_map(|validator| validator.api_url())
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -7,9 +7,9 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rand = {version = "0.7.3", features = ["wasm-bindgen"]}
|
||||
rand = { version = "0.7.3", features = ["wasm-bindgen"] }
|
||||
|
||||
crypto = { path = "../../crypto" }
|
||||
crypto = { path = "../../crypto", features = ["symmetric", "rand"] }
|
||||
nymsphinx-addressing = { path = "../addressing" }
|
||||
nymsphinx-params = { path = "../params" }
|
||||
nymsphinx-types = { path = "../types" }
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::AckKey;
|
||||
use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, NewCipher};
|
||||
use crypto::symmetric::stream_cipher::{self, encrypt, iv_from_slice, random_iv, IvSizeUser};
|
||||
use nymsphinx_params::{
|
||||
packet_sizes::PacketSize, AckEncryptionAlgorithm, SerializedFragmentIdentifier, FRAG_ID_LEN,
|
||||
};
|
||||
@@ -33,7 +32,7 @@ pub fn recover_identifier(
|
||||
return None;
|
||||
}
|
||||
|
||||
let iv_size = <AckEncryptionAlgorithm as NewCipher>::NonceSize::to_usize();
|
||||
let iv_size = AckEncryptionAlgorithm::iv_size();
|
||||
let iv = iv_from_slice::<AckEncryptionAlgorithm>(&iv_id_ciphertext[..iv_size]);
|
||||
|
||||
let id = stream_cipher::decrypt::<AckEncryptionAlgorithm>(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::{typenum::Unsigned, GenericArray};
|
||||
use crypto::symmetric::stream_cipher::{generate_key, CipherKey, NewCipher};
|
||||
use crypto::symmetric::stream_cipher::{generate_key, CipherKey, KeySizeUser};
|
||||
use nymsphinx_params::AckEncryptionAlgorithm;
|
||||
use pemstore::traits::PemStorableKey;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
@@ -33,11 +32,14 @@ impl AckKey {
|
||||
}
|
||||
|
||||
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, AckKeyConversionError> {
|
||||
if bytes.len() != <AckEncryptionAlgorithm as NewCipher>::KeySize::to_usize() {
|
||||
if bytes.len() != AckEncryptionAlgorithm::key_size() {
|
||||
return Err(AckKeyConversionError::BytesOfInvalidLengthError);
|
||||
}
|
||||
|
||||
Ok(AckKey(GenericArray::clone_from_slice(bytes)))
|
||||
// Ok(AckKey(GenericArray::clone_from_slice(bytes)))
|
||||
Ok(AckKey(
|
||||
CipherKey::<AckEncryptionAlgorithm>::clone_from_slice(bytes),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
|
||||
@@ -7,7 +7,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crypto = { path = "../../crypto" } # all addresses are expressed in terms on their crypto keys
|
||||
crypto = { path = "../../crypto", features = ["asymmetric"] } # all addresses are expressed in terms on their crypto keys
|
||||
nymsphinx-types = { path = "../types" } # we need to be able to refer to some types defined inside sphinx crate
|
||||
serde = "1.0" # implementing serialization/deserialization for some types, like `Recipient`
|
||||
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use crypto::generic_array::typenum::Unsigned;
|
||||
use crypto::{
|
||||
crypto_hash,
|
||||
generic_array::GenericArray,
|
||||
symmetric::stream_cipher::{generate_key, CipherKey, NewCipher},
|
||||
Digest,
|
||||
generic_array::{typenum::Unsigned, GenericArray},
|
||||
symmetric::stream_cipher::{generate_key, CipherKey, KeySizeUser},
|
||||
OutputSizeUser,
|
||||
};
|
||||
use nymsphinx_params::{ReplySurbEncryptionAlgorithm, ReplySurbKeyDigestAlgorithm};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
|
||||
pub type EncryptionKeyDigest =
|
||||
GenericArray<u8, <ReplySurbKeyDigestAlgorithm as Digest>::OutputSize>;
|
||||
GenericArray<u8, <ReplySurbKeyDigestAlgorithm as OutputSizeUser>::OutputSize>;
|
||||
|
||||
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as NewCipher>::KeySize;
|
||||
pub type SurbEncryptionKeySize = <ReplySurbEncryptionAlgorithm as KeySizeUser>::KeySize;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SurbEncryptionKey(CipherKey<ReplySurbEncryptionAlgorithm>);
|
||||
@@ -45,7 +44,7 @@ impl SurbEncryptionKey {
|
||||
}
|
||||
|
||||
pub fn try_from_bytes(bytes: &[u8]) -> Result<Self, SurbEncryptionKeyError> {
|
||||
if bytes.len() != SurbEncryptionKeySize::to_usize() {
|
||||
if bytes.len() != SurbEncryptionKeySize::USIZE {
|
||||
return Err(SurbEncryptionKeyError::BytesOfInvalidLengthError);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod encryption_key;
|
||||
pub mod reply_surb;
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::encryption_key::{
|
||||
SurbEncryptionKey, SurbEncryptionKeyError, SurbEncryptionKeySize, Unsigned,
|
||||
};
|
||||
use crypto::Digest;
|
||||
use crate::encryption_key::{SurbEncryptionKey, SurbEncryptionKeyError, SurbEncryptionKeySize};
|
||||
use crypto::{generic_array::typenum::Unsigned, Digest};
|
||||
use nymsphinx_addressing::clients::Recipient;
|
||||
use nymsphinx_addressing::nodes::{NymNodeRoutingAddress, MAX_NODE_ADDRESS_UNPADDED_LEN};
|
||||
use nymsphinx_params::packet_sizes::PacketSize;
|
||||
@@ -65,7 +63,7 @@ pub struct ReplySurb {
|
||||
// Serialize + Deserialize is not really used anymore (it was for a CBOR experiment)
|
||||
// however, if we decided we needed it again, it's already here
|
||||
impl Serialize for ReplySurb {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
@@ -139,7 +137,7 @@ impl ReplySurb {
|
||||
|
||||
// the SURB itself consists of SURB_header, first hop address and set of payload keys
|
||||
// (note extra 1 for the gateway)
|
||||
SurbEncryptionKeySize::to_usize()
|
||||
SurbEncryptionKeySize::USIZE
|
||||
+ HEADER_SIZE
|
||||
+ NODE_ADDRESS_LENGTH
|
||||
+ (1 + mix_hops as usize) * PAYLOAD_KEY_SIZE
|
||||
@@ -160,9 +158,9 @@ impl ReplySurb {
|
||||
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, ReplySurbError> {
|
||||
let encryption_key =
|
||||
SurbEncryptionKey::try_from_bytes(&bytes[..SurbEncryptionKeySize::to_usize()])?;
|
||||
SurbEncryptionKey::try_from_bytes(&bytes[..SurbEncryptionKeySize::USIZE])?;
|
||||
|
||||
let surb = match SURB::from_bytes(&bytes[SurbEncryptionKeySize::to_usize()..]) {
|
||||
let surb = match SURB::from_bytes(&bytes[SurbEncryptionKeySize::USIZE..]) {
|
||||
Err(err) => return Err(ReplySurbError::RecoveryError(err)),
|
||||
Ok(surb) => surb,
|
||||
};
|
||||
|
||||
@@ -7,5 +7,5 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
crypto = { path = "../../crypto" }
|
||||
crypto = { path = "../../crypto", features = ["hashing", "symmetric"] }
|
||||
nymsphinx-types = { path = "../types" }
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::aes::Aes128Ctr;
|
||||
use crypto::aes::Aes128;
|
||||
use crypto::blake3;
|
||||
use crypto::ctr;
|
||||
|
||||
type Aes128Ctr = ctr::Ctr64LE<Aes128>;
|
||||
|
||||
// Re-export for ease of use
|
||||
pub use packet_modes::PacketMode;
|
||||
|
||||
Generated
+5
-39
@@ -27,12 +27,6 @@ version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
@@ -90,21 +84,6 @@ dependencies = [
|
||||
"opaque-debug 0.2.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake3"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "526c210b4520e416420759af363083471656e819a75e831b8d2c9d5a584f2413"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"constant_time_eq",
|
||||
"crypto-mac 0.11.1",
|
||||
"digest 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.7.3"
|
||||
@@ -230,12 +209,6 @@ version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "contracts-common"
|
||||
version = "0.1.0"
|
||||
@@ -320,17 +293,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
name = "crypto"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"blake3",
|
||||
"bs58",
|
||||
"cipher",
|
||||
"config",
|
||||
"digest 0.9.0",
|
||||
"ed25519-dalek",
|
||||
"generic-array 0.14.5",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"log",
|
||||
"nymsphinx-types",
|
||||
"pemstore",
|
||||
"rand",
|
||||
@@ -450,9 +415,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ed25519"
|
||||
version = "1.3.0"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816"
|
||||
checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39"
|
||||
dependencies = [
|
||||
"signature",
|
||||
]
|
||||
@@ -881,6 +846,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"hex-literal",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"url",
|
||||
@@ -1676,9 +1642,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zeroize_derive"
|
||||
version = "1.2.2"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73"
|
||||
checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -35,7 +35,7 @@ cosmwasm-schema = "1.0.0-beta3"
|
||||
fixed = "1.1"
|
||||
rand_chacha = "0.2"
|
||||
rand = "0.7"
|
||||
crypto = { path = "../../common/crypto" }
|
||||
crypto = { path = "../../common/crypto", features = ["asymmetric", "rand"] }
|
||||
|
||||
[build-dependencies]
|
||||
vergen = { version = "5", default-features = false, features = ["build", "git", "rustc"] }
|
||||
|
||||
@@ -335,7 +335,7 @@ pub fn migrate(_deps: DepsMut<'_>, _env: Env, _msg: MigrateMsg) -> Result<Respon
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::support::tests;
|
||||
use config::defaults::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;
|
||||
@@ -345,7 +345,7 @@ pub mod tests {
|
||||
let mut deps = mock_dependencies();
|
||||
let env = mock_env();
|
||||
let msg = InstantiateMsg {
|
||||
rewarding_validator_address: config::defaults::DEFAULT_REWARDING_VALIDATOR.to_string(),
|
||||
rewarding_validator_address: DEFAULT_NETWORK.rewarding_validator_address().to_string(),
|
||||
};
|
||||
let info = mock_info("creator", &[]);
|
||||
|
||||
|
||||
@@ -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::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;
|
||||
@@ -83,7 +83,7 @@ pub mod test_helpers {
|
||||
pub fn init_contract() -> OwnedDeps<MemoryStorage, MockApi, MockQuerier<Empty>> {
|
||||
let mut deps = mock_dependencies();
|
||||
let msg = InstantiateMsg {
|
||||
rewarding_validator_address: config::defaults::DEFAULT_REWARDING_VALIDATOR.to_string(),
|
||||
rewarding_validator_address: DEFAULT_NETWORK.rewarding_validator_address().to_string(),
|
||||
};
|
||||
let env = mock_env();
|
||||
let info = mock_info("creator", &[]);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
use network_defaults::{
|
||||
default_api_endpoints, default_network, default_nymd_endpoints, DEFAULT_MIXNET_CONTRACT_ADDRESS,
|
||||
};
|
||||
use network_defaults::{default_api_endpoints, default_nymd_endpoints, DEFAULT_NETWORK};
|
||||
use validator_client::nymd::QueryNymdClient;
|
||||
|
||||
pub(crate) fn new_nymd_client() -> validator_client::Client<QueryNymdClient> {
|
||||
let network = default_network();
|
||||
let mixnet_contract = DEFAULT_MIXNET_CONTRACT_ADDRESS.to_string();
|
||||
let network = DEFAULT_NETWORK;
|
||||
let mixnet_contract = network.mixnet_contract_address().to_string();
|
||||
let nymd_url = default_nymd_endpoints()[0].clone();
|
||||
let api_url = default_api_endpoints()[0].clone();
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crypto::generic_array::{typenum::Unsigned, GenericArray};
|
||||
use crypto::symmetric::stream_cipher::{random_iv, NewCipher, IV as CryptoIV};
|
||||
use crypto::symmetric::stream_cipher::{random_iv, IvSizeUser, IV as CryptoIV};
|
||||
use nymsphinx::params::GatewayEncryptionAlgorithm;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use thiserror::Error;
|
||||
|
||||
type NonceSize = <GatewayEncryptionAlgorithm as NewCipher>::NonceSize;
|
||||
type NonceSize = <GatewayEncryptionAlgorithm as IvSizeUser>::IvSize;
|
||||
|
||||
// I think 'IV' looks better than 'Iv', feel free to change that.
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub use crypto::generic_array;
|
||||
use crypto::hmac::{hmac::Mac, HmacOutput};
|
||||
use crypto::hmac::HmacOutput;
|
||||
use crypto::OutputSizeUser;
|
||||
use nymsphinx::params::GatewayIntegrityHmacAlgorithm;
|
||||
pub use types::*;
|
||||
|
||||
@@ -15,4 +16,4 @@ pub type GatewayMac = HmacOutput<GatewayIntegrityHmacAlgorithm>;
|
||||
|
||||
// TODO: could using `Mac` trait here for OutputSize backfire?
|
||||
// Should hmac itself be exposed, imported and used instead?
|
||||
pub type GatewayMacSize = <GatewayIntegrityHmacAlgorithm as Mac>::OutputSize;
|
||||
pub type GatewayMacSize = <GatewayIntegrityHmacAlgorithm as OutputSizeUser>::OutputSize;
|
||||
|
||||
@@ -7,7 +7,7 @@ use crypto::generic_array::{
|
||||
GenericArray,
|
||||
};
|
||||
use crypto::hmac::{compute_keyed_hmac, recompute_keyed_hmac_and_verify_tag};
|
||||
use crypto::symmetric::stream_cipher::{self, CipherKey, NewCipher, IV};
|
||||
use crypto::symmetric::stream_cipher::{self, CipherKey, KeySizeUser, IV};
|
||||
use nymsphinx::params::{GatewayEncryptionAlgorithm, GatewayIntegrityHmacAlgorithm};
|
||||
use pemstore::traits::PemStorableKey;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
@@ -17,7 +17,7 @@ pub type SharedKeySize = Sum<EncryptionKeySize, MacKeySize>;
|
||||
|
||||
// we're using 16 byte long key in sphinx, so let's use the same one here
|
||||
type MacKeySize = U16;
|
||||
type EncryptionKeySize = <GatewayEncryptionAlgorithm as NewCipher>::KeySize;
|
||||
type EncryptionKeySize = <GatewayEncryptionAlgorithm as KeySizeUser>::KeySize;
|
||||
|
||||
/// Shared key used when computing MAC for messages exchanged between client and its gateway.
|
||||
pub type MacKey = GenericArray<u8, MacKeySize>;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use bip39::core::str::FromStr;
|
||||
use bip39::Mnemonic;
|
||||
use config::defaults::DEFAULT_NETWORK;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
use url::Url;
|
||||
@@ -19,10 +20,7 @@ use bandwidth_claim_contract::payment::LinkPaymentData;
|
||||
use credentials::token::bandwidth::TokenCredential;
|
||||
use crypto::asymmetric::identity::{PublicKey, Signature, SIGNATURE_LENGTH};
|
||||
use gateway_client::bandwidth::eth_contract;
|
||||
use network_defaults::{
|
||||
DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS, DEFAULT_MIXNET_CONTRACT_ADDRESS, ETH_EVENT_NAME,
|
||||
ETH_MIN_BLOCK_DEPTH,
|
||||
};
|
||||
use network_defaults::{ETH_EVENT_NAME, ETH_MIN_BLOCK_DEPTH};
|
||||
use validator_client::nymd::{AccountId, NymdClient, SigningNymdClient};
|
||||
|
||||
pub(crate) struct ERC20Bridge {
|
||||
@@ -42,11 +40,11 @@ impl ERC20Bridge {
|
||||
let mnemonic =
|
||||
Mnemonic::from_str(&cosmos_mnemonic).expect("Invalid Cosmos mnemonic provided");
|
||||
let nymd_client = NymdClient::connect_with_mnemonic(
|
||||
config::defaults::default_network(),
|
||||
DEFAULT_NETWORK,
|
||||
nymd_url.as_ref(),
|
||||
AccountId::from_str(DEFAULT_MIXNET_CONTRACT_ADDRESS).ok(),
|
||||
AccountId::from_str(DEFAULT_NETWORK.mixnet_contract_address()).ok(),
|
||||
None,
|
||||
AccountId::from_str(DEFAULT_BANDWIDTH_CLAIM_CONTRACT_ADDRESS).ok(),
|
||||
AccountId::from_str(DEFAULT_NETWORK.bandwidth_claim_contract_address()).ok(),
|
||||
mnemonic,
|
||||
None,
|
||||
)
|
||||
|
||||
Generated
+883
-1023
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,7 @@
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"bs58": "^4.0.1",
|
||||
"clsx": "^1.1.1",
|
||||
"date-fns": "^2.28.0",
|
||||
"notistack": "^2.0.3",
|
||||
"qrcode.react": "^1.0.1",
|
||||
"react": "^17.0.2",
|
||||
@@ -38,8 +39,8 @@
|
||||
"@babel/preset-env": "^7.15.0",
|
||||
"@babel/preset-react": "^7.14.5",
|
||||
"@svgr/webpack": "^6.1.1",
|
||||
"@tauri-apps/api": "^1.0.0-beta.6",
|
||||
"@tauri-apps/cli": "^1.0.0-beta.9",
|
||||
"@tauri-apps/api": "^1.0.0-rc.1",
|
||||
"@tauri-apps/cli": "^1.0.0-rc.5",
|
||||
"@types/bs58": "^4.0.1",
|
||||
"@types/qrcode.react": "^1.0.2",
|
||||
"@types/react-router-dom": "^5.1.8",
|
||||
|
||||
@@ -8,26 +8,34 @@ repository = ""
|
||||
default-run = "nym_wallet"
|
||||
edition = "2021"
|
||||
build = "src/build.rs"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.58"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1.0.0-beta.4" }
|
||||
tauri-build = { version = "=1.0.0-rc.2", features = [] }
|
||||
|
||||
tauri-codegen = "=1.0.0-rc.1"
|
||||
tauri-macros = "=1.0.0-rc.1"
|
||||
|
||||
[dependencies]
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
strum = { version = "0.23", features = ["derive"] }
|
||||
tauri = { version = "1.0.0-beta.8", features = ["shell-open"] }
|
||||
tokio = { version = "1.10", features = ["sync"] }
|
||||
dirs = "4.0"
|
||||
bip39 = "1.0"
|
||||
thiserror = "1.0"
|
||||
tendermint-rpc = "0.23.0"
|
||||
url = "2.2"
|
||||
rand = "0.6.5"
|
||||
dirs = "4.0"
|
||||
eyre = "0.6.5"
|
||||
rand = "0.6.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
strum = { version = "0.23", features = ["derive"] }
|
||||
tauri = { version = "=1.0.0-rc.2", features = [
|
||||
"clipboard-all",
|
||||
"shell-open",
|
||||
"window-maximize",
|
||||
] }
|
||||
tendermint-rpc = "0.23.0"
|
||||
thiserror = "1.0"
|
||||
tokio = { version = "1.10", features = ["sync"] }
|
||||
toml = "0.5.8"
|
||||
url = "2.2"
|
||||
|
||||
aes-gcm = "0.9.4"
|
||||
argon2 = { version = "0.3.2", features = ["std"] }
|
||||
@@ -45,26 +53,13 @@ vesting-contract-common = { path = "../../common/cosmwasm-smart-contracts/vestin
|
||||
config = { path = "../../common/config" }
|
||||
coconut-interface = { path = "../../common/coconut-interface" }
|
||||
credentials = { path = "../../common/credentials" }
|
||||
|
||||
# Used for Type conversion, can be extracted but its a lot of work
|
||||
vesting-contract = { path = "../../contracts/vesting" }
|
||||
|
||||
[dev-dependencies]
|
||||
ts-rs = "5.1"
|
||||
ts-rs = "6.1.2"
|
||||
tempfile = "3.3.0"
|
||||
|
||||
[dev-dependencies.mixnet-contract-common]
|
||||
path = "../../common/cosmwasm-smart-contracts/mixnet-contract"
|
||||
features = ["ts-rs"]
|
||||
|
||||
[dev-dependencies.validator-client]
|
||||
path = "../../common/client-libs/validator-client"
|
||||
features = ["typescript-types"]
|
||||
|
||||
[dev-dependencies.vesting-contract-common]
|
||||
path = "../../common/cosmwasm-smart-contracts/vesting-contract"
|
||||
features = ["ts-rs"]
|
||||
|
||||
[features]
|
||||
default = ["custom-protocol"]
|
||||
custom-protocol = ["tauri/custom-protocol"]
|
||||
|
||||
@@ -14,6 +14,7 @@ use strum::IntoEnumIterator;
|
||||
use validator_client::nymd::{CosmosCoin, GasPrice};
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export, export_to = "../src/types/rust/denom.ts"))]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||
pub enum Denom {
|
||||
Major,
|
||||
@@ -48,6 +49,7 @@ impl TryFrom<CosmosDenom> for Denom {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/coin.ts"))]
|
||||
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
|
||||
pub struct Coin {
|
||||
amount: String,
|
||||
|
||||
@@ -1,34 +1,37 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::network::Network;
|
||||
use config::defaults::all::SupportedNetworks;
|
||||
use crate::network::Network as WalletNetwork;
|
||||
use config::defaults::{all::SupportedNetworks, ValidatorDetails};
|
||||
use config::NymConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::{fs, io, path::PathBuf};
|
||||
use strum::IntoEnumIterator;
|
||||
use url::Url;
|
||||
|
||||
mod template;
|
||||
|
||||
use template::config_template;
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
// Base configuration is not part of the configuration file as it's not intended to be changed.
|
||||
#[serde(skip)]
|
||||
base: Base,
|
||||
|
||||
// Network level configuration
|
||||
network: Network,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Base {
|
||||
struct Base {
|
||||
/// Information on all the networks that the wallet connects to.
|
||||
networks: SupportedNetworks,
|
||||
}
|
||||
|
||||
impl Default for Base {
|
||||
fn default() -> Self {
|
||||
let networks = Network::iter().map(|network| network.into()).collect();
|
||||
let networks = WalletNetwork::iter()
|
||||
.map(|network| network.into())
|
||||
.collect();
|
||||
Base {
|
||||
networks: SupportedNetworks::new(networks),
|
||||
}
|
||||
@@ -37,7 +40,8 @@ impl Default for Base {
|
||||
|
||||
impl NymConfig for Config {
|
||||
fn template() -> &'static str {
|
||||
config_template()
|
||||
// For now we're not using a template
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
fn default_root_directory() -> PathBuf {
|
||||
@@ -58,10 +62,32 @@ impl NymConfig for Config {
|
||||
fn data_directory(&self) -> PathBuf {
|
||||
self.root_directory().join("data")
|
||||
}
|
||||
|
||||
fn save_to_file(&self, custom_location: Option<PathBuf>) -> io::Result<()> {
|
||||
let config_toml = toml::to_string_pretty(&self)
|
||||
.map_err(|toml_err| io::Error::new(io::ErrorKind::Other, toml_err))?;
|
||||
|
||||
// Make sure the whole directory structure actually exists
|
||||
match custom_location.clone() {
|
||||
Some(loc) => {
|
||||
if let Some(parent_dir) = loc.parent() {
|
||||
fs::create_dir_all(parent_dir)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
None => fs::create_dir_all(self.config_directory()),
|
||||
}?;
|
||||
|
||||
fs::write(
|
||||
custom_location.unwrap_or_else(|| self.config_directory().join(Self::config_file_name())),
|
||||
config_toml,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn get_nymd_validator_url(&self, network: Network) -> Url {
|
||||
pub fn get_nymd_validator_url(&self, network: WalletNetwork) -> Url {
|
||||
// TODO make this a random choice
|
||||
if let Some(Some(validator_details)) = self
|
||||
.base
|
||||
@@ -75,7 +101,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_validator_api_url(&self, network: Network) -> Url {
|
||||
pub fn get_validator_api_url(&self, network: WalletNetwork) -> Url {
|
||||
// TODO make this a random choice
|
||||
if let Some(Some(validator_details)) = self
|
||||
.base
|
||||
@@ -89,7 +115,7 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_mixnet_contract_address(&self, network: Network) -> Option<cosmrs::AccountId> {
|
||||
pub fn get_mixnet_contract_address(&self, network: WalletNetwork) -> Option<cosmrs::AccountId> {
|
||||
self
|
||||
.base
|
||||
.networks
|
||||
@@ -99,7 +125,7 @@ impl Config {
|
||||
.ok()
|
||||
}
|
||||
|
||||
pub fn get_vesting_contract_address(&self, network: Network) -> Option<cosmrs::AccountId> {
|
||||
pub fn get_vesting_contract_address(&self, network: WalletNetwork) -> Option<cosmrs::AccountId> {
|
||||
self
|
||||
.base
|
||||
.networks
|
||||
@@ -111,7 +137,7 @@ impl Config {
|
||||
|
||||
pub fn get_bandwidth_claim_contract_address(
|
||||
&self,
|
||||
network: Network,
|
||||
network: WalletNetwork,
|
||||
) -> Option<cosmrs::AccountId> {
|
||||
self
|
||||
.base
|
||||
@@ -122,3 +148,64 @@ impl Config {
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Network {
|
||||
// User supplied additional validator urls in addition to the hardcoded ones.
|
||||
// NOTE: these are separate fields, rather than a map, to force the serialization order.
|
||||
mainnet: Option<Vec<ValidatorDetails>>,
|
||||
sandbox: Option<Vec<ValidatorDetails>>,
|
||||
qa: Option<Vec<ValidatorDetails>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use config::defaults::all::Network as NetworkConfig;
|
||||
|
||||
fn test_config() -> Config {
|
||||
Config {
|
||||
base: Base::default(),
|
||||
network: Network {
|
||||
mainnet: Some(vec![
|
||||
// Add the default one, although the hardcoded default isn't intended to be included in
|
||||
// the config file.
|
||||
NetworkConfig::MAINNET.validators().next().unwrap().clone(),
|
||||
// An additional one
|
||||
ValidatorDetails {
|
||||
nymd_url: "https://42".to_string(),
|
||||
api_url: None,
|
||||
},
|
||||
]),
|
||||
sandbox: Some(NetworkConfig::SANDBOX.validators().cloned().collect()),
|
||||
qa: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_to_toml() {
|
||||
assert_eq!(
|
||||
toml::to_string_pretty(&test_config()).unwrap(),
|
||||
r#"[[network.mainnet]]
|
||||
nymd_url = 'https://rpc.nyx.nodes.guru/'
|
||||
api_url = 'https://api.nyx.nodes.guru/'
|
||||
|
||||
[[network.mainnet]]
|
||||
nymd_url = 'https://42'
|
||||
|
||||
[[network.sandbox]]
|
||||
nymd_url = 'https://sandbox-validator.nymtech.net'
|
||||
api_url = 'https://sandbox-validator.nymtech.net/api'
|
||||
"#
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn serialize_and_deserialize_to_toml() {
|
||||
let config = test_config();
|
||||
let config_str = toml::to_string_pretty(&config).unwrap();
|
||||
let config_from_toml = toml::from_str(&config_str).unwrap();
|
||||
assert_eq!(config, config_from_toml);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub(crate) fn config_template() -> &'static str {
|
||||
r#"
|
||||
# This is a TOML config file.
|
||||
# For more information, see https://github.com/toml-lang/toml
|
||||
|
||||
##### main base tauri-wallet config options #####
|
||||
|
||||
[base]
|
||||
|
||||
# Validator server to which the API will be getting information about the network.
|
||||
validator_url = '{{ base.validator_url }}'
|
||||
|
||||
"#
|
||||
}
|
||||
@@ -86,33 +86,3 @@ fn main() {
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
ts_rs::export! {
|
||||
mixnet_contract_common::MixNode => "../src/types/rust/mixnode.ts",
|
||||
crate::coin::Coin => "../src/types/rust/coin.ts",
|
||||
crate::network::Network => "../src/types/rust/network.ts",
|
||||
crate::mixnet::account::Balance => "../src/types/rust/balance.ts",
|
||||
mixnet_contract_common::Gateway => "../src/types/rust/gateway.ts",
|
||||
crate::mixnet::send::TauriTxResult => "../src/types/rust/tauritxresult.ts",
|
||||
crate::mixnet::send::TransactionDetails => "../src/types/rust/transactiondetails.ts",
|
||||
validator_client::nymd::fee::helpers::Operation => "../src/types/rust/operation.ts",
|
||||
crate::coin::Denom => "../src/types/rust/denom.ts",
|
||||
crate::utils::DelegationResult => "../src/types/rust/delegationresult.ts",
|
||||
crate::mixnet::account::Account => "../src/types/rust/account.ts",
|
||||
crate::mixnet::account::CreatedAccount => "../src/types/rust/createdaccount.ts",
|
||||
crate::mixnet::admin::TauriContractStateParams => "../src/types/rust/stateparams.ts",
|
||||
validator_client::models::CoreNodeStatusResponse => "../src/types/corenodestatusresponse.ts",
|
||||
validator_client::models::MixnodeStatus => "../src/types/rust/mixnodestatus.ts",
|
||||
validator_client::models::MixnodeStatusResponse => "../src/types/rust/mixnodestatusresponse.ts",
|
||||
validator_client::models::RewardEstimationResponse => "../src/types/rust/rewardestimationresponse.ts",
|
||||
validator_client::models::StakeSaturationResponse => "../src/types/rust/stakesaturaionresponse.ts",
|
||||
validator_client::models::InclusionProbabilityResponse => "../src/types/rust/inclusionprobabilityresponse.ts",
|
||||
vesting_contract_common::Period => "../src/types/rust/period.ts",
|
||||
crate::vesting::PledgeData => "../src/types/rust/pledgedata.ts",
|
||||
crate::vesting::OriginalVestingResponse => "../src/types/rust/originalvestingresponse.ts",
|
||||
crate::vesting::VestingAccountInfo => "../src/types/rust/vestingaccountinfo.ts",
|
||||
crate::vesting::VestingPeriod => "../src/types/rust/vestingperiod.ts",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use config::defaults::{mainnet, qa, sandbox};
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/network.ts"))]
|
||||
#[derive(Copy, Clone, Debug, Deserialize, EnumIter, Eq, Hash, PartialEq, Serialize)]
|
||||
pub enum Network {
|
||||
QA,
|
||||
|
||||
@@ -13,6 +13,7 @@ use strum::IntoEnumIterator;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/account.ts"))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Account {
|
||||
contract_address: String,
|
||||
@@ -31,6 +32,7 @@ impl Account {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/createdaccount.ts"))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CreatedAccount {
|
||||
account: Account,
|
||||
@@ -38,6 +40,7 @@ pub struct CreatedAccount {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/balance.ts"))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Balance {
|
||||
coin: Coin,
|
||||
@@ -129,7 +132,7 @@ async fn _connect_with_mnemonic(
|
||||
mnemonic: Mnemonic,
|
||||
state: tauri::State<'_, Arc<RwLock<State>>>,
|
||||
) -> Result<Account, BackendError> {
|
||||
let default_network = Network::try_from(config::defaults::default_network())?;
|
||||
let default_network = Network::try_from(config::defaults::DEFAULT_NETWORK)?;
|
||||
let mut default_account = None;
|
||||
for network in Network::iter() {
|
||||
let client = {
|
||||
@@ -162,6 +165,7 @@ async fn _connect_with_mnemonic(
|
||||
w_state.add_client(network, client);
|
||||
}
|
||||
|
||||
default_account
|
||||
.ok_or_else(|| BackendError::NetworkNotSupported(config::defaults::default_network()))
|
||||
default_account.ok_or(BackendError::NetworkNotSupported(
|
||||
config::defaults::DEFAULT_NETWORK,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/stateparams.ts"))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct TauriContractStateParams {
|
||||
minimum_mixnode_pledge: String,
|
||||
|
||||
@@ -10,6 +10,7 @@ use tokio::sync::RwLock;
|
||||
use validator_client::nymd::{AccountId, CosmosCoin};
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/tauritxresult.ts"))]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct TauriTxResult {
|
||||
block_height: u64,
|
||||
@@ -21,6 +22,10 @@ pub struct TauriTxResult {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../src/types/rust/transactiondetails.ts")
|
||||
)]
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub struct TransactionDetails {
|
||||
amount: Coin,
|
||||
|
||||
@@ -10,6 +10,7 @@ pub mod delegate;
|
||||
pub mod queries;
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/pledgedata.ts"))]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct PledgeData {
|
||||
pub amount: Coin,
|
||||
@@ -32,6 +33,10 @@ impl PledgeData {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../src/types/rust/originalvestingresponse.ts")
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct OriginalVestingResponse {
|
||||
amount: Coin,
|
||||
@@ -50,6 +55,10 @@ impl From<VestingOriginalVestingResponse> for OriginalVestingResponse {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(
|
||||
test,
|
||||
ts(export, export_to = "../src/types/rust/vestingaccountinfo.ts")
|
||||
)]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct VestingAccountInfo {
|
||||
owner_address: String,
|
||||
@@ -76,6 +85,7 @@ impl From<VestingAccount> for VestingAccountInfo {
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/vestingperiod.ts"))]
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct VestingPeriod {
|
||||
start_time: u64,
|
||||
|
||||
@@ -59,6 +59,7 @@ pub async fn outdated_get_approximate_fee(
|
||||
}
|
||||
|
||||
#[cfg_attr(test, derive(ts_rs::TS))]
|
||||
#[cfg_attr(test, ts(export, export_to = "../src/types/rust/delegationresult.ts"))]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct DelegationResult {
|
||||
source_address: String,
|
||||
|
||||
@@ -49,6 +49,12 @@
|
||||
"active": false
|
||||
},
|
||||
"allowlist": {
|
||||
"window": {
|
||||
"maximize": true
|
||||
},
|
||||
"clipboard": {
|
||||
"all": true
|
||||
},
|
||||
"shell": {
|
||||
"open": true
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import { ListItem, ListItemText, Select } from '@mui/material'
|
||||
import React, { useState } from 'react'
|
||||
|
||||
type TPool = 'balance' | 'locked'
|
||||
|
||||
export const TokenPoolSelector: React.FC<{ onSelect: (pool: TPool) => void }> = ({ onSelect }) => {
|
||||
const [value, setValue] = useState<TPool>()
|
||||
|
||||
return (
|
||||
<>
|
||||
<Select label="Token Pool" value={value}>
|
||||
<ListItem>
|
||||
<ListItemText primary="Balance" secondary="123 nymt" />
|
||||
</ListItem>
|
||||
</Select>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -8,7 +8,9 @@ import {
|
||||
getSpendableCoins,
|
||||
getOriginalVesting,
|
||||
getCurrentVestingPeriod,
|
||||
getVestingAccountInfo,
|
||||
} from '../requests'
|
||||
import { VestingAccountInfo } from 'src/types/rust/vestingaccountinfo'
|
||||
|
||||
type TTokenAllocation = {
|
||||
[key in 'vesting' | 'vested' | 'locked' | 'spendable']: Coin['amount']
|
||||
@@ -20,6 +22,7 @@ export type TUseuserBalance = {
|
||||
tokenAllocation?: TTokenAllocation
|
||||
originalVesting?: OriginalVestingResponse
|
||||
currentVestingPeriod?: Period
|
||||
vestingAccountInfo?: VestingAccountInfo
|
||||
isLoading: boolean
|
||||
fetchBalance: () => void
|
||||
clearBalance: () => void
|
||||
@@ -33,6 +36,7 @@ export const useGetBalance = (address?: string): TUseuserBalance => {
|
||||
const [tokenAllocation, setTokenAllocation] = useState<TTokenAllocation>()
|
||||
const [originalVesting, setOriginalVesting] = useState<OriginalVestingResponse>()
|
||||
const [currentVestingPeriod, setCurrentVestingPeriod] = useState<Period>()
|
||||
const [vestingAccountInfo, setVestingAccountInfo] = useState<VestingAccountInfo>()
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
|
||||
const fetchBalance = useCallback(async () => {
|
||||
@@ -54,15 +58,23 @@ export const useGetBalance = (address?: string): TUseuserBalance => {
|
||||
setIsLoading(true)
|
||||
if (address) {
|
||||
try {
|
||||
const [originalVestingValue, vestingCoins, vestedCoins, lockedCoins, spendableCoins, currentVestingPeriod] =
|
||||
await Promise.all([
|
||||
getOriginalVesting(address),
|
||||
getVestingCoins(address),
|
||||
getVestedCoins(address),
|
||||
getLockedCoins(address),
|
||||
getSpendableCoins(address),
|
||||
getCurrentVestingPeriod(address),
|
||||
])
|
||||
const [
|
||||
originalVestingValue,
|
||||
vestingCoins,
|
||||
vestedCoins,
|
||||
lockedCoins,
|
||||
spendableCoins,
|
||||
currentVestingPeriod,
|
||||
vestingAccountInfo,
|
||||
] = await Promise.all([
|
||||
getOriginalVesting(address),
|
||||
getVestingCoins(address),
|
||||
getVestedCoins(address),
|
||||
getLockedCoins(address),
|
||||
getSpendableCoins(address),
|
||||
getCurrentVestingPeriod(address),
|
||||
getVestingAccountInfo(address),
|
||||
])
|
||||
setOriginalVesting(originalVestingValue)
|
||||
setCurrentVestingPeriod(currentVestingPeriod)
|
||||
setTokenAllocation({
|
||||
@@ -71,6 +83,7 @@ export const useGetBalance = (address?: string): TUseuserBalance => {
|
||||
locked: lockedCoins.amount,
|
||||
spendable: spendableCoins.amount,
|
||||
})
|
||||
setVestingAccountInfo(vestingAccountInfo)
|
||||
} catch (e) {
|
||||
clearTokenAllocation()
|
||||
clearOriginalVesting()
|
||||
@@ -110,6 +123,7 @@ export const useGetBalance = (address?: string): TUseuserBalance => {
|
||||
tokenAllocation,
|
||||
originalVesting,
|
||||
currentVestingPeriod,
|
||||
vestingAccountInfo,
|
||||
fetchBalance,
|
||||
clearBalance,
|
||||
clearAll,
|
||||
|
||||
@@ -23,7 +23,7 @@ export const BalanceCard = () => {
|
||||
{!userBalance.error && (
|
||||
<Typography
|
||||
data-testid="refresh-success"
|
||||
sx={{ color: 'nym.background.dark' }}
|
||||
sx={{ color: 'nym.background.dark', textTransform: 'uppercase' }}
|
||||
variant="h5"
|
||||
fontWeight="700"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import React, { useContext } from 'react'
|
||||
import { Box, Tooltip, Typography } from '@mui/material'
|
||||
import { format } from 'date-fns'
|
||||
import { ClientContext } from '../../../context/main'
|
||||
|
||||
const calculateMarkerPosition = (arrLength: number, index: number) => (1 / arrLength) * 100 * index
|
||||
|
||||
export const VestingTimeline: React.FC<{ percentageComplete: number }> = ({ percentageComplete }) => {
|
||||
const {
|
||||
userBalance: { currentVestingPeriod, vestingAccountInfo },
|
||||
} = useContext(ClientContext)
|
||||
|
||||
const nextPeriod =
|
||||
typeof currentVestingPeriod === 'object' && !!vestingAccountInfo?.periods
|
||||
? Number(vestingAccountInfo?.periods[currentVestingPeriod.In + 1]?.start_time)
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<Box display="flex" flexDirection="column" gap={1} position="relative" width="100%">
|
||||
<svg width="100%" height="12">
|
||||
<rect y="2" width="100%" height="6" rx="0" fill="#E6E6E6" />
|
||||
<rect y="2" width={`${percentageComplete}%`} height="6" rx="0" fill="#121726" />
|
||||
{vestingAccountInfo?.periods.map((period, i, arr) => (
|
||||
<Marker
|
||||
position={`${calculateMarkerPosition(arr.length, i)}%`}
|
||||
color={+percentageComplete.toFixed(2) >= calculateMarkerPosition(arr.length, i) ? '#121726' : '#B9B9B9'}
|
||||
tooltipText={format(new Date(Number(period.start_time) * 1000), 'HH:mm do MMM yyyy')}
|
||||
key={i}
|
||||
/>
|
||||
))}
|
||||
<Marker
|
||||
position="calc(100% - 4px)"
|
||||
color={percentageComplete === 100 ? '#121726' : '#B9B9B9'}
|
||||
tooltipText="End of vesting schedule"
|
||||
/>
|
||||
</svg>
|
||||
{nextPeriod && (
|
||||
<Typography variant="caption" sx={{ color: 'grey.500', position: 'absolute', top: 15, left: 0 }}>
|
||||
Next vesting period: {format(new Date(nextPeriod * 1000), 'HH:mm do MMM yyyy')}
|
||||
</Typography>
|
||||
)}
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const Marker: React.FC<{ tooltipText: string; color: string; position: string }> = ({
|
||||
tooltipText,
|
||||
color,
|
||||
position,
|
||||
}) => (
|
||||
<Tooltip title={tooltipText}>
|
||||
<rect x={position} width="4" height="12" rx="1" fill={color} style={{ cursor: 'pointer' }} />
|
||||
</Tooltip>
|
||||
)
|
||||
@@ -20,6 +20,7 @@ import { NymCard, InfoTooltip, Title, Fee } from '../../components'
|
||||
import { ClientContext } from '../../context/main'
|
||||
import { withdrawVestedCoins } from '../../requests'
|
||||
import { Period } from '../../types'
|
||||
import { VestingTimeline } from './components/vesting-timeline'
|
||||
|
||||
export const VestingCard = () => {
|
||||
const { userBalance } = useContext(ClientContext)
|
||||
@@ -55,7 +56,7 @@ export const VestingCard = () => {
|
||||
<VestingSchedule />
|
||||
<TokenTransfer />
|
||||
<Box display="flex" justifyContent="space-between" alignItems="center">
|
||||
<Fee feeType="Send" />
|
||||
{userBalance.tokenAllocation?.spendable !== '0' ? <Fee feeType="Send" /> : <div />}
|
||||
<Button
|
||||
size="large"
|
||||
variant="contained"
|
||||
@@ -79,7 +80,7 @@ export const VestingCard = () => {
|
||||
}
|
||||
}}
|
||||
endIcon={isLoading && <CircularProgress size={16} color="inherit" />}
|
||||
disabled={isLoading}
|
||||
disabled={isLoading || userBalance.tokenAllocation?.spendable === '0'}
|
||||
disableElevation
|
||||
>
|
||||
Transfer
|
||||
@@ -103,8 +104,9 @@ const VestingSchedule = () => {
|
||||
const calculatePercentage = () => {
|
||||
const { tokenAllocation, originalVesting } = userBalance
|
||||
if (tokenAllocation?.vesting && tokenAllocation.vested && tokenAllocation.vested !== '0' && originalVesting) {
|
||||
const percentage = Math.round((+tokenAllocation.vested / +originalVesting?.amount.amount) * 100)
|
||||
setVestedPercentage(percentage)
|
||||
const percentage = (+tokenAllocation.vested / +originalVesting?.amount.amount) * 100
|
||||
const rounded = percentage.toFixed(2)
|
||||
setVestedPercentage(+rounded)
|
||||
} else {
|
||||
setVestedPercentage(0)
|
||||
}
|
||||
@@ -135,13 +137,8 @@ const VestingSchedule = () => {
|
||||
</TableCell>
|
||||
<TableCell sx={{ borderBottom: 'none' }}>
|
||||
<Box display="flex" alignItems="center" gap={1}>
|
||||
<Typography variant="caption">{`${vestedPercentage}%`}</Typography>
|
||||
<LinearProgress
|
||||
sx={{ flexBasis: '99%' }}
|
||||
variant="determinate"
|
||||
value={vestedPercentage}
|
||||
color="inherit"
|
||||
/>
|
||||
<Typography variant="body2">{`${vestedPercentage}%`}</Typography>
|
||||
<VestingTimeline percentageComplete={vestedPercentage} />
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell sx={{ borderBottom: 'none' }} align="right">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { invoke } from '@tauri-apps/api'
|
||||
import { VestingAccountInfo } from 'src/types/rust/vestingaccountinfo'
|
||||
import { majorToMinor, minorToMajor } from '.'
|
||||
import { Coin, OriginalVestingResponse, Period } from '../types'
|
||||
import { Coin, DelegationResult, OriginalVestingResponse, Period } from '../types'
|
||||
|
||||
export const getLockedCoins = async (address: string): Promise<Coin> => {
|
||||
const res: Coin = await invoke('locked_coins', { address })
|
||||
@@ -23,8 +24,8 @@ export const getVestedCoins = async (vestingAccountAddress: string): Promise<Coi
|
||||
|
||||
export const getOriginalVesting = async (vestingAccountAddress: string): Promise<OriginalVestingResponse> => {
|
||||
const res: OriginalVestingResponse = await invoke('original_vesting', { vestingAccountAddress })
|
||||
const majorValue = await minorToMajor(res.amount.amount)
|
||||
return {...res, amount: majorValue}
|
||||
const majorValue = await minorToMajor(res.amount.amount)
|
||||
return { ...res, amount: majorValue }
|
||||
}
|
||||
|
||||
export const withdrawVestedCoins = async (amount: string) => {
|
||||
@@ -32,4 +33,19 @@ export const withdrawVestedCoins = async (amount: string) => {
|
||||
await invoke('withdraw_vested_coins', { amount: { amount: minor.amount, denom: 'Minor' } })
|
||||
}
|
||||
|
||||
export const getCurrentVestingPeriod = async (address: string): Promise<Period> => await invoke('get_current_vesting_period', {address})
|
||||
export const getCurrentVestingPeriod = async (address: string): Promise<Period> =>
|
||||
await invoke('get_current_vesting_period', { address })
|
||||
|
||||
export const vestingDelegateToMixnode = async ({
|
||||
identity,
|
||||
amount,
|
||||
}: {
|
||||
identity: string
|
||||
amount: Coin
|
||||
}): Promise<DelegationResult> => await invoke('vesting_delegate_to_mixnode', { identity, amount })
|
||||
|
||||
export const vestingUnelegateFromMixnode = async (identity: string): Promise<DelegationResult> =>
|
||||
await invoke('vesting_delegate_to_mixnode', { identity })
|
||||
|
||||
export const getVestingAccountInfo = async (address: string): Promise<VestingAccountInfo> =>
|
||||
await invoke('get_account_info', { address })
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Denom } from "./denom";
|
||||
import type { Denom } from "./denom";
|
||||
|
||||
export interface Account {
|
||||
contract_address: string;
|
||||
client_address: string;
|
||||
denom: Denom;
|
||||
}
|
||||
export interface Account { contract_address: string, client_address: string, denom: Denom, }
|
||||
@@ -1,6 +1,3 @@
|
||||
import { Coin } from "./coin";
|
||||
import type { Coin } from "./coin";
|
||||
|
||||
export interface Balance {
|
||||
coin: Coin;
|
||||
printable_balance: string;
|
||||
}
|
||||
export interface Balance { coin: Coin, printable_balance: string, }
|
||||
@@ -1,6 +1,3 @@
|
||||
import { Denom } from "./denom";
|
||||
import type { Denom } from "./denom";
|
||||
|
||||
export interface Coin {
|
||||
amount: string;
|
||||
denom: Denom;
|
||||
}
|
||||
export interface Coin { amount: string, denom: Denom, }
|
||||
@@ -1,4 +1,2 @@
|
||||
export interface CoreNodeStatusResponse {
|
||||
identity: string;
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface CoreNodeStatusResponse { identity: string, count: number, }
|
||||
@@ -1,6 +1,3 @@
|
||||
import { Account } from "./account";
|
||||
import type { Account } from "./account";
|
||||
|
||||
export interface CreatedAccount {
|
||||
account: Account;
|
||||
mnemonic: string;
|
||||
}
|
||||
export interface CreatedAccount { account: Account, mnemonic: string, }
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Coin } from "./coin";
|
||||
import type { Coin } from "./coin";
|
||||
|
||||
export interface DelegationResult {
|
||||
source_address: string;
|
||||
target_address: string;
|
||||
amount: Coin | null;
|
||||
}
|
||||
export interface DelegationResult { source_address: string, target_address: string, amount: Coin | null, }
|
||||
@@ -1 +1,2 @@
|
||||
|
||||
export type Denom = "Major" | "Minor";
|
||||
@@ -1,9 +1,2 @@
|
||||
export interface Gateway {
|
||||
host: string;
|
||||
mix_port: number;
|
||||
clients_port: number;
|
||||
location: string;
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
}
|
||||
|
||||
export interface Gateway { host: string, mix_port: number, clients_port: number, location: string, sphinx_key: string, identity_key: string, version: string, }
|
||||
@@ -1,4 +1,2 @@
|
||||
export interface InclusionProbabilityResponse {
|
||||
in_active: number;
|
||||
in_reserve: number;
|
||||
}
|
||||
|
||||
export interface InclusionProbabilityResponse { in_active: number, in_reserve: number, }
|
||||
@@ -4,17 +4,20 @@ export * from './coin'
|
||||
export * from './delegationresult'
|
||||
export * from './denom'
|
||||
export * from './gateway'
|
||||
export * from './inclusionprobabilityresponse'
|
||||
export * from './mixnode'
|
||||
export * from './mixnodestatus'
|
||||
export * from './mixnodestatus'
|
||||
export * from './mixnodestatusresponse'
|
||||
export * from './mixnodestatusresponse'
|
||||
export * from './network'
|
||||
export * from './operation'
|
||||
export * from './originalvestingresponse'
|
||||
export * from './rewardedsetnodestatus'
|
||||
export * from './rewardestimationresponse'
|
||||
export * from './stakesaturationresponse'
|
||||
export * from './stateparams'
|
||||
export * from './tauritxresult'
|
||||
export * from './transactiondetails'
|
||||
export * from './mixnodestatus'
|
||||
export * from './mixnodestatusresponse'
|
||||
export * from './stakesaturaionresponse'
|
||||
export * from './rewardestimationresponse'
|
||||
export * from './mixnodestatus'
|
||||
export * from './mixnodestatusresponse'
|
||||
export * from './inclusionprobabilityresponse'
|
||||
export * from './network'
|
||||
export * from './originalvestingresponse'
|
||||
export * from './vestingaccountinfo'
|
||||
export * from './vestingperiod'
|
||||
|
||||
@@ -1,10 +1,2 @@
|
||||
export interface MixNode {
|
||||
host: string;
|
||||
mix_port: number;
|
||||
verloc_port: number;
|
||||
http_api_port: number;
|
||||
sphinx_key: string;
|
||||
identity_key: string;
|
||||
version: string;
|
||||
profit_margin_percent: number;
|
||||
}
|
||||
|
||||
export interface MixNode { host: string, mix_port: number, verloc_port: number, http_api_port: number, sphinx_key: string, identity_key: string, version: string, profit_margin_percent: number, }
|
||||
@@ -1 +1,2 @@
|
||||
export type MixnodeStatus = "Active" | "Standby" | "Inactive" | "NotFound";
|
||||
|
||||
export type MixnodeStatus = "active" | "standby" | "inactive" | "not_found";
|
||||
@@ -1,5 +1,3 @@
|
||||
import { MixnodeStatus } from "./mixnodestatus";
|
||||
import type { MixnodeStatus } from "./mixnodestatus";
|
||||
|
||||
export interface MixnodeStatusResponse {
|
||||
status: MixnodeStatus;
|
||||
}
|
||||
export interface MixnodeStatusResponse { status: MixnodeStatus, }
|
||||
@@ -1 +1,2 @@
|
||||
|
||||
export type Network = "QA" | "SANDBOX" | "MAINNET";
|
||||
@@ -1,31 +1,2 @@
|
||||
export type Operation =
|
||||
| "Upload"
|
||||
| "Init"
|
||||
| "Migrate"
|
||||
| "ChangeAdmin"
|
||||
| "Send"
|
||||
| "BondMixnode"
|
||||
| "BondMixnodeOnBehalf"
|
||||
| "UnbondMixnode"
|
||||
| "UnbondMixnodeOnBehalf"
|
||||
| "UpdateMixnodeConfig"
|
||||
| "DelegateToMixnode"
|
||||
| "DelegateToMixnodeOnBehalf"
|
||||
| "UndelegateFromMixnode"
|
||||
| "UndelegateFromMixnodeOnBehalf"
|
||||
| "BondGateway"
|
||||
| "BondGatewayOnBehalf"
|
||||
| "UnbondGateway"
|
||||
| "UnbondGatewayOnBehalf"
|
||||
| "UpdateContractSettings"
|
||||
| "BeginMixnodeRewarding"
|
||||
| "FinishMixnodeRewarding"
|
||||
| "TrackUnbondGateway"
|
||||
| "TrackUnbondMixnode"
|
||||
| "WithdrawVestedCoins"
|
||||
| "TrackUndelegation"
|
||||
| "CreatePeriodicVestingAccount"
|
||||
| "AdvanceCurrentInterval"
|
||||
| "WriteRewardedSet"
|
||||
| "ClearRewardedSet"
|
||||
| "UpdateMixnetAddress";
|
||||
|
||||
export type Operation = "Upload" | "Init" | "Migrate" | "ChangeAdmin" | "Send" | "BondMixnode" | "BondMixnodeOnBehalf" | "UnbondMixnode" | "UnbondMixnodeOnBehalf" | "UpdateMixnodeConfig" | "DelegateToMixnode" | "DelegateToMixnodeOnBehalf" | "UndelegateFromMixnode" | "UndelegateFromMixnodeOnBehalf" | "BondGateway" | "BondGatewayOnBehalf" | "UnbondGateway" | "UnbondGatewayOnBehalf" | "UpdateContractSettings" | "BeginMixnodeRewarding" | "FinishMixnodeRewarding" | "TrackUnbondGateway" | "TrackUnbondMixnode" | "WithdrawVestedCoins" | "TrackUndelegation" | "CreatePeriodicVestingAccount" | "AdvanceCurrentInterval" | "WriteRewardedSet" | "ClearRewardedSet" | "UpdateMixnetAddress";
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Coin } from "./coin";
|
||||
import type { Coin } from "./coin";
|
||||
|
||||
export interface OriginalVestingResponse {
|
||||
amount: Coin;
|
||||
number_of_periods: number;
|
||||
period_duration: bigint;
|
||||
}
|
||||
export interface OriginalVestingResponse { amount: Coin, number_of_periods: number, period_duration: bigint, }
|
||||
@@ -1 +1,2 @@
|
||||
export type Period = "Before" | number | "After";
|
||||
|
||||
export type Period = "Before" | { In: number } | "After";
|
||||
@@ -1,6 +1,3 @@
|
||||
import { Coin } from "./coin";
|
||||
import type { Coin } from "./coin";
|
||||
|
||||
export interface PledgeData {
|
||||
amount: Coin;
|
||||
block_time: bigint;
|
||||
}
|
||||
export interface PledgeData { amount: Coin, block_time: bigint, }
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export type RewardedSetNodeStatus = "Active" | "Standby";
|
||||
@@ -1,9 +1,2 @@
|
||||
export interface RewardEstimationResponse {
|
||||
estimated_total_node_reward: bigint;
|
||||
estimated_operator_reward: bigint;
|
||||
estimated_delegators_reward: bigint;
|
||||
current_interval_start: bigint;
|
||||
current_interval_end: bigint;
|
||||
current_interval_uptime: number;
|
||||
as_at: bigint;
|
||||
}
|
||||
|
||||
export interface RewardEstimationResponse { estimated_total_node_reward: bigint, estimated_operator_reward: bigint, estimated_delegators_reward: bigint, current_interval_start: bigint, current_interval_end: bigint, current_interval_uptime: number, as_at: bigint, }
|
||||
@@ -1,4 +0,0 @@
|
||||
export interface StakeSaturationResponse {
|
||||
saturation: number;
|
||||
as_at: bigint;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
export interface StakeSaturationResponse { saturation: number, as_at: bigint, }
|
||||
@@ -1,6 +1,2 @@
|
||||
export interface TauriContractStateParams {
|
||||
minimum_mixnode_pledge: string;
|
||||
minimum_gateway_pledge: string;
|
||||
mixnode_rewarded_set_size: number;
|
||||
mixnode_active_set_size: number;
|
||||
}
|
||||
|
||||
export interface TauriContractStateParams { minimum_mixnode_pledge: string, minimum_gateway_pledge: string, mixnode_rewarded_set_size: number, mixnode_active_set_size: number, }
|
||||
@@ -1,10 +1,3 @@
|
||||
import { TransactionDetails } from "./transactiondetails";
|
||||
import type { TransactionDetails } from "./transactiondetails";
|
||||
|
||||
export interface TauriTxResult {
|
||||
block_height: bigint;
|
||||
code: number;
|
||||
details: TransactionDetails;
|
||||
gas_used: bigint;
|
||||
gas_wanted: bigint;
|
||||
tx_hash: string;
|
||||
}
|
||||
export interface TauriTxResult { block_height: bigint, code: number, details: TransactionDetails, gas_used: bigint, gas_wanted: bigint, tx_hash: string, }
|
||||
@@ -1,7 +1,3 @@
|
||||
import { Coin } from "./coin";
|
||||
import type { Coin } from "./coin";
|
||||
|
||||
export interface TransactionDetails {
|
||||
amount: Coin;
|
||||
from_address: string;
|
||||
to_address: string;
|
||||
}
|
||||
export interface TransactionDetails { amount: Coin, from_address: string, to_address: string, }
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user