diff --git a/CHANGELOG.md b/CHANGELOG.md index ccaa5b2981..c49e6f3ec3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// - validator-api: Added new endpoints for coconut spending flow and communications with coconut & multisig contracts ([#1261]) - validator-api: add `uptime`, `estimated_operator_apy`, `estimated_delegators_apy` to `/mixnodes/detailed` endpoint ([#1393]) - network-statistics: a new mixnet service that aggregates and exposes anonymized data about mixnet services ([#1328]) +- wallet: when simulating gas costs, an automatic adjustment is being used ([#1388]). - mixnode: Added basic mixnode hardware reporting to the HTTP API ([#1308]). ### Fixed @@ -54,6 +55,7 @@ Post 1.0.0 release, the changelog format is based on [Keep a Changelog](https:// [#1329]: https://github.com/nymtech/nym/pull/1329 [#1353]: https://github.com/nymtech/nym/pull/1353 [#1376]: https://github.com/nymtech/nym/pull/1376 +[#1388]: https://github.com/nymtech/nym/pull/1388 [#1393]: https://github.com/nymtech/nym/pull/1393 ## [nym-contracts-v1.0.1](https://github.com/nymtech/nym/tree/nym-contracts-v1.0.1) (2022-06-22) diff --git a/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs b/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs index 1f690d6812..215c5739b1 100644 --- a/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs +++ b/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs @@ -8,7 +8,7 @@ use crate::nymd::cosmwasm_client::types::*; use crate::nymd::error::NymdError; use crate::nymd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER}; use crate::nymd::wallet::DirectSecp256k1HdWallet; -use crate::nymd::{Coin, GasPrice, TxResponse}; +use crate::nymd::{Coin, GasAdjustable, GasPrice, TxResponse}; use async_trait::async_trait; use cosmrs::bank::MsgSend; use cosmrs::distribution::MsgWithdrawDelegatorReward; @@ -504,7 +504,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient { .gas_used; let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER); - let gas = ((gas_estimation.value() as f32 * multiplier) as u64).into(); + let gas = gas_estimation.adjust_gas(multiplier); debug!("Gas estimation: {}", gas_estimation); debug!("Multiplying the estimation by {}", multiplier); diff --git a/common/client-libs/validator-client/src/nymd/fee/mod.rs b/common/client-libs/validator-client/src/nymd/fee/mod.rs index 7044fc6f9d..c349437daa 100644 --- a/common/client-libs/validator-client/src/nymd/fee/mod.rs +++ b/common/client-libs/validator-client/src/nymd/fee/mod.rs @@ -1,17 +1,20 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use crate::nymd::Gas; use cosmrs::tx; use serde::{Deserialize, Serialize}; pub mod gas_price; -pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: f32 = 1.3; +pub type GasAdjustment = f32; + +pub const DEFAULT_SIMULATED_GAS_MULTIPLIER: GasAdjustment = 1.3; #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Fee { Manual(#[serde(with = "sealed::TxFee")] tx::Fee), - Auto(Option), + Auto(Option), } impl From for Fee { @@ -20,8 +23,8 @@ impl From for Fee { } } -impl From for Fee { - fn from(multiplier: f32) -> Self { +impl From for Fee { + fn from(multiplier: GasAdjustment) -> Self { Fee::Auto(Some(multiplier)) } } @@ -32,6 +35,21 @@ impl Default for Fee { } } +pub trait GasAdjustable { + fn adjust_gas(&self, adjustment: GasAdjustment) -> Self; +} + +impl GasAdjustable for Gas { + fn adjust_gas(&self, adjustment: GasAdjustment) -> Self { + if adjustment == 1.0 { + *self + } else { + let adjusted = (self.value() as f32 * adjustment).ceil(); + (adjusted as u64).into() + } + } +} + // a workaround to provide serde implementation for tx::Fee. We don't want to ever expose any of those // types to the public and ideally they will get replaced by proper implementation inside comrs mod sealed { diff --git a/common/client-libs/validator-client/src/nymd/mod.rs b/common/client-libs/validator-client/src/nymd/mod.rs index 4f33a40f98..ca512d044d 100644 --- a/common/client-libs/validator-client/src/nymd/mod.rs +++ b/common/client-libs/validator-client/src/nymd/mod.rs @@ -15,7 +15,6 @@ use cosmrs::rpc::HttpClientUrl; use cosmrs::tx::Msg; use cosmwasm_std::Uint128; use execute::execute; -pub use fee::gas_price::GasPrice; use mixnet_contract_common::mixnode::DelegationEvent; use mixnet_contract_common::{ ContractStateParams, Delegation, ExecuteMsg, Gateway, GatewayBond, GatewayBondResponse, @@ -50,6 +49,7 @@ pub use cosmrs::tx::{self, Gas}; pub use cosmrs::Coin as CosmosCoin; pub use cosmrs::{bip32, AccountId, Decimal, Denom}; pub use cosmwasm_std::Coin as CosmWasmCoin; +pub use fee::{gas_price::GasPrice, GasAdjustable, GasAdjustment}; pub use signing_client::Client as SigningNymdClient; pub use traits::{VestingQueryClient, VestingSigningClient}; @@ -270,6 +270,10 @@ impl NymdClient { self.client.gas_price() } + pub fn gas_adjustment(&self) -> GasAdjustment { + self.simulated_gas_multiplier + } + pub async fn account_sequence(&self) -> Result where C: SigningCosmWasmClient + Sync, diff --git a/common/types/src/fees.rs b/common/types/src/fees.rs index 5037646c31..95045fcc70 100644 --- a/common/types/src/fees.rs +++ b/common/types/src/fees.rs @@ -1,18 +1,84 @@ +use crate::currency::MajorCurrencyAmount; use serde::{Deserialize, Serialize}; - use validator_client::nymd::Fee; -use crate::currency::MajorCurrencyAmount; +#[cfg(feature = "generate-ts")] +use ts_rs::{Dependency, TS}; -#[cfg_attr(feature = "generate-ts", derive(ts_rs::TS))] -#[cfg_attr( - feature = "generate-ts", - ts(export_to = "ts-packages/types/src/types/rust/FeeDetails.ts") -)] #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FeeDetails { // expected to be used by the wallet in order to display detailed fee information to the user pub amount: Option, - #[cfg_attr(feature = "generate-ts", ts(skip))] pub fee: Fee, } + +#[cfg(feature = "generate-ts")] +impl TS for FeeDetails { + const EXPORT_TO: Option<&'static str> = Some("ts-packages/types/src/types/rust/FeeDetails.ts"); + + fn decl() -> String { + format!("type {} = {};", Self::name(), Self::inline()) + } + + fn name() -> String { + "FeeDetails".into() + } + + fn inline() -> String { + "{ amount: MajorCurrencyAmount | null, fee: Fee }".into() + } + + fn dependencies() -> Vec { + vec![ + Dependency::from_ty::() + .expect("TS was incorrectly defined on `CurrencyDenom`"), + Dependency::from_ty::() + .expect("TS was incorrectly defined on `ts_type_helpers::Fee`"), + ] + } + + fn transparent() -> bool { + false + } +} + +// this should really be sealed and NEVER EVER used as "normal" types, +// but due to our typescript requirements, we have to expose it to generate +// the types... +#[cfg(feature = "generate-ts")] +pub mod ts_type_helpers { + use serde::{Deserialize, Serialize}; + use validator_client::nymd::GasAdjustment; + + #[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)] + #[ts(export_to = "ts-packages/types/src/types/rust/Fee.ts")] + pub enum Fee { + Manual(CosmosFee), + Auto(Option), + } + + #[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)] + #[ts(export_to = "ts-packages/types/src/types/rust/CosmosFee.ts")] + // this should corresponds to cosmrs::tx::Fee + // IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations + // on the type. The below struct might have to get readjusted if we update cosmrs!! + pub struct CosmosFee { + amount: Vec, + gas_limit: u64, + payer: Option, + granter: Option, + } + + // Note: I've got a feeling this one will bite us hard at some point... + #[derive(Debug, Clone, Serialize, Deserialize, ts_rs::TS)] + #[ts(export_to = "ts-packages/types/src/types/rust/Coin.ts")] + // this should corresponds to cosmrs::Coin + // IMPORTANT NOTE: this should work as of cosmrs 0.7.1 due to their `FromStr` implementations + // on the type. The below struct might have to get readjusted if we update cosmrs!! + pub struct Coin { + denom: String, + // this is not entirely true, but for the purposes + // of ts_rs, it's sufficient for the time being + amount: u64, + } +} diff --git a/nym-wallet/src-tauri/src/operations/simulate/admin.rs b/nym-wallet/src-tauri/src/operations/simulate/admin.rs index ac698f86c3..053f61b35c 100644 --- a/nym-wallet/src-tauri/src/operations/simulate/admin.rs +++ b/nym-wallet/src-tauri/src/operations/simulate/admin.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BackendError; -use crate::operations::simulate::{FeeDetails, SimulateResult}; +use crate::operations::simulate::FeeDetails; +use crate::simulate::detailed_fee; use crate::State; use mixnet_contract_common::{ContractStateParams, ExecuteMsg}; use nym_wallet_types::admin::TauriContractStateParams; @@ -19,7 +20,6 @@ pub async fn simulate_update_contract_settings( let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -28,5 +28,5 @@ pub async fn simulate_update_contract_settings( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } diff --git a/nym-wallet/src-tauri/src/operations/simulate/cosmos.rs b/nym-wallet/src-tauri/src/operations/simulate/cosmos.rs index 413df4e887..282ff5b0fb 100644 --- a/nym-wallet/src-tauri/src/operations/simulate/cosmos.rs +++ b/nym-wallet/src-tauri/src/operations/simulate/cosmos.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BackendError; -use crate::operations::simulate::{FeeDetails, SimulateResult}; +use crate::operations::simulate::FeeDetails; +use crate::simulate::detailed_fee; use crate::state::State; use nym_types::currency::MajorCurrencyAmount; use std::str::FromStr; @@ -23,7 +24,6 @@ pub async fn simulate_send( let client = guard.current_client()?; let from_address = client.nymd.address().clone(); - let gas_price = client.nymd.gas_price().clone(); // TODO: I'm still not 100% convinced whether this should be exposed here or handled somewhere else in the client code let msg = MsgSend { @@ -33,5 +33,5 @@ pub async fn simulate_send( }; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } diff --git a/nym-wallet/src-tauri/src/operations/simulate/mixnet.rs b/nym-wallet/src-tauri/src/operations/simulate/mixnet.rs index 903819e235..4fbefee216 100644 --- a/nym-wallet/src-tauri/src/operations/simulate/mixnet.rs +++ b/nym-wallet/src-tauri/src/operations/simulate/mixnet.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BackendError; -use crate::nymd_client; -use crate::operations::simulate::{FeeDetails, SimulateResult}; +use crate::operations::simulate::FeeDetails; +use crate::simulate::detailed_fee; use crate::State; use mixnet_contract_common::IdentityKey; use mixnet_contract_common::{ExecuteMsg, Gateway, MixNode}; @@ -23,7 +23,6 @@ pub async fn simulate_bond_gateway( let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); // TODO: I'm still not 100% convinced whether this should be exposed here or handled somewhere else in the client code let msg = client.nymd.wrap_contract_execute_message( @@ -36,7 +35,7 @@ pub async fn simulate_bond_gateway( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -44,10 +43,8 @@ pub async fn simulate_unbond_gateway( state: tauri::State<'_, Arc>>, ) -> Result { let guard = state.read().await; - let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -56,7 +53,7 @@ pub async fn simulate_unbond_gateway( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -71,7 +68,6 @@ pub async fn simulate_bond_mixnode( let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -83,7 +79,7 @@ pub async fn simulate_bond_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -91,10 +87,8 @@ pub async fn simulate_unbond_mixnode( state: tauri::State<'_, Arc>>, ) -> Result { let guard = state.read().await; - let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -103,7 +97,7 @@ pub async fn simulate_unbond_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -112,10 +106,8 @@ pub async fn simulate_update_mixnode( state: tauri::State<'_, Arc>>, ) -> Result { let guard = state.read().await; - let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -126,7 +118,7 @@ pub async fn simulate_update_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -140,7 +132,6 @@ pub async fn simulate_delegate_to_mixnode( let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -151,7 +142,7 @@ pub async fn simulate_delegate_to_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -160,10 +151,8 @@ pub async fn simulate_undelegate_from_mixnode( state: tauri::State<'_, Arc>>, ) -> Result { let guard = state.read().await; - let client = guard.current_client()?; let mixnet_contract = client.nymd.mixnet_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( mixnet_contract, @@ -174,29 +163,27 @@ pub async fn simulate_undelegate_from_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] pub async fn simulate_claim_operator_reward( state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) - .simulate_claim_operator_reward(None) - .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client.nymd.simulate_claim_operator_reward(None).await?; + Ok(detailed_fee(client, result)) } #[tauri::command] pub async fn simulate_compound_operator_reward( state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) - .simulate_compound_operator_reward(None) - .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client.nymd.simulate_compound_operator_reward(None).await?; + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -204,11 +191,13 @@ pub async fn simulate_claim_delegator_reward( mix_identity: IdentityKey, state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client + .nymd .simulate_claim_delegator_reward(mix_identity, None) .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -216,9 +205,11 @@ pub async fn simulate_compound_delegator_reward( mix_identity: IdentityKey, state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client + .nymd .simulate_compound_delegator_reward(mix_identity, None) .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } diff --git a/nym-wallet/src-tauri/src/operations/simulate/mod.rs b/nym-wallet/src-tauri/src/operations/simulate/mod.rs index 4cbe3c0664..61e4179687 100644 --- a/nym-wallet/src-tauri/src/operations/simulate/mod.rs +++ b/nym-wallet/src-tauri/src/operations/simulate/mod.rs @@ -1,16 +1,31 @@ // Copyright 2022 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +use cosmrs::tx; +use cosmrs::tx::Gas; use nym_types::currency::MajorCurrencyAmount; use nym_types::fees::FeeDetails; -use validator_client::nymd::cosmwasm_client::types::GasInfo; -use validator_client::nymd::{tx, CosmosCoin, Fee, GasPrice}; +use validator_client::nymd::cosmwasm_client::types::{GasInfo, SimulateResponse}; +use validator_client::nymd::{ + CosmosCoin, Fee, GasAdjustable, GasAdjustment, GasPrice, SigningNymdClient, +}; +use validator_client::Client; pub mod admin; pub mod cosmos; pub mod mixnet; pub mod vesting; +pub(crate) fn detailed_fee( + client: &Client, + simulate_response: SimulateResponse, +) -> FeeDetails { + let gas_price = client.nymd.gas_price().clone(); + let gas_adjustment = client.nymd.gas_adjustment(); + + SimulateResult::new(simulate_response.gas_info, gas_price, gas_adjustment).detailed_fee() +} + // technically we could have also exposed a result: Option field from the SimulateResponse, // but in the context of the wallet it's really irrelevant and useless for the time being pub(crate) struct SimulateResult { @@ -19,13 +34,19 @@ pub(crate) struct SimulateResult { // for example if you attempt to send a 'BondMixnode' with invalid signature pub gas_info: Option, pub gas_price: GasPrice, + pub gas_adjustment: GasAdjustment, } impl SimulateResult { - pub fn new(gas_info: Option, gas_price: GasPrice) -> Self { + pub fn new( + gas_info: Option, + gas_price: GasPrice, + gas_adjustment: GasAdjustment, + ) -> Self { SimulateResult { gas_info, gas_price, + gas_adjustment, } } @@ -37,18 +58,20 @@ impl SimulateResult { } } - fn to_fee_amount(&self) -> Option { + fn adjusted_gas(&self) -> Option { self.gas_info - .map(|gas_info| &self.gas_price * gas_info.gas_used) + .map(|gas_info| gas_info.gas_used.adjust_gas(self.gas_adjustment)) + } + + fn to_fee_amount(&self) -> Option { + self.adjusted_gas().map(|gas| &self.gas_price * gas) } fn to_fee(&self) -> Fee { - self.to_fee_amount() - .and_then(|fee_amount| { - self.gas_info.map(|gas_info| { - let gas_limit = gas_info.gas_used; - tx::Fee::from_amount_and_gas(fee_amount, gas_limit).into() - }) + self.adjusted_gas() + .map(|gas| { + let fee_amount = &self.gas_price * gas; + tx::Fee::from_amount_and_gas(fee_amount, gas).into() }) .unwrap_or_default() } diff --git a/nym-wallet/src-tauri/src/operations/simulate/vesting.rs b/nym-wallet/src-tauri/src/operations/simulate/vesting.rs index b0f3f649d2..f01ca16fe9 100644 --- a/nym-wallet/src-tauri/src/operations/simulate/vesting.rs +++ b/nym-wallet/src-tauri/src/operations/simulate/vesting.rs @@ -2,8 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::error::BackendError; -use crate::nymd_client; -use crate::operations::simulate::{FeeDetails, SimulateResult}; +use crate::operations::simulate::FeeDetails; +use crate::simulate::detailed_fee; use crate::State; use mixnet_contract_common::IdentityKey; use mixnet_contract_common::{Gateway, MixNode}; @@ -24,7 +24,6 @@ pub async fn simulate_vesting_bond_gateway( let client = guard.current_client()?; let vesting_contract = client.nymd.vesting_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( vesting_contract, @@ -37,7 +36,7 @@ pub async fn simulate_vesting_bond_gateway( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -48,7 +47,6 @@ pub async fn simulate_vesting_unbond_gateway( let client = guard.current_client()?; let vesting_contract = client.nymd.vesting_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( vesting_contract, @@ -57,7 +55,7 @@ pub async fn simulate_vesting_unbond_gateway( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -72,7 +70,6 @@ pub async fn simulate_vesting_bond_mixnode( let client = guard.current_client()?; let vesting_contract = client.nymd.vesting_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( vesting_contract, @@ -85,7 +82,7 @@ pub async fn simulate_vesting_bond_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -96,7 +93,6 @@ pub async fn simulate_vesting_unbond_mixnode( let client = guard.current_client()?; let vesting_contract = client.nymd.vesting_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( vesting_contract, @@ -105,7 +101,7 @@ pub async fn simulate_vesting_unbond_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -117,7 +113,6 @@ pub async fn simulate_vesting_update_mixnode( let client = guard.current_client()?; let vesting_contract = client.nymd.vesting_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( vesting_contract, @@ -128,7 +123,7 @@ pub async fn simulate_vesting_update_mixnode( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -141,7 +136,6 @@ pub async fn simulate_withdraw_vested_coins( let client = guard.current_client()?; let vesting_contract = client.nymd.vesting_contract_address(); - let gas_price = client.nymd.gas_price().clone(); let msg = client.nymd.wrap_contract_execute_message( vesting_contract, @@ -150,29 +144,33 @@ pub async fn simulate_withdraw_vested_coins( )?; let result = client.nymd.simulate(vec![msg]).await?; - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] pub async fn simulate_vesting_claim_operator_reward( state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client + .nymd .simulate_vesting_claim_operator_reward(None) .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] pub async fn simulate_vesting_compound_operator_reward( state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client + .nymd .simulate_vesting_compound_operator_reward(None) .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -180,11 +178,13 @@ pub async fn simulate_vesting_claim_delegator_reward( mix_identity: IdentityKey, state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client + .nymd .simulate_vesting_claim_delegator_reward(mix_identity, None) .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } #[tauri::command] @@ -192,9 +192,11 @@ pub async fn simulate_vesting_compound_delegator_reward( mix_identity: IdentityKey, state: tauri::State<'_, Arc>>, ) -> Result { - let result = nymd_client!(state) + let guard = state.read().await; + let client = guard.current_client()?; + let result = client + .nymd .simulate_vesting_compound_delegator_reward(mix_identity, None) .await?; - let gas_price = nymd_client!(state).gas_price().clone(); - Ok(SimulateResult::new(result.gas_info, gas_price).detailed_fee()) + Ok(detailed_fee(client, result)) } diff --git a/tools/ts-rs-cli/src/main.rs b/tools/ts-rs-cli/src/main.rs index 909ea574bf..b5f06dd38f 100644 --- a/tools/ts-rs-cli/src/main.rs +++ b/tools/ts-rs-cli/src/main.rs @@ -9,7 +9,7 @@ use nym_types::delegation::{ Delegation, DelegationEvent, DelegationEventKind, DelegationRecord, DelegationResult, DelegationWithEverything, DelegationsSummaryResponse, PendingUndelegate, }; -use nym_types::fees::FeeDetails; +use nym_types::fees::{self, FeeDetails}; use nym_types::gas::{Gas, GasInfo}; use nym_types::gateway::{Gateway, GatewayBond}; use nym_types::mixnode::{MixNode, MixNodeBond}; @@ -68,6 +68,11 @@ fn main() { do_export!(DelegationsSummaryResponse); do_export!(DelegationWithEverything); do_export!(FeeDetails); + // I'm explicitly using full(-ish) path as to indicate + // those are not "proper" types to be used elsewhere + do_export!(fees::ts_type_helpers::Fee); + do_export!(fees::ts_type_helpers::CosmosFee); + do_export!(fees::ts_type_helpers::Coin); do_export!(Gas); do_export!(GasInfo); do_export!(Gateway); diff --git a/ts-packages/types/src/types/rust/Coin.ts b/ts-packages/types/src/types/rust/Coin.ts new file mode 100644 index 0000000000..e02141439d --- /dev/null +++ b/ts-packages/types/src/types/rust/Coin.ts @@ -0,0 +1,2 @@ + +export interface Coin { denom: string, amount: bigint, } \ No newline at end of file diff --git a/ts-packages/types/src/types/rust/CosmosFee.ts b/ts-packages/types/src/types/rust/CosmosFee.ts new file mode 100644 index 0000000000..c4220b1658 --- /dev/null +++ b/ts-packages/types/src/types/rust/CosmosFee.ts @@ -0,0 +1,3 @@ +import type { Coin } from "./Coin"; + +export interface CosmosFee { amount: Array, gas_limit: bigint, payer: string | null, granter: string | null, } \ No newline at end of file diff --git a/ts-packages/types/src/types/rust/Fee.ts b/ts-packages/types/src/types/rust/Fee.ts new file mode 100644 index 0000000000..43312ae631 --- /dev/null +++ b/ts-packages/types/src/types/rust/Fee.ts @@ -0,0 +1,3 @@ +import type { CosmosFee } from "./CosmosFee"; + +export type Fee = { Manual: CosmosFee } | { Auto: number | null }; \ No newline at end of file diff --git a/ts-packages/types/src/types/rust/FeeDetails.ts b/ts-packages/types/src/types/rust/FeeDetails.ts index f01aa05f06..234734f6a8 100644 --- a/ts-packages/types/src/types/rust/FeeDetails.ts +++ b/ts-packages/types/src/types/rust/FeeDetails.ts @@ -1,5 +1,4 @@ -import type { MajorCurrencyAmount } from './Currency'; +import type { Fee } from "./Fee"; +import type { MajorCurrencyAmount } from "./Currency"; -export interface FeeDetails { - amount: MajorCurrencyAmount | null; -} +export type FeeDetails = { amount: MajorCurrencyAmount | null, fee: Fee }; \ No newline at end of file