Skip to content

Commit

Permalink
add UDT type script for invoice
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyukang committed Jun 11, 2024
1 parent 0fed258 commit 0954d83
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 18 deletions.
66 changes: 50 additions & 16 deletions src/invoice/invoice_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -153,21 +154,6 @@ pub struct InvoiceData {
pub attrs: Vec<Attribute>,
}

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`:
Expand All @@ -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!(
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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::<CkbInvoice>(&res.unwrap()).unwrap();
assert_eq!(decoded, invoice);
}
}
5 changes: 5 additions & 0 deletions src/rpc/invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -23,6 +24,7 @@ pub struct NewInvoiceParams {
pub final_cltv: Option<u64>,
#[serde_as(as = "Option<U64Hex>")]
pub final_htlc_timeout: Option<u64>,
pub udt_type_script: Option<Script>,
}

#[derive(Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -91,6 +93,9 @@ where
if let Some(final_cltv) = params.final_cltv {
invoice_builder = invoice_builder.final_cltv(final_cltv);
};
if let Some(udt_type_script) = &params.udt_type_script {
invoice_builder = invoice_builder.udt_type_script(udt_type_script.clone().into());
};

match invoice_builder.build() {
Ok(invoice) => match self.store.insert_invoice(invoice.clone()) {
Expand Down
14 changes: 12 additions & 2 deletions tests/bruno/e2e/udt/07-node2-gen-invoice.bru
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ body:json {
{
"amount": "0xc8",
"currency": "Ckb",
"description": "test invoice generated by node3",
"description": "test invoice generated by node2",
"expiry": "0xe10",
"final_cltv": "0x28",
"payment_preimage": "{{payment_preimage}}"
"payment_preimage": "{{payment_preimage}}",
"udt_type_script": {
"code_hash": "0xe1e354d6d643ad42724d40967e334984534e0367405c5ae42a9d7d63d77df419",
"hash_type": "data1",
"args": "0x32e555f3ff8e135cece1351a6a2971518392c1e30375c1e006ad0ce8eac07947"
}
}
]
}
Expand All @@ -55,6 +60,11 @@ script:post-response {
// Sleep for sometime to make sure current operation finishes before next request starts.
await new Promise(r => setTimeout(r, 100));
console.log("generated result: ", res.body.result);
// assert `UdtScript` is present in the response data
let udt_script_attr = res.body.result.invoice.data.attrs.find((attr) => attr.UdtScript);
if (udt_script_attr.UdtScript === undefined) {
throw new Error("UdtScript is not present in the response data");
}
bru.setVar("payment_hash", res.body.result.invoice.data.payment_hash);
bru.setVar("payment_amount", res.body.result.invoice.amount);
}

0 comments on commit 0954d83

Please sign in to comment.