Make wallet denom dynamic

Making denom dynamic enables coin transfers on other nets than the
default sandbox net, such as mainnet.
This commit is contained in:
Jon Häggblad
2022-03-01 12:20:27 +01:00
parent 4d0b5b34ec
commit 18837220f4
17 changed files with 238 additions and 105 deletions
Generated
+2 -1
View File
@@ -3669,6 +3669,7 @@ dependencies = [
"cfg-if 1.0.0",
"hex-literal",
"serde",
"thiserror",
"url",
]
@@ -8248,4 +8249,4 @@ checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33"
dependencies = [
"cc",
"libc",
]
]
@@ -24,7 +24,7 @@ where
pub fn connect_with_signer<U>(
endpoint: U,
signer: DirectSecp256k1HdWallet,
gas_price: Option<GasPrice>,
gas_price: GasPrice,
) -> Result<signing_client::Client, NymdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
@@ -644,7 +644,7 @@ impl Client {
pub fn connect_with_signer<U>(
endpoint: U,
signer: DirectSecp256k1HdWallet,
gas_price: Option<GasPrice>,
gas_price: GasPrice,
) -> Result<Self, NymdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
@@ -653,7 +653,7 @@ impl Client {
Ok(Client {
rpc_client,
signer,
gas_price: gas_price.unwrap_or_default(),
gas_price,
})
}
}
@@ -71,11 +71,9 @@ impl FromStr for GasPrice {
}
}
impl Default for GasPrice {
fn default() -> Self {
format!("{}{}", defaults::GAS_PRICE_AMOUNT, defaults::DENOM)
.parse()
.unwrap()
impl GasPrice {
pub fn new_with_default_price(denom: String) -> Result<Self, NymdError> {
format!("{}{}", defaults::GAS_PRICE_AMOUNT, denom).parse()
}
}
@@ -85,7 +83,8 @@ mod tests {
#[test]
fn default_gas_price_is_valid() {
let _ = GasPrice::default();
let denom = "unym".parse().unwrap();
let _ = GasPrice::new_with_default_price(denom);
}
#[test]
@@ -74,7 +74,7 @@ impl NymdClient<QueryNymdClient> {
vesting_contract_address,
erc20_bridge_contract_address,
client_address: None,
custom_gas_limits: Default::default(),
custom_gas_limits: HashMap::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
})
}
@@ -83,6 +83,7 @@ impl NymdClient<QueryNymdClient> {
impl NymdClient<SigningNymdClient> {
// maybe the wallet could be made into a generic, but for now, let's just have this one implementation
pub fn connect_with_signer<U>(
network: config::defaults::all::Network,
endpoint: U,
mixnet_contract_address: Option<AccountId>,
vesting_contract_address: Option<AccountId>,
@@ -93,11 +94,13 @@ impl NymdClient<SigningNymdClient> {
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let denom = network.denom();
let client_address = signer
.try_derive_accounts()?
.into_iter()
.map(|account| account.address)
.collect();
let gas_price = gas_price.unwrap_or(GasPrice::new_with_default_price(denom)?);
Ok(NymdClient {
client: SigningNymdClient::connect_with_signer(endpoint, signer, gas_price)?,
@@ -105,7 +108,7 @@ impl NymdClient<SigningNymdClient> {
vesting_contract_address,
erc20_bridge_contract_address,
client_address: Some(client_address),
custom_gas_limits: Default::default(),
custom_gas_limits: HashMap::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
})
}
@@ -123,12 +126,14 @@ impl NymdClient<SigningNymdClient> {
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let prefix = network.bech32_prefix();
let denom = network.denom();
let wallet = DirectSecp256k1HdWallet::from_mnemonic(prefix, mnemonic)?;
let client_address = wallet
.try_derive_accounts()?
.into_iter()
.map(|account| account.address)
.collect();
let gas_price = gas_price.unwrap_or(GasPrice::new_with_default_price(denom)?);
Ok(NymdClient {
client: SigningNymdClient::connect_with_signer(endpoint, wallet, gas_price)?,
@@ -136,7 +141,7 @@ impl NymdClient<SigningNymdClient> {
vesting_contract_address,
erc20_bridge_contract_address,
client_address: Some(client_address),
custom_gas_limits: Default::default(),
custom_gas_limits: HashMap::default(),
simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER,
})
}
@@ -161,13 +166,6 @@ impl<C> NymdClient<C> {
.ok_or(NymdError::NoContractAddressAvailable)
}
// now the question is as follows: will denom always be in the format of `u{prefix}`?
pub fn denom(&self) -> Result<Denom, NymdError> {
Ok(format!("u{}", self.mixnet_contract_address()?.prefix())
.parse()
.unwrap())
}
pub fn address(&self) -> &AccountId
where
C: SigningCosmWasmClient,
@@ -57,15 +57,13 @@ pub struct DirectSecp256k1HdWallet {
}
impl DirectSecp256k1HdWallet {
pub fn builder() -> DirectSecp256k1HdWalletBuilder {
DirectSecp256k1HdWalletBuilder::default()
pub fn builder(prefix: String) -> 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> {
DirectSecp256k1HdWalletBuilder::new()
.with_prefix(prefix)
.build(mnemonic)
DirectSecp256k1HdWalletBuilder::new(prefix).build(mnemonic)
}
pub fn generate(prefix: String, word_count: usize) -> Result<Self, NymdError> {
@@ -147,20 +145,14 @@ pub struct DirectSecp256k1HdWalletBuilder {
prefix: String,
}
impl Default for DirectSecp256k1HdWalletBuilder {
fn default() -> Self {
impl DirectSecp256k1HdWalletBuilder {
pub fn new(prefix: String) -> Self {
DirectSecp256k1HdWalletBuilder {
bip39_password: String::new(),
hd_paths: vec![defaults::COSMOS_DERIVATION_PATH.parse().unwrap()],
prefix: defaults::BECH32_PREFIX.to_string(),
prefix,
}
}
}
impl DirectSecp256k1HdWalletBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn with_bip39_password<S: Into<String>>(mut self, password: S) -> Self {
self.bip39_password = password.into();
+1
View File
@@ -10,4 +10,5 @@ edition = "2021"
cfg-if = "1.0.0"
hex-literal = "0.3.3"
serde = {version = "1.0", features = ["derive"]}
thiserror = "1.0"
url = "2.2"
+42 -1
View File
@@ -2,10 +2,18 @@
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::{collections::HashMap, fmt, str::FromStr};
use crate::{mainnet, qa, sandbox, ValidatorDetails};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum NetworkDefaultsError {
#[error("The provided network was invalid")]
MalformedNetworkProvided(String),
}
#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub enum Network {
QA,
@@ -21,6 +29,39 @@ impl Network {
Self::MAINNET => String::from(mainnet::BECH32_PREFIX),
}
}
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),
}
}
}
impl FromStr for Network {
type Err = NetworkDefaultsError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"qa" => Ok(Network::QA),
"sandbox" => Ok(Network::SANDBOX),
"mainnet" => Ok(Network::MAINNET),
_ => Err(NetworkDefaultsError::MalformedNetworkProvided(
s.to_string(),
)),
}
}
}
impl fmt::Display for Network {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Network::QA => f.write_str("QA"),
Network::SANDBOX => f.write_str("Sandbox"),
Network::MAINNET => f.write_str("Mainnet"),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
+1
View File
@@ -882,6 +882,7 @@ dependencies = [
"cfg-if",
"hex-literal",
"serde",
"thiserror",
"url",
]
+1
View File
@@ -2767,6 +2767,7 @@ dependencies = [
"cfg-if 1.0.0",
"hex-literal",
"serde",
"thiserror",
"url",
]
+146 -54
View File
@@ -2,14 +2,12 @@
use crate::error::BackendError;
use crate::network::Network;
use ::config::defaults::DENOM;
use cosmrs::Decimal;
use cosmrs::Denom as CosmosDenom;
use cosmwasm_std::Coin as CosmWasmCoin;
use cosmwasm_std::Uint128;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Add, Sub};
use std::str::FromStr;
use strum::IntoEnumIterator;
@@ -24,15 +22,6 @@ pub enum Denom {
const MINOR_IN_MAJOR: f64 = 1_000_000.;
impl fmt::Display for Denom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Denom::Major => f.write_str(&DENOM[1..]),
Denom::Minor => f.write_str(DENOM),
}
}
}
impl FromStr for Denom {
type Err = BackendError;
@@ -65,19 +54,14 @@ pub struct Coin {
denom: Denom,
}
// TODO convert to TryFrom
impl From<GasPrice> for Coin {
fn from(g: GasPrice) -> Coin {
Coin {
amount: g.amount.to_string(),
denom: Denom::from_str(&g.denom.to_string()).unwrap(),
}
}
}
impl TryFrom<GasPrice> for Coin {
type Error = BackendError;
impl fmt::Display for Coin {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&format!("{} {}", self.amount, self.denom))
fn try_from(g: GasPrice) -> Result<Self, Self::Error> {
Ok(Coin {
amount: g.amount.to_string(),
denom: Denom::from_str(&g.denom.to_string())?,
})
}
}
@@ -126,6 +110,7 @@ impl Sub for Coin {
}
impl Coin {
#[allow(unused)]
pub fn major<T: ToString>(amount: T) -> Coin {
Coin {
amount: amount.to_string(),
@@ -133,6 +118,7 @@ impl Coin {
}
}
#[allow(unused)]
pub fn minor<T: ToString>(amount: T) -> Coin {
Coin {
amount: amount.to_string(),
@@ -171,34 +157,45 @@ impl Coin {
self.amount.clone()
}
#[allow(unused)]
pub fn denom(&self) -> Denom {
self.denom.clone()
}
}
impl TryFrom<Coin> for CosmWasmCoin {
type Error = BackendError;
// Helper function that returns the local denom in terms of the specified network denom.
fn denom_as_string(&self, network_denom: &CosmosDenom) -> Result<String, BackendError> {
// Currently there is the widespread assumption that network denomination is always in
// `Denom::Minor`, and starts with 'u'.
let network_denom = network_denom.to_string();
if !network_denom.starts_with('u') {
return Err(BackendError::InvalidNetworkDenom(network_denom));
}
fn try_from(coin: Coin) -> Result<CosmWasmCoin, Self::Error> {
Ok(CosmWasmCoin::new(
Uint128::try_from(coin.amount.as_str()).unwrap().u128(),
coin.denom.to_string(),
))
Ok(match &self.denom {
Denom::Minor => network_denom,
Denom::Major => network_denom[1..].to_string(),
})
}
}
impl TryFrom<Coin> for CosmosCoin {
type Error = BackendError;
fn try_from(coin: Coin) -> Result<CosmosCoin, BackendError> {
match Decimal::from_str(&coin.amount) {
Ok(d) => Ok(CosmosCoin {
amount: d,
denom: CosmosDenom::from_str(&coin.denom.to_string())?,
pub fn into_cosmos_coin(self, network_denom: &CosmosDenom) -> Result<CosmosCoin, BackendError> {
match Decimal::from_str(&self.amount) {
Ok(amount) => Ok(CosmosCoin {
amount,
denom: CosmosDenom::from_str(&self.denom_as_string(network_denom)?)?,
}),
Err(e) => Err(e.into()),
}
}
pub fn into_cosmwasm_coin(
self,
network_denom: &CosmosDenom,
) -> Result<CosmWasmCoin, BackendError> {
Ok(CosmWasmCoin {
denom: self.denom_as_string(network_denom)?,
amount: Uint128::try_from(self.amount.as_str())?,
})
}
}
impl From<CosmosCoin> for Coin {
@@ -221,13 +218,14 @@ impl From<CosmWasmCoin> for Coin {
#[cfg(test)]
mod test {
use crate::coin::{Coin, Denom};
use super::*;
use crate::error::BackendError;
use cosmrs::Coin as CosmosCoin;
use cosmrs::Decimal;
use cosmrs::Denom as CosmosDenom;
use cosmwasm_std::Coin as CosmWasmCoin;
use serde_json::json;
use std::convert::{TryFrom, TryInto};
use std::convert::TryFrom;
use std::str::FromStr;
#[test]
@@ -252,6 +250,19 @@ mod test {
assert_eq!(major_coin, test_major_coin);
}
#[test]
fn denom_from_str() {
assert_eq!(Denom::from_str("unym").unwrap(), Denom::Minor);
assert_eq!(Denom::from_str("nym").unwrap(), Denom::Major);
assert_eq!(Denom::from_str("minor").unwrap(), Denom::Minor);
assert_eq!(Denom::from_str("major").unwrap(), Denom::Major);
assert!(matches!(
Denom::from_str("foo").unwrap_err(),
BackendError::InvalidDenom { .. },
));
}
#[test]
fn denom_conversions() {
let minor = Coin::minor("1");
@@ -263,6 +274,66 @@ mod test {
assert_eq!(minor, Coin::minor("1"));
}
#[test]
fn network_denom_is_assumed_to_be_in_minor_denom() {
let network_denom = CosmosDenom::from_str("nym").unwrap();
assert!(matches!(
Coin::minor("42")
.denom_as_string(&network_denom)
.unwrap_err(),
BackendError::InvalidNetworkDenom { .. }
));
}
#[test]
fn local_denom_to_interpreted_using_network_denom() {
let network_denom = CosmosDenom::from_str("unym").unwrap();
assert_eq!(
Coin::minor("42").denom_as_string(&network_denom).unwrap(),
"unym",
);
assert_eq!(
Coin::major("42").denom_as_string(&network_denom).unwrap(),
"nym",
);
}
#[test]
fn coin_to_coin_minor() {
let network_denom = CosmosDenom::from_str("unym").unwrap();
let coin = Coin::minor("42");
let cosmoswasm_coin = coin.clone().into_cosmwasm_coin(&network_denom).unwrap();
assert_eq!(cosmoswasm_coin, CosmWasmCoin::new(42, "unym"),);
let cosmos_coin = coin.into_cosmos_coin(&network_denom).unwrap();
assert_eq!(
cosmos_coin,
CosmosCoin {
denom: CosmosDenom::from_str("unym").unwrap(),
amount: Decimal::from_str("42").unwrap(),
},
);
}
#[test]
fn coin_to_coin_major() {
let network_denom = CosmosDenom::from_str("unym").unwrap();
let coin = Coin::major("52");
let cosmoswasm_coin = coin.clone().into_cosmwasm_coin(&network_denom).unwrap();
assert_eq!(cosmoswasm_coin, CosmWasmCoin::new(52, "nym"),);
let cosmos_coin = coin.into_cosmos_coin(&network_denom).unwrap();
assert_eq!(
cosmos_coin,
CosmosCoin {
denom: CosmosDenom::from_str("nym").unwrap(),
amount: Decimal::from_str("52").unwrap(),
},
);
}
fn amounts() -> Vec<&'static str> {
vec![
"1",
@@ -288,23 +359,24 @@ mod test {
#[test]
fn coin_to_cosmoswasm() {
let network_denom = CosmosDenom::from_str("unym").unwrap();
for amount in amounts() {
let coin: Coin = Coin::minor(amount).into();
let cosmoswasm_coin: CosmWasmCoin = coin.try_into().unwrap();
let coin = Coin::minor(amount);
let cosmoswasm_coin: CosmWasmCoin = coin.into_cosmwasm_coin(&network_denom).unwrap();
assert_eq!(
cosmoswasm_coin,
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), Denom::Minor.to_string())
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), "unym")
);
assert_eq!(
Coin::try_from(cosmoswasm_coin).unwrap(),
Coin::minor(amount)
);
let coin: Coin = Coin::major(amount).into();
let cosmoswasm_coin: CosmWasmCoin = coin.try_into().unwrap();
let coin = Coin::major(amount);
let cosmoswasm_coin: CosmWasmCoin = coin.into_cosmwasm_coin(&network_denom).unwrap();
assert_eq!(
cosmoswasm_coin,
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), Denom::Major.to_string())
CosmWasmCoin::new(amount.parse::<u128>().unwrap(), "nym")
);
assert_eq!(
Coin::try_from(cosmoswasm_coin).unwrap(),
@@ -315,25 +387,26 @@ mod test {
#[test]
fn coin_to_cosmos() {
let network_denom = CosmosDenom::from_str("unym").unwrap();
for amount in amounts() {
let coin: Coin = Coin::minor(amount).into();
let cosmos_coin: CosmosCoin = coin.try_into().unwrap();
let coin = Coin::minor(amount);
let cosmos_coin: CosmosCoin = coin.into_cosmos_coin(&network_denom).unwrap();
assert_eq!(
cosmos_coin,
CosmosCoin {
amount: Decimal::from_str(amount).unwrap(),
denom: CosmosDenom::from_str(&Denom::Minor.to_string()).unwrap()
denom: CosmosDenom::from_str("unym").unwrap()
}
);
assert_eq!(Coin::try_from(cosmos_coin).unwrap(), Coin::minor(amount));
let coin: Coin = Coin::major(amount).into();
let cosmos_coin: CosmosCoin = coin.try_into().unwrap();
let coin = Coin::major(amount);
let cosmos_coin: CosmosCoin = coin.into_cosmos_coin(&network_denom).unwrap();
assert_eq!(
cosmos_coin,
CosmosCoin {
amount: Decimal::from_str(amount).unwrap(),
denom: CosmosDenom::from_str(&Denom::Major.to_string()).unwrap()
denom: CosmosDenom::from_str("nym").unwrap()
}
);
assert_eq!(Coin::try_from(cosmos_coin).unwrap(), Coin::major(amount));
@@ -355,4 +428,23 @@ mod test {
assert_eq!(Coin::minor("1") - Coin::major("1"), Coin::minor("-999999"));
assert_eq!(Coin::major("1") - Coin::minor("1"), Coin::major("0.999999"));
}
#[test]
fn coin_from_gas_price() {
assert_eq!(
Coin::try_from(GasPrice::from_str("42unym").unwrap()).unwrap(),
Coin {
amount: "42".to_string(),
denom: Denom::Minor,
}
);
assert_eq!(
Coin::try_from(GasPrice::from_str("42nym").unwrap()).unwrap(),
Coin {
amount: "42".to_string(),
denom: Denom::Major,
}
);
}
}
+2
View File
@@ -61,6 +61,8 @@ pub enum BackendError {
NoBalance(String),
#[error("{0} is not a valid denomination string")]
InvalidDenom(String),
#[error("{0} is not a valid network denomination string")]
InvalidNetworkDenom(String),
#[error("The provided network is not supported (yet)")]
NetworkNotSupported(config::defaults::all::Network),
#[error("Could not access the local data storage directory")]
@@ -4,7 +4,6 @@ use crate::nymd_client;
use crate::state::State;
use crate::{Gateway, MixNode};
use mixnet_contract_common::{GatewayBond, MixNodeBond};
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
@@ -15,8 +14,10 @@ pub async fn bond_gateway(
owner_signature: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
let denom = state.read().await.current_network().denom();
let pledge = pledge.into_cosmwasm_coin(&denom)?;
nymd_client!(state)
.bond_gateway(gateway, owner_signature, pledge.try_into()?)
.bond_gateway(gateway, owner_signature, pledge)
.await?;
Ok(())
}
@@ -44,8 +45,10 @@ pub async fn bond_mixnode(
pledge: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
let denom = state.read().await.current_network().denom();
let pledge = pledge.into_cosmwasm_coin(&denom)?;
nymd_client!(state)
.bond_mixnode(mixnode, owner_signature, pledge.try_into()?)
.bond_mixnode(mixnode, owner_signature, pledge)
.await?;
Ok(())
}
@@ -5,7 +5,6 @@ use crate::state::State;
use crate::utils::DelegationResult;
use cosmwasm_std::Coin as CosmWasmCoin;
use mixnet_contract_common::PagedDelegatorDelegationsResponse;
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
@@ -15,7 +14,8 @@ pub async fn delegate_to_mixnode(
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, BackendError> {
let delegation: CosmWasmCoin = amount.try_into()?;
let denom = state.read().await.current_network().denom();
let delegation: CosmWasmCoin = amount.into_cosmwasm_coin(&denom)?;
nymd_client!(state)
.delegate_to_mixnode(identity, &delegation)
.await?;
@@ -3,7 +3,6 @@ use crate::error::BackendError;
use crate::nymd_client;
use crate::state::State;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use std::str::FromStr;
use std::sync::Arc;
use tendermint_rpc::endpoint::broadcast::tx_commit::Response;
@@ -50,7 +49,8 @@ pub async fn send(
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<TauriTxResult, BackendError> {
let address = AccountId::from_str(address)?;
let cosmos_amount: CosmosCoin = amount.clone().try_into()?;
let network_denom = state.read().await.current_network().denom();
let cosmos_amount: CosmosCoin = amount.clone().into_cosmos_coin(&network_denom)?;
let result = nymd_client!(state)
.send(&address, vec![cosmos_amount], memo)
.await?;
@@ -4,7 +4,6 @@ use crate::nymd_client;
use crate::state::State;
use crate::{Gateway, MixNode};
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
use validator_client::nymd::VestingSigningClient;
@@ -16,8 +15,10 @@ pub async fn vesting_bond_gateway(
owner_signature: String,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
let denom = state.read().await.current_network().denom();
let pledge = pledge.into_cosmwasm_coin(&denom)?;
nymd_client!(state)
.vesting_bond_gateway(gateway, &owner_signature, pledge.try_into()?)
.vesting_bond_gateway(gateway, &owner_signature, pledge)
.await?;
Ok(())
}
@@ -45,8 +46,10 @@ pub async fn vesting_bond_mixnode(
pledge: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
let denom = state.read().await.current_network().denom();
let pledge = pledge.into_cosmwasm_coin(&denom)?;
nymd_client!(state)
.vesting_bond_mixnode(mixnode, &owner_signature, pledge.try_into()?)
.vesting_bond_mixnode(mixnode, &owner_signature, pledge)
.await?;
Ok(())
}
@@ -56,8 +59,8 @@ pub async fn withdraw_vested_coins(
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<(), BackendError> {
nymd_client!(state)
.withdraw_vested_coins(amount.try_into()?)
.await?;
let denom = state.read().await.current_network().denom();
let amount = amount.into_cosmwasm_coin(&denom)?;
nymd_client!(state).withdraw_vested_coins(amount).await?;
Ok(())
}
@@ -3,8 +3,6 @@ use crate::error::BackendError;
use crate::nymd_client;
use crate::state::State;
use crate::utils::DelegationResult;
use cosmwasm_std::Coin as CosmWasmCoin;
use std::convert::TryInto;
use std::sync::Arc;
use tokio::sync::RwLock;
use validator_client::nymd::VestingSigningClient;
@@ -15,7 +13,8 @@ pub async fn vesting_delegate_to_mixnode(
amount: Coin,
state: tauri::State<'_, Arc<RwLock<State>>>,
) -> Result<DelegationResult, BackendError> {
let delegation: CosmWasmCoin = amount.try_into()?;
let denom = state.read().await.current_network().denom();
let delegation = amount.into_cosmwasm_coin(&denom)?;
nymd_client!(state)
.vesting_delegate_to_mixnode(identity, &delegation)
.await?;