mirror of
https://github.com/aljazceru/cdk.git
synced 2026-02-09 15:16:00 +01:00
refactor: move client to wallet mod
refactor: client error refactor: mint error mod refactor: error codes refactor: remove enum numbers
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
use std::fmt;
|
||||
use std::string::FromUtf8Error;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use serde_json::Value;
|
||||
use thiserror::Error;
|
||||
|
||||
@@ -79,7 +79,7 @@ pub enum Error {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct ErrorResponse {
|
||||
pub code: u32,
|
||||
pub code: ErrorCode,
|
||||
pub error: Option<String>,
|
||||
pub detail: Option<String>,
|
||||
}
|
||||
@@ -98,24 +98,73 @@ impl fmt::Display for ErrorResponse {
|
||||
|
||||
impl ErrorResponse {
|
||||
pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
|
||||
match serde_json::from_str::<ErrorResponse>(json) {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Ok(Self {
|
||||
code: 999,
|
||||
error: Some(json.to_string()),
|
||||
detail: None,
|
||||
}),
|
||||
}
|
||||
let value: Value = serde_json::from_str(json)?;
|
||||
|
||||
Self::from_value(value)
|
||||
}
|
||||
|
||||
pub fn from_value(value: Value) -> Result<Self, serde_json::Error> {
|
||||
match serde_json::from_value::<ErrorResponse>(value.clone()) {
|
||||
Ok(res) => Ok(res),
|
||||
Err(_) => Ok(Self {
|
||||
code: 999,
|
||||
code: ErrorCode::Unknown(999),
|
||||
error: Some(value.to_string()),
|
||||
detail: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum ErrorCode {
|
||||
TokenAlreadySpent,
|
||||
QuoteNotPaid,
|
||||
KeysetNotFound,
|
||||
Unknown(u16),
|
||||
}
|
||||
|
||||
impl Serialize for ErrorCode {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let code = match self {
|
||||
ErrorCode::TokenAlreadySpent => 11001,
|
||||
ErrorCode::QuoteNotPaid => 20001,
|
||||
ErrorCode::KeysetNotFound => 12001,
|
||||
ErrorCode::Unknown(code) => *code,
|
||||
};
|
||||
|
||||
serializer.serialize_u16(code)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for ErrorCode {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let code = u16::deserialize(deserializer)?;
|
||||
|
||||
let error_code = match code {
|
||||
11001 => ErrorCode::TokenAlreadySpent,
|
||||
20001 => ErrorCode::QuoteNotPaid,
|
||||
12001 => ErrorCode::KeysetNotFound,
|
||||
c => ErrorCode::Unknown(c),
|
||||
};
|
||||
|
||||
Ok(error_code)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ErrorCode {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let code = match self {
|
||||
Self::TokenAlreadySpent => 11001,
|
||||
Self::QuoteNotPaid => 20001,
|
||||
Self::KeysetNotFound => 12001,
|
||||
Self::Unknown(code) => *code,
|
||||
};
|
||||
write!(f, "{}", code)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ pub use lightning_invoice::{self, Bolt11Invoice};
|
||||
|
||||
pub mod amount;
|
||||
pub mod cdk_database;
|
||||
#[cfg(feature = "wallet")]
|
||||
pub mod client;
|
||||
pub mod dhke;
|
||||
pub mod error;
|
||||
#[cfg(feature = "mint")]
|
||||
@@ -23,8 +21,8 @@ pub mod util;
|
||||
pub mod wallet;
|
||||
|
||||
pub use self::amount::Amount;
|
||||
#[cfg(feature = "wallet")]
|
||||
pub use self::client::HttpClient;
|
||||
pub use self::util::SECP256K1;
|
||||
#[cfg(feature = "wallet")]
|
||||
pub use self::wallet::client::HttpClient;
|
||||
|
||||
pub type Result<T, E = Box<dyn std::error::Error>> = std::result::Result<T, E>;
|
||||
|
||||
100
crates/cdk/src/mint/error.rs
Normal file
100
crates/cdk/src/mint/error.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use http::StatusCode;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::cdk_database;
|
||||
use crate::error::{ErrorCode, ErrorResponse};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Unknown Keyset
|
||||
#[error("Unknown Keyset")]
|
||||
UnknownKeySet,
|
||||
/// Inactive Keyset
|
||||
#[error("Inactive Keyset")]
|
||||
InactiveKeyset,
|
||||
#[error("No key for amount")]
|
||||
AmountKey,
|
||||
#[error("Amount")]
|
||||
Amount,
|
||||
#[error("Duplicate proofs")]
|
||||
DuplicateProofs,
|
||||
#[error("Token Already Spent")]
|
||||
TokenAlreadySpent,
|
||||
#[error("Token Pending")]
|
||||
TokenPending,
|
||||
#[error("Quote not paid")]
|
||||
UnpaidQuote,
|
||||
#[error("Unknown quote")]
|
||||
UnknownQuote,
|
||||
#[error("Unknown secret kind")]
|
||||
UnknownSecretKind,
|
||||
#[error("Cannot have multiple units")]
|
||||
MultipleUnits,
|
||||
#[error("Blinded Message is already signed")]
|
||||
BlindedMessageAlreadySigned,
|
||||
#[error(transparent)]
|
||||
Cashu(#[from] crate::error::Error),
|
||||
#[error(transparent)]
|
||||
Secret(#[from] crate::secret::Error),
|
||||
#[error(transparent)]
|
||||
NUT00(#[from] crate::nuts::nut00::Error),
|
||||
#[error(transparent)]
|
||||
NUT11(#[from] crate::nuts::nut11::Error),
|
||||
#[error(transparent)]
|
||||
Nut12(#[from] crate::nuts::nut12::Error),
|
||||
#[error(transparent)]
|
||||
Nut14(#[from] crate::nuts::nut14::Error),
|
||||
/// Database Error
|
||||
#[error(transparent)]
|
||||
Database(#[from] cdk_database::Error),
|
||||
#[error("`{0}`")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl From<Error> for cdk_database::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
Self::Database(Box::new(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for ErrorResponse {
|
||||
fn from(err: Error) -> ErrorResponse {
|
||||
match err {
|
||||
Error::TokenAlreadySpent => ErrorResponse {
|
||||
code: ErrorCode::TokenAlreadySpent,
|
||||
error: Some(err.to_string()),
|
||||
detail: None,
|
||||
},
|
||||
_ => ErrorResponse {
|
||||
code: ErrorCode::Unknown(9999),
|
||||
error: Some(err.to_string()),
|
||||
detail: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for (StatusCode, ErrorResponse) {
|
||||
fn from(err: Error) -> (StatusCode, ErrorResponse) {
|
||||
(StatusCode::NOT_FOUND, err.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_error_response_enum() {
|
||||
let error = Error::TokenAlreadySpent;
|
||||
|
||||
let response: ErrorResponse = error.into();
|
||||
|
||||
let json = serde_json::to_string(&response).unwrap();
|
||||
|
||||
let error_response: ErrorResponse = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(response.code, error_response.code);
|
||||
}
|
||||
}
|
||||
@@ -3,90 +3,21 @@ use std::sync::Arc;
|
||||
|
||||
use bitcoin::bip32::{ChildNumber, DerivationPath, ExtendedPrivKey};
|
||||
use bitcoin::secp256k1::{self, Secp256k1};
|
||||
use http::StatusCode;
|
||||
use error::Error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::{debug, error, info};
|
||||
|
||||
use self::nut11::enforce_sig_flag;
|
||||
use crate::cdk_database::{self, MintDatabase};
|
||||
use crate::dhke::{hash_to_curve, sign_message, verify_message};
|
||||
use crate::error::ErrorResponse;
|
||||
use crate::nuts::nut11::enforce_sig_flag;
|
||||
use crate::nuts::*;
|
||||
use crate::types::{MeltQuote, MintQuote};
|
||||
use crate::url::UncheckedUrl;
|
||||
use crate::util::unix_time;
|
||||
use crate::Amount;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Unknown Keyset
|
||||
#[error("Unknown Keyset")]
|
||||
UnknownKeySet,
|
||||
/// Inactive Keyset
|
||||
#[error("Inactive Keyset")]
|
||||
InactiveKeyset,
|
||||
#[error("No key for amount")]
|
||||
AmountKey,
|
||||
#[error("Amount")]
|
||||
Amount,
|
||||
#[error("Duplicate proofs")]
|
||||
DuplicateProofs,
|
||||
#[error("Token Spent")]
|
||||
TokenSpent,
|
||||
#[error("Token Pending")]
|
||||
TokenPending,
|
||||
#[error("Quote not paid")]
|
||||
UnpaidQuote,
|
||||
#[error("`{0}`")]
|
||||
Custom(String),
|
||||
#[error(transparent)]
|
||||
Cashu(#[from] crate::error::Error),
|
||||
#[error(transparent)]
|
||||
Secret(#[from] crate::secret::Error),
|
||||
#[error(transparent)]
|
||||
NUT00(#[from] crate::nuts::nut00::Error),
|
||||
#[error(transparent)]
|
||||
NUT11(#[from] crate::nuts::nut11::Error),
|
||||
#[error(transparent)]
|
||||
Nut12(#[from] crate::nuts::nut12::Error),
|
||||
#[error(transparent)]
|
||||
Nut14(#[from] crate::nuts::nut14::Error),
|
||||
/// Database Error
|
||||
#[error(transparent)]
|
||||
Database(#[from] crate::cdk_database::Error),
|
||||
#[error("Unknown quote")]
|
||||
UnknownQuote,
|
||||
#[error("Unknown secret kind")]
|
||||
UnknownSecretKind,
|
||||
#[error("Cannot have multiple units")]
|
||||
MultipleUnits,
|
||||
#[error("Blinded Message is already signed")]
|
||||
BlindedMessageAlreadySigned,
|
||||
}
|
||||
|
||||
impl From<Error> for cdk_database::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
Self::Database(Box::new(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for ErrorResponse {
|
||||
fn from(err: Error) -> ErrorResponse {
|
||||
ErrorResponse {
|
||||
code: 9999,
|
||||
error: Some(err.to_string()),
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for (StatusCode, ErrorResponse) {
|
||||
fn from(err: Error) -> (StatusCode, ErrorResponse) {
|
||||
(StatusCode::NOT_FOUND, err.into())
|
||||
}
|
||||
}
|
||||
pub mod error;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Mint {
|
||||
@@ -493,7 +424,7 @@ impl Mint {
|
||||
let y: PublicKey = hash_to_curve(&proof.secret.to_bytes())?;
|
||||
|
||||
if self.localstore.get_spent_proof_by_y(&y).await?.is_some() {
|
||||
return Err(Error::TokenSpent);
|
||||
return Err(Error::TokenAlreadySpent);
|
||||
}
|
||||
|
||||
if self.localstore.get_pending_proof_by_y(&y).await?.is_some() {
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
use reqwest::Client;
|
||||
use serde_json::Value;
|
||||
use thiserror::Error;
|
||||
use tracing::instrument;
|
||||
use url::Url;
|
||||
|
||||
use super::Error;
|
||||
use crate::error::ErrorResponse;
|
||||
use crate::nuts::{
|
||||
BlindedMessage, CheckStateRequest, CheckStateResponse, CurrencyUnit, Id, KeySet, KeysResponse,
|
||||
@@ -16,28 +16,6 @@ use crate::nuts::{
|
||||
};
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Unknown Keyset
|
||||
#[error("Url Path segments could not be joined")]
|
||||
UrlPathSegments,
|
||||
/// Serde Json error
|
||||
#[error(transparent)]
|
||||
SerdeJsonError(#[from] serde_json::Error),
|
||||
/// From hex error
|
||||
#[error(transparent)]
|
||||
ReqwestError(#[from] reqwest::Error),
|
||||
/// Unknown error response
|
||||
#[error("Unknown Error response: `{0}`")]
|
||||
UnknownErrorResponse(String),
|
||||
}
|
||||
|
||||
impl From<ErrorResponse> for Error {
|
||||
fn from(err: ErrorResponse) -> Error {
|
||||
Self::UnknownErrorResponse(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn join_url(url: Url, paths: &[&str]) -> Result<Url, Error> {
|
||||
let mut url = url;
|
||||
for path in paths {
|
||||
115
crates/cdk/src/wallet/error.rs
Normal file
115
crates/cdk/src/wallet/error.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use std::num::ParseIntError;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::cdk_database;
|
||||
use crate::error::{ErrorCode, ErrorResponse};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Insufficient Funds
|
||||
#[error("Insufficient Funds")]
|
||||
InsufficientFunds,
|
||||
/// Quote Expired
|
||||
#[error("Quote Expired")]
|
||||
QuoteExpired,
|
||||
/// Unknown Quote
|
||||
#[error("Quote Unknown")]
|
||||
QuoteUnknown,
|
||||
/// Not active keyset
|
||||
#[error("No active keyset")]
|
||||
NoActiveKeyset,
|
||||
/// Invalid DLEQ prood
|
||||
#[error("Could not verify Dleq")]
|
||||
CouldNotVerifyDleq,
|
||||
/// P2PK spending conditions not met
|
||||
#[error("P2PK Condition Not met `{0}`")]
|
||||
P2PKConditionsNotMet(String),
|
||||
/// Invalid Spending Conditions
|
||||
#[error("Invalid Spending Conditions: `{0}`")]
|
||||
InvalidSpendConditions(String),
|
||||
/// Preimage not provided
|
||||
#[error("Preimage not provided")]
|
||||
PreimageNotProvided,
|
||||
#[error("Unknown Key")]
|
||||
UnknownKey,
|
||||
/// Spending Locktime not provided
|
||||
#[error("Spending condition locktime not provided")]
|
||||
LocktimeNotProvided,
|
||||
/// Unknown Keyset
|
||||
#[error("Url Path segments could not be joined")]
|
||||
UrlPathSegments,
|
||||
/// Quote not paid
|
||||
#[error("Quote not paid")]
|
||||
QuoteNotePaid,
|
||||
/// Token Already spent error
|
||||
#[error("Token Already Spent Error")]
|
||||
TokenAlreadySpent,
|
||||
/// Keyset Not Found
|
||||
#[error("Keyset Not Found")]
|
||||
KeysetNotFound,
|
||||
/// From hex error
|
||||
#[error(transparent)]
|
||||
ReqwestError(#[from] reqwest::Error),
|
||||
/// Unknown error response
|
||||
#[error("Unknown Error response: `{0}`")]
|
||||
UnknownErrorResponse(String),
|
||||
/// CDK Error
|
||||
#[error(transparent)]
|
||||
Cashu(#[from] crate::error::Error),
|
||||
/// Cashu Url Error
|
||||
#[error(transparent)]
|
||||
CashuUrl(#[from] crate::url::Error),
|
||||
/// Database Error
|
||||
#[error(transparent)]
|
||||
Database(#[from] crate::cdk_database::Error),
|
||||
/// NUT00 Error
|
||||
#[error(transparent)]
|
||||
NUT00(#[from] crate::nuts::nut00::Error),
|
||||
/// NUT01 Error
|
||||
#[error(transparent)]
|
||||
NUT01(#[from] crate::nuts::nut01::Error),
|
||||
/// NUT11 Error
|
||||
#[error(transparent)]
|
||||
NUT11(#[from] crate::nuts::nut11::Error),
|
||||
/// NUT12 Error
|
||||
#[error(transparent)]
|
||||
NUT12(#[from] crate::nuts::nut12::Error),
|
||||
/// Parse int
|
||||
#[error(transparent)]
|
||||
ParseInt(#[from] ParseIntError),
|
||||
/// Parse invoice error
|
||||
#[error(transparent)]
|
||||
Invoice(#[from] lightning_invoice::ParseOrSemanticError),
|
||||
/// Serde Error
|
||||
#[error(transparent)]
|
||||
Serde(#[from] serde_json::Error),
|
||||
/// Nostr Client Error
|
||||
#[cfg(feature = "nostr")]
|
||||
#[error(transparent)]
|
||||
NostrClient(#[from] nostr_sdk::client::Error),
|
||||
/// Nostr Key Error
|
||||
#[cfg(feature = "nostr")]
|
||||
#[error(transparent)]
|
||||
NostrKey(#[from] nostr_sdk::key::Error),
|
||||
/// Custom Error
|
||||
#[error("`{0}`")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl From<Error> for cdk_database::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
Self::Database(Box::new(e))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ErrorResponse> for Error {
|
||||
fn from(err: ErrorResponse) -> Error {
|
||||
match err.code {
|
||||
ErrorCode::QuoteNotPaid => Self::QuoteNotePaid,
|
||||
ErrorCode::TokenAlreadySpent => Self::TokenAlreadySpent,
|
||||
ErrorCode::KeysetNotFound => Self::KeysetNotFound,
|
||||
_ => Self::UnknownErrorResponse(err.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
//! Cashu Wallet
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::num::ParseIntError;
|
||||
use std::ops::Deref;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
@@ -11,17 +10,16 @@ use bitcoin::hashes::sha256::Hash as Sha256Hash;
|
||||
use bitcoin::hashes::Hash;
|
||||
use bitcoin::secp256k1::XOnlyPublicKey;
|
||||
use bitcoin::Network;
|
||||
use error::Error;
|
||||
#[cfg(feature = "nostr")]
|
||||
use nostr_sdk::nips::nip04;
|
||||
#[cfg(feature = "nostr")]
|
||||
use nostr_sdk::{Filter, Timestamp};
|
||||
use thiserror::Error;
|
||||
use tokio::sync::RwLock;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::amount::SplitTarget;
|
||||
use crate::cdk_database::{self, WalletDatabase};
|
||||
use crate::client::HttpClient;
|
||||
use crate::dhke::{construct_proofs, hash_to_curve};
|
||||
use crate::nuts::{
|
||||
nut10, nut12, Conditions, CurrencyUnit, Id, KeySet, KeySetInfo, Keys, Kind,
|
||||
@@ -32,78 +30,10 @@ use crate::nuts::{
|
||||
use crate::types::{MeltQuote, Melted, MintQuote, ProofInfo};
|
||||
use crate::url::UncheckedUrl;
|
||||
use crate::util::{hex, unix_time};
|
||||
use crate::{Amount, Bolt11Invoice};
|
||||
use crate::{Amount, Bolt11Invoice, HttpClient};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
/// Insufficient Funds
|
||||
#[error("Insufficient Funds")]
|
||||
InsufficientFunds,
|
||||
#[error("Quote Expired")]
|
||||
QuoteExpired,
|
||||
#[error("Quote Unknown")]
|
||||
QuoteUnknown,
|
||||
#[error("No active keyset")]
|
||||
NoActiveKeyset,
|
||||
#[error(transparent)]
|
||||
Cashu(#[from] crate::error::Error),
|
||||
#[error("Could not verify Dleq")]
|
||||
CouldNotVerifyDleq,
|
||||
#[error("P2PK Condition Not met `{0}`")]
|
||||
P2PKConditionsNotMet(String),
|
||||
#[error("Invalid Spending Conditions: `{0}`")]
|
||||
InvalidSpendConditions(String),
|
||||
#[error("Preimage not provided")]
|
||||
PreimageNotProvided,
|
||||
#[error("Unknown Key")]
|
||||
UnknownKey,
|
||||
/// Spending Locktime not provided
|
||||
#[error("Spending condition locktime not provided")]
|
||||
LocktimeNotProvided,
|
||||
/// Cashu Url Error
|
||||
#[error(transparent)]
|
||||
CashuUrl(#[from] crate::url::Error),
|
||||
/// NUT11 Error
|
||||
#[error(transparent)]
|
||||
Client(#[from] crate::client::Error),
|
||||
/// Database Error
|
||||
#[error(transparent)]
|
||||
Database(#[from] crate::cdk_database::Error),
|
||||
/// NUT00 Error
|
||||
#[error(transparent)]
|
||||
NUT00(#[from] crate::nuts::nut00::Error),
|
||||
/// NUT01 Error
|
||||
#[error(transparent)]
|
||||
NUT01(#[from] crate::nuts::nut01::Error),
|
||||
/// NUT11 Error
|
||||
#[error(transparent)]
|
||||
NUT11(#[from] crate::nuts::nut11::Error),
|
||||
/// NUT12 Error
|
||||
#[error(transparent)]
|
||||
NUT12(#[from] crate::nuts::nut12::Error),
|
||||
/// Parse int
|
||||
#[error(transparent)]
|
||||
ParseInt(#[from] ParseIntError),
|
||||
/// Parse invoice error
|
||||
#[error(transparent)]
|
||||
Invoice(#[from] lightning_invoice::ParseOrSemanticError),
|
||||
#[error(transparent)]
|
||||
Serde(#[from] serde_json::Error),
|
||||
#[cfg(feature = "nostr")]
|
||||
#[error(transparent)]
|
||||
NostrClient(#[from] nostr_sdk::client::Error),
|
||||
#[cfg(feature = "nostr")]
|
||||
#[error(transparent)]
|
||||
NostrKey(#[from] nostr_sdk::key::Error),
|
||||
#[error("`{0}`")]
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl From<Error> for cdk_database::Error {
|
||||
fn from(e: Error) -> Self {
|
||||
Self::Database(Box::new(e))
|
||||
}
|
||||
}
|
||||
pub mod client;
|
||||
pub mod error;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Wallet {
|
||||
Reference in New Issue
Block a user