use crate::nyxd::contract_traits::{DkgQueryClient, PagedDkgQueryClient};
use crate::nyxd::error::NyxdError;
use nym_coconut_dkg_common::types::{EpochId, NodeIndex};
use nym_coconut_dkg_common::verification_key::ContractVKShare;
use nym_compact_ecash::error::CompactEcashError;
use nym_compact_ecash::{Base58, VerificationKeyAuth};
use std::fmt::{Display, Formatter};
use thiserror::Error;
use url::Url;
#[derive(Clone)]
pub struct EcashApiClient {
pub api_client: nym_http_api_client::Client,
pub verification_key: VerificationKeyAuth,
pub node_id: NodeIndex,
pub cosmos_address: cosmrs::AccountId,
}
impl Display for EcashApiClient {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"[id: {}] {} @ ({})",
self.node_id,
self.cosmos_address,
self.api_client
.base_urls()
.iter()
.map(|url| url.to_string())
.collect::<Vec<String>>()
.join(", ")
)
}
}
#[derive(Debug, Error)]
pub enum EcashApiError {
#[error("the provided key share hasn't been verified")]
UnverifiedShare,
#[error("failed to query the contract: {source}")]
ContractQueryFailure {
#[from]
source: NyxdError,
},
#[error("the provided announce address is malformed: {source}")]
MalformedAnnounceAddress {
#[from]
source: url::ParseError,
},
#[error("the provided verification key is malformed: {source}")]
MalformedVerificationKey {
#[from]
source: CompactEcashError,
},
#[error("failed to create API client: {0}")]
ClientError(String),
#[error("the provided account address is malformed: {source}")]
MalformedAccountAddress {
#[from]
source: cosmrs::ErrorReport,
},
#[error("nym api error")]
NymApi {
#[from]
source: crate::ValidatorClientError,
},
}
impl TryFrom<ContractVKShare> for EcashApiClient {
type Error = EcashApiError;
fn try_from(share: ContractVKShare) -> Result<Self, Self::Error> {
if !share.verified {
return Err(EcashApiError::UnverifiedShare);
}
let url_address = Url::parse(&share.announce_address)?;
let api_client = nym_http_api_client::Client::builder(url_address)
.map_err(|e| EcashApiError::ClientError(e.to_string()))?
.build()
.map_err(|e| EcashApiError::ClientError(e.to_string()))?;
Ok(EcashApiClient {
api_client,
verification_key: VerificationKeyAuth::try_from_bs58(&share.share)?,
node_id: share.node_index,
cosmos_address: share.owner.as_str().parse()?,
})
}
}
pub async fn all_ecash_api_clients<C>(
client: &C,
epoch_id: EpochId,
) -> Result<Vec<EcashApiClient>, EcashApiError>
where
C: DkgQueryClient,
{
client
.get_all_verification_key_shares(epoch_id)
.await?
.into_iter()
.map(TryInto::try_into)
.collect::<Result<Vec<_>, _>>()
}