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::{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 From<cdk_common::Amount<CurrencyUnit>> for AmountMessage {
95 fn from(value: cdk_common::Amount<CurrencyUnit>) -> Self {
96 Self {
97 value: value.value(),
98 unit: value.unit().to_string(),
99 }
100 }
101}
102
103impl TryFrom<AmountMessage> for cdk_common::Amount<CurrencyUnit> {
104 type Error = crate::error::Error;
105 fn try_from(value: AmountMessage) -> Result<Self, Self::Error> {
106 let unit = CurrencyUnit::from_str(&value.unit)?;
107 Ok(cdk_common::Amount::new(value.value, unit))
108 }
109}
110
111pub(crate) trait IntoProtoAmount {
113 fn into_proto(self) -> Option<AmountMessage>;
114}
115
116impl IntoProtoAmount for Option<cdk_common::Amount<CurrencyUnit>> {
117 fn into_proto(self) -> Option<AmountMessage> {
118 self.map(Into::into)
119 }
120}
121
122pub(crate) trait TryFromProtoAmount {
123 fn try_from_proto(
124 self,
125 ) -> Result<Option<cdk_common::Amount<CurrencyUnit>>, crate::error::Error>;
126}
127
128impl TryFromProtoAmount for Option<AmountMessage> {
129 fn try_from_proto(
130 self,
131 ) -> Result<Option<cdk_common::Amount<CurrencyUnit>>, crate::error::Error> {
132 match self {
133 Some(amount) => Ok(Some(amount.try_into()?)),
134 None => Ok(None),
135 }
136 }
137}
138
139impl TryFrom<MakePaymentResponse> for CdkMakePaymentResponse {
140 type Error = crate::error::Error;
141 fn try_from(value: MakePaymentResponse) -> Result<Self, Self::Error> {
142 let status: cdk_common::nuts::MeltQuoteState = value.status().into();
145 let payment_proof = value.payment_proof;
146 let total_spent = value
147 .total_spent
148 .ok_or(crate::error::Error::MissingAmount)?
149 .try_into()?;
150 let payment_identifier = value
151 .payment_identifier
152 .ok_or(crate::error::Error::InvalidPaymentIdentifier)?;
153 Ok(Self {
154 payment_lookup_id: payment_identifier.try_into()?,
155 payment_proof,
156 status,
157 total_spent,
158 })
159 }
160}
161
162impl From<CdkMakePaymentResponse> for MakePaymentResponse {
163 fn from(value: CdkMakePaymentResponse) -> Self {
164 Self {
165 payment_identifier: Some(value.payment_lookup_id.into()),
166 payment_proof: value.payment_proof,
167 status: QuoteState::from(value.status).into(),
168 total_spent: Some(value.total_spent.into()),
169 extra_json: None,
170 }
171 }
172}
173
174impl From<CreateIncomingPaymentResponse> for CreatePaymentResponse {
175 fn from(value: CreateIncomingPaymentResponse) -> Self {
176 Self {
177 request_identifier: Some(value.request_lookup_id.into()),
178 request: value.request,
179 expiry: value.expiry,
180 extra_json: None,
181 }
182 }
183}
184
185impl TryFrom<CreatePaymentResponse> for CreateIncomingPaymentResponse {
186 type Error = crate::error::Error;
187
188 fn try_from(value: CreatePaymentResponse) -> Result<Self, Self::Error> {
189 let request_identifier = value
190 .request_identifier
191 .ok_or(crate::error::Error::InvalidPaymentIdentifier)?;
192 Ok(Self {
193 request_lookup_id: request_identifier.try_into()?,
194 request: value.request,
195 expiry: value.expiry,
196 extra_json: Some(
197 serde_json::from_str(value.extra_json.unwrap_or_default().as_str())
198 .unwrap_or_default(),
199 ),
200 })
201 }
202}
203impl From<CdkPaymentQuoteResponse> for PaymentQuoteResponse {
204 fn from(value: CdkPaymentQuoteResponse) -> Self {
205 Self {
206 request_identifier: value.request_lookup_id.map(|i| i.into()),
207 amount: Some(value.amount.into()),
208 fee: Some(value.fee.into()),
209 state: QuoteState::from(value.state).into(),
210 extra_json: None,
211 }
212 }
213}
214
215impl TryFrom<PaymentQuoteResponse> for CdkPaymentQuoteResponse {
216 type Error = crate::error::Error;
217 fn try_from(value: PaymentQuoteResponse) -> Result<Self, Self::Error> {
218 let state_val = value.state();
219 let request_identifier = value.request_identifier;
220
221 Ok(Self {
222 request_lookup_id: request_identifier
223 .map(|i| i.try_into().expect("valid request identifier")),
224 amount: value
225 .amount
226 .ok_or(crate::error::Error::MissingAmount)?
227 .try_into()?,
228 fee: value
229 .fee
230 .ok_or(crate::error::Error::MissingAmount)?
231 .try_into()?,
232 state: state_val.into(),
233 })
234 }
235}
236
237impl From<MeltOptions> for CdkMeltOptions {
238 fn from(value: MeltOptions) -> Self {
239 match value.options.expect("option defined") {
240 melt_options::Options::Mpp(mpp) => Self::Mpp {
241 mpp: cashu::nuts::nut15::Mpp {
242 amount: mpp.amount.into(),
243 },
244 },
245 melt_options::Options::Amountless(amountless) => Self::Amountless {
246 amountless: cashu::nuts::nut23::Amountless {
247 amount_msat: amountless.amount_msat.into(),
248 },
249 },
250 }
251 }
252}
253
254impl From<CdkMeltOptions> for MeltOptions {
255 fn from(value: CdkMeltOptions) -> Self {
256 match value {
257 CdkMeltOptions::Mpp { mpp } => Self {
258 options: Some(melt_options::Options::Mpp(Mpp {
259 amount: mpp.amount.into(),
260 })),
261 },
262 CdkMeltOptions::Amountless { amountless } => Self {
263 options: Some(melt_options::Options::Amountless(Amountless {
264 amount_msat: amountless.amount_msat.into(),
265 })),
266 },
267 }
268 }
269}
270
271impl From<QuoteState> for cdk_common::nuts::MeltQuoteState {
272 fn from(value: QuoteState) -> Self {
273 match value {
274 QuoteState::Unpaid => Self::Unpaid,
275 QuoteState::Paid => Self::Paid,
276 QuoteState::Pending => Self::Pending,
277 QuoteState::Unknown => Self::Unknown,
278 QuoteState::Failed => Self::Failed,
279 QuoteState::Issued => Self::Unknown,
280 QuoteState::Unspecified => Self::Unknown,
281 }
282 }
283}
284
285impl From<cdk_common::nuts::MeltQuoteState> for QuoteState {
286 fn from(value: cdk_common::nuts::MeltQuoteState) -> Self {
287 match value {
288 cdk_common::nuts::MeltQuoteState::Unpaid => Self::Unpaid,
289 cdk_common::nuts::MeltQuoteState::Paid => Self::Paid,
290 cdk_common::nuts::MeltQuoteState::Pending => Self::Pending,
291 cdk_common::nuts::MeltQuoteState::Unknown => Self::Unknown,
292 cdk_common::nuts::MeltQuoteState::Failed => Self::Failed,
293 }
294 }
295}
296
297impl From<cdk_common::nuts::MintQuoteState> for QuoteState {
298 fn from(value: cdk_common::nuts::MintQuoteState) -> Self {
299 match value {
300 cdk_common::nuts::MintQuoteState::Unpaid => Self::Unpaid,
301 cdk_common::nuts::MintQuoteState::Paid => Self::Paid,
302 cdk_common::nuts::MintQuoteState::Issued => Self::Issued,
303 }
304 }
305}
306
307impl From<WaitPaymentResponse> for WaitIncomingPaymentResponse {
308 fn from(value: WaitPaymentResponse) -> Self {
309 Self {
310 payment_identifier: Some(value.payment_identifier.into()),
311 payment_amount: Some(value.payment_amount.into()),
312 payment_id: value.payment_id,
313 }
314 }
315}
316
317impl TryFrom<WaitIncomingPaymentResponse> for WaitPaymentResponse {
318 type Error = crate::error::Error;
319
320 fn try_from(value: WaitIncomingPaymentResponse) -> Result<Self, Self::Error> {
321 let payment_identifier = value
322 .payment_identifier
323 .ok_or(crate::error::Error::InvalidPaymentIdentifier)?
324 .try_into()?;
325
326 Ok(Self {
327 payment_identifier,
328 payment_amount: value
329 .payment_amount
330 .ok_or(crate::error::Error::MissingAmount)?
331 .try_into()?,
332 payment_id: value.payment_id,
333 })
334 }
335}