cdk_payment_processor/proto/
mod.rs1use std::str::FromStr;
2
3use cdk_common::payment::{
4 CreateIncomingPaymentResponse, MakePaymentResponse as CdkMakePaymentResponse,
5 PaymentIdentifier as CdkPaymentIdentifier, PaymentQuoteResponse as CdkPaymentQuoteResponse,
6 WaitPaymentResponse,
7};
8use cdk_common::{Amount, CurrencyUnit, MeltOptions as CdkMeltOptions};
9
10mod client;
11mod server;
12
13pub use client::PaymentProcessorClient;
14pub use server::PaymentProcessorServer;
15
16tonic::include_proto!("cdk_payment_processor");
17
18impl From<CdkPaymentIdentifier> for PaymentIdentifier {
19 fn from(value: CdkPaymentIdentifier) -> Self {
20 match value {
21 CdkPaymentIdentifier::Label(id) => Self {
22 r#type: PaymentIdentifierType::Label.into(),
23 value: Some(payment_identifier::Value::Id(id)),
24 },
25 CdkPaymentIdentifier::OfferId(id) => Self {
26 r#type: PaymentIdentifierType::OfferId.into(),
27 value: Some(payment_identifier::Value::Id(id)),
28 },
29 CdkPaymentIdentifier::PaymentHash(hash) => Self {
30 r#type: PaymentIdentifierType::PaymentHash.into(),
31 value: Some(payment_identifier::Value::Hash(hex::encode(hash))),
32 },
33 CdkPaymentIdentifier::Bolt12PaymentHash(hash) => Self {
34 r#type: PaymentIdentifierType::Bolt12PaymentHash.into(),
35 value: Some(payment_identifier::Value::Hash(hex::encode(hash))),
36 },
37 CdkPaymentIdentifier::CustomId(id) => Self {
38 r#type: PaymentIdentifierType::CustomId.into(),
39 value: Some(payment_identifier::Value::Id(id)),
40 },
41 CdkPaymentIdentifier::PaymentId(hash) => Self {
42 r#type: PaymentIdentifierType::PaymentId.into(),
43 value: Some(payment_identifier::Value::Hash(hex::encode(hash))),
44 },
45 }
46 }
47}
48
49impl TryFrom<PaymentIdentifier> for CdkPaymentIdentifier {
50 type Error = crate::error::Error;
51
52 fn try_from(value: PaymentIdentifier) -> Result<Self, Self::Error> {
53 match (value.r#type(), value.value) {
54 (PaymentIdentifierType::Label, Some(payment_identifier::Value::Id(id))) => {
55 Ok(CdkPaymentIdentifier::Label(id))
56 }
57 (PaymentIdentifierType::OfferId, Some(payment_identifier::Value::Id(id))) => {
58 Ok(CdkPaymentIdentifier::OfferId(id))
59 }
60 (PaymentIdentifierType::PaymentHash, Some(payment_identifier::Value::Hash(hash))) => {
61 let decoded = hex::decode(hash)?;
62 let hash_array: [u8; 32] = decoded
63 .try_into()
64 .map_err(|_| crate::error::Error::InvalidHash)?;
65 Ok(CdkPaymentIdentifier::PaymentHash(hash_array))
66 }
67 (
68 PaymentIdentifierType::Bolt12PaymentHash,
69 Some(payment_identifier::Value::Hash(hash)),
70 ) => {
71 let decoded = hex::decode(hash)?;
72 let hash_array: [u8; 32] = decoded
73 .try_into()
74 .map_err(|_| crate::error::Error::InvalidHash)?;
75 Ok(CdkPaymentIdentifier::Bolt12PaymentHash(hash_array))
76 }
77 (PaymentIdentifierType::CustomId, Some(payment_identifier::Value::Id(id))) => {
78 Ok(CdkPaymentIdentifier::CustomId(id))
79 }
80 (PaymentIdentifierType::PaymentId, Some(payment_identifier::Value::Hash(hash))) => {
81 let decoded = hex::decode(hash)?;
82 let hash_array: [u8; 32] = decoded
83 .try_into()
84 .map_err(|_| crate::error::Error::InvalidHash)?;
85 Ok(CdkPaymentIdentifier::PaymentId(hash_array))
86 }
87 _ => Err(crate::error::Error::InvalidPaymentIdentifier),
88 }
89 }
90}
91
92impl TryFrom<MakePaymentResponse> for CdkMakePaymentResponse {
93 type Error = crate::error::Error;
94 fn try_from(value: MakePaymentResponse) -> Result<Self, Self::Error> {
95 let status: cdk_common::nuts::MeltQuoteState = value.status().into();
98 let payment_proof = value.payment_proof;
99 let unit = CurrencyUnit::from_str(&value.unit)?;
100 let payment_identifier = value
101 .payment_identifier
102 .ok_or(crate::error::Error::InvalidPaymentIdentifier)?;
103 Ok(Self {
104 payment_lookup_id: payment_identifier.try_into()?,
105 payment_proof,
106 status,
107 total_spent: Amount::new(value.total_spent, unit),
108 })
109 }
110}
111
112impl From<CdkMakePaymentResponse> for MakePaymentResponse {
113 fn from(value: CdkMakePaymentResponse) -> Self {
114 Self {
115 payment_identifier: Some(value.payment_lookup_id.into()),
116 payment_proof: value.payment_proof,
117 status: QuoteState::from(value.status).into(),
118 total_spent: value.total_spent.value(),
119 unit: value.total_spent.unit().to_string(),
120 extra_json: None,
121 }
122 }
123}
124
125impl From<CreateIncomingPaymentResponse> for CreatePaymentResponse {
126 fn from(value: CreateIncomingPaymentResponse) -> Self {
127 Self {
128 request_identifier: Some(value.request_lookup_id.into()),
129 request: value.request,
130 expiry: value.expiry,
131 extra_json: None,
132 }
133 }
134}
135
136impl TryFrom<CreatePaymentResponse> for CreateIncomingPaymentResponse {
137 type Error = crate::error::Error;
138
139 fn try_from(value: CreatePaymentResponse) -> Result<Self, Self::Error> {
140 let request_identifier = value
141 .request_identifier
142 .ok_or(crate::error::Error::InvalidPaymentIdentifier)?;
143 Ok(Self {
144 request_lookup_id: request_identifier.try_into()?,
145 request: value.request,
146 expiry: value.expiry,
147 extra_json: Some(
148 serde_json::from_str(value.extra_json.unwrap_or_default().as_str())
149 .unwrap_or_default(),
150 ),
151 })
152 }
153}
154impl From<CdkPaymentQuoteResponse> for PaymentQuoteResponse {
155 fn from(value: CdkPaymentQuoteResponse) -> Self {
156 Self {
157 request_identifier: value.request_lookup_id.map(|i| i.into()),
158 amount: value.amount.value(),
159 fee: value.fee.value(),
160 unit: value.amount.unit().to_string(),
161 state: QuoteState::from(value.state).into(),
162 extra_json: None,
163 }
164 }
165}
166
167impl From<PaymentQuoteResponse> for CdkPaymentQuoteResponse {
168 fn from(value: PaymentQuoteResponse) -> Self {
169 let state_val = value.state();
170 let request_identifier = value.request_identifier;
171 let unit = CurrencyUnit::from_str(&value.unit).unwrap_or_default();
172
173 Self {
174 request_lookup_id: request_identifier
175 .map(|i| i.try_into().expect("valid request identifier")),
176 amount: Amount::new(value.amount, unit.clone()),
177 fee: Amount::new(value.fee, unit),
178 state: state_val.into(),
179 }
180 }
181}
182
183impl From<MeltOptions> for CdkMeltOptions {
184 fn from(value: MeltOptions) -> Self {
185 match value.options.expect("option defined") {
186 melt_options::Options::Mpp(mpp) => Self::Mpp {
187 mpp: cashu::nuts::nut15::Mpp {
188 amount: mpp.amount.into(),
189 },
190 },
191 melt_options::Options::Amountless(amountless) => Self::Amountless {
192 amountless: cashu::nuts::nut23::Amountless {
193 amount_msat: amountless.amount_msat.into(),
194 },
195 },
196 }
197 }
198}
199
200impl From<CdkMeltOptions> for MeltOptions {
201 fn from(value: CdkMeltOptions) -> Self {
202 match value {
203 CdkMeltOptions::Mpp { mpp } => Self {
204 options: Some(melt_options::Options::Mpp(Mpp {
205 amount: mpp.amount.into(),
206 })),
207 },
208 CdkMeltOptions::Amountless { amountless } => Self {
209 options: Some(melt_options::Options::Amountless(Amountless {
210 amount_msat: amountless.amount_msat.into(),
211 })),
212 },
213 }
214 }
215}
216
217impl From<QuoteState> for cdk_common::nuts::MeltQuoteState {
218 fn from(value: QuoteState) -> Self {
219 match value {
220 QuoteState::Unpaid => Self::Unpaid,
221 QuoteState::Paid => Self::Paid,
222 QuoteState::Pending => Self::Pending,
223 QuoteState::Unknown => Self::Unknown,
224 QuoteState::Failed => Self::Failed,
225 QuoteState::Issued => Self::Unknown,
226 QuoteState::Unspecified => Self::Unknown,
227 }
228 }
229}
230
231impl From<cdk_common::nuts::MeltQuoteState> for QuoteState {
232 fn from(value: cdk_common::nuts::MeltQuoteState) -> Self {
233 match value {
234 cdk_common::nuts::MeltQuoteState::Unpaid => Self::Unpaid,
235 cdk_common::nuts::MeltQuoteState::Paid => Self::Paid,
236 cdk_common::nuts::MeltQuoteState::Pending => Self::Pending,
237 cdk_common::nuts::MeltQuoteState::Unknown => Self::Unknown,
238 cdk_common::nuts::MeltQuoteState::Failed => Self::Failed,
239 }
240 }
241}
242
243impl From<cdk_common::nuts::MintQuoteState> for QuoteState {
244 fn from(value: cdk_common::nuts::MintQuoteState) -> Self {
245 match value {
246 cdk_common::nuts::MintQuoteState::Unpaid => Self::Unpaid,
247 cdk_common::nuts::MintQuoteState::Paid => Self::Paid,
248 cdk_common::nuts::MintQuoteState::Issued => Self::Issued,
249 }
250 }
251}
252
253impl From<WaitPaymentResponse> for WaitIncomingPaymentResponse {
254 fn from(value: WaitPaymentResponse) -> Self {
255 Self {
256 payment_identifier: Some(value.payment_identifier.into()),
257 payment_amount: value.payment_amount.value(),
258 unit: value.payment_amount.unit().to_string(),
259 payment_id: value.payment_id,
260 }
261 }
262}
263
264impl TryFrom<WaitIncomingPaymentResponse> for WaitPaymentResponse {
265 type Error = crate::error::Error;
266
267 fn try_from(value: WaitIncomingPaymentResponse) -> Result<Self, Self::Error> {
268 let payment_identifier = value
269 .payment_identifier
270 .ok_or(crate::error::Error::InvalidPaymentIdentifier)?
271 .try_into()?;
272 let unit = CurrencyUnit::from_str(&value.unit)?;
273
274 Ok(Self {
275 payment_identifier,
276 payment_amount: Amount::new(value.payment_amount, unit),
277 payment_id: value.payment_id,
278 })
279 }
280}