// Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::nymd::cosmwasm_client::signing_client; use crate::nymd::cosmwasm_client::types::{ Account, ChangeAdminResult, ContractCodeId, ExecuteResult, InstantiateOptions, InstantiateResult, MigrateResult, SequenceResponse, SimulateResponse, UploadResult, }; use crate::nymd::error::NymdError; use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER; use crate::nymd::wallet::DirectSecp256k1HdWallet; use cosmrs::cosmwasm; use cosmrs::rpc::Error as TendermintRpcError; 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, GatewayOwnershipResponse, IdentityKey, Interval, LayerDistribution, MixNode, MixNodeBond, MixOwnershipResponse, MixnetContractVersion, MixnodeRewardingStatusResponse, PagedDelegatorDelegationsResponse, PagedGatewayResponse, PagedMixDelegationsResponse, PagedMixnodeResponse, PagedRewardedSetResponse, QueryMsg, RewardedSetUpdateDetails, }; use network_defaults::DEFAULT_NETWORK; use serde::Serialize; use std::convert::TryInto; use vesting_contract_common::ExecuteMsg as VestingExecuteMsg; pub use crate::nymd::cosmwasm_client::client::CosmWasmClient; pub use crate::nymd::cosmwasm_client::signing_client::SigningCosmWasmClient; pub use crate::nymd::fee::Fee; pub use coin::Coin; pub use cosmrs::bank::MsgSend; pub use cosmrs::rpc::endpoint::tx::Response as TxResponse; pub use cosmrs::rpc::endpoint::validators::Response as ValidatorResponse; pub use cosmrs::rpc::HttpClient as QueryNymdClient; pub use cosmrs::rpc::Paging; pub use cosmrs::tendermint::abci::responses::{DeliverTx, Event}; pub use cosmrs::tendermint::abci::tag::Tag; pub use cosmrs::tendermint::block::Height; pub use cosmrs::tendermint::hash; pub use cosmrs::tendermint::validator::Info as TendermintValidatorInfo; pub use cosmrs::tendermint::Time as TendermintTime; 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 signing_client::Client as SigningNymdClient; pub use traits::{VestingQueryClient, VestingSigningClient}; pub mod coin; pub mod cosmwasm_client; pub mod error; pub mod fee; pub mod traits; pub mod wallet; #[derive(Debug)] pub struct NymdClient { client: C, mixnet_contract_address: AccountId, vesting_contract_address: AccountId, bandwidth_claim_contract_address: AccountId, coconut_bandwidth_contract_address: AccountId, multisig_contract_address: AccountId, client_address: Option>, simulated_gas_multiplier: f32, } impl NymdClient { pub fn with_mixnet_contract_address(mut self, address: AccountId) -> Self { self.mixnet_contract_address = address; self } pub fn with_vesting_contract_address(mut self, address: AccountId) -> Self { self.vesting_contract_address = address; self } pub fn with_bandwidth_claim_contract_address(mut self, address: AccountId) -> Self { self.bandwidth_claim_contract_address = address; self } pub fn with_coconut_bandwidth_contract_address(mut self, address: AccountId) -> Self { self.coconut_bandwidth_contract_address = address; self } pub fn with_multisig_contract_address(mut self, address: AccountId) -> Self { self.multisig_contract_address = address; self } } impl NymdClient { pub fn connect(endpoint: U) -> Result, NymdError> where U: TryInto, { Ok(NymdClient { client: QueryNymdClient::new(endpoint)?, client_address: None, simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, mixnet_contract_address: DEFAULT_NETWORK .mixnet_contract_address() .parse() .expect("Error parsing mixnet contract address"), vesting_contract_address: DEFAULT_NETWORK .vesting_contract_address() .parse() .expect("Error parsing vesting contract address"), bandwidth_claim_contract_address: DEFAULT_NETWORK .bandwidth_claim_contract_address() .parse() .expect("Error parsing bandwidth claim contract address"), coconut_bandwidth_contract_address: DEFAULT_NETWORK .coconut_bandwidth_contract_address() .parse() .unwrap(), multisig_contract_address: DEFAULT_NETWORK.multisig_contract_address().parse().unwrap(), }) } } impl NymdClient { // maybe the wallet could be made into a generic, but for now, let's just have this one implementation pub fn connect_with_signer( network: config::defaults::all::Network, endpoint: U, signer: DirectSecp256k1HdWallet, gas_price: Option, ) -> Result, NymdError> where U: TryInto, { let denom = network.mix_denom().base; 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)?, client_address: Some(client_address), simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, mixnet_contract_address: DEFAULT_NETWORK .mixnet_contract_address() .parse() .expect("Error parsing mixnet contract address"), vesting_contract_address: DEFAULT_NETWORK .vesting_contract_address() .parse() .expect("Error parsing vesting contract address"), bandwidth_claim_contract_address: DEFAULT_NETWORK .bandwidth_claim_contract_address() .parse() .expect("Error parsing bandwidth claim contract address"), coconut_bandwidth_contract_address: DEFAULT_NETWORK .coconut_bandwidth_contract_address() .parse() .unwrap(), multisig_contract_address: DEFAULT_NETWORK.multisig_contract_address().parse().unwrap(), }) } pub fn connect_with_mnemonic( network: config::defaults::all::Network, endpoint: U, mnemonic: bip39::Mnemonic, gas_price: Option, ) -> Result, NymdError> where U: TryInto, { let prefix = network.bech32_prefix(); let denom = network.mix_denom().base; 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)?, client_address: Some(client_address), simulated_gas_multiplier: DEFAULT_SIMULATED_GAS_MULTIPLIER, mixnet_contract_address: network .mixnet_contract_address() .parse() .expect("Error parsing mixnet contract address"), vesting_contract_address: network .vesting_contract_address() .parse() .expect("Error parsing vesting contract address"), bandwidth_claim_contract_address: network .bandwidth_claim_contract_address() .parse() .expect("Error parsing bandwidth claim contract address"), coconut_bandwidth_contract_address: network .coconut_bandwidth_contract_address() .parse() .unwrap(), multisig_contract_address: network.multisig_contract_address().parse().unwrap(), }) } } impl NymdClient { pub fn mixnet_contract_address(&self) -> &AccountId { &self.mixnet_contract_address } pub fn vesting_contract_address(&self) -> &AccountId { &self.vesting_contract_address } pub fn bandwidth_claim_contract_address(&self) -> &AccountId { &self.bandwidth_claim_contract_address } pub fn coconut_bandwidth_contract_address(&self) -> &AccountId { &self.coconut_bandwidth_contract_address } pub fn multisig_contract_address(&self) -> &AccountId { &self.multisig_contract_address } pub fn set_simulated_gas_multiplier(&mut self, multiplier: f32) { self.simulated_gas_multiplier = multiplier; } pub fn wrap_contract_execute_message( &self, contract_address: &AccountId, msg: &M, funds: Vec, ) -> Result where C: SigningCosmWasmClient, M: ?Sized + Serialize, { Ok(cosmwasm::MsgExecuteContract { sender: self.address().clone(), contract: contract_address.clone(), msg: serde_json::to_vec(msg)?, funds: funds.into_iter().map(Into::into).collect(), }) } pub fn address(&self) -> &AccountId where C: SigningCosmWasmClient, { // if this is a signing client (as required by the trait bound), it must have the address set &self.client_address.as_ref().unwrap()[0] } pub fn gas_price(&self) -> &GasPrice where C: SigningCosmWasmClient, { self.client.gas_price() } pub async fn account_sequence(&self) -> Result where C: SigningCosmWasmClient + Sync, { self.client.get_sequence(self.address()).await } pub async fn get_account_details( &self, address: &AccountId, ) -> Result, NymdError> where C: SigningCosmWasmClient + Sync, { self.client.get_account(address).await } pub async fn get_current_block_timestamp(&self) -> Result where C: CosmWasmClient + Sync, { self.get_block_timestamp(None).await } pub async fn get_block_timestamp( &self, height: Option, ) -> Result where C: CosmWasmClient + Sync, { Ok(self.client.get_block(height).await?.block.header.time) } pub async fn get_current_block_height(&self) -> Result where C: CosmWasmClient + Sync, { self.client.get_height().await } /// Obtains the hash of a block specified by the provided height. /// /// # Arguments /// /// * `height`: height of the block for which we want to obtain the hash. pub async fn get_block_hash(&self, height: u32) -> Result where C: CosmWasmClient + Sync, { self.client .get_block(Some(height)) .await .map(|block| block.block_id.hash) } pub async fn get_validators( &self, height: u64, paging: Paging, ) -> Result where C: CosmWasmClient + Sync, { Ok(self.client.validators(height as u32, paging).await?) } pub async fn get_balance( &self, address: &AccountId, denom: String, ) -> Result, NymdError> where C: CosmWasmClient + Sync, { self.client.get_balance(address, denom).await } pub async fn get_tx(&self, id: tx::Hash) -> Result where C: CosmWasmClient + Sync, { self.client.get_tx(id).await } pub async fn get_total_supply(&self) -> Result, NymdError> where C: CosmWasmClient + Sync, { self.client.get_total_supply().await } pub async fn get_contract_settings(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::StateParams {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_operator_rewards(&self, address: String) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::QueryOperatorReward { address }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_delegator_rewards( &self, address: String, mix_identity: IdentityKey, proxy: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::QueryDelegatorReward { address, mix_identity, proxy, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_pending_delegation_events( &self, owner_address: String, proxy_address: Option, ) -> Result, NymdError> where C: CosmWasmClient + Sync, { let request = QueryMsg::GetPendingDelegationEvents { owner_address, proxy_address, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_current_epoch(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetCurrentEpoch {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_mixnet_contract_version(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetContractVersion {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_rewarding_status( &self, mix_identity: mixnet_contract_common::IdentityKey, interval_id: u32, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetRewardingStatus { mix_identity, interval_id, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn query_current_rewarded_set_height(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetCurrentRewardedSetHeight {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn query_current_rewarded_set_update_details( &self, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetRewardedSetUpdateDetails {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_rewarded_set_identities_paged( &self, start_after: Option, page_limit: Option, height: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetRewardedSet { height, start_after, limit: page_limit, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_layer_distribution(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::LayerDistribution {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_reward_pool(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetRewardPool {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_circulating_supply(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetCirculatingSupply {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_sybil_resistance_percent(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetSybilResistancePercent {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_active_set_work_factor(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetActiveSetWorkFactor {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_interval_reward_percent(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetIntervalRewardPercent {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_epochs_in_interval(&self) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetEpochsInInterval {}; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } /// Checks whether there is a bonded mixnode associated with the provided client's address pub async fn owns_mixnode(&self, address: &AccountId) -> Result, NymdError> where C: CosmWasmClient + Sync, { let request = QueryMsg::OwnsMixnode { address: address.to_string(), }; let response: MixOwnershipResponse = self .client .query_contract_smart(self.mixnet_contract_address(), &request) .await?; Ok(response.mixnode) } /// Checks whether there is a bonded gateway associated with the provided client's address pub async fn owns_gateway(&self, address: &AccountId) -> Result, NymdError> where C: CosmWasmClient + Sync, { let request = QueryMsg::OwnsGateway { address: address.to_string(), }; let response: GatewayOwnershipResponse = self .client .query_contract_smart(self.mixnet_contract_address(), &request) .await?; Ok(response.gateway) } pub async fn get_mixnodes_paged( &self, start_after: Option, page_limit: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetMixNodes { start_after, limit: page_limit, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn get_gateways_paged( &self, start_after: Option, page_limit: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetGateways { start_after, limit: page_limit, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } /// Gets list of all delegations towards particular mixnode on particular page. pub async fn get_mix_delegations_paged( &self, mix_identity: IdentityKey, start_after: Option<(String, u64)>, page_limit: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetMixnodeDelegations { mix_identity: mix_identity.to_owned(), start_after, limit: page_limit, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } /// Gets list of all the mixnodes on which a particular address delegated. pub async fn get_delegator_delegations_paged( &self, delegator: String, start_after: Option, page_limit: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetDelegatorDelegations { delegator, start_after, limit: page_limit, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } /// Checks value of delegation of given client towards particular mixnode. pub async fn get_delegation_details( &self, mix_identity: IdentityKey, delegator: &AccountId, proxy: Option, ) -> Result where C: CosmWasmClient + Sync, { let request = QueryMsg::GetDelegationDetails { mix_identity, delegator: delegator.to_string(), proxy, }; self.client .query_contract_smart(self.mixnet_contract_address(), &request) .await } pub async fn simulate(&self, messages: I) -> Result where C: SigningCosmWasmClient + Sync, I: IntoIterator + Send, M: Msg, { self.client .simulate( self.address(), messages .into_iter() .map(|msg| msg.into_any()) .collect::, _>>() .map_err(|_| { NymdError::SerializationError("custom simulate messages".to_owned()) })?, "simulating execution of transactions", ) .await } /// Send funds from one address to another pub async fn send( &self, recipient: &AccountId, amount: Vec, memo: impl Into + Send + 'static, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .send_tokens(self.address(), recipient, amount, fee, memo) .await } /// Send funds from one address to multiple others pub async fn send_multiple( &self, msgs: Vec<(AccountId, Vec)>, memo: impl Into + Send + 'static, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .send_tokens_multiple(self.address(), msgs, fee, memo) .await } pub async fn execute( &self, contract_address: &AccountId, msg: &M, fee: Fee, memo: impl Into + Send + 'static, funds: Vec, ) -> Result where C: SigningCosmWasmClient + Sync, M: ?Sized + Serialize + Sync, { self.client .execute(self.address(), contract_address, msg, fee, memo, funds) .await } pub async fn execute_multiple( &self, contract_address: &AccountId, msgs: I, fee: Fee, memo: impl Into + Send + 'static, ) -> Result where C: SigningCosmWasmClient + Sync, I: IntoIterator)> + Send, M: Serialize, { self.client .execute_multiple(self.address(), contract_address, msgs, fee, memo) .await } pub async fn upload( &self, wasm_code: Vec, memo: impl Into + Send + 'static, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .upload(self.address(), wasm_code, fee, memo) .await } pub async fn instantiate( &self, code_id: ContractCodeId, msg: &M, label: String, memo: impl Into + Send + 'static, options: Option, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, M: ?Sized + Serialize + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .instantiate(self.address(), code_id, msg, label, fee, memo, options) .await } pub async fn update_admin( &self, contract_address: &AccountId, new_admin: &AccountId, memo: impl Into + Send + 'static, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .update_admin(self.address(), contract_address, new_admin, fee, memo) .await } pub async fn clear_admin( &self, contract_address: &AccountId, memo: impl Into + Send + 'static, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .clear_admin(self.address(), contract_address, fee, memo) .await } pub async fn migrate( &self, contract_address: &AccountId, code_id: ContractCodeId, msg: &M, memo: impl Into + Send + 'static, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, M: ?Sized + Serialize + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); self.client .migrate(self.address(), contract_address, code_id, fee, msg, memo) .await } #[execute("mixnet")] fn _compound_operator_reward(&self, fee: Option) -> (ExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { (ExecuteMsg::CompoundOperatorReward {}, fee) } #[execute("mixnet")] fn _claim_operator_reward(&self, fee: Option) -> (ExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { (ExecuteMsg::ClaimOperatorReward {}, fee) } #[execute("mixnet")] fn _compound_delegator_reward( &self, mix_identity: IdentityKey, fee: Option, ) -> (ExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { (ExecuteMsg::CompoundDelegatorReward { mix_identity }, fee) } #[execute("mixnet")] fn _claim_delegator_reward( &self, mix_identity: IdentityKey, fee: Option, ) -> (ExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { (ExecuteMsg::ClaimDelegatorReward { mix_identity }, fee) } #[execute("vesting")] fn _vesting_compound_delegator_reward( &self, mix_identity: IdentityKey, fee: Option, ) -> (VestingExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { ( VestingExecuteMsg::CompoundDelegatorReward { mix_identity }, fee, ) } #[execute("vesting")] fn _vesting_claim_operator_reward(&self, fee: Option) -> (VestingExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { (VestingExecuteMsg::ClaimOperatorReward {}, fee) } #[execute("vesting")] fn _vesting_compound_operator_reward( &self, fee: Option, ) -> (VestingExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { (VestingExecuteMsg::CompoundOperatorReward {}, fee) } #[execute("vesting")] fn _vesting_claim_delegator_reward( &self, mix_identity: IdentityKey, fee: Option, ) -> (VestingExecuteMsg, Option) where C: SigningCosmWasmClient + Sync, { ( VestingExecuteMsg::ClaimDelegatorReward { mix_identity }, fee, ) } /// Announce a mixnode, paying a fee. pub async fn bond_mixnode( &self, mixnode: MixNode, owner_signature: String, pledge: Coin, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::BondMixnode { mix_node: mixnode, owner_signature, }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Bonding mixnode from rust!", vec![pledge], ) .await } /// Announce a mixnode on behalf of the owner, paying a fee. pub async fn bond_mixnode_on_behalf( &self, mixnode: MixNode, owner: String, owner_signature: String, pledge: Coin, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::BondMixnodeOnBehalf { mix_node: mixnode, owner, owner_signature, }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Bonding mixnode on behalf from rust!", vec![pledge], ) .await } /// Announce multiple mixnodes on behalf of other owners, paying a fee. pub async fn bond_multiple_mixnodes_on_behalf( &self, mixnode_bonds_with_sigs: Vec<(MixNodeBond, String)>, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let reqs: Vec<(ExecuteMsg, Vec)> = mixnode_bonds_with_sigs .into_iter() .map(|(bond, owner_signature)| { ( ExecuteMsg::BondMixnodeOnBehalf { mix_node: bond.mix_node, owner: bond.owner.to_string(), owner_signature, }, vec![bond.pledge_amount.into()], ) }) .collect(); self.client .execute_multiple( self.address(), self.mixnet_contract_address(), reqs, fee, "Bonding multiple mixnodes on behalf from rust!", ) .await } /// Unbond a mixnode, removing it from the network and reclaiming staked coins pub async fn unbond_mixnode(&self, fee: Option) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UnbondMixnode {}; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Unbonding mixnode from rust!", vec![], ) .await } /// Unbond a mixnode on behalf of the owner, removing it from the network and reclaiming staked coins pub async fn unbond_mixnode_on_behalf( &self, owner: String, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UnbondMixnodeOnBehalf { owner }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Unbonding mixnode on behalf from rust!", vec![], ) .await } /// Update the configuration of a mixnode. Right now, only possible for profit margin. pub async fn update_mixnode_config( &self, profit_margin_percent: u8, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UpdateMixnodeConfig { profit_margin_percent, }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Updating mixnode configuration from rust!", vec![], ) .await } /// Delegates specified amount of stake to particular mixnode. pub async fn delegate_to_mixnode( &self, mix_identity: &str, amount: Coin, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::DelegateToMixnode { mix_identity: mix_identity.to_string(), }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Delegating to mixnode from rust!", vec![amount], ) .await } /// Delegates specified amount of stake to particular mixnode on /// behalf of a particular delegator. pub async fn delegate_to_mixnode_on_behalf( &self, mix_identity: &str, delegate: &str, amount: Coin, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::DelegateToMixnodeOnBehalf { mix_identity: mix_identity.to_string(), delegate: delegate.to_string(), }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Delegating to mixnode on behalf from rust!", vec![amount], ) .await } /// Delegates specified amount of stake to multiple mixnodes on behalf of multiple delegators. pub async fn delegate_to_multiple_mixnodes_on_behalf( &self, mixnode_delegations: Vec, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let reqs: Vec<(ExecuteMsg, Vec)> = mixnode_delegations .into_iter() .map(|delegation| { ( ExecuteMsg::DelegateToMixnodeOnBehalf { mix_identity: delegation.node_identity(), delegate: delegation.owner().to_string(), }, vec![delegation.amount().clone().into()], ) }) .collect(); self.client .execute_multiple( self.address(), self.mixnet_contract_address(), reqs, fee, "Delegating to multiple mixnodes on behalf from rust!", ) .await } /// Removes stake delegation from a particular mixnode. pub async fn remove_mixnode_delegation( &self, mix_identity: &str, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UndelegateFromMixnode { mix_identity: mix_identity.to_string(), }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Removing mixnode delegation from rust!", vec![], ) .await } /// Removes stake delegation from a particular mixnode on behalf of a particular delegator. pub async fn remove_mixnode_delegation_on_behalf( &self, mix_identity: &str, delegate: &str, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UndelegateFromMixnodeOnBehalf { mix_identity: mix_identity.to_string(), delegate: delegate.to_string(), }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Removing mixnode delegation on behalf from rust!", vec![], ) .await } /// Announce a gateway, paying a fee. pub async fn bond_gateway( &self, gateway: Gateway, owner_signature: String, pledge: Coin, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::BondGateway { gateway, owner_signature, }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Bonding gateway from rust!", vec![pledge], ) .await } /// Announce a gateway on behalf of the owner, paying a fee. pub async fn bond_gateway_on_behalf( &self, gateway: Gateway, owner: String, owner_signature: String, pledge: Coin, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::BondGatewayOnBehalf { gateway, owner, owner_signature, }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Bonding gateway on behalf from rust!", vec![pledge], ) .await } /// Announce multiple gateways on behalf of other owners, paying a fee. pub async fn bond_multiple_gateways_on_behalf( &self, gateway_bonds_with_sigs: Vec<(GatewayBond, String)>, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let reqs: Vec<(ExecuteMsg, Vec)> = gateway_bonds_with_sigs .into_iter() .map(|(bond, owner_signature)| { ( ExecuteMsg::BondGatewayOnBehalf { gateway: bond.gateway, owner: bond.owner.to_string(), owner_signature, }, vec![bond.pledge_amount.into()], ) }) .collect(); self.client .execute_multiple( self.address(), self.mixnet_contract_address(), reqs, fee, "Bonding multiple gateways on behalf from rust!", ) .await } /// Unbond a gateway, removing it from the network and reclaiming staked coins pub async fn unbond_gateway(&self, fee: Option) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UnbondGateway {}; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Unbonding gateway from rust!", vec![], ) .await } /// Unbond a gateway on behalf of the owner, removing it from the /// network and reclaiming staked coins pub async fn unbond_gateway_on_behalf( &self, owner: String, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UnbondGatewayOnBehalf { owner }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Unbonding gateway on behalf from rust!", vec![], ) .await } pub async fn update_contract_settings( &self, new_params: ContractStateParams, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::UpdateContractStateParams(new_params); self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Updating contract state from rust!", vec![], ) .await } pub async fn advance_current_epoch(&self, fee: Option) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::AdvanceCurrentEpoch {}; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Advance current epoch", vec![], ) .await } pub async fn reconcile_delegations(&self, fee: Option) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::ReconcileDelegations {}; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Reconciling delegation events", vec![], ) .await } pub async fn checkpoint_mixnodes(&self, fee: Option) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::CheckpointMixnodes {}; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Snapshotting mixnodes", vec![], ) .await } pub async fn write_rewarded_set( &self, rewarded_set: Vec, expected_active_set_size: u32, fee: Option, ) -> Result where C: SigningCosmWasmClient + Sync, { let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); let req = ExecuteMsg::WriteRewardedSet { rewarded_set, expected_active_set_size, }; self.client .execute( self.address(), self.mixnet_contract_address(), &req, fee, "Writing rewarded set", vec![], ) .await } }