nym_validator_client/coconut/
mod.rs1use crate::nyxd::contract_traits::{DkgQueryClient, PagedDkgQueryClient};
5use crate::nyxd::error::NyxdError;
6use nym_coconut_dkg_common::types::{EpochId, NodeIndex};
7use nym_coconut_dkg_common::verification_key::ContractVKShare;
8use nym_compact_ecash::error::CompactEcashError;
9use nym_compact_ecash::{Base58, VerificationKeyAuth};
10use std::fmt::{Display, Formatter};
11use thiserror::Error;
12use url::Url;
13
14#[derive(Clone)]
16pub struct EcashApiClient {
17 pub api_client: nym_http_api_client::Client,
18 pub verification_key: VerificationKeyAuth,
19 pub node_id: NodeIndex,
20 pub cosmos_address: cosmrs::AccountId,
21}
22
23impl Display for EcashApiClient {
24 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
25 write!(
26 f,
27 "[id: {}] {} @ ({})",
28 self.node_id,
29 self.cosmos_address,
30 self.api_client
31 .base_urls()
32 .iter()
33 .map(|url| url.to_string())
34 .collect::<Vec<String>>()
35 .join(", ")
36 )
37 }
38}
39
40#[derive(Debug, Error)]
44pub enum EcashApiError {
45 #[error("the provided key share hasn't been verified")]
47 UnverifiedShare,
48
49 #[error("failed to query the contract: {source}")]
50 ContractQueryFailure {
51 #[from]
52 source: NyxdError,
53 },
54
55 #[error("the provided announce address is malformed: {source}")]
56 MalformedAnnounceAddress {
57 #[from]
58 source: url::ParseError,
59 },
60
61 #[error("the provided verification key is malformed: {source}")]
62 MalformedVerificationKey {
63 #[from]
64 source: CompactEcashError,
65 },
66
67 #[error("failed to create API client: {0}")]
68 ClientError(String),
69
70 #[error("the provided account address is malformed: {source}")]
71 MalformedAccountAddress {
72 #[from]
73 source: cosmrs::ErrorReport,
74 },
75
76 #[error("nym api error")]
77 NymApi {
78 #[from]
79 source: crate::ValidatorClientError,
80 },
81}
82
83impl TryFrom<ContractVKShare> for EcashApiClient {
84 type Error = EcashApiError;
85
86 fn try_from(share: ContractVKShare) -> Result<Self, Self::Error> {
87 if !share.verified {
88 return Err(EcashApiError::UnverifiedShare);
89 }
90
91 let url_address = Url::parse(&share.announce_address)?;
92
93 let api_client = nym_http_api_client::Client::builder(url_address)
100 .map_err(|e| EcashApiError::ClientError(e.to_string()))?
101 .build()
102 .map_err(|e| EcashApiError::ClientError(e.to_string()))?;
103
104 Ok(EcashApiClient {
105 api_client,
106 verification_key: VerificationKeyAuth::try_from_bs58(&share.share)?,
107 node_id: share.node_index,
108 cosmos_address: share.owner.as_str().parse()?,
109 })
110 }
111}
112
113pub async fn all_ecash_api_clients<C>(
114 client: &C,
115 epoch_id: EpochId,
116) -> Result<Vec<EcashApiClient>, EcashApiError>
117where
118 C: DkgQueryClient + Sync + Send,
119{
120 client
122 .get_all_verification_key_shares(epoch_id)
123 .await?
124 .into_iter()
125 .map(TryInto::try_into)
126 .collect::<Result<Vec<_>, _>>()
127
128 }