This commit is contained in:
Jędrzej Stuczyński
2023-07-31 11:42:50 +01:00
parent aa7a6114be
commit e2bf9daf52
26 changed files with 1679 additions and 1344 deletions
Generated
+1
View File
@@ -4885,6 +4885,7 @@ dependencies = [
"colored",
"cosmrs",
"cosmwasm-std",
"cw-utils",
"cw3",
"cw4",
"eyre",
@@ -45,6 +45,7 @@ cosmrs = { workspace = true, features = ["bip32", "cosmwasm"] }
tendermint-rpc = { workspace = true }
eyre = { version = "0.6", optional = true }
cw-utils = { workspace = true }
cw3 = { workspace = true }
cw4 = { workspace = true }
prost = { version = "0.11", default-features = false }
+401 -394
View File
@@ -16,9 +16,8 @@ pub use nym_mixnet_contract_common::{
};
use url::Url;
use crate::nyxd::contract_traits::{DkgQueryClient, MixnetQueryClient};
#[cfg(feature = "http-client")]
use crate::nyxd::QueryNyxdClient;
// use crate::nyxd::contract_traits::{DkgQueryClient, MixnetQueryClient};
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{self, CosmWasmClient, NyxdClient};
use nym_api_requests::models::MixNodeBondAnnotated;
use nym_coconut_dkg_common::{types::EpochId, verification_key::ContractVKShare};
@@ -31,11 +30,11 @@ use nym_mixnet_contract_common::{
};
use nym_network_defaults::NymNetworkDetails;
use std::str::FromStr;
use tendermint_rpc::HttpClient;
#[cfg(all(feature = "signing", feature = "http-client"))]
use crate::nyxd::SigningNyxdClient;
#[cfg(all(feature = "signing", feature = "http-client"))]
use crate::signing::direct_wallet::DirectSecp256k1HdWallet;
use crate::signing::signer::NoSigner;
#[must_use]
#[derive(Debug, Clone)]
@@ -116,29 +115,32 @@ impl Config {
}
}
pub struct Client<C> {
pub struct Client<C, S = NoSigner> {
#[deprecated]
mixnode_page_limit: Option<u32>,
#[deprecated]
gateway_page_limit: Option<u32>,
#[deprecated]
mixnode_delegations_page_limit: Option<u32>,
#[deprecated]
rewarded_set_page_limit: Option<u32>,
// ideally they would have been read-only, but unfortunately rust doesn't have such features
pub nym_api: nym_api::Client,
pub nyxd: NyxdClient<C>,
pub nyxd: NyxdClient<C, S>,
}
#[cfg(all(feature = "signing", feature = "http-client"))]
impl Client<SigningNyxdClient<DirectSecp256k1HdWallet>> {
impl Client<HttpClient, DirectSecp256k1HdWallet> {
pub fn new_signing(
config: Config,
mnemonic: bip39::Mnemonic,
) -> Result<Client<SigningNyxdClient<DirectSecp256k1HdWallet>>, ValidatorClientError> {
) -> Result<Client<HttpClient, DirectSecp256k1HdWallet>, ValidatorClientError> {
let nym_api_client = nym_api::Client::new(config.api_url.clone());
let nyxd_client = NyxdClient::connect_with_mnemonic(
config.nyxd_config.clone(),
config.nyxd_url.as_str(),
mnemonic,
None,
)?;
Ok(Client {
@@ -157,13 +159,14 @@ impl Client<SigningNyxdClient<DirectSecp256k1HdWallet>> {
}
pub fn set_nyxd_simulated_gas_multiplier(&mut self, multiplier: f32) {
self.nyxd.set_simulated_gas_multiplier(multiplier)
todo!()
// self.nyxd.set_simulated_gas_multiplier(multiplier)
}
}
#[cfg(feature = "http-client")]
impl Client<QueryNyxdClient> {
pub fn new_query(config: Config) -> Result<Client<QueryNyxdClient>, ValidatorClientError> {
impl Client<HttpClient> {
pub fn new_query(config: Config) -> Result<Client<HttpClient>, ValidatorClientError> {
let nym_api_client = nym_api::Client::new(config.api_url.clone());
let nyxd_client =
NyxdClient::connect(config.nyxd_config.clone(), config.nyxd_url.as_str())?;
@@ -195,375 +198,379 @@ impl<C> Client<C> {
}
pub fn get_mixnet_contract_address(&self) -> cosmrs::AccountId {
self.nyxd.mixnet_contract_address().clone()
// TODO: deal with the expect
self.nyxd
.mixnet_contract_address()
.expect("mixnet contract address is not available")
.clone()
}
pub async fn get_all_node_families(&self) -> Result<Vec<Family>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut families = Vec::new();
let mut start_after = None;
loop {
let paged_response = self
.nyxd
.get_all_node_families_paged(start_after.take(), None)
.await?;
families.extend(paged_response.families);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(families)
}
pub async fn get_all_family_members(
&self,
) -> Result<Vec<(IdentityKey, FamilyHead)>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut members = Vec::new();
let mut start_after = None;
loop {
let paged_response = self
.nyxd
.get_all_family_members_paged(start_after.take(), None)
.await?;
members.extend(paged_response.members);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(members)
}
// basically handles paging for us
pub async fn get_all_nyxd_rewarded_set_mixnodes(
&self,
) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut identities = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_rewarded_set_paged(start_after.take(), self.rewarded_set_page_limit)
.await?;
identities.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(identities)
}
pub async fn get_all_nyxd_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut mixnodes = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_mixnode_bonds_paged(self.mixnode_page_limit, start_after.take())
.await?;
mixnodes.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(mixnodes)
}
pub async fn get_all_nyxd_mixnodes_detailed(
&self,
) -> Result<Vec<MixNodeDetails>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut mixnodes = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_mixnodes_detailed_paged(self.mixnode_page_limit, start_after.take())
.await?;
mixnodes.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(mixnodes)
}
pub async fn get_all_nyxd_unbonded_mixnodes(
&self,
) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut mixnodes = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_unbonded_paged(self.mixnode_page_limit, start_after.take())
.await?;
mixnodes.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(mixnodes)
}
pub async fn get_all_nyxd_unbonded_mixnodes_by_owner(
&self,
owner: &cosmrs::AccountId,
) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut mixnodes = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_unbonded_by_owner_paged(owner, self.mixnode_page_limit, start_after.take())
.await?;
mixnodes.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(mixnodes)
}
pub async fn get_all_nyxd_unbonded_mixnodes_by_identity(
&self,
identity_key: String,
) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut mixnodes = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_unbonded_by_identity_paged(
identity_key.clone(),
self.mixnode_page_limit,
start_after.take(),
)
.await?;
mixnodes.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(mixnodes)
}
pub async fn get_all_nyxd_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut gateways = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_gateways_paged(start_after.take(), self.gateway_page_limit)
.await?;
gateways.append(&mut paged_response.nodes);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(gateways)
}
pub async fn get_all_nyxd_single_mixnode_delegations(
&self,
mix_id: MixId,
) -> Result<Vec<Delegation>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut delegations = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_mixnode_delegations_paged(
mix_id,
start_after.take(),
self.mixnode_delegations_page_limit,
)
.await?;
delegations.append(&mut paged_response.delegations);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(delegations)
}
pub async fn get_all_delegator_delegations(
&self,
delegation_owner: &cosmrs::AccountId,
) -> Result<Vec<Delegation>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut delegations = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_delegator_delegations_paged(
delegation_owner.to_string(),
start_after.take(),
self.mixnode_delegations_page_limit,
)
.await?;
delegations.append(&mut paged_response.delegations);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(delegations)
}
pub async fn get_all_network_delegations(&self) -> Result<Vec<Delegation>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut delegations = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_all_network_delegations_paged(
start_after.take(),
self.mixnode_delegations_page_limit,
)
.await?;
delegations.append(&mut paged_response.delegations);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(delegations)
}
pub async fn get_all_nyxd_pending_epoch_events(
&self,
) -> Result<Vec<PendingEpochEvent>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut events = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_pending_epoch_events_paged(start_after.take(), self.rewarded_set_page_limit)
.await?;
events.append(&mut paged_response.events);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(events)
}
pub async fn get_all_nyxd_pending_interval_events(
&self,
) -> Result<Vec<PendingIntervalEvent>, ValidatorClientError>
where
C: CosmWasmClient + Sync + Send,
{
let mut events = Vec::new();
let mut start_after = None;
loop {
let mut paged_response = self
.nyxd
.get_pending_interval_events_paged(start_after.take(), self.rewarded_set_page_limit)
.await?;
events.append(&mut paged_response.events);
if let Some(start_after_res) = paged_response.start_next_after {
start_after = Some(start_after_res)
} else {
break;
}
}
Ok(events)
}
// pub async fn get_all_node_families(&self) -> Result<Vec<Family>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut families = Vec::new();
// let mut start_after = None;
//
// loop {
// let paged_response = self
// .nyxd
// .get_all_node_families_paged(start_after.take(), None)
// .await?;
// families.extend(paged_response.families);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(families)
// }
//
// pub async fn get_all_family_members(
// &self,
// ) -> Result<Vec<(IdentityKey, FamilyHead)>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut members = Vec::new();
// let mut start_after = None;
//
// loop {
// let paged_response = self
// .nyxd
// .get_all_family_members_paged(start_after.take(), None)
// .await?;
// members.extend(paged_response.members);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(members)
// }
//
// // basically handles paging for us
// pub async fn get_all_nyxd_rewarded_set_mixnodes(
// &self,
// ) -> Result<Vec<(MixId, RewardedSetNodeStatus)>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut identities = Vec::new();
// let mut start_after = None;
//
// loop {
// let mut paged_response = self
// .nyxd
// .get_rewarded_set_paged(start_after.take(), self.rewarded_set_page_limit)
// .await?;
// identities.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(identities)
// }
//
// pub async fn get_all_nyxd_mixnode_bonds(&self) -> Result<Vec<MixNodeBond>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut mixnodes = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_mixnode_bonds_paged(self.mixnode_page_limit, start_after.take())
// .await?;
// mixnodes.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(mixnodes)
// }
//
// pub async fn get_all_nyxd_mixnodes_detailed(
// &self,
// ) -> Result<Vec<MixNodeDetails>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut mixnodes = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_mixnodes_detailed_paged(self.mixnode_page_limit, start_after.take())
// .await?;
// mixnodes.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(mixnodes)
// }
//
// pub async fn get_all_nyxd_unbonded_mixnodes(
// &self,
// ) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut mixnodes = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_unbonded_paged(self.mixnode_page_limit, start_after.take())
// .await?;
// mixnodes.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(mixnodes)
// }
//
// pub async fn get_all_nyxd_unbonded_mixnodes_by_owner(
// &self,
// owner: &cosmrs::AccountId,
// ) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut mixnodes = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_unbonded_by_owner_paged(owner, self.mixnode_page_limit, start_after.take())
// .await?;
// mixnodes.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(mixnodes)
// }
//
// pub async fn get_all_nyxd_unbonded_mixnodes_by_identity(
// &self,
// identity_key: String,
// ) -> Result<Vec<(MixId, UnbondedMixnode)>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut mixnodes = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_unbonded_by_identity_paged(
// identity_key.clone(),
// self.mixnode_page_limit,
// start_after.take(),
// )
// .await?;
// mixnodes.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(mixnodes)
// }
//
// pub async fn get_all_nyxd_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut gateways = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_gateways_paged(start_after.take(), self.gateway_page_limit)
// .await?;
// gateways.append(&mut paged_response.nodes);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(gateways)
// }
//
// pub async fn get_all_nyxd_single_mixnode_delegations(
// &self,
// mix_id: MixId,
// ) -> Result<Vec<Delegation>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut delegations = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_mixnode_delegations_paged(
// mix_id,
// start_after.take(),
// self.mixnode_delegations_page_limit,
// )
// .await?;
// delegations.append(&mut paged_response.delegations);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(delegations)
// }
//
// pub async fn get_all_delegator_delegations(
// &self,
// delegation_owner: &cosmrs::AccountId,
// ) -> Result<Vec<Delegation>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut delegations = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_delegator_delegations_paged(
// delegation_owner.to_string(),
// start_after.take(),
// self.mixnode_delegations_page_limit,
// )
// .await?;
// delegations.append(&mut paged_response.delegations);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(delegations)
// }
//
// pub async fn get_all_network_delegations(&self) -> Result<Vec<Delegation>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut delegations = Vec::new();
// let mut start_after = None;
// loop {
// let mut paged_response = self
// .nyxd
// .get_all_network_delegations_paged(
// start_after.take(),
// self.mixnode_delegations_page_limit,
// )
// .await?;
// delegations.append(&mut paged_response.delegations);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(delegations)
// }
//
// pub async fn get_all_nyxd_pending_epoch_events(
// &self,
// ) -> Result<Vec<PendingEpochEvent>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut events = Vec::new();
// let mut start_after = None;
//
// loop {
// let mut paged_response = self
// .nyxd
// .get_pending_epoch_events_paged(start_after.take(), self.rewarded_set_page_limit)
// .await?;
// events.append(&mut paged_response.events);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(events)
// }
//
// pub async fn get_all_nyxd_pending_interval_events(
// &self,
// ) -> Result<Vec<PendingIntervalEvent>, ValidatorClientError>
// where
// C: CosmWasmClient + Sync + Send,
// {
// let mut events = Vec::new();
// let mut start_after = None;
//
// loop {
// let mut paged_response = self
// .nyxd
// .get_pending_interval_events_paged(start_after.take(), self.rewarded_set_page_limit)
// .await?;
// events.append(&mut paged_response.events);
//
// if let Some(start_after_res) = paged_response.start_next_after {
// start_after = Some(start_after_res)
// } else {
// break;
// }
// }
//
// Ok(events)
// }
}
// validator-api wrappers
@@ -633,20 +640,20 @@ pub struct CoconutApiClient {
}
impl CoconutApiClient {
pub async fn all_coconut_api_clients<C>(
client: &C,
epoch_id: EpochId,
) -> Result<Vec<Self>, ValidatorClientError>
where
C: DkgQueryClient + Sync + Send,
{
Ok(client
.get_all_verification_key_shares(epoch_id)
.await?
.into_iter()
.filter_map(Self::try_from)
.collect())
}
// pub async fn all_coconut_api_clients<C>(
// client: &C,
// epoch_id: EpochId,
// ) -> Result<Vec<Self>, ValidatorClientError>
// where
// C: DkgQueryClient + Sync + Send,
// {
// Ok(client
// .get_all_verification_key_shares(epoch_id)
// .await?
// .into_iter()
// .filter_map(Self::try_from)
// .collect())
// }
fn try_from(share: ContractVKShare) -> Option<Self> {
if share.verified {
@@ -1,7 +1,8 @@
use crate::nyxd::error::NyxdError;
use crate::nyxd::{Config as ClientConfig, NyxdClient, QueryNyxdClient};
use crate::nyxd::{Config as ClientConfig, QueryHttpNyxdClient};
use crate::{NymApiClient, ValidatorClientError};
// use crate::nyxd::contract_traits::MixnetQueryClient;
use crate::nyxd::contract_traits::MixnetQueryClient;
use colored::Colorize;
use core::fmt;
@@ -53,7 +54,7 @@ pub async fn test_nyxd_url_connection(
let config = ClientConfig::try_from_nym_network_details(&network)
.expect("failed to create valid nyxd client config");
let mut nyxd_client = NyxdClient::<QueryNyxdClient>::connect(config, nyxd_url.as_str())?;
let mut nyxd_client = QueryHttpNyxdClient::connect(config, nyxd_url.as_str())?;
// possibly redundant, but lets just leave it here
nyxd_client.set_mixnet_contract_address(address);
match test_nyxd_connection(network, &nyxd_url, &nyxd_client).await {
@@ -75,7 +76,7 @@ fn setup_connection_tests<H: BuildHasher + 'static>(
let config = ClientConfig::try_from_nym_network_details(&network)
.expect("failed to create valid nyxd client config");
if let Ok(mut client) = NyxdClient::<QueryNyxdClient>::connect(config, url.as_str()) {
if let Ok(mut client) = QueryHttpNyxdClient::connect(config, url.as_str()) {
// possibly redundant, but lets just leave it here
client.set_mixnet_contract_address(address);
Some(ClientForConnectionTest::Nyxd(
@@ -112,7 +113,7 @@ fn extract_and_collect_results_into_map(
async fn test_nyxd_connection(
network: NymNetworkDetails,
url: &Url,
client: &NyxdClient<QueryNyxdClient>,
client: &QueryHttpNyxdClient,
) -> ConnectionResult {
let result = match timeout(
Duration::from_secs(CONNECTION_TEST_TIMEOUT_SEC),
@@ -186,7 +187,7 @@ async fn test_nym_api_connection(
}
enum ClientForConnectionTest {
Nyxd(NymNetworkDetails, Url, Box<NyxdClient<QueryNyxdClient>>),
Nyxd(NymNetworkDetails, Url, Box<QueryHttpNyxdClient>),
Api(NymNetworkDetails, Url, NymApiClient),
}
@@ -1,33 +1,65 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::error::NyxdError;
use crate::nyxd::{CosmWasmClient, NyxdClient};
use nym_coconut_bandwidth_contract_common::msg::QueryMsg;
use nym_coconut_bandwidth_contract_common::msg::QueryMsg as CoconutBandwidthQueryMsg;
use nym_coconut_bandwidth_contract_common::spend_credential::SpendCredentialResponse;
use crate::nyxd::contract_traits::NymContractsProvider;
use async_trait::async_trait;
use serde::Deserialize;
#[async_trait]
pub trait CoconutBandwidthQueryClient {
async fn get_spent_credential(
async fn query_coconut_bandwidth_contract<T>(
&self,
blinded_serial_number: String,
) -> Result<SpendCredentialResponse, NyxdError>;
}
query: CoconutBandwidthQueryMsg,
) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> CoconutBandwidthQueryClient for NyxdClient<C> {
async fn get_spent_credential(
&self,
blinded_serial_number: String,
) -> Result<SpendCredentialResponse, NyxdError> {
let request = QueryMsg::GetSpentCredential {
self.query_coconut_bandwidth_contract(CoconutBandwidthQueryMsg::GetSpentCredential {
blinded_serial_number,
};
self.client
.query_contract_smart(self.coconut_bandwidth_contract_address(), &request)
})
.await
}
}
#[async_trait]
impl<C> CoconutBandwidthQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_coconut_bandwidth_contract<T>(
&self,
query: CoconutBandwidthQueryMsg,
) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let coconut_bandwidth_contract_address = self
.coconut_bandwidth_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("coconut bandwidth contract"))?;
self.query_contract_smart(coconut_bandwidth_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: CoconutBandwidthQueryClient + Send + Sync>(
client: C,
msg: CoconutBandwidthQueryMsg,
) {
unimplemented!()
}
}
@@ -1,6 +1,7 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{CosmWasmClient, NyxdClient};
use async_trait::async_trait;
@@ -176,29 +177,32 @@ pub trait DkgQueryClient {
}
#[async_trait]
impl<C> DkgQueryClient for NyxdClient<C>
impl<C> DkgQueryClient for C
where
C: CosmWasmClient + Send + Sync,
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.client
.query_contract_smart(self.coconut_dkg_contract_address(), &query)
let dkg_contract_address = &self
.dkg_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("dkg contract"))?;
self.query_contract_smart(dkg_contract_address, &query)
.await
}
}
#[async_trait]
impl<C> DkgQueryClient for crate::Client<C>
where
C: CosmWasmClient + Sync + Send,
{
async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.nyxd.query_dkg_contract(query).await
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: DkgQueryClient + Send + Sync>(
client: C,
msg: DkgQueryMsg,
) {
unimplemented!()
}
}
@@ -1,28 +1,57 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{CosmWasmClient, NyxdClient};
use nym_group_contract_common::msg::QueryMsg;
use async_trait::async_trait;
use cw4::MemberResponse;
use nym_group_contract_common::msg::QueryMsg as GroupQueryMsg;
use serde::Deserialize;
#[async_trait]
pub trait GroupQueryClient {
async fn member(&self, addr: String) -> Result<MemberResponse, NyxdError>;
}
async fn query_group_contract<T>(&self, query: GroupQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> GroupQueryClient for NyxdClient<C> {
async fn member(&self, addr: String) -> Result<MemberResponse, NyxdError> {
let request = QueryMsg::Member {
addr,
at_height: None,
};
self.client
.query_contract_smart(self.group_contract_address(), &request)
async fn member(
&self,
addr: String,
at_height: Option<u64>,
) -> Result<MemberResponse, NyxdError> {
self.query_group_contract(GroupQueryMsg::Member { addr, at_height })
.await
}
}
#[async_trait]
impl<C> GroupQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_group_contract<T>(&self, query: GroupQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let group_contract_address = &self
.group_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("group contract"))?;
self.query_contract_smart(group_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: GroupQueryClient + Send + Sync>(
client: C,
msg: GroupQueryMsg,
) {
unimplemented!()
}
}
@@ -1,9 +1,10 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub use crate::nyxd::cosmwasm_client::client::CosmWasmClient;
use crate::define_paged_response;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::NyxdClient;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::signing::Nonce;
@@ -93,8 +94,8 @@ pub trait MixnetQueryClient {
async fn get_all_family_members_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
start_after: Option<String>,
) -> Result<PagedMembersResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetAllMembersPaged { limit, start_after })
.await
@@ -435,46 +436,177 @@ pub trait MixnetQueryClient {
async fn get_node_family_by_label(
&self,
label: &str,
label: String,
) -> Result<FamilyByLabelResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel {
label: label.to_string(),
})
.await
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByLabel { label })
.await
}
async fn get_node_family_by_head(&self, head: &str) -> Result<FamilyByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead {
head: head.to_string(),
})
.await
}
}
#[async_trait]
impl<C> MixnetQueryClient for NyxdClient<C>
where
C: CosmWasmClient + Sync + Send,
{
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.client
.query_contract_smart(self.mixnet_contract_address(), &query)
async fn get_node_family_by_head(
&self,
head: String,
) -> Result<FamilyByHeadResponse, NyxdError> {
self.query_mixnet_contract(MixnetQueryMsg::GetFamilyByHead { head })
.await
}
}
// extension trait to the query client to deal with the paged queries
// (it didn't feel appropriate to combine it with the existing trait
#[async_trait]
impl<C> MixnetQueryClient for crate::Client<C>
pub trait PagedMixnetClient: MixnetQueryClient + Send + Sync {
// async fn get_all_node_families(&self) -> Result<Vec<Family>, NyxdError> {
// let mut res = Vec::new();
// let mut start_after = None;
//
// loop {
// let paged_response = self
// .get_all_node_families_paged(start_after.take(), None)
// .await?;
// res.extend(paged_response.families);
//
// if let Some(start_next_after) = paged_response.start_next_after {
// start_after = Some(start_next_after)
// } else {
// break;
// }
// }
//
// Ok(res)
// }
// define_paged_response!(
// get_all_node_families,
// Family,
// get_all_node_families_paged,
// families
// );
}
#[async_trait]
impl<T> PagedMixnetClient for T where T: MixnetQueryClient {}
#[async_trait]
impl<C> MixnetQueryClient for C
where
C: CosmWasmClient + Sync + Send,
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_mixnet_contract<T>(&self, query: MixnetQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.nyxd.query_mixnet_contract(query).await
let mixnet_contract_address = &self
.mixnet_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("mixnet contract"))?;
self.query_contract_smart(mixnet_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: MixnetQueryClient + Send + Sync>(
client: C,
msg: MixnetQueryMsg,
) {
todo!()
// match msg {
// MixnetQueryMsg::GetAllFamiliesPaged { limit, start_after } => client
// .get_all_family_members_paged(limit, start_after)
// .await
// .map(|_| ()),
// MixnetQueryMsg::GetAllMembersPaged { limit, start_after } => client
// .get_all_family_members_paged(limit, start_after)
// .await
// .map(|_| ()),
// MixnetQueryMsg::GetFamilyByHead { head } => {
// client.get_node_family_by_head(head).await.map(|_| ())
// }
// MixnetQueryMsg::GetFamilyByLabel { label } => {
// client.get_node_family_by_label(label).await.map(|_| ())
// }
// MixnetQueryMsg::GetFamilyMembersByHead { head } => todo!(),
// MixnetQueryMsg::GetFamilyMembersByLabel { label } => todo!(),
// MixnetQueryMsg::GetContractVersion {} => {
// client.get_mixnet_contract_version().await.map(|_| ())
// }
// MixnetQueryMsg::GetCW2ContractVersion {} => todo!(),
// MixnetQueryMsg::GetRewardingValidatorAddress {} => {
// client.get_rewarding_validator_address().await.map(|_| ())
// }
// MixnetQueryMsg::GetStateParams {} => todo!(),
// MixnetQueryMsg::GetState {} => client.get_mixnet_contract_state().await.map(|_| ()),
// MixnetQueryMsg::GetRewardingParams {} => {}
// MixnetQueryMsg::GetEpochStatus {} => {}
// MixnetQueryMsg::GetCurrentIntervalDetails {} => {}
// MixnetQueryMsg::GetRewardedSet { limit, start_after } => {}
// MixnetQueryMsg::GetMixNodeBonds { limit, start_after } => {}
// MixnetQueryMsg::GetMixNodesDetailed { limit, start_after } => {}
// MixnetQueryMsg::GetUnbondedMixNodes { limit, start_after } => {}
// MixnetQueryMsg::GetUnbondedMixNodesByOwner {
// owner,
// limit,
// start_after,
// } => {}
// MixnetQueryMsg::GetUnbondedMixNodesByIdentityKey {
// identity_key,
// limit,
// start_after,
// } => {}
// MixnetQueryMsg::GetOwnedMixnode { address } => {}
// MixnetQueryMsg::GetMixnodeDetails { mix_id } => {}
// MixnetQueryMsg::GetMixnodeRewardingDetails { mix_id } => {}
// MixnetQueryMsg::GetStakeSaturation { mix_id } => {}
// MixnetQueryMsg::GetUnbondedMixNodeInformation { mix_id } => {}
// MixnetQueryMsg::GetBondedMixnodeDetailsByIdentity { mix_identity } => {}
// MixnetQueryMsg::GetLayerDistribution {} => {}
// MixnetQueryMsg::GetGateways { start_after, limit } => {}
// MixnetQueryMsg::GetGatewayBond { identity } => {}
// MixnetQueryMsg::GetOwnedGateway { address } => {}
// MixnetQueryMsg::GetMixnodeDelegations {
// mix_id,
// start_after,
// limit,
// } => {}
// MixnetQueryMsg::GetDelegatorDelegations {
// delegator,
// start_after,
// limit,
// } => {}
// MixnetQueryMsg::GetDelegationDetails {
// mix_id,
// delegator,
// proxy,
// } => {}
// MixnetQueryMsg::GetAllDelegations { start_after, limit } => {}
// MixnetQueryMsg::GetPendingOperatorReward { address } => {}
// MixnetQueryMsg::GetPendingMixNodeOperatorReward { mix_id } => {}
// MixnetQueryMsg::GetPendingDelegatorReward {
// address,
// mix_id,
// proxy,
// } => {}
// MixnetQueryMsg::GetEstimatedCurrentEpochOperatorReward {
// mix_id,
// estimated_performance,
// } => {}
// MixnetQueryMsg::GetEstimatedCurrentEpochDelegatorReward {
// address,
// mix_id,
// proxy,
// estimated_performance,
// } => {}
// MixnetQueryMsg::GetPendingEpochEvents { limit, start_after } => {}
// MixnetQueryMsg::GetPendingIntervalEvents { limit, start_after } => {}
// MixnetQueryMsg::GetPendingEpochEvent { event_id } => {}
// MixnetQueryMsg::GetPendingIntervalEvent { event_id } => {}
// MixnetQueryMsg::GetNumberOfPendingEvents {} => {}
// MixnetQueryMsg::GetSigningNonce { address } => {}
// }
// .expect("ignore error")
}
}
@@ -1,7 +1,11 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
// TODO: expose query-related capabilities to wasm client...
use cosmrs::AccountId;
use nym_network_defaults::NymContracts;
use std::str::FromStr;
// TODO: all of those could/should be derived via a macro
mod coconut_bandwidth_query_client;
mod dkg_query_client;
@@ -12,20 +16,20 @@ mod name_service_query_client;
mod sp_directory_query_client;
mod vesting_query_client;
#[cfg(feature = "signing")]
mod coconut_bandwidth_signing_client;
#[cfg(feature = "signing")]
mod dkg_signing_client;
#[cfg(feature = "signing")]
mod mixnet_signing_client;
#[cfg(feature = "signing")]
mod multisig_signing_client;
#[cfg(feature = "signing")]
mod name_service_signing_client;
#[cfg(feature = "signing")]
mod sp_directory_signing_client;
#[cfg(feature = "signing")]
mod vesting_signing_client;
// #[cfg(feature = "signing")]
// mod coconut_bandwidth_signing_client;
// #[cfg(feature = "signing")]
// mod dkg_signing_client;
// #[cfg(feature = "signing")]
// mod mixnet_signing_client;
// #[cfg(feature = "signing")]
// mod multisig_signing_client;
// #[cfg(feature = "signing")]
// mod name_service_signing_client;
// #[cfg(feature = "signing")]
// mod sp_directory_signing_client;
// #[cfg(feature = "signing")]
// mod vesting_signing_client;
pub use coconut_bandwidth_query_client::CoconutBandwidthQueryClient;
pub use dkg_query_client::DkgQueryClient;
@@ -36,17 +40,112 @@ pub use name_service_query_client::NameServiceQueryClient;
pub use sp_directory_query_client::SpDirectoryQueryClient;
pub use vesting_query_client::VestingQueryClient;
#[cfg(feature = "signing")]
pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
#[cfg(feature = "signing")]
pub use dkg_signing_client::DkgSigningClient;
#[cfg(feature = "signing")]
pub use mixnet_signing_client::MixnetSigningClient;
#[cfg(feature = "signing")]
pub use multisig_signing_client::MultisigSigningClient;
#[cfg(feature = "signing")]
pub use name_service_signing_client::NameServiceSigningClient;
#[cfg(feature = "signing")]
pub use sp_directory_signing_client::SpDirectorySigningClient;
#[cfg(feature = "signing")]
pub use vesting_signing_client::VestingSigningClient;
// #[cfg(feature = "signing")]
// pub use coconut_bandwidth_signing_client::CoconutBandwidthSigningClient;
// #[cfg(feature = "signing")]
// pub use dkg_signing_client::DkgSigningClient;
// #[cfg(feature = "signing")]
// pub use mixnet_signing_client::MixnetSigningClient;
// #[cfg(feature = "signing")]
// pub use multisig_signing_client::MultisigSigningClient;
// #[cfg(feature = "signing")]
// pub use name_service_signing_client::NameServiceSigningClient;
// #[cfg(feature = "signing")]
// pub use sp_directory_signing_client::SpDirectorySigningClient;
// #[cfg(feature = "signing")]
// pub use vesting_signing_client::VestingSigningClient;
pub trait NymContractsProvider {
// main
fn mixnet_contract_address(&self) -> Option<&AccountId>;
fn vesting_contract_address(&self) -> Option<&AccountId>;
// coconut-related
fn coconut_bandwidth_contract_address(&self) -> Option<&AccountId>;
fn dkg_contract_address(&self) -> Option<&AccountId>;
fn group_contract_address(&self) -> Option<&AccountId>;
fn multisig_contract_address(&self) -> Option<&AccountId>;
// SPs
fn name_service_contract_address(&self) -> Option<&AccountId>;
fn service_provider_contract_address(&self) -> Option<&AccountId>;
}
#[derive(Debug, Clone)]
pub struct TypedNymContracts {
pub mixnet_contract_address: Option<AccountId>,
pub vesting_contract_address: Option<AccountId>,
pub coconut_bandwidth_contract_address: Option<AccountId>,
pub group_contract_address: Option<AccountId>,
pub multisig_contract_address: Option<AccountId>,
pub coconut_dkg_contract_address: Option<AccountId>,
pub service_provider_directory_contract_address: Option<AccountId>,
pub name_service_contract_address: Option<AccountId>,
}
impl TryFrom<NymContracts> for TypedNymContracts {
type Error = <AccountId as FromStr>::Err;
fn try_from(value: NymContracts) -> Result<Self, Self::Error> {
Ok(TypedNymContracts {
mixnet_contract_address: value
.mixnet_contract_address
.map(|addr| addr.parse())
.transpose()?,
vesting_contract_address: value
.vesting_contract_address
.map(|addr| addr.parse())
.transpose()?,
coconut_bandwidth_contract_address: value
.coconut_bandwidth_contract_address
.map(|addr| addr.parse())
.transpose()?,
group_contract_address: value
.group_contract_address
.map(|addr| addr.parse())
.transpose()?,
multisig_contract_address: value
.multisig_contract_address
.map(|addr| addr.parse())
.transpose()?,
coconut_dkg_contract_address: value
.coconut_dkg_contract_address
.map(|addr| addr.parse())
.transpose()?,
service_provider_directory_contract_address: value
.service_provider_directory_contract_address
.map(|addr| addr.parse())
.transpose()?,
name_service_contract_address: value
.name_service_contract_address
.map(|addr| addr.parse())
.transpose()?,
})
}
}
// a simple helper macro to define a function to repeatedly call a paged query until a full response is constructed
#[macro_export]
macro_rules! define_paged_response {
( $f: ident, $r: ty, $fc: ident, $field: ident ) => {
async fn $f(&self) -> Result<Vec<$r>, NyxdError> {
let mut res = Vec::new();
let mut start_after = None;
loop {
let paged_response = self.$fc(start_after.take(), None).await?;
res.extend(paged_response.$field);
if let Some(start_next_after) = paged_response.start_next_after {
start_after = Some(start_next_after)
} else {
break;
}
}
Ok(res)
}
};
}
@@ -1,23 +1,93 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2022-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::{CosmWasmClient, NyxdClient};
use cw3::{ProposalListResponse, ProposalResponse};
use nym_multisig_contract_common::msg::QueryMsg;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cw3::{
ProposalListResponse, ProposalResponse, VoteListResponse, VoteResponse, VoterListResponse,
VoterResponse,
};
use cw_utils::ThresholdResponse;
use nym_multisig_contract_common::msg::QueryMsg as MultisigQueryMsg;
use serde::Deserialize;
#[async_trait]
pub trait MultisigQueryClient {
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NyxdError>;
async fn query_multisig_contract<T>(&self, query: MultisigQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn query_threshold(&self) -> Result<ThresholdResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::Threshold {})
.await
}
async fn query_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::Proposal { proposal_id })
.await
}
async fn list_proposals(
&self,
start_after: Option<u64>,
limit: Option<u32>,
) -> Result<ProposalListResponse, NyxdError>;
) -> Result<ProposalListResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::ListProposals { start_after, limit })
.await
}
async fn reverse_proposals(
&self,
start_before: Option<u64>,
limit: Option<u32>,
) -> Result<ProposalListResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::ReverseProposals {
start_before,
limit,
})
.await
}
async fn query_vote(&self, proposal_id: u64, voter: String) -> Result<VoteResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::Vote { proposal_id, voter })
.await
}
async fn list_votes(
&self,
proposal_id: u64,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<VoteListResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::ListVotes {
proposal_id,
start_after,
limit,
})
.await
}
async fn query_voter(&self, address: String) -> Result<VoterResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::Voter { address })
.await
}
async fn list_voters(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<VoterListResponse, NyxdError> {
self.query_multisig_contract(MultisigQueryMsg::ListVoters { start_after, limit })
.await
}
// technically it's not deprecated, just not implemented, but I need clippy to point it out to me before I make a PR
#[deprecated]
async fn query_config(&self) -> Result<(), NyxdError> {
unimplemented!()
}
async fn get_all_proposals(&self) -> Result<Vec<ProposalResponse>, NyxdError> {
let mut proposals = Vec::new();
@@ -41,22 +111,63 @@ pub trait MultisigQueryClient {
}
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> MultisigQueryClient for NyxdClient<C> {
async fn get_proposal(&self, proposal_id: u64) -> Result<ProposalResponse, NyxdError> {
let request = QueryMsg::Proposal { proposal_id };
self.client
.query_contract_smart(self.multisig_contract_address(), &request)
.await
}
async fn list_proposals(
&self,
start_after: Option<u64>,
limit: Option<u32>,
) -> Result<ProposalListResponse, NyxdError> {
let request = QueryMsg::ListProposals { start_after, limit };
self.client
.query_contract_smart(self.multisig_contract_address(), &request)
impl<C> MultisigQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_multisig_contract<T>(&self, query: MultisigQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let multisig_contract_address = &self
.multisig_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("multisig contract"))?;
self.query_contract_smart(multisig_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
async fn all_query_variants_are_covered<C: MultisigQueryClient + Send + Sync>(
client: C,
msg: MultisigQueryMsg,
) {
match msg {
MultisigQueryMsg::Threshold {} => client.query_threshold().await.map(|_| ()),
MultisigQueryMsg::Proposal { proposal_id } => {
client.query_proposal(proposal_id).await.map(|_| ())
}
MultisigQueryMsg::ListProposals { start_after, limit } => {
client.list_proposals(start_after, limit).await.map(|_| ())
}
MultisigQueryMsg::ReverseProposals {
start_before,
limit,
} => client
.reverse_proposals(start_before, limit)
.await
.map(|_| ()),
MultisigQueryMsg::Vote { proposal_id, voter } => {
client.query_vote(proposal_id, voter).await.map(|_| ())
}
MultisigQueryMsg::ListVotes {
proposal_id,
start_after,
limit,
} => client
.list_votes(proposal_id, start_after, limit)
.await
.map(|_| ()),
MultisigQueryMsg::Voter { address } => client.query_voter(address).await.map(|_| ()),
MultisigQueryMsg::ListVoters { start_after, limit } => {
client.list_voters(start_after, limit).await.map(|_| ())
}
MultisigQueryMsg::Config {} => client.query_config().await.map(|_| ()),
}
.expect("ignore error")
}
}
@@ -1,3 +1,8 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{error::NyxdError, CosmWasmClient};
use async_trait::async_trait;
use cosmrs::AccountId;
use nym_contracts_common::{signing::Nonce, ContractBuildInformation};
@@ -8,8 +13,6 @@ use nym_name_service_common::{
};
use serde::Deserialize;
use crate::nyxd::{error::NyxdError, CosmWasmClient, NyxdClient};
#[async_trait]
pub trait NameServiceQueryClient {
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
@@ -81,36 +84,33 @@ pub trait NameServiceQueryClient {
.await
}
}
#[async_trait]
impl<C> NameServiceQueryClient for NyxdClient<C>
impl<C> NameServiceQueryClient for C
where
C: CosmWasmClient + Send + Sync,
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.client
.query_contract_smart(
self.name_service_contract_address().ok_or(
NyxdError::NoContractAddressAvailable("name service contract".to_string()),
)?,
&query,
)
let name_service_contract_address = &self
.name_service_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("name service contract"))?;
self.query_contract_smart(name_service_contract_address, &query)
.await
}
}
#[async_trait]
impl<C> NameServiceQueryClient for crate::Client<C>
where
C: CosmWasmClient + Send + Sync,
{
async fn query_name_service_contract<T>(&self, query: NameQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.nyxd.query_name_service_contract(query).await
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: NameServiceQueryClient + Send + Sync>(
client: C,
msg: NameQueryMsg,
) {
unimplemented!()
}
}
@@ -10,6 +10,7 @@ use nym_service_provider_directory_common::{
};
use serde::Deserialize;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::{error::NyxdError, CosmWasmClient, NyxdClient};
#[async_trait]
@@ -89,36 +90,33 @@ pub trait SpDirectoryQueryClient {
}
#[async_trait]
impl<C> SpDirectoryQueryClient for NyxdClient<C>
impl<C> SpDirectoryQueryClient for C
where
C: CosmWasmClient + Send + Sync,
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_service_provider_contract<T>(&self, query: SpQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.client
.query_contract_smart(
self.service_provider_contract_address().ok_or(
NyxdError::NoContractAddressAvailable(
"service provider directory contract".to_string(),
),
)?,
&query,
)
let sp_directory_contract_address =
&self.service_provider_contract_address().ok_or_else(|| {
NyxdError::unavailable_contract_address("service provider directory contract")
})?;
self.query_contract_smart(sp_directory_contract_address, &query)
.await
}
}
#[async_trait]
impl<C> SpDirectoryQueryClient for crate::Client<C>
where
C: CosmWasmClient + Send + Sync,
{
async fn query_service_provider_contract<T>(&self, query: SpQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.nyxd.query_service_provider_contract(query).await
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: SpDirectoryQueryClient + Send + Sync>(
client: C,
msg: SpQueryMsg,
) {
unimplemented!()
}
}
@@ -1,10 +1,10 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::coin::Coin;
pub use crate::nyxd::cosmwasm_client::client::CosmWasmClient;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::NyxdClient;
use crate::nyxd::{CosmWasmClient, NyxdClient};
use async_trait::async_trait;
use cosmwasm_std::{Coin as CosmWasmCoin, Timestamp};
use nym_contracts_common::ContractBuildInformation;
@@ -334,13 +334,32 @@ pub trait VestingQueryClient {
}
#[async_trait]
impl<C: CosmWasmClient + Sync + Send> VestingQueryClient for NyxdClient<C> {
impl<C> VestingQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_vesting_contract<T>(&self, query: VestingQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
self.client
.query_contract_smart(self.vesting_contract_address(), &query)
let vesting_contract_address = &self
.vesting_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("vesting contract"))?;
self.query_contract_smart(vesting_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
// it's enough that this compiles
#[deprecated]
async fn all_query_variants_are_covered<C: VestingQueryClient + Send + Sync>(
client: C,
msg: VestingQueryMsg,
) {
unimplemented!()
}
}
@@ -0,0 +1,12 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod query_client;
#[cfg(feature = "signing")]
pub mod signing_client;
pub use query_client::CosmWasmClient;
#[cfg(feature = "signing")]
pub use signing_client::SigningCosmWasmClient;
@@ -1,4 +1,4 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd;
@@ -39,25 +39,15 @@ use tendermint_rpc::{
Order,
};
pub const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
pub const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
#[cfg(feature = "http-client")]
#[async_trait]
impl CosmWasmClient for cosmrs::rpc::HttpClient {
fn broadcast_polling_rate(&self) -> Duration {
Duration::from_secs(4)
}
fn broadcast_timeout(&self) -> Duration {
Duration::from_secs(60)
}
}
impl CosmWasmClient for cosmrs::rpc::HttpClient {}
#[async_trait]
pub trait CosmWasmClient: TendermintClient {
// this should probably get redesigned, but I'm leaving those like that temporarily to fix
// the underlying issue more quickly
fn broadcast_polling_rate(&self) -> Duration;
fn broadcast_timeout(&self) -> Duration;
// helper method to remove duplicate code involved in making abci requests with protobuf messages
// TODO: perhaps it should have an additional argument to determine whether the response should
// require proof?
@@ -268,10 +258,20 @@ pub trait CosmWasmClient: TendermintClient {
Ok(tendermint_rpc::client::Client::broadcast_tx_commit(self, tx).await?)
}
async fn broadcast_tx<T>(&self, tx: T) -> Result<TxResponse, NyxdError>
async fn broadcast_tx<T>(
&self,
tx: T,
timeout: impl Into<Option<Duration>> + Send,
poll_interval: impl Into<Option<Duration>> + Send,
) -> Result<TxResponse, NyxdError>
where
T: Into<Vec<u8>> + Send,
{
let timeout = timeout.into().unwrap_or(DEFAULT_BROADCAST_TIMEOUT);
let poll_interval = poll_interval
.into()
.unwrap_or(DEFAULT_BROADCAST_POLLING_RATE);
let broadcasted = CosmWasmClient::broadcast_tx_sync(self, tx).await?;
if broadcasted.code.is_err() {
@@ -292,10 +292,10 @@ pub trait CosmWasmClient: TendermintClient {
"Polling for result of including {} in a block...",
broadcasted.hash
);
if tokio::time::Instant::now().duration_since(start) >= self.broadcast_timeout() {
if tokio::time::Instant::now().duration_since(start) >= timeout {
return Err(NyxdError::BroadcastTimeout {
hash: tx_hash,
timeout: self.broadcast_timeout(),
timeout,
});
}
@@ -303,7 +303,7 @@ pub trait CosmWasmClient: TendermintClient {
return Ok(poll_res);
}
tokio::time::sleep(self.broadcast_polling_rate()).await;
tokio::time::sleep(poll_interval).await;
}
}
@@ -1,7 +1,7 @@
// Copyright 2021-2023 - Nym Technologies SA <contact@nymtech.net>
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::nyxd::cosmwasm_client::client::CosmWasmClient;
use crate::nyxd::cosmwasm_client::client_traits::CosmWasmClient;
use crate::nyxd::cosmwasm_client::helpers::{compress_wasm_code, CheckResponse};
use crate::nyxd::cosmwasm_client::logs::{self, parse_raw_logs};
use crate::nyxd::cosmwasm_client::types::*;
@@ -9,6 +9,7 @@ use crate::nyxd::error::NyxdError;
use crate::nyxd::fee::{Fee, DEFAULT_SIMULATED_GAS_MULTIPLIER};
use crate::nyxd::{Coin, GasAdjustable, GasPrice, TxResponse};
use crate::signing::signer::OfflineSigner;
use crate::signing::tx_signer::TxSigner;
use crate::signing::SignerData;
use async_trait::async_trait;
use cosmrs::abci::GasInfo;
@@ -26,21 +27,9 @@ use serde::Serialize;
use sha2::Digest;
use sha2::Sha256;
use std::convert::TryInto;
use std::time::{Duration, SystemTime};
use std::time::SystemTime;
use tendermint_rpc::endpoint::broadcast;
#[cfg(feature = "http-client")]
use crate::signing::tx_signer::TxSigner;
#[cfg(feature = "http-client")]
use tendermint_rpc::{Error as TendermintRpcError, SimpleRequest};
#[cfg(feature = "http-client")]
use cosmrs::rpc::{HttpClient, HttpClientUrl};
pub const DEFAULT_BROADCAST_POLLING_RATE: Duration = Duration::from_secs(4);
pub const DEFAULT_BROADCAST_TIMEOUT: Duration = Duration::from_secs(60);
fn empty_fee() -> tx::Fee {
tx::Fee {
amount: vec![],
@@ -65,15 +54,16 @@ fn single_unspecified_signer_auth(
}
#[async_trait]
pub trait SigningCosmWasmClient: CosmWasmClient {
type Signer: OfflineSigner + Send + Sync;
fn signer(&self) -> &Self::Signer;
pub trait SigningCosmWasmClient: CosmWasmClient + TxSigner
where
NyxdError: From<<Self as OfflineSigner>::Error>,
{
// TODO: would it somehow be possible to get rid of this method and allow for
// blanket implementation for anything that provides CosmWasmClient + TxSigner?
fn gas_price(&self) -> &GasPrice;
fn signer_public_key(&self, signer_address: &AccountId) -> Option<tx::SignerPublicKey> {
let account = self.signer().find_account(signer_address).ok()?;
let account = self.find_account(signer_address).ok()?;
Some(account.public_key().into())
}
@@ -587,9 +577,9 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
let multiplier = multiplier.unwrap_or(DEFAULT_SIMULATED_GAS_MULTIPLIER);
let gas = gas_estimation.adjust_gas(multiplier);
debug!("Gas estimation: {}", gas_estimation);
debug!("Multiplying the estimation by {}", multiplier);
debug!("Final gas limit used: {}", gas);
debug!("Gas estimation: {gas_estimation}");
debug!("Multiplying the estimation by {multiplier}");
debug!("Final gas limit used: {gas}");
let fee = self.gas_price() * gas;
Ok::<tx::Fee, NyxdError>(tx::Fee::from_amount_and_gas(fee, gas))
@@ -687,7 +677,7 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
.to_bytes()
.map_err(|_| NyxdError::SerializationError("Tx".to_owned()))?;
self.broadcast_tx(tx_bytes).await
self.broadcast_tx(tx_bytes, None, None).await
}
async fn sign(
@@ -710,161 +700,14 @@ pub trait SigningCosmWasmClient: CosmWasmClient {
}
};
self.sign_direct(signer_address, messages, fee, memo, signer_data)
}
fn sign_amino(
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
signer_data: SignerData,
) -> Result<tx::Raw, NyxdError>;
fn sign_direct(
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
signer_data: SignerData,
) -> Result<tx::Raw, NyxdError>;
}
#[cfg(feature = "http-client")]
#[derive(Debug)]
pub struct Client<S> {
// TODO: somehow nicely hide this guy if we decide to use our client in offline mode,
// maybe just convert it into an option?
// or maybe we need another level of indirection. tbd.
rpc_client: HttpClient,
tx_signer: TxSigner<S>,
gas_price: GasPrice,
broadcast_polling_rate: Duration,
broadcast_timeout: Duration,
}
#[cfg(feature = "http-client")]
impl<S> Client<S> {
pub fn connect_with_signer<U: Clone>(
endpoint: U,
signer: S,
gas_price: GasPrice,
) -> Result<Self, NyxdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let rpc_client = HttpClient::new(endpoint)?;
Ok(Client {
rpc_client,
tx_signer: TxSigner::new(signer),
gas_price,
broadcast_polling_rate: DEFAULT_BROADCAST_POLLING_RATE,
broadcast_timeout: DEFAULT_BROADCAST_TIMEOUT,
})
}
pub fn offline(signer: S) -> TxSigner<S>
where
S: OfflineSigner,
{
TxSigner::new(signer)
}
pub fn change_endpoint<U>(&mut self, new_endpoint: U) -> Result<(), NyxdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
let new_rpc_client = HttpClient::new(new_endpoint)?;
self.rpc_client = new_rpc_client;
Ok(())
}
pub fn into_signer(self) -> S {
self.tx_signer.into_inner_signer()
}
pub fn set_broadcast_polling_rate(&mut self, broadcast_polling_rate: Duration) {
self.broadcast_polling_rate = broadcast_polling_rate
}
pub fn set_broadcast_timeout(&mut self, broadcast_timeout: Duration) {
self.broadcast_timeout = broadcast_timeout
}
}
#[cfg(feature = "http-client")]
#[async_trait]
impl<S> tendermint_rpc::client::Client for Client<S>
where
S: Send + Sync,
{
async fn perform<R>(&self, request: R) -> Result<R::Output, tendermint_rpc::Error>
where
R: SimpleRequest,
{
self.rpc_client.perform(request).await
}
}
#[cfg(feature = "http-client")]
#[async_trait]
impl<S> CosmWasmClient for Client<S>
where
S: Send + Sync,
{
fn broadcast_polling_rate(&self) -> Duration {
self.broadcast_polling_rate
}
fn broadcast_timeout(&self) -> Duration {
self.broadcast_timeout
}
}
#[cfg(feature = "http-client")]
#[async_trait]
impl<S> SigningCosmWasmClient for Client<S>
where
S: OfflineSigner + Send + Sync,
NyxdError: From<S::Error>,
{
type Signer = S;
fn signer(&self) -> &Self::Signer {
self.tx_signer.signer()
}
fn gas_price(&self) -> &GasPrice {
&self.gas_price
}
fn sign_amino(
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
signer_data: SignerData,
) -> Result<tx::Raw, NyxdError> {
Ok(self
.tx_signer
.sign_amino(signer_address, messages, fee, memo, signer_data)?)
}
fn sign_direct(
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
signer_data: SignerData,
) -> Result<tx::Raw, NyxdError> {
Ok(self
.tx_signer
.sign_direct(signer_address, messages, fee, memo, signer_data)?)
Ok(<Self as TxSigner>::sign_direct(
self,
signer_address,
messages,
fee,
memo,
signer_data,
)?)
}
}
@@ -1,37 +1,153 @@
// Copyright 2021 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[cfg(feature = "http-client")]
use crate::nyxd::cosmwasm_client::client_traits::{CosmWasmClient, SigningCosmWasmClient};
use crate::nyxd::error::NyxdError;
#[cfg(feature = "http-client")]
use cosmrs::rpc::{Error as TendermintRpcError, HttpClient, HttpClientUrl};
#[cfg(feature = "http-client")]
use std::convert::TryInto;
use crate::nyxd::{Config, GasPrice, TendermintClient};
use crate::signing::signer::{NoSigner, OfflineSigner};
use crate::signing::tx_signer::TxSigner;
use crate::signing::AccountData;
use async_trait::async_trait;
use cosmrs::rpc::Error as TendermintRpcError;
use cosmrs::AccountId;
use tendermint_rpc::SimpleRequest;
pub mod client;
pub mod client_traits;
mod helpers;
pub mod logs;
pub mod types;
#[cfg(feature = "signing")]
pub mod signing_client;
#[cfg(feature = "http-client")]
pub fn connect<U>(endpoint: U) -> Result<HttpClient, NyxdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
Ok(HttpClient::new(endpoint)?)
#[derive(Debug)]
pub(crate) struct SigningClientOptions {
gas_price: GasPrice,
}
#[cfg(all(feature = "signing", feature = "http-client"))]
pub fn connect_with_signer<S, U: Clone>(
endpoint: U,
impl<'a> From<&'a Config> for SigningClientOptions {
fn from(value: &'a Config) -> Self {
SigningClientOptions {
gas_price: value.gas_price.clone(),
}
}
}
// convenience wrapper around query client to allow for optional signing
#[derive(Debug)]
pub(crate) struct MaybeSigningClient<C, S = NoSigner> {
client: C,
signer: S,
gas_price: crate::nyxd::GasPrice,
) -> Result<signing_client::Client<S>, NyxdError>
where
U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
{
signing_client::Client::connect_with_signer(endpoint, signer, gas_price)
opts: SigningClientOptions,
derived_addresses: Option<Vec<AccountId>>,
}
impl<C> MaybeSigningClient<C> {
pub(crate) fn new(client: C, opts: SigningClientOptions) -> Self {
MaybeSigningClient {
client,
signer: Default::default(),
opts,
derived_addresses: None,
}
}
}
impl<C, S> MaybeSigningClient<C, S> {
pub(crate) fn new_signing(
client: C,
signer: S,
opts: SigningClientOptions,
) -> Result<Self, S::Error>
where
S: OfflineSigner,
{
let derived_addresses = signer
.get_accounts()?
.into_iter()
.map(|account| account.address)
.collect();
Ok(MaybeSigningClient {
client,
signer,
opts,
derived_addresses: Some(derived_addresses),
})
}
pub(crate) fn derived_addresses(&self) -> &[AccountId] {
// the unwrap is fine here as you can't construct a signing client without setting the addresses
self.derived_addresses.as_ref().unwrap()
}
}
#[async_trait]
impl<C, S> TendermintClient for MaybeSigningClient<C, S>
where
C: TendermintClient + Send + Sync,
S: Send + Sync,
{
async fn perform<R>(&self, request: R) -> Result<R::Output, TendermintRpcError>
where
R: SimpleRequest,
{
self.client.perform(request).await
}
}
#[async_trait]
impl<C, S> CosmWasmClient for MaybeSigningClient<C, S>
where
C: CosmWasmClient + Send + Sync,
S: Send + Sync,
{
}
impl<C, S> OfflineSigner for MaybeSigningClient<C, S>
where
C: CosmWasmClient,
S: OfflineSigner,
{
type Error = S::Error;
fn get_accounts(&self) -> Result<Vec<AccountData>, Self::Error> {
self.signer.get_accounts()
}
}
impl<C, S> TxSigner for MaybeSigningClient<C, S>
where
C: CosmWasmClient,
S: OfflineSigner,
{
}
#[async_trait]
impl<C, S> SigningCosmWasmClient for MaybeSigningClient<C, S>
where
C: CosmWasmClient + Send + Sync,
S: OfflineSigner + Send + Sync,
NyxdError: From<S::Error>,
{
fn gas_price(&self) -> &GasPrice {
&self.opts.gas_price
}
}
//
// #[cfg(feature = "http-client")]
// pub fn connect<U>(endpoint: U) -> Result<MaybeSigningClient<HttpClient>, NyxdError>
// where
// U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
// {
// Ok(HttpClient::new(endpoint)?)
// }
//
// #[cfg(all(feature = "signing", feature = "http-client"))]
// pub fn connect_with_signer<S, U: Clone>(
// endpoint: U,
// signer: S,
// gas_price: crate::nyxd::GasPrice,
// ) -> Result<MaybeSigningClient<HttpClient, S>, NyxdError>
// where
// U: TryInto<HttpClientUrl, Error = TendermintRpcError>,
// {
// signing_client::Client::connect_with_signer(endpoint, signer, gas_price)
// }
@@ -224,4 +224,8 @@ impl NyxdError {
_ => false,
}
}
pub fn unavailable_contract_address<S: Into<String>>(contract_type: S) -> Self {
NyxdError::NoContractAddressAvailable(contract_type.into())
}
}
@@ -6,6 +6,7 @@ use cosmrs::Coin;
use cosmrs::Gas;
use cosmwasm_std::{Decimal, Fraction, Uint128};
use nym_config::defaults;
use nym_network_defaults::{ChainDetails, NymNetworkDetails};
use std::ops::Mul;
use std::str::FromStr;
@@ -73,6 +74,19 @@ impl FromStr for GasPrice {
}
}
impl<'a> TryFrom<&'a NymNetworkDetails> for GasPrice {
type Error = NyxdError;
fn try_from(value: &'a NymNetworkDetails) -> Result<Self, Self::Error> {
format!(
"{}{}",
value.default_gas_price_amount(),
value.chain_details.mix_denom.base
)
.parse()
}
}
impl GasPrice {
pub fn new_with_default_price(denom: &str) -> Result<Self, NyxdError> {
format!("{}{}", defaults::GAS_PRICE_AMOUNT, denom).parse()
File diff suppressed because it is too large Load Diff
@@ -35,6 +35,7 @@ pub enum DirectSecp256k1HdWalletError {
AccountDerivationError { source: eyre::Report },
}
// TODO: maybe lock this one behind feature flag?
#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
pub struct DirectSecp256k1HdWallet {
/// Base secret
@@ -94,3 +94,25 @@ pub trait OfflineSigner {
// fn sign_amino_with_account(&self, signer: &AccountData, sign_doc: AminoSignDoc) -> Result<tx::Raw, Self::Error>;
}
#[derive(Debug, Default, Copy, Clone)]
pub struct NoSigner;
// #[derive(Debug, Copy, Clone, Error)]
// #[error("no signer is available")]
// struct SignerUnavailable;
//
// // trait bound requirements
// impl From<SigningError> for SignerUnavailable {
// fn from(_: SigningError) -> Self {
// SignerUnavailable
// }
// }
//
// impl OfflineSigner for NoSigner {
// type Error = SignerUnavailable;
//
// fn get_accounts(&self) -> Result<Vec<AccountData>, Self::Error> {
// return Err(SignerUnavailable);
// }
// }
@@ -5,54 +5,98 @@ use crate::signing::signer::{OfflineSigner, SigningError};
use crate::signing::SignerData;
use cosmrs::tx::{SignDoc, SignerInfo};
use cosmrs::{tx, AccountId, Any};
//
// #[derive(Debug)]
// /// A client that has only one responsibility - sign transactions
// /// and not touch chain.
// pub struct TxSigner<S> {
// signer: S,
// }
//
// impl<S> TxSigner<S> {
// pub fn new(signer: S) -> Self {
// TxSigner { signer }
// }
//
// pub fn signer(&self) -> &S {
// &self.signer
// }
//
// pub fn into_inner_signer(self) -> S {
// self.signer
// }
//
// pub fn sign_amino(
// &self,
// _signer_address: &AccountId,
// _messages: Vec<Any>,
// _fee: tx::Fee,
// _memo: impl Into<String> + Send + 'static,
// _signer_data: SignerData,
// ) -> Result<tx::Raw, S::Error>
// where
// S: OfflineSigner,
// {
// unimplemented!()
// }
//
// // TODO: change this sucker to use the trait better
// pub fn sign_direct(
// &self,
// signer_address: &AccountId,
// messages: Vec<Any>,
// fee: tx::Fee,
// memo: impl Into<String> + Send + 'static,
// signer_data: SignerData,
// ) -> Result<tx::Raw, S::Error>
// where
// S: OfflineSigner,
// {
// let account_from_signer = self.signer.find_account(signer_address)?;
//
// // TODO: experiment with this field
// let timeout_height = 0u32;
//
// let tx_body = tx::Body::new(messages, memo, timeout_height);
// let signer_info =
// SignerInfo::single_direct(Some(account_from_signer.public_key), signer_data.sequence);
// let auth_info = signer_info.auth_info(fee);
//
// let sign_doc = SignDoc::new(
// &tx_body,
// &auth_info,
// &signer_data.chain_id,
// signer_data.account_number,
// )
// .map_err(|source| SigningError::SignDocFailure { source })?;
//
// self.signer
// .sign_direct_with_account(&account_from_signer, sign_doc)
// }
// }
#[derive(Debug)]
/// A client that has only one responsibility - sign transactions
/// and not touch chain.
pub struct TxSigner<S> {
signer: S,
}
impl<S> TxSigner<S> {
pub fn new(signer: S) -> Self {
TxSigner { signer }
}
pub fn signer(&self) -> &S {
&self.signer
}
pub fn into_inner_signer(self) -> S {
self.signer
}
pub fn sign_amino(
// extension trait for the OfflineSigner to allow to sign transactions
pub trait TxSigner: OfflineSigner {
fn sign_amino(
&self,
_signer_address: &AccountId,
_messages: Vec<Any>,
_fee: tx::Fee,
_memo: impl Into<String> + Send + 'static,
_signer_data: SignerData,
) -> Result<tx::Raw, S::Error>
where
S: OfflineSigner,
{
) -> Result<tx::Raw, <Self as OfflineSigner>::Error> {
unimplemented!()
}
// TODO: change this sucker to use the trait better
pub fn sign_direct(
fn sign_direct(
&self,
signer_address: &AccountId,
messages: Vec<Any>,
fee: tx::Fee,
memo: impl Into<String> + Send + 'static,
signer_data: SignerData,
) -> Result<tx::Raw, S::Error>
where
S: OfflineSigner,
{
let account_from_signer = self.signer.find_account(signer_address)?;
) -> Result<tx::Raw, <Self as OfflineSigner>::Error> {
let account_from_signer = self.find_account(signer_address)?;
// TODO: experiment with this field
let timeout_height = 0u32;
@@ -70,7 +114,6 @@ impl<S> TxSigner<S> {
)
.map_err(|source| SigningError::SignDocFailure { source })?;
self.signer
.sign_direct_with_account(&account_from_signer, sign_doc)
self.sign_direct_with_account(&account_from_signer, sign_doc)
}
}
+4
View File
@@ -164,6 +164,10 @@ impl NymNetworkDetails {
}
}
pub fn default_gas_price_amount(&self) -> f64 {
GAS_PRICE_AMOUNT
}
#[must_use]
pub fn with_network_name(mut self, network_name: String) -> Self {
self.network_name = network_name;
+1
View File
@@ -4561,6 +4561,7 @@ dependencies = [
"colored 2.0.4",
"cosmrs",
"cosmwasm-std",
"cw-utils",
"cw3",
"cw4",
"eyre",
+1
View File
@@ -3415,6 +3415,7 @@ dependencies = [
"colored 2.0.4",
"cosmrs",
"cosmwasm-std",
"cw-utils",
"cw3",
"cw4",
"eyre",