use crate::collect_paged;
use crate::nyxd::contract_traits::NymContractsProvider;
use crate::nyxd::error::NyxdError;
use crate::nyxd::CosmWasmClient;
use async_trait::async_trait;
use cosmrs::AccountId;
use cosmwasm_std::Addr;
use nym_coconut_dkg_common::dealer::RegisteredDealerDetails;
use nym_coconut_dkg_common::types::{ChunkIndex, NodeIndex, StateAdvanceResponse};
use serde::Deserialize;
use tracing::trace;
pub use nym_coconut_dkg_common::{
dealer::{DealerDetailsResponse, PagedDealerIndexResponse, PagedDealerResponse},
dealing::{
DealerDealingsStatusResponse, DealingChunkResponse, DealingChunkStatusResponse,
DealingMetadataResponse, DealingStatusResponse,
},
msg::QueryMsg as DkgQueryMsg,
types::{DealerDetails, DealingIndex, Epoch, EpochId, EpochState, State},
verification_key::{
ContractVKShare, PagedVKSharesResponse, VerificationKeyShare, VkShareResponse,
},
};
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait DkgQueryClient {
async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>;
async fn get_state(&self) -> Result<State, NyxdError> {
let request = DkgQueryMsg::GetState {};
self.query_dkg_contract(request).await
}
async fn get_current_epoch(&self) -> Result<Epoch, NyxdError> {
let request = DkgQueryMsg::GetCurrentEpochState {};
self.query_dkg_contract(request).await
}
async fn get_epoch_at_height(&self, height: u64) -> Result<Option<Epoch>, NyxdError> {
let request = DkgQueryMsg::GetEpochStateAtHeight { height };
self.query_dkg_contract(request).await
}
async fn can_advance_state(&self) -> Result<StateAdvanceResponse, NyxdError> {
let request = DkgQueryMsg::CanAdvanceState {};
self.query_dkg_contract(request).await
}
async fn get_current_epoch_threshold(&self) -> Result<Option<u64>, NyxdError> {
let request = DkgQueryMsg::GetCurrentEpochThreshold {};
self.query_dkg_contract(request).await
}
async fn get_epoch_threshold(&self, epoch_id: EpochId) -> Result<Option<u64>, NyxdError> {
let request = DkgQueryMsg::GetEpochThreshold { epoch_id };
self.query_dkg_contract(request).await
}
async fn get_registered_dealer_details(
&self,
address: &AccountId,
epoch_id: Option<EpochId>,
) -> Result<RegisteredDealerDetails, NyxdError> {
let request = DkgQueryMsg::GetRegisteredDealer {
dealer_address: address.to_string(),
epoch_id,
};
self.query_dkg_contract(request).await
}
async fn get_dealer_details(
&self,
address: &AccountId,
) -> Result<DealerDetailsResponse, NyxdError> {
let request = DkgQueryMsg::GetDealerDetails {
dealer_address: address.to_string(),
};
self.query_dkg_contract(request).await
}
async fn get_current_dealers_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealerResponse, NyxdError> {
let request = DkgQueryMsg::GetCurrentDealers { start_after, limit };
self.query_dkg_contract(request).await
}
async fn get_epoch_dealers_paged(
&self,
epoch_id: EpochId,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealerResponse, NyxdError> {
let request = DkgQueryMsg::GetEpochDealers {
epoch_id,
start_after,
limit,
};
self.query_dkg_contract(request).await
}
async fn get_epoch_dealers_addresses_paged(
&self,
epoch_id: EpochId,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealerResponse, NyxdError> {
let request = DkgQueryMsg::GetEpochDealersAddresses {
epoch_id,
start_after,
limit,
};
self.query_dkg_contract(request).await
}
async fn get_dealer_indices_paged(
&self,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedDealerIndexResponse, NyxdError> {
let request = DkgQueryMsg::GetDealerIndices { start_after, limit };
self.query_dkg_contract(request).await
}
async fn get_dealings_metadata(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> Result<DealingMetadataResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingsMetadata {
epoch_id,
dealer,
dealing_index,
};
self.query_dkg_contract(request).await
}
async fn get_dealer_dealings_status(
&self,
epoch_id: EpochId,
dealer: String,
) -> Result<DealerDealingsStatusResponse, NyxdError> {
let request = DkgQueryMsg::GetDealerDealingsStatus { epoch_id, dealer };
self.query_dkg_contract(request).await
}
async fn get_dealing_status(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
) -> Result<DealingStatusResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingStatus {
epoch_id,
dealer,
dealing_index,
};
self.query_dkg_contract(request).await
}
async fn get_dealing_chunk_status(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
) -> Result<DealingChunkStatusResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingChunkStatus {
epoch_id,
dealer,
dealing_index,
chunk_index,
};
self.query_dkg_contract(request).await
}
async fn get_dealing_chunk(
&self,
epoch_id: EpochId,
dealer: String,
dealing_index: DealingIndex,
chunk_index: ChunkIndex,
) -> Result<DealingChunkResponse, NyxdError> {
let request = DkgQueryMsg::GetDealingChunk {
epoch_id,
dealer,
dealing_index,
chunk_index,
};
self.query_dkg_contract(request).await
}
async fn get_vk_share(
&self,
epoch_id: EpochId,
owner: String,
) -> Result<VkShareResponse, NyxdError> {
let request = DkgQueryMsg::GetVerificationKey { epoch_id, owner };
self.query_dkg_contract(request).await
}
async fn get_vk_shares_paged(
&self,
epoch_id: EpochId,
start_after: Option<String>,
limit: Option<u32>,
) -> Result<PagedVKSharesResponse, NyxdError> {
let request = DkgQueryMsg::GetVerificationKeys {
epoch_id,
limit,
start_after,
};
self.query_dkg_contract(request).await
}
async fn get_contract_cw2_version(&self) -> Result<cw2::ContractVersion, NyxdError> {
self.query_dkg_contract(DkgQueryMsg::GetCW2ContractVersion {})
.await
}
}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
pub trait PagedDkgQueryClient: DkgQueryClient {
async fn get_all_current_dealers(&self) -> Result<Vec<DealerDetails>, NyxdError> {
collect_paged!(self, get_current_dealers_paged, dealers)
}
async fn get_all_epoch_dealers(
&self,
epoch_id: EpochId,
) -> Result<Vec<DealerDetails>, NyxdError> {
collect_paged!(self, get_epoch_dealers_paged, dealers, epoch_id)
}
async fn get_all_epoch_dealers_addresses(
&self,
epoch_id: EpochId,
) -> Result<Vec<DealerDetails>, NyxdError> {
collect_paged!(self, get_epoch_dealers_addresses_paged, dealers, epoch_id)
}
async fn get_all_dealer_indices(&self) -> Result<Vec<(Addr, NodeIndex)>, NyxdError> {
collect_paged!(self, get_dealer_indices_paged, indices)
}
async fn get_all_verification_key_shares(
&self,
epoch_id: EpochId,
) -> Result<Vec<ContractVKShare>, NyxdError> {
collect_paged!(self, get_vk_shares_paged, shares, epoch_id)
}
}
#[async_trait]
impl<T> PagedDkgQueryClient for T where T: DkgQueryClient {}
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
#[cfg_attr(not(target_arch = "wasm32"), async_trait)]
impl<C> DkgQueryClient for C
where
C: CosmWasmClient + NymContractsProvider + Send + Sync,
{
async fn query_dkg_contract<T>(&self, query: DkgQueryMsg) -> Result<T, NyxdError>
where
for<'a> T: Deserialize<'a>,
{
let dkg_contract_address = &self
.dkg_contract_address()
.ok_or_else(|| NyxdError::unavailable_contract_address("dkg contract"))?;
trace!("using the following dkg contract: {dkg_contract_address}");
self.query_contract_smart(dkg_contract_address, &query)
.await
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::nyxd::contract_traits::tests::IgnoreValue;
use nym_coconut_dkg_common::msg::QueryMsg;
#[allow(dead_code)]
fn all_query_variants_are_covered<C: DkgQueryClient + Send + Sync>(
client: C,
msg: DkgQueryMsg,
) {
match msg {
DkgQueryMsg::GetState {} => client.get_state().ignore(),
DkgQueryMsg::GetCurrentEpochState {} => client.get_current_epoch().ignore(),
DkgQueryMsg::GetEpochStateAtHeight { height } => {
client.get_epoch_at_height(height).ignore()
}
DkgQueryMsg::CanAdvanceState {} => client.can_advance_state().ignore(),
DkgQueryMsg::GetCurrentEpochThreshold {} => {
client.get_current_epoch_threshold().ignore()
}
DkgQueryMsg::GetEpochThreshold { epoch_id } => {
client.get_epoch_threshold(epoch_id).ignore()
}
DkgQueryMsg::GetRegisteredDealer {
dealer_address,
epoch_id,
} => client
.get_registered_dealer_details(&dealer_address.parse().unwrap(), epoch_id)
.ignore(),
DkgQueryMsg::GetDealerDetails { dealer_address } => client
.get_dealer_details(&dealer_address.parse().unwrap())
.ignore(),
DkgQueryMsg::GetCurrentDealers { limit, start_after } => client
.get_current_dealers_paged(start_after, limit)
.ignore(),
QueryMsg::GetEpochDealers {
epoch_id,
limit,
start_after,
} => client
.get_epoch_dealers_paged(epoch_id, start_after, limit)
.ignore(),
QueryMsg::GetEpochDealersAddresses {
epoch_id,
limit,
start_after,
} => client
.get_epoch_dealers_addresses_paged(epoch_id, start_after, limit)
.ignore(),
DkgQueryMsg::GetDealerIndices { limit, start_after } => {
client.get_dealer_indices_paged(start_after, limit).ignore()
}
DkgQueryMsg::GetDealingStatus {
epoch_id,
dealer,
dealing_index,
} => client
.get_dealing_status(epoch_id, dealer, dealing_index)
.ignore(),
DkgQueryMsg::GetDealingsMetadata {
epoch_id,
dealer,
dealing_index,
} => client
.get_dealings_metadata(epoch_id, dealer, dealing_index)
.ignore(),
QueryMsg::GetDealerDealingsStatus { epoch_id, dealer } => {
client.get_dealer_dealings_status(epoch_id, dealer).ignore()
}
DkgQueryMsg::GetDealingChunkStatus {
epoch_id,
dealer,
dealing_index,
chunk_index,
} => client
.get_dealing_chunk_status(epoch_id, dealer, dealing_index, chunk_index)
.ignore(),
DkgQueryMsg::GetDealingChunk {
epoch_id,
dealer,
dealing_index,
chunk_index,
} => client
.get_dealing_chunk(epoch_id, dealer, dealing_index, chunk_index)
.ignore(),
DkgQueryMsg::GetVerificationKey { epoch_id, owner } => {
client.get_vk_share(epoch_id, owner).ignore()
}
DkgQueryMsg::GetVerificationKeys {
epoch_id,
limit,
start_after,
} => client
.get_vk_shares_paged(epoch_id, start_after, limit)
.ignore(),
DkgQueryMsg::GetCW2ContractVersion {} => client.get_contract_cw2_version().ignore(),
};
}
}