1use crate::Hash;
22use hex;
23use secp256k1::ecdsa::Signature;
24use secp256k1::{Message, Secp256k1};
25use serde::{Deserialize, Serialize};
26use sha2::{Digest, Sha256};
27
28pub const PAYMENT_PROTOCOL_VERSION: u32 = 1;
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct PaymentDetails {
34 pub network: String,
36 pub outputs: Vec<PaymentOutput>,
38 pub time: u64,
40 pub expires: Option<u64>,
42 pub memo: Option<String>,
44 pub payment_url: Option<String>,
46 pub merchant_data: Option<Vec<u8>>,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
52pub struct PaymentOutput {
53 pub script: Vec<u8>,
55 pub amount: Option<u64>,
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct SignedRefundAddress {
62 pub address: PaymentOutput,
64 pub signature: Vec<u8>,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct PaymentRequest {
71 pub payment_details: PaymentDetails,
73 pub merchant_pubkey: Option<Vec<u8>>,
76 pub signature: Option<Vec<u8>>,
78 pub authorized_refund_addresses: Option<Vec<SignedRefundAddress>>,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
85pub struct Payment {
86 pub transactions: Vec<Vec<u8>>,
88 pub refund_to: Option<Vec<PaymentOutput>>,
90 pub merchant_data: Option<Vec<u8>>,
92 pub memo: Option<String>,
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct PaymentACK {
99 pub payment: Payment,
101 pub memo: Option<String>,
103 pub signature: Option<Vec<u8>>,
105}
106
107impl PaymentACK {
108 pub fn sign(&mut self, private_key: &secp256k1::SecretKey) -> Result<(), Bip70Error> {
110 let mut ack_for_signing = self.clone();
112 ack_for_signing.signature = None;
113
114 let serialized = bincode::serialize(&ack_for_signing)
115 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
116
117 let mut hasher = Sha256::new();
119 hasher.update(&serialized);
120 let hash = hasher.finalize();
121
122 let message = Message::from_digest(hash.into());
124
125 let secp = Secp256k1::new();
127 let signature = secp.sign_ecdsa(&message, private_key);
128
129 self.signature = Some(signature.serialize_compact().to_vec());
131
132 Ok(())
133 }
134
135 pub fn verify_signature(&self, merchant_pubkey: &[u8]) -> Result<(), Bip70Error> {
137 let signature_bytes = self
138 .signature
139 .as_ref()
140 .ok_or_else(|| Bip70Error::SignatureError("No signature".to_string()))?;
141
142 let pubkey = secp256k1::PublicKey::from_slice(merchant_pubkey)
144 .map_err(|e| Bip70Error::SignatureError(format!("Invalid public key: {e}")))?;
145
146 let signature = Signature::from_compact(signature_bytes)
148 .map_err(|e| Bip70Error::SignatureError(format!("Invalid signature: {e}")))?;
149
150 let mut ack_for_verification = self.clone();
152 ack_for_verification.signature = None;
153
154 let serialized = bincode::serialize(&ack_for_verification)
155 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
156
157 let mut hasher = Sha256::new();
159 hasher.update(&serialized);
160 let hash = hasher.finalize();
161
162 let message = Message::from_digest(hash.into());
164
165 let secp = Secp256k1::new();
167 secp.verify_ecdsa(&message, &signature, &pubkey)
168 .map_err(|_| {
169 Bip70Error::SignatureError("PaymentACK signature verification failed".to_string())
170 })?;
171
172 Ok(())
173 }
174}
175
176impl PaymentRequest {
177 pub fn new(network: String, outputs: Vec<PaymentOutput>, time: u64) -> Self {
179 Self {
180 payment_details: PaymentDetails {
181 network,
182 outputs,
183 time,
184 expires: None,
185 memo: None,
186 payment_url: None,
187 merchant_data: None,
188 },
189 merchant_pubkey: None,
190 signature: None,
191 authorized_refund_addresses: None,
192 }
193 }
194
195 pub fn with_merchant_key(mut self, pubkey: [u8; 33]) -> Self {
197 self.merchant_pubkey = Some(pubkey.to_vec());
198 self
199 }
200
201 pub fn with_authorized_refund(mut self, signed_refund: SignedRefundAddress) -> Self {
203 if self.authorized_refund_addresses.is_none() {
204 self.authorized_refund_addresses = Some(Vec::new());
205 }
206 self.authorized_refund_addresses
207 .as_mut()
208 .unwrap()
209 .push(signed_refund);
210 self
211 }
212
213 pub fn with_expires(mut self, expires: u64) -> Self {
215 self.payment_details.expires = Some(expires);
216 self
217 }
218
219 pub fn with_memo(mut self, memo: String) -> Self {
221 self.payment_details.memo = Some(memo);
222 self
223 }
224
225 pub fn with_payment_url(mut self, url: String) -> Self {
227 self.payment_details.payment_url = Some(url);
228 self
229 }
230
231 pub fn with_merchant_data(mut self, data: Vec<u8>) -> Self {
233 self.payment_details.merchant_data = Some(data);
234 self
235 }
236
237 pub fn sign(&mut self, private_key: &secp256k1::SecretKey) -> Result<(), Bip70Error> {
239 let serialized = bincode::serialize(&self.payment_details)
241 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
242
243 let mut hasher = Sha256::new();
245 hasher.update(&serialized);
246 let hash = hasher.finalize();
247
248 let message = Message::from_digest(hash.into());
250
251 let secp = Secp256k1::new();
253 let signature = secp.sign_ecdsa(&message, private_key);
254 let pubkey = secp256k1::PublicKey::from_secret_key(&secp, private_key);
255 let pubkey_serialized = pubkey.serialize();
256
257 self.signature = Some(signature.serialize_compact().to_vec());
259 self.merchant_pubkey = Some(pubkey_serialized.to_vec());
260
261 Ok(())
262 }
263
264 pub fn verify_signature(&self) -> Result<(), Bip70Error> {
266 let pubkey = self
267 .merchant_pubkey
268 .as_ref()
269 .ok_or_else(|| Bip70Error::SignatureError("No merchant public key".to_string()))?;
270 let signature_bytes = self
271 .signature
272 .as_ref()
273 .ok_or_else(|| Bip70Error::SignatureError("No signature".to_string()))?;
274
275 let pubkey = secp256k1::PublicKey::from_slice(pubkey)
277 .map_err(|e| Bip70Error::SignatureError(format!("Invalid public key: {e}")))?;
278
279 let signature = Signature::from_compact(signature_bytes)
281 .map_err(|e| Bip70Error::SignatureError(format!("Invalid signature: {e}")))?;
282
283 let serialized = bincode::serialize(&self.payment_details)
285 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
286
287 let mut hasher = Sha256::new();
289 hasher.update(&serialized);
290 let hash = hasher.finalize();
291
292 let message = Message::from_digest(hash.into());
294
295 let secp = Secp256k1::new();
297 secp.verify_ecdsa(&message, &signature, &pubkey)
298 .map_err(|_| Bip70Error::SignatureError("Signature verification failed".to_string()))?;
299
300 Ok(())
301 }
302
303 pub fn validate(&self) -> Result<(), Bip70Error> {
305 if let Some(expires) = self.payment_details.expires {
307 let now = crate::time::current_timestamp();
308 if now > expires {
309 return Err(Bip70Error::Expired);
310 }
311 }
312
313 if self.payment_details.outputs.is_empty() {
315 return Err(Bip70Error::InvalidRequest("No payment outputs".to_string()));
316 }
317
318 let valid_networks = ["main", "test", "regtest"];
320 if !valid_networks.contains(&self.payment_details.network.as_str()) {
321 return Err(Bip70Error::InvalidRequest(format!(
322 "Invalid network: {}",
323 self.payment_details.network
324 )));
325 }
326
327 Ok(())
328 }
329}
330
331impl Payment {
332 pub fn new(transactions: Vec<Vec<u8>>) -> Self {
334 Self {
335 transactions,
336 refund_to: None,
337 merchant_data: None,
338 memo: None,
339 }
340 }
341
342 pub fn with_refund_to(mut self, outputs: Vec<PaymentOutput>) -> Self {
344 self.refund_to = Some(outputs);
345 self
346 }
347
348 pub fn validate_refund_addresses(
350 &self,
351 authorized_refunds: &[SignedRefundAddress],
352 ) -> Result<(), Bip70Error> {
353 if let Some(ref refund_to) = self.refund_to {
354 for refund_addr in refund_to {
355 let is_authorized = authorized_refunds.iter().any(|auth| {
357 auth.address.script == refund_addr.script
358 && auth.address.amount == refund_addr.amount
359 });
360
361 if !is_authorized {
362 return Err(Bip70Error::InvalidPayment(format!(
363 "Refund address not authorized: {:?}",
364 refund_addr.script
365 )));
366 }
367 }
368 }
369 Ok(())
370 }
371
372 pub fn with_merchant_data(mut self, data: Vec<u8>) -> Self {
374 self.merchant_data = Some(data);
375 self
376 }
377
378 pub fn with_memo(mut self, memo: String) -> Self {
380 self.memo = Some(memo);
381 self
382 }
383
384 pub fn validate(&self) -> Result<(), Bip70Error> {
386 if self.transactions.is_empty() {
387 return Err(Bip70Error::InvalidPayment("No transactions".to_string()));
388 }
389
390 Ok(())
391 }
392}
393
394#[derive(Debug, thiserror::Error)]
396pub enum Bip70Error {
397 #[error("Payment request expired")]
398 Expired,
399
400 #[error("Invalid payment request: {0}")]
401 InvalidRequest(String),
402
403 #[error("Invalid payment: {0}")]
404 InvalidPayment(String),
405
406 #[error("Certificate validation failed: {0}")]
407 CertificateError(String),
408
409 #[error("Signature verification failed: {0}")]
410 SignatureError(String),
411
412 #[error("HTTP error: {0}")]
413 HttpError(String),
414
415 #[error("Serialization error: {0}")]
416 SerializationError(String),
417
418 #[error("Validation error: {0}")]
419 ValidationError(String),
420}
421
422pub struct PaymentProtocolClient;
427
428impl PaymentProtocolClient {
429 pub fn validate_payment_request(
431 payment_request: &PaymentRequest,
432 expected_merchant_pubkey: Option<&[u8]>,
433 ) -> Result<(), Bip70Error> {
434 payment_request.verify_signature()?;
436
437 payment_request.validate()?;
439
440 if let Some(expected_pubkey) = expected_merchant_pubkey {
442 if let Some(ref req_pubkey) = payment_request.merchant_pubkey {
443 if req_pubkey.as_slice() != expected_pubkey {
444 return Err(Bip70Error::SignatureError(
445 "PaymentRequest pubkey mismatch".to_string(),
446 ));
447 }
448 }
449 }
450
451 Ok(())
452 }
453
454 pub fn validate_payment_ack(
459 payment_ack: &PaymentACK,
460 merchant_signature: &[u8],
461 merchant_pubkey: &[u8],
462 ) -> Result<(), Bip70Error> {
463 if let Some(ref sig) = payment_ack.signature {
465 if !sig.is_empty() {
466 return payment_ack.verify_signature(merchant_pubkey);
467 }
468 }
469
470 if !merchant_signature.is_empty() {
472 let pubkey = secp256k1::PublicKey::from_slice(merchant_pubkey)
473 .map_err(|e| Bip70Error::SignatureError(format!("Invalid pubkey: {e}")))?;
474
475 let mut ack_for_verification = payment_ack.clone();
477 ack_for_verification.signature = None;
478
479 let serialized = bincode::serialize(&ack_for_verification)
480 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
481
482 let mut hasher = Sha256::new();
483 hasher.update(&serialized);
484 let hash = hasher.finalize();
485
486 let message = Message::from_digest(hash.into());
487
488 let signature = Signature::from_compact(merchant_signature)
489 .map_err(|e| Bip70Error::SignatureError(format!("Invalid signature: {e}")))?;
490
491 let secp = Secp256k1::new();
492 secp.verify_ecdsa(&message, &signature, &pubkey)
493 .map_err(|_| {
494 Bip70Error::SignatureError(
495 "PaymentACK signature verification failed".to_string(),
496 )
497 })?;
498 }
499
500 Ok(())
501 }
502}
503
504pub struct PaymentProtocolServer;
509
510impl PaymentProtocolServer {
511 pub fn create_signed_payment_request(
513 details: PaymentDetails,
514 merchant_private_key: &secp256k1::SecretKey,
515 authorized_refunds: Option<Vec<SignedRefundAddress>>,
516 ) -> Result<PaymentRequest, Bip70Error> {
517 let mut payment_request = PaymentRequest {
518 payment_details: details,
519 merchant_pubkey: None,
520 signature: None,
521 authorized_refund_addresses: authorized_refunds,
522 };
523
524 payment_request.sign(merchant_private_key)?;
526
527 Ok(payment_request)
528 }
529
530 pub fn process_payment(
532 payment: &Payment,
533 original_request: &PaymentRequest,
534 merchant_private_key: Option<&secp256k1::SecretKey>,
535 ) -> Result<PaymentACK, Bip70Error> {
536 payment.validate()?;
538
539 if let Some(ref authorized_refunds) = original_request.authorized_refund_addresses {
541 payment.validate_refund_addresses(authorized_refunds)?;
542 }
543
544 if let Some(ref payment_merchant_data) = payment.merchant_data {
546 if let Some(ref request_merchant_data) = original_request.payment_details.merchant_data
547 {
548 if payment_merchant_data != request_merchant_data {
549 return Err(Bip70Error::ValidationError(
550 "Merchant data mismatch".to_string(),
551 ));
552 }
553 }
554 } else if original_request.payment_details.merchant_data.is_some() {
555 return Err(Bip70Error::ValidationError(
556 "Payment missing merchant data".to_string(),
557 ));
558 }
559
560 Self::verify_payment_transactions(payment, original_request)?;
562
563 let mut payment_ack = PaymentACK {
565 payment: payment.clone(),
566 memo: Some("Payment received".to_string()),
567 signature: None, };
569
570 if let Some(private_key) = merchant_private_key {
572 payment_ack.sign(private_key)?;
573 }
574
575 Ok(payment_ack)
576 }
577
578 fn verify_payment_transactions(
580 payment: &Payment,
581 original_request: &PaymentRequest,
582 ) -> Result<(), Bip70Error> {
583 use crate::Transaction;
584
585 let mut all_outputs = Vec::new();
587 for tx_bytes in &payment.transactions {
588 let tx: Transaction = bincode::deserialize(tx_bytes)
589 .map_err(|e| Bip70Error::SerializationError(format!("Invalid transaction: {e}")))?;
590
591 for output in &tx.outputs {
593 all_outputs.push(PaymentOutput {
594 script: output.script_pubkey.clone(),
595 amount: Some(output.value as u64), });
597 }
598 }
599
600 for requested_output in &original_request.payment_details.outputs {
603 let found = all_outputs.iter().any(|output| {
604 output.script == requested_output.script
605 && match (output.amount, requested_output.amount) {
606 (Some(amt), Some(req_amt)) => amt >= req_amt, (Some(_), None) => true, (None, Some(_)) => false, (None, None) => true, }
611 });
612
613 if !found {
614 return Err(Bip70Error::ValidationError(format!(
615 "Payment missing required output: script={}, amount={:?}",
616 hex::encode(&requested_output.script),
617 requested_output.amount
618 )));
619 }
620 }
621
622 Ok(())
623 }
624
625 pub fn sign_refund_address(
627 address: PaymentOutput,
628 merchant_private_key: &secp256k1::SecretKey,
629 ) -> Result<SignedRefundAddress, Bip70Error> {
630 let serialized = bincode::serialize(&address)
632 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
633
634 let mut hasher = Sha256::new();
636 hasher.update(&serialized);
637 let hash = hasher.finalize();
638
639 let message = Message::from_digest(hash.into());
641
642 let secp = Secp256k1::new();
643 let signature = secp.sign_ecdsa(&message, merchant_private_key);
644
645 Ok(SignedRefundAddress {
646 address,
647 signature: signature.serialize_compact().to_vec(),
648 })
649 }
650
651 pub fn verify_refund_address(
653 signed_refund: &SignedRefundAddress,
654 merchant_pubkey: &[u8],
655 ) -> Result<(), Bip70Error> {
656 let pubkey = secp256k1::PublicKey::from_slice(merchant_pubkey)
657 .map_err(|e| Bip70Error::SignatureError(format!("Invalid pubkey: {e}")))?;
658
659 let serialized = bincode::serialize(&signed_refund.address)
660 .map_err(|e| Bip70Error::SerializationError(e.to_string()))?;
661
662 let mut hasher = Sha256::new();
663 hasher.update(&serialized);
664 let hash = hasher.finalize();
665
666 let message = Message::from_digest(hash.into());
667
668 let signature = Signature::from_compact(&signed_refund.signature)
669 .map_err(|e| Bip70Error::SignatureError(format!("Invalid signature: {e}")))?;
670
671 let secp = Secp256k1::new();
672 secp.verify_ecdsa(&message, &signature, &pubkey)
673 .map_err(|_| {
674 Bip70Error::SignatureError(
675 "Refund address signature verification failed".to_string(),
676 )
677 })?;
678
679 Ok(())
680 }
681}
682
683#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
687pub struct CovenantProof {
688 pub template_hash: Hash,
690 pub transaction_template: TransactionTemplate,
692 pub payment_request_id: String,
694 pub created_at: u64,
696 pub signature: Option<Vec<u8>>,
698}
699
700#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
702pub struct TransactionTemplate {
703 pub version: u32,
704 pub inputs: Vec<TemplateInput>,
705 pub outputs: Vec<TemplateOutput>,
706 pub lock_time: u32,
707}
708
709#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
711pub struct TemplateInput {
712 pub prevout_hash: Hash,
713 pub prevout_index: u32,
714 pub sequence: u32,
715}
716
717#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
719pub struct TemplateOutput {
720 pub value: u64,
721 pub script_pubkey: Vec<u8>,
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize)]
726pub enum SettlementStatus {
727 ProofCreated,
729 ProofBroadcast,
731 InMempool { tx_hash: Hash },
733 Settled {
735 tx_hash: Hash,
736 block_hash: Hash,
737 confirmation_count: u32,
738 },
739 Failed { reason: String },
741}
742
743#[cfg(test)]
744mod tests {
745 use super::*;
746
747 #[test]
748 fn test_payment_request_creation() {
749 let output = PaymentOutput {
750 script: vec![blvm_consensus::opcodes::OP_1],
751 amount: Some(100000), };
753
754 let request = PaymentRequest::new("main".to_string(), vec![output], 1234567890);
755
756 assert_eq!(request.payment_details.network, "main");
757 assert_eq!(request.payment_details.outputs.len(), 1);
758 assert_eq!(request.payment_details.time, 1234567890);
759 }
760
761 #[test]
762 fn test_payment_request_validation() {
763 let request = PaymentRequest::new(
764 "main".to_string(),
765 vec![PaymentOutput {
766 script: vec![blvm_consensus::opcodes::OP_1],
767 amount: Some(100000),
768 }],
769 1234567890,
770 );
771
772 assert!(request.validate().is_ok());
773 }
774
775 #[test]
776 fn test_payment_request_expired() {
777 let expired_time = 1000;
778 let request = PaymentRequest::new(
779 "main".to_string(),
780 vec![PaymentOutput {
781 script: vec![blvm_consensus::opcodes::OP_1],
782 amount: Some(100000),
783 }],
784 expired_time,
785 )
786 .with_expires(1001);
787
788 let result = request.validate();
790 assert!(result.is_err());
791 }
792
793 #[test]
794 fn test_payment_creation() {
795 let tx = vec![0x01, 0x00, 0x00, 0x00]; let payment = Payment::new(vec![tx.clone()]);
797
798 assert_eq!(payment.transactions.len(), 1);
799 assert_eq!(payment.transactions[0], tx);
800 }
801
802 #[test]
803 fn test_payment_validation() {
804 let payment = Payment::new(vec![vec![0x01, 0x02, 0x03]]);
805 assert!(payment.validate().is_ok());
806
807 let empty_payment = Payment::new(vec![]);
808 assert!(empty_payment.validate().is_err());
809 }
810}