diff --git a/src/invoice/invoice_impl.rs b/src/invoice/invoice_impl.rs index 738bbe9a1..8c6feb73d 100644 --- a/src/invoice/invoice_impl.rs +++ b/src/invoice/invoice_impl.rs @@ -29,6 +29,7 @@ use std::{cmp::Ordering, str::FromStr}; const SIGNATURE_U5_SIZE: usize = 104; +/// The currency of the invoice, can also used to represent the CKB network chain. #[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)] pub enum Currency { Ckb, @@ -153,21 +154,6 @@ pub struct InvoiceData { pub attrs: Vec, } -macro_rules! attr_getter { - ($name:ident, $attr_name:ident, $attr:ty) => { - pub fn $name(&self) -> Option<&$attr> { - self.data - .attrs - .iter() - .filter_map(|attr| match attr { - Attribute::$attr_name(val) => Some(val), - _ => None, - }) - .next() - } - }; -} - /// Represents a syntactically and semantically correct lightning BOLT11 invoice /// /// There are three ways to construct a `CkbInvoice`: @@ -185,6 +171,21 @@ pub struct CkbInvoice { pub data: InvoiceData, } +macro_rules! attr_getter { + ($name:ident, $attr_name:ident, $attr:ty) => { + pub fn $name(&self) -> Option<&$attr> { + self.data + .attrs + .iter() + .filter_map(|attr| match attr { + Attribute::$attr_name(val) => Some(val), + _ => None, + }) + .next() + } + }; +} + impl CkbInvoice { fn hrp_part(&self) -> String { format!( @@ -311,6 +312,17 @@ impl CkbInvoice { }) } + pub fn udt_type_script(&self) -> Option<&Script> { + self.data + .attrs + .iter() + .filter_map(|attr| match attr { + Attribute::UdtScript(script) => Some(&script.0), + _ => None, + }) + .next() + } + attr_getter!(payee_pub_key, PayeePublicKey, PublicKey); attr_getter!(expiry_time, ExpiryTime, Duration); attr_getter!(description, Description, String); @@ -320,7 +332,6 @@ impl CkbInvoice { FinalHtlcMinimumCltvExpiry, u64 ); - attr_getter!(udt_script, UdtScript, CkbScript); attr_getter!(payment_preimage, PaymentPreimage, Hash256); attr_getter!(fallback_address, FallbackAddr, String); } @@ -618,6 +629,10 @@ impl InvoiceBuilder { self } + pub fn udt_type_script(self, script: Script) -> Self { + self.add_attr(Attribute::UdtScript(CkbScript(script))) + } + attr_setter!(payment_preimage, PaymentPreimage, Hash256); attr_setter!(description, Description, String); attr_setter!(payee_pub_key, PayeePublicKey, PublicKey); @@ -1224,4 +1239,23 @@ mod tests { let payment_preimage = invoice.payment_preimage(); assert!(payment_preimage.is_none()); } + + #[test] + fn test_invoice_udt_script() { + let script = Script::default(); + let private_key = gen_rand_private_key(); + let invoice = InvoiceBuilder::new(Currency::Ckb) + .amount(Some(1280)) + .prefix(Some(SiPrefix::Kilo)) + .payment_hash(rand_sha256_hash()) + .udt_type_script(script.clone()) + .build_with_sign(|hash| Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)) + .unwrap(); + assert_eq!(invoice.udt_type_script().unwrap(), &script); + + let res = serde_json::to_string(&invoice); + assert_eq!(res.is_ok(), true); + let decoded = serde_json::from_str::(&res.unwrap()).unwrap(); + assert_eq!(decoded, invoice); + } } diff --git a/src/rpc/invoice.rs b/src/rpc/invoice.rs index 48dfebb26..82b4a83e6 100644 --- a/src/rpc/invoice.rs +++ b/src/rpc/invoice.rs @@ -3,6 +3,7 @@ use std::time::Duration; use crate::ckb::serde_utils::{U128Hex, U64Hex}; use crate::ckb::types::Hash256; use crate::invoice::{CkbInvoice, Currency, InvoiceBuilder, InvoiceStore}; +use ckb_jsonrpc_types::Script; use jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE; use jsonrpsee::{core::async_trait, proc_macros::rpc, types::ErrorObjectOwned}; use serde::{Deserialize, Serialize}; @@ -23,6 +24,7 @@ pub struct NewInvoiceParams { pub final_cltv: Option, #[serde_as(as = "Option")] pub final_htlc_timeout: Option, + pub udt_type_script: Option