From 67ce8a98a57b4c0f632f23615b4892c8a90dc27b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Wed, 7 Feb 2024 16:06:13 +0000 Subject: [PATCH] wip in removing the Credential type for more strongly typed alternative --- common/bandwidth-controller/src/lib.rs | 2 +- .../client-libs/gateway-client/src/client.rs | 2 +- common/coconut-interface/Cargo.toml | 2 +- common/credential-utils/Cargo.toml | 1 + common/credentials/Cargo.toml | 4 +- .../credentials/src/coconut/bandwidth/mod.rs | 39 ++++++++--- common/credentials/src/coconut/credential.rs | 6 +- gateway/gateway-requests/src/lib.rs | 2 +- gateway/gateway-requests/src/models.rs | 18 +++++ gateway/src/node/client_handling/bandwidth.rs | 38 +++++++++- gateway/src/node/client_handling/mod.rs | 6 +- .../connection_handler/authenticated.rs | 69 ++++++++++++------- .../websocket/connection_handler/coconut.rs | 36 ++++++---- nym-api/nym-api-requests/Cargo.toml | 2 + .../nym-api-requests/src/coconut/models.rs | 27 +++++--- nym-connect/desktop/Cargo.lock | 16 +++++ nym-wallet/Cargo.lock | 9 +++ 17 files changed, 209 insertions(+), 70 deletions(-) diff --git a/common/bandwidth-controller/src/lib.rs b/common/bandwidth-controller/src/lib.rs index d6f5dfb731..6d78bd7401 100644 --- a/common/bandwidth-controller/src/lib.rs +++ b/common/bandwidth-controller/src/lib.rs @@ -56,7 +56,7 @@ impl BandwidthController { Ok(obtain_aggregate_verification_key(&coconut_api_clients).await?) } - pub async fn prepare_coconut_credential( + pub async fn prepare_bandwidth_credential( &self, ) -> Result where diff --git a/common/client-libs/gateway-client/src/client.rs b/common/client-libs/gateway-client/src/client.rs index 08d25beed7..b1ebb23fa4 100644 --- a/common/client-libs/gateway-client/src/client.rs +++ b/common/client-libs/gateway-client/src/client.rs @@ -574,7 +574,7 @@ impl GatewayClient { .bandwidth_controller .as_ref() .unwrap() - .prepare_coconut_credential() + .prepare_bandwidth_credential() .await?; self.claim_coconut_bandwidth(prepared_credential.data, prepared_credential.epoch_id) diff --git a/common/coconut-interface/Cargo.toml b/common/coconut-interface/Cargo.toml index dc81f4847f..a85115d95f 100644 --- a/common/coconut-interface/Cargo.toml +++ b/common/coconut-interface/Cargo.toml @@ -11,4 +11,4 @@ getset = "0.1.1" serde = { workspace = true, features = ["derive"] } thiserror = { workspace = true } -nym-coconut = {path = "../nymcoconut" } +nym-coconut = { path = "../nymcoconut" } diff --git a/common/credential-utils/Cargo.toml b/common/credential-utils/Cargo.toml index 1b5ebfd5bd..232c9cdb1f 100644 --- a/common/credential-utils/Cargo.toml +++ b/common/credential-utils/Cargo.toml @@ -12,6 +12,7 @@ thiserror = { workspace = true } tokio = { workspace = true } nym-bandwidth-controller = { path = "../../common/bandwidth-controller" } +nym-coconut = { path = "../nymcoconut" } nym-credentials = { path = "../../common/credentials" } nym-credential-storage = { path = "../../common/credential-storage" } nym-validator-client = { path = "../../common/client-libs/validator-client" } diff --git a/common/credentials/Cargo.toml b/common/credentials/Cargo.toml index f08a3a5cd5..55894c3754 100644 --- a/common/credentials/Cargo.toml +++ b/common/credentials/Cargo.toml @@ -17,10 +17,10 @@ zeroize = { workspace = true } # I guess temporarily until we get serde support in coconut up and running nym-coconut-interface = { path = "../coconut-interface" } -nym-crypto = { path = "../crypto", features = ["rand", "asymmetric"] } +nym-crypto = { path = "../crypto", features = ["rand", "asymmetric", "serde"] } nym-api-requests = { path = "../../nym-api/nym-api-requests" } nym-validator-client = { path = "../client-libs/validator-client", default-features = false } -serde = { version = "1.0.189", features = ["derive"] } +serde = { workspace = true, features = ["derive"] } [dev-dependencies] rand = "0.7.3" diff --git a/common/credentials/src/coconut/bandwidth/mod.rs b/common/credentials/src/coconut/bandwidth/mod.rs index 8e5a7d5631..8fe23a444b 100644 --- a/common/credentials/src/coconut/bandwidth/mod.rs +++ b/common/credentials/src/coconut/bandwidth/mod.rs @@ -27,7 +27,7 @@ pub fn bandwidth_credential_params() -> &'static Parameters { BANDWIDTH_CREDENTIAL_PARAMS.get_or_init(IssuanceBandwidthCredential::default_parameters) } -#[derive(Zeroize, ZeroizeOnDrop, Clone, Debug, Serialize, Deserialize)] +#[derive(Zeroize, Copy, Clone, Debug, Serialize, Deserialize)] pub enum CredentialType { Voucher, FreePass, @@ -37,6 +37,10 @@ impl CredentialType { pub fn is_free_pass(&self) -> bool { matches!(self, CredentialType::FreePass) } + + pub fn is_voucher(&self) -> bool { + matches!(self, CredentialType::Voucher) + } } impl Display for CredentialType { @@ -50,24 +54,24 @@ impl Display for CredentialType { #[derive(Debug, Clone)] pub struct CredentialSigningData { - pub(crate) pedersen_commitments_openings: Vec, + pub pedersen_commitments_openings: Vec, - pub(crate) blind_sign_request: BlindSignRequest, + pub blind_sign_request: BlindSignRequest, - pub(crate) public_attributes_plain: Vec, + pub public_attributes_plain: Vec, - pub(crate) typ: CredentialType, + pub typ: CredentialType, } #[derive(Debug, Serialize, Deserialize)] pub struct CredentialSpendingData { - pub(crate) embedded_private_attributes: usize, + pub embedded_private_attributes: usize, - pub(crate) verify_credential_request: VerifyCredentialRequest, + pub verify_credential_request: VerifyCredentialRequest, - pub(crate) public_attributes_plain: Vec, + pub public_attributes_plain: Vec, - pub(crate) typ: CredentialType, + pub typ: CredentialType, } impl CredentialSpendingData { @@ -90,4 +94,21 @@ impl CredentialSpendingData { &public_attributes, ) } + + pub fn validate_type_attribute(&self) -> bool { + // the first attribute is variant specific bandwidth encoding, the second one should be the type + let Some(type_plain) = self.public_attributes_plain.get(1) else { + return false; + }; + + match self.typ { + CredentialType::Voucher => type_plain == VOUCHER_INFO_TYPE, + CredentialType::FreePass => type_plain == FREE_PASS_INFO_TYPE, + } + } + + pub fn get_bandwidth_attribute(&self) -> Option<&String> { + // the first attribute is variant specific bandwidth encoding, the second one should be the type + self.public_attributes_plain.first() + } } diff --git a/common/credentials/src/coconut/credential.rs b/common/credentials/src/coconut/credential.rs index 6863200e17..446682a398 100644 --- a/common/credentials/src/coconut/credential.rs +++ b/common/credentials/src/coconut/credential.rs @@ -2,9 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 pub trait NymCredential { - fn prove_credential(&self); - - // pub attr - // hashed - // private + fn prove_credential(&self) -> Result<(), ()>; } diff --git a/gateway/gateway-requests/src/lib.rs b/gateway/gateway-requests/src/lib.rs index 9bc55978d9..9bb25dc45c 100644 --- a/gateway/gateway-requests/src/lib.rs +++ b/gateway/gateway-requests/src/lib.rs @@ -9,7 +9,7 @@ pub use types::*; pub mod authentication; pub mod iv; -mod models; +pub mod models; pub mod registration; pub mod types; diff --git a/gateway/gateway-requests/src/models.rs b/gateway/gateway-requests/src/models.rs index 1f155e7711..43881d3ceb 100644 --- a/gateway/gateway-requests/src/models.rs +++ b/gateway/gateway-requests/src/models.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::GatewayRequestsError; +use nym_coconut_interface::CoconutError; use nym_credentials::coconut::bandwidth::CredentialSpendingData; use serde::{Deserialize, Serialize}; @@ -20,6 +21,23 @@ impl CredentialSpendingWithEpoch { CredentialSpendingWithEpoch { data, epoch_id } } + pub fn matches_blinded_serial_number( + &self, + blinded_serial_number_bs58: &str, + ) -> Result { + self.data + .verify_credential_request + .has_blinded_serial_number(blinded_serial_number_bs58) + } + + pub fn unchecked_voucher_value(&self) -> u64 { + self.data + .get_bandwidth_attribute() + .expect("failed to extract bandwidth attribute") + .parse() + .expect("failed to parse voucher value") + } + pub fn to_bytes(&self) -> Vec { todo!() } diff --git a/gateway/src/node/client_handling/bandwidth.rs b/gateway/src/node/client_handling/bandwidth.rs index e1b4d831e0..d5ea02b2d2 100644 --- a/gateway/src/node/client_handling/bandwidth.rs +++ b/gateway/src/node/client_handling/bandwidth.rs @@ -1,13 +1,49 @@ -// Copyright 2021 - Nym Technologies SA +// Copyright 2021-2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use log::error; use nym_coconut_interface::Credential; +use nym_credentials::coconut::bandwidth::CredentialType; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum BandwidthError {} pub struct Bandwidth { value: u64, } impl Bandwidth { + pub const fn new(value: u64) -> Bandwidth { + Bandwidth { value } + } + + pub fn try_from_raw_value(value: &String, typ: CredentialType) -> Result { + // let bandwidth_value = match credential.data.typ { + // CredentialType::Voucher => { + // todo!() + // } + // CredentialType::FreePass => { + // error!("unimplemented handling of free pass credential"); + // return Err(()); + // } + // }; + + /* + if bandwidth_value > i64::MAX as u64 { + // note that this would have represented more than 1 exabyte, + // which is like 125,000 worth of hard drives so I don't think we have + // to worry about it for now... + warn!("Somehow we received bandwidth value higher than 9223372036854775807. We don't really want to deal with this now"); + return Err(RequestHandlingError::UnsupportedBandwidthValue( + bandwidth_value, + )); + } + */ + + todo!() + } + pub fn value(&self) -> u64 { self.value } diff --git a/gateway/src/node/client_handling/mod.rs b/gateway/src/node/client_handling/mod.rs index ff4691e256..ae26cc558d 100644 --- a/gateway/src/node/client_handling/mod.rs +++ b/gateway/src/node/client_handling/mod.rs @@ -1,9 +1,11 @@ -// Copyright 2020 - Nym Technologies SA +// Copyright 2020-2024 - Nym Technologies SA // SPDX-License-Identifier: GPL-3.0-only +use crate::node::client_handling::bandwidth::Bandwidth; + pub(crate) mod active_clients; mod bandwidth; pub(crate) mod embedded_network_requester; pub(crate) mod websocket; -pub(crate) const FREE_TESTNET_BANDWIDTH_VALUE: i64 = 64 * 1024 * 1024 * 1024; // 64GB +pub(crate) const FREE_TESTNET_BANDWIDTH_VALUE: Bandwidth = Bandwidth::new(64 * 1024 * 1024 * 1024); // 64GB diff --git a/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs b/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs index b97bae206f..548037e9d3 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/authenticated.rs @@ -19,8 +19,11 @@ use thiserror::Error; use tokio::io::{AsyncRead, AsyncWrite}; use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError}; +use nym_coconut_interface::CoconutError; +use nym_credentials::coconut::bandwidth::CredentialType; use std::{convert::TryFrom, process, time::Duration}; +use crate::node::client_handling::bandwidth::BandwidthError; use crate::node::{ client_handling::{ bandwidth::Bandwidth, @@ -76,11 +79,20 @@ pub(crate) enum RequestHandlingError { #[error("Coconut interface error - {0}")] CoconutInterfaceError(#[from] nym_coconut_interface::error::CoconutInterfaceError), + #[error("coconut failure: {0}")] + CoconutError(#[from] CoconutError), + #[error("coconut api query failure: {0}")] CoconutApiError(#[from] CoconutApiError), #[error("Credential error - {0}")] CredentialError(#[from] nym_credentials::error::Error), + + #[error("failed to recover bandwidth value: {0}")] + BandwidthRecoveryFailure(#[from] BandwidthError), + + #[error("free pass credentials haven't been implemented yet")] + UnimplementedFreePass, } impl RequestHandlingError { @@ -177,10 +189,10 @@ where /// # Arguments /// /// * `amount`: amount to increase the available bandwidth by. - async fn increase_bandwidth(&self, amount: i64) -> Result<(), RequestHandlingError> { + async fn increase_bandwidth(&self, bandwidth: Bandwidth) -> Result<(), RequestHandlingError> { self.inner .storage - .increase_bandwidth(self.client.address, amount) + .increase_bandwidth(self.client.address, bandwidth.value() as i64) .await?; Ok(()) } @@ -232,40 +244,45 @@ where let aggregated_verification_key = self .inner .coconut_verifier - .verification_key(*credential.epoch_id()) + .verification_key(credential.epoch_id) .await?; - if !credential.verify(&aggregated_verification_key) { + if !credential.data.validate_type_attribute() { + unimplemented!() + } + + let Some(bandwidth_attribute) = credential.data.get_bandwidth_attribute() else { + unimplemented!() + }; + + let bandwidth = Bandwidth::try_from_raw_value(bandwidth_attribute, credential.data.typ)?; + + if !credential.data.verify(&aggregated_verification_key) { return Err(RequestHandlingError::InvalidBandwidthCredential( String::from("credential failed to verify on gateway"), )); } - let api_clients = self - .inner - .coconut_verifier - .api_clients(*credential.epoch_id()) - .await?; + match credential.data.typ { + CredentialType::Voucher => { + let api_clients = self + .inner + .coconut_verifier + .api_clients(credential.epoch_id) + .await?; - self.inner - .coconut_verifier - .release_funds(&api_clients, &credential) - .await?; - - let bandwidth = Bandwidth::from(credential); - let bandwidth_value = bandwidth.value(); - - if bandwidth_value > i64::MAX as u64 { - // note that this would have represented more than 1 exabyte, - // which is like 125,000 worth of hard drives so I don't think we have - // to worry about it for now... - warn!("Somehow we received bandwidth value higher than 9223372036854775807. We don't really want to deal with this now"); - return Err(RequestHandlingError::UnsupportedBandwidthValue( - bandwidth_value, - )); + self.inner + .coconut_verifier + .release_bandwidth_voucher_funds(&api_clients, credential) + .await?; + } + CredentialType::FreePass => { + error!("unimplemented handling of free pass credential"); + return Err(RequestHandlingError::UnimplementedFreePass); + } } - self.increase_bandwidth(bandwidth_value as i64).await?; + self.increase_bandwidth(bandwidth).await?; let available_total = self.get_available_bandwidth().await?; Ok(ServerResponse::Bandwidth { available_total }) diff --git a/gateway/src/node/client_handling/websocket/connection_handler/coconut.rs b/gateway/src/node/client_handling/websocket/connection_handler/coconut.rs index 58b32f7031..c8c00c774f 100644 --- a/gateway/src/node/client_handling/websocket/connection_handler/coconut.rs +++ b/gateway/src/node/client_handling/websocket/connection_handler/coconut.rs @@ -4,6 +4,7 @@ use super::authenticated::RequestHandlingError; use log::*; use nym_coconut_interface::{Credential, VerificationKey}; +use nym_gateway_requests::models::CredentialSpendingWithEpoch; use nym_validator_client::coconut::all_coconut_api_clients; use nym_validator_client::nym_api::EpochId; use nym_validator_client::nyxd::contract_traits::MultisigQueryClient; @@ -151,21 +152,31 @@ impl CoconutVerifier { Ok(all_coconut_api_clients(self.nyxd_client.read().await.deref(), epoch_id).await?) } - pub async fn release_funds( + pub async fn release_bandwidth_voucher_funds( &self, api_clients: &[CoconutApiClient], - credential: &Credential, + credential: CredentialSpendingWithEpoch, ) -> Result<(), RequestHandlingError> { + if !credential.data.typ.is_voucher() { + unimplemented!() + } + + // safety: the voucher funds are released after the credential has already been verified locally + // and the underlying bandwidth value has been extracted, so the below MUST succeed + let voucher_amount = credential.unchecked_voucher_value() as u128; + + let blinded_serial_number = credential + .data + .verify_credential_request + .blinded_serial_number_bs58(); + let res = self .nyxd_client .write() .await .spend_credential( - Coin::new( - credential.voucher_value().into(), - self.mix_denom_base.clone(), - ), - credential.blinded_serial_number(), + Coin::new(voucher_amount, &self.mix_denom_base), + blinded_serial_number, self.address.to_string(), None, ) @@ -186,27 +197,28 @@ impl CoconutVerifier { .await .query_proposal(proposal_id) .await?; - if !credential.has_blinded_serial_number(&proposal.description)? { + if !credential.matches_blinded_serial_number(&proposal.description)? { return Err(RequestHandlingError::ProposalIdError { reason: String::from("proposal has different serial number"), }); } let req = nym_api_requests::coconut::VerifyCredentialBody::new( - credential.clone(), + credential, proposal_id, self.address.clone(), ); for client in api_clients { let ret = client.api_client.verify_bandwidth_credential(&req).await; + let client_url = client.api_client.nym_api.current_url(); match ret { Ok(res) => { if !res.verification_result { - debug!("Validator {} didn't accept the credential. It will probably vote No on the spending proposal", client.api_client.nym_api.current_url()); + warn!("Validator at {client_url} didn't accept the credential. It will probably vote No on the spending proposal"); } } - Err(e) => { - warn!("Validator {} could not be reached. There might be a problem with the coconut endpoint - {:?}", client.api_client.nym_api.current_url(), e); + Err(err) => { + warn!("Validator at {client_url} could not be reached. There might be a problem with the coconut endpoint: {err}"); } } } diff --git a/nym-api/nym-api-requests/Cargo.toml b/nym-api/nym-api-requests/Cargo.toml index 1befc394cf..aaf7309fcf 100644 --- a/nym-api/nym-api-requests/Cargo.toml +++ b/nym-api/nym-api-requests/Cargo.toml @@ -16,7 +16,9 @@ serde = { workspace = true, features = ["derive"] } ts-rs = { workspace = true, optional = true } tendermint = { workspace = true } +nym-coconut = { path = "../../common/nymcoconut" } nym-coconut-interface = { path = "../../common/coconut-interface" } +#nym-credentials = { path = "../../common/credentials" } nym-crypto = { path = "../../common/crypto", features = ["serde", "asymmetric"]} nym-mixnet-contract-common = { path= "../../common/cosmwasm-smart-contracts/mixnet-contract" } diff --git a/nym-api/nym-api-requests/src/coconut/models.rs b/nym-api/nym-api-requests/src/coconut/models.rs index aa6e82ef00..15efe1a9f6 100644 --- a/nym-api/nym-api-requests/src/coconut/models.rs +++ b/nym-api/nym-api-requests/src/coconut/models.rs @@ -1,11 +1,11 @@ -// Copyright 2023 - Nym Technologies SA +// Copyright 2023-2024 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 use crate::coconut::helpers::issued_credential_plaintext; use cosmrs::AccountId; -use nym_coconut_interface::{ - error::CoconutInterfaceError, hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, - Bytable, Credential, VerificationKey, +use nym_coconut::{ + hash_to_scalar, Attribute, BlindSignRequest, BlindedSignature, Bytable, CoconutError, + Signature, VerificationKey, }; use nym_crypto::asymmetric::identity; use serde::{Deserialize, Serialize}; @@ -14,21 +14,30 @@ use tendermint::hash::Hash; #[derive(Serialize, Deserialize)] pub struct VerifyCredentialBody { - pub credential: Credential, + /// The cryptographic material required for spending the underlying credential. + pub credential_data: (), + /// The (DKG) epoch id under which the credential has been issued so that the verifier + /// could use correct verification key for validation. + pub epoch_id: u64, + + /// Multisig proposal for releasing funds for the provided bandwidth credential pub proposal_id: u64, + /// Cosmos address of the spender of the credential pub gateway_cosmos_addr: AccountId, } impl VerifyCredentialBody { pub fn new( - credential: Credential, + credential_data: (), + epoch_id: u64, proposal_id: u64, gateway_cosmos_addr: AccountId, ) -> VerifyCredentialBody { VerifyCredentialBody { - credential, + credential_data, + epoch_id, proposal_id, gateway_cosmos_addr, } @@ -115,7 +124,7 @@ impl BlindedSignatureResponse { bs58::encode(&self.to_bytes()).into_string() } - pub fn from_base58_string>(val: I) -> Result { + pub fn from_base58_string>(val: I) -> Result { let bytes = bs58::decode(val).into_vec()?; Self::from_bytes(&bytes) } @@ -124,7 +133,7 @@ impl BlindedSignatureResponse { self.blinded_signature.to_byte_vec() } - pub fn from_bytes(bytes: &[u8]) -> Result { + pub fn from_bytes(bytes: &[u8]) -> Result { Ok(BlindedSignatureResponse { blinded_signature: BlindedSignature::from_bytes(bytes)?, }) diff --git a/nym-connect/desktop/Cargo.lock b/nym-connect/desktop/Cargo.lock index 7b45691803..6712290bda 100644 --- a/nym-connect/desktop/Cargo.lock +++ b/nym-connect/desktop/Cargo.lock @@ -958,6 +958,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +[[package]] +name = "const-str" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aca749d3d3f5b87a0d6100509879f9cf486ab510803a4a4e1001da1ff61c2bd6" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -3688,6 +3694,7 @@ dependencies = [ "cosmrs", "cosmwasm-std", "getset", + "nym-coconut", "nym-coconut-interface", "nym-crypto", "nym-mixnet-contract-common", @@ -3723,6 +3730,7 @@ dependencies = [ "clap", "clap_complete", "clap_complete_fig", + "const-str", "log", "pretty_env_logger", "schemars", @@ -3763,6 +3771,7 @@ dependencies = [ "serde", "serde_json", "sha2 0.10.8", + "si-scale", "sqlx", "tap", "thiserror", @@ -4142,6 +4151,7 @@ dependencies = [ "cfg-if", "dotenvy", "hex-literal", + "log", "once_cell", "schemars", "serde", @@ -6225,6 +6235,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "si-scale" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44beb68bf488343b13ddbd74d1d5d5e6559a58b6dfaee74eb8d5ed4f7ed7666f" + [[package]] name = "signal-hook" version = "0.3.17" diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 2209e5d647..0b68b813dd 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -750,6 +750,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" +[[package]] +name = "const-str" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aca749d3d3f5b87a0d6100509879f9cf486ab510803a4a4e1001da1ff61c2bd6" + [[package]] name = "convert_case" version = "0.4.0" @@ -3092,6 +3098,7 @@ dependencies = [ "cosmrs 0.15.0 (git+https://github.com/jstuczyn/cosmos-rust?branch=nym-temp/all-validator-features)", "cosmwasm-std", "getset", + "nym-coconut", "nym-coconut-interface", "nym-crypto", "nym-mixnet-contract-common", @@ -3109,6 +3116,7 @@ dependencies = [ "clap", "clap_complete", "clap_complete_fig", + "const-str", "log", "pretty_env_logger", "schemars", @@ -3317,6 +3325,7 @@ dependencies = [ "cfg-if", "dotenvy", "hex-literal", + "log", "once_cell", "schemars", "serde",