diff --git a/.gitignore b/.gitignore index 7b9453f..3b518b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /target /Cargo.lock /.DS_Store +.vscode/ /proto/out/* !/proto/out/.gitkeep diff --git a/bindings/una-js/index.d.ts b/bindings/una-js/index.d.ts index fcb1902..53df225 100644 --- a/bindings/una-js/index.d.ts +++ b/bindings/una-js/index.d.ts @@ -8,6 +8,7 @@ export class Node { constructor(backend: Backend, config: NodeConfig) createInvoice(invoice: CreateInvoiceParams): Promise getInfo(): Promise + getInvoice(payementHash: String): Promise payInvoice(invoice: PayInvoiceParams): Promise } @@ -37,6 +38,22 @@ export interface CreateInvoiceResult { payment_request: string; } +export type InvoiceStatus = "Pending" | "Settled" | "Cancelled" | "Accepted"; + +export interface Invoice { + amount: number; + amount_msat: number; + bolt11: string; + creation_date: number; + expiry: number; + memo: string; + payment_hash: string; + pre_image?: string | null; + settle_date?: number | null; + settled: boolean; + status: InvoiceStatus; +} + export type Network = | ("mainnet" | "testnet" | "regtest") | { diff --git a/bindings/una-js/src/lib.rs b/bindings/una-js/src/lib.rs index 4d0ac69..3d7e866 100644 --- a/bindings/una-js/src/lib.rs +++ b/bindings/una-js/src/lib.rs @@ -101,6 +101,27 @@ impl JsNode { ) } + #[napi( + ts_args_type = "paymentHash: string", + ts_return_type = "Promise" + )] + pub fn get_invoice(&self, env: Env, payment_hash: String) -> Result { + let node = self.0.clone(); + + env.execute_tokio_future( + async move { + let invoice = node + .lock() + .await + .get_invoice(payment_hash) + .await + .or_napi_error()?; + Ok(invoice) + }, + |&mut env, invoice| Ok(env.to_js_value(&invoice)), + ) + } + #[napi( ts_args_type = "invoice: PayInvoiceParams", ts_return_type = "Promise" diff --git a/bindings/una-js/test.mjs b/bindings/una-js/test.mjs index fbf8166..8f9de55 100644 --- a/bindings/una-js/test.mjs +++ b/bindings/una-js/test.mjs @@ -5,20 +5,20 @@ const config = { rest: { url: "https://127.0.0.1:8081", macaroon: - "0201036c6e6402f801030a100249a596de122aa0b6cee0d446f166231201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a66d3da5b13d50b2c506a2191927bce8ef13e8fd192af2c69b5dcefddb97199d", + "0201036c6e6402f801030a1090788030ebddcc36000f194b061613a41201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620b1f79f1a88e156dff7b533a32a23abbe22546a6ef2e81dccd2991a2786007dff", tls_certificate: - "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949434a7a434341637967417749424167495141553567664541653374586471776a6c494b476f6e6a414b42676771686b6a4f50515144416a41784d5238770a485159445651514b45785a73626d5167595856306232646c626d56795958526c5a43426a5a584a304d51347744415944565151444577566862476c6a5a5441650a467730794d6a41344d5455784e544d334e444a61467730794d7a45774d5441784e544d334e444a614d444578487a416442674e5642416f54466d78755a4342680a645852765a3256755a584a686447566b49474e6c636e5178446a414d42674e5642414d544257467361574e6c4d466b77457759484b6f5a497a6a3043415159490a4b6f5a497a6a30444151634451674145796c494245585854544d6f76526f594c515064454c6a38626a7257656744637556564b3044744b4a78774d65773754440a342b6f4c754438334c546b697137446b2b6d6842505a6e782f4f4754474b7a754a4c314465364f4278544342776a414f42674e56485138424166384542414d430a41715177457759445652306c42417777436759494b775942425155484177457744775944565230544151482f42415577417745422f7a416442674e56485134450a4667515563616b6351494e38553048734c735752527544394d304f47306d6b77617759445652305242475177596f4946595778705932574343577876593246730a6147397a644949465957787059325743446e4276624746794c5734784c57467361574e6c67675231626d6c3467677031626d6c346347466a61325630676764690a64575a6a623235756877522f4141414268784141414141414141414141414141414141414141414268775373465141454d416f4743437147534d343942414d430a41306b414d45594349514364767236702f466446464866597871596279594b483635344e6e7372557779344f544648386c31727662514968414f5433546c437a0a77477863642b35416367364e31596472652b76544f2f34525371636c7a5a6532776151520a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a", + "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949434a7a43434163796741774942416749514f66564e7a49356e622b465831757662674844302b7a414b42676771686b6a4f50515144416a41784d5238770a485159445651514b45785a73626d5167595856306232646c626d56795958526c5a43426a5a584a304d51347744415944565151444577566862476c6a5a5441650a467730794d6a41344d4467774e6a4d314d7a6c61467730794d7a45774d444d774e6a4d314d7a6c614d444578487a416442674e5642416f54466d78755a4342680a645852765a3256755a584a686447566b49474e6c636e5178446a414d42674e5642414d544257467361574e6c4d466b77457759484b6f5a497a6a3043415159490a4b6f5a497a6a3044415163445167414578375568773146647543444f7a42456d634f346c374f6a33476b47674e734b75337a36454761782b39713042546655320a4d48336435396b45466a3534517562685739746942797669594d6e736633314f4537733744714f4278544342776a414f42674e56485138424166384542414d430a41715177457759445652306c42417777436759494b775942425155484177457744775944565230544151482f42415577417745422f7a416442674e56485134450a4667515572683771416c497875576e6a56536e4779352f4d4e77563454636f77617759445652305242475177596f4946595778705932574343577876593246730a6147397a644949465957787059325743446e4276624746794c5734304c57467361574e6c67675231626d6c3467677031626d6c346347466a61325630676764690a64575a6a623235756877522f4141414268784141414141414141414141414141414141414141414268775373464141454d416f4743437147534d343942414d430a41306b414d455943495143305536414d4a5a2b2f506c6859567a505736793637746877566b316743525243386d4c416c6e37752b4d514968414d675a6e4944370a7265727147474555386334622f6967697479776a36516737415a6e354c65306f696a6c450a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a", }, }, cln: { grpc: { url: "https://localhost:11002", tls_certificate: - "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d494942636a434341526967417749424167494a414d466c546169526559526a4d416f4743437147534d343942414d434d4259784644415342674e5642414d4d0d0a43324e73626942536232393049454e424d434158445463314d4445774d5441774d4441774d466f59447a51774f5459774d5441784d4441774d444177576a41570d0a4d52517745675944565151444441746a62473467556d3976644342445154425a4d424d4742797147534d34394167454743437147534d343941774548413049410d0a424c4344514c387469663542445051643943715976776361756749752b757274616e554359536c6b4b714b3736562f4d66646b307372464c364c6d6e684b32720d0a61434c494b475841334f4f545038426e5a5a3144547a4b6a5454424c4d426b4741315564455151534d42434341324e73626f494a6247396a5957786f62334e300d0a4d42304741315564446751574242526a68486d527145316c775a56656b53735a374f56456d4a6c65736a415042674e5648524d4241663845425441444151482f0d0a4d416f4743437147534d343942414d43413067414d45554349474b772b784259364f656b334b6c675957693050346459525a57632b67537343616835513554620d0a4a575959416945413538316b475337347335694a58475950514351416d777531524b4577426139432b625552526e4569676b633d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", + "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d4949426354434341526967417749424167494a415065324934484e463673474d416f4743437147534d343942414d434d4259784644415342674e5642414d4d0d0a43324e73626942536232393049454e424d434158445463314d4445774d5441774d4441774d466f59447a51774f5459774d5441784d4441774d444177576a41570d0a4d52517745675944565151444441746a62473467556d3976644342445154425a4d424d4742797147534d34394167454743437147534d343941774548413049410d0a424e30454c4e62366a3477674d693761695455322b79334c444272754a71546d672f533361772f50756d58785a71674c6a746d6a654e746f6f6a44364474654d0d0a4931444a4877354366765777796a6d72496455587346616a5454424c4d426b4741315564455151534d42434341324e73626f494a6247396a5957786f62334e300d0a4d4230474131556444675157424251477178664e67534f32393055445254786a4a7a6a65774364534e44415042674e5648524d4241663845425441444151482f0d0a4d416f4743437147534d343942414d43413063414d4551434941765a4b39647a6344356a6f7a7347666473493346685032337a364754656773384a695a574b530d0a5479597a416941546f7970426f4c77684d33645443764f3679626248626375422f78532f62665458765336774749453774773d3d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", tls_client_certificate: - "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d49494252544342374b41444167454341676b416a707851696b2f6852626b77436759494b6f5a497a6a304541774977466a45554d424947413155454177774c0d0a5932787549464a7662335167513045774942634e4e7a55774d5441784d4441774d444177576867504e4441354e6a41784d4445774d4441774d4442614d426f780d0a4744415742674e5642414d4d44324e736269426e636e426a49454e73615756756444425a4d424d4742797147534d34394167454743437147534d3439417745480d0a413049414247516a7057383170623545486749616878497165424e4d4138762f367070515761354f57366b33646e55484f434f465539686e72755630664d4a490d0a367444487363614a6c64327978666970575277712f2b6d32537a4f6a485441624d426b4741315564455151534d42434341324e73626f494a6247396a5957786f0d0a62334e304d416f4743437147534d343942414d43413067414d4555434951446e703555734f64457335304a6e3839596a5367456572635a4952314e70726831610d0a384e6b657736566d32514967523433303231333450654337617477363046524d3338414974433767672f686c78534c304f577a787833673d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", + "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d494942526a4342374b41444167454341676b4132595a375737573739526777436759494b6f5a497a6a304541774977466a45554d424947413155454177774c0d0a5932787549464a7662335167513045774942634e4e7a55774d5441784d4441774d444177576867504e4441354e6a41784d4445774d4441774d4442614d426f780d0a4744415742674e5642414d4d44324e736269426e636e426a49454e73615756756444425a4d424d4742797147534d34394167454743437147534d3439417745480d0a413049414248454b66516b6763733930516c36522f686e31305331482b676b6169455975646d327a6d647665374e494e51464d7179533879546b674c6a474c780d0a613072376e2b394e5a4351334a5041357a424e42646f6b3941586d6a485441624d426b4741315564455151534d42434341324e73626f494a6247396a5957786f0d0a62334e304d416f4743437147534d343942414d4341306b414d4559434951443462584675435832534f34744d2f4a4258376b32514a49494d3369726c533633550d0a46534475736272437777496841496c656435564854327547302b454135335a7a6677354a70477374563659526a52424e445a6d45783479340d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", tls_client_key: - "2d2d2d2d2d424547494e2050524956415445204b45592d2d2d2d2d0d0a4d494748416745414d424d4742797147534d34394167454743437147534d3439417745484247307761774942415151676c5a43666461766d53776b4939526c6a0d0a427062636e6f737757355351764348474b7346637744767642794b6852414e434141526b493656764e61572b52423443476f63534b6e67545441504c2f2b71610d0a55466d75546c75704e335a31427a676a685650595a36376c64487a43534f725178374847695a58647373583471566b634b762f70746b737a0d0a2d2d2d2d2d454e442050524956415445204b45592d2d2d2d2d0d0a", + "2d2d2d2d2d424547494e2050524956415445204b45592d2d2d2d2d0d0a4d494748416745414d424d4742797147534d34394167454743437147534d343941774548424730776177494241515167756c4e4532566247504a6a4c2b6b322b0d0a6f334249584b533032434657423663356f46363968516270566b796852414e4341415278436e304a49484c5064454a656b66345a39644574522f6f4a476f68470d0a4c6e5a7473356e6233757a53445542544b736b764d6b3549433478693857744b2b352f765457516b4e7954774f6377545158614a505146350d0a2d2d2d2d2d454e442050524956415445204b45592d2d2d2d2d0d0a", }, }, eclair: { @@ -40,23 +40,23 @@ async function test_node(backend, config) { node .getInfo() - .then((info) => console.log(info)) + .then((info) => console.log('getInfo(): ', info)) .catch((err) => console.log(err.message, err.code)); - node - .createInvoice(invoice) - .then((invoice) => console.log(invoice)) - .catch((err) => console.log(err.message, err.code)); + const createInvoiceResult = await node.createInvoice(invoice).catch((err) => console.log(err.message, err.code)); + console.log('createInvoice(): ', createInvoiceResult); + const getInvoiceResult = await node.getInvoice(createInvoiceResult.payment_hash).catch((err) => console.log(err.message, err.code)); + console.log('getInvoice(): ', getInvoiceResult); node .payInvoice({ payment_request: - "lnbcrt10u1p30ag67p5v45p0xljwcktszppfj8a3wcg460xrwwhpt0xcghx36xcsr3dkz7spp5nctfmzx6k5dyv693t52y0fs95zrk33f37mue5f3geu4wt9cwgltsdpz2phkcctjypykuan0d93k2grxdaezqcn0vgxqyjw5qcqp2rzjq25z6j80gkd8vyr5nptma4lnmhjvyq66eretzvy5a4gty72g8xpejqqqdsqqqqgqqyqqqqlgqqqqqqgq9q9qyysgqd4e22wy6ejggnpg8kfkuxf6vkgxejfe4283zjgsfxmd8w7dsvk7k43lsgakwzyanzfu372w8ke8tsuyzmp28kng4e6xyz8eyh99ncagpa8myt0", + "lnbcrt500u1p30lxcjpp5nqerez0kcz78dakgd5kystfyf3nndzqxcuj3dc52vf42uvhlkemqdqqcqzpgxqyz5vqsp5r6ahdt5em43pt8578z4xvkzm9ah70x97ey0f768xx8r9msvlza6s9qyyssqfrt207yknpnvshqxtuku03r3rt99hvswpk7px0qy95yrym7md2mnfttxyhmxkjdm7agrqggcdf4at6ld9lkwx4q664y4hrrnd5p8argpx5yhdy", }) - .then((result) => console.log(result)) + .then((result) => console.log('payInvoice(): ', result)) .catch((err) => console.log(err.message, err.code)); } // test_node("LndRest", config.lnd.rest); -test_node("EclairRest", config.eclair.rest); -// test_node("ClnGrpc", config.cln.grpc); +// test_node("EclairRest", config.eclair.rest); +test_node("ClnGrpc", config.cln.grpc); diff --git a/bindings/una-python/src/lib.rs b/bindings/una-python/src/lib.rs index ee134f0..95cafc3 100644 --- a/bindings/una-python/src/lib.rs +++ b/bindings/una-python/src/lib.rs @@ -11,8 +11,8 @@ use una_core::{ }, node::{Node, NodeMethods}, types::{ - Backend, CreateInvoiceParams, CreateInvoiceResult, NodeConfig, NodeInfo, PayInvoiceParams, - PayInvoiceResult, + Backend, CreateInvoiceParams, CreateInvoiceResult, Invoice, NodeConfig, NodeInfo, + PayInvoiceParams, PayInvoiceResult, }, }; @@ -105,6 +105,21 @@ impl PyNode { Ok(result) }) } + + pub fn get_invoice<'p>(&self, py: Python<'p>, payment_hash: String) -> PyResult<&'p PyAny> { + let node = self.0.clone(); + + pyo3_asyncio::tokio::future_into_py(py, async move { + let result = node + .lock() + .await + .get_invoice(payment_hash) + .await + .or_py_error()?; + let result = Python::with_gil(|py| pythonize::(py, &result).or_py_error())?; + Ok(result) + }) + } } /// A Python module implemented in Rust. diff --git a/bindings/una-python/test.py b/bindings/una-python/test.py index 867eb84..812b4f6 100644 --- a/bindings/una-python/test.py +++ b/bindings/una-python/test.py @@ -9,30 +9,34 @@ async def lnd_rest(): config_lnd_rest = dict({ "url": "https://127.0.0.1:8081", - "macaroon": "0201036c6e6402f801030a100249a596de122aa0b6cee0d446f166231201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620a66d3da5b13d50b2c506a2191927bce8ef13e8fd192af2c69b5dcefddb97199d", - "tls_certificate": "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949434a7a434341637967417749424167495141553567664541653374586471776a6c494b476f6e6a414b42676771686b6a4f50515144416a41784d5238770a485159445651514b45785a73626d5167595856306232646c626d56795958526c5a43426a5a584a304d51347744415944565151444577566862476c6a5a5441650a467730794d6a41344d5455784e544d334e444a61467730794d7a45774d5441784e544d334e444a614d444578487a416442674e5642416f54466d78755a4342680a645852765a3256755a584a686447566b49474e6c636e5178446a414d42674e5642414d544257467361574e6c4d466b77457759484b6f5a497a6a3043415159490a4b6f5a497a6a30444151634451674145796c494245585854544d6f76526f594c515064454c6a38626a7257656744637556564b3044744b4a78774d65773754440a342b6f4c754438334c546b697137446b2b6d6842505a6e782f4f4754474b7a754a4c314465364f4278544342776a414f42674e56485138424166384542414d430a41715177457759445652306c42417777436759494b775942425155484177457744775944565230544151482f42415577417745422f7a416442674e56485134450a4667515563616b6351494e38553048734c735752527544394d304f47306d6b77617759445652305242475177596f4946595778705932574343577876593246730a6147397a644949465957787059325743446e4276624746794c5734784c57467361574e6c67675231626d6c3467677031626d6c346347466a61325630676764690a64575a6a623235756877522f4141414268784141414141414141414141414141414141414141414268775373465141454d416f4743437147534d343942414d430a41306b414d45594349514364767236702f466446464866597871596279594b483635344e6e7372557779344f544648386c31727662514968414f5433546c437a0a77477863642b35416367364e31596472652b76544f2f34525371636c7a5a6532776151520a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a" + "macaroon": "0201036c6e6402f801030a1090788030ebddcc36000f194b061613a41201301a160a0761646472657373120472656164120577726974651a130a04696e666f120472656164120577726974651a170a08696e766f69636573120472656164120577726974651a210a086d616361726f6f6e120867656e6572617465120472656164120577726974651a160a076d657373616765120472656164120577726974651a170a086f6666636861696e120472656164120577726974651a160a076f6e636861696e120472656164120577726974651a140a057065657273120472656164120577726974651a180a067369676e6572120867656e657261746512047265616400000620b1f79f1a88e156dff7b533a32a23abbe22546a6ef2e81dccd2991a2786007dff", + "tls_certificate": "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0a4d4949434a7a43434163796741774942416749514f66564e7a49356e622b465831757662674844302b7a414b42676771686b6a4f50515144416a41784d5238770a485159445651514b45785a73626d5167595856306232646c626d56795958526c5a43426a5a584a304d51347744415944565151444577566862476c6a5a5441650a467730794d6a41344d4467774e6a4d314d7a6c61467730794d7a45774d444d774e6a4d314d7a6c614d444578487a416442674e5642416f54466d78755a4342680a645852765a3256755a584a686447566b49474e6c636e5178446a414d42674e5642414d544257467361574e6c4d466b77457759484b6f5a497a6a3043415159490a4b6f5a497a6a3044415163445167414578375568773146647543444f7a42456d634f346c374f6a33476b47674e734b75337a36454761782b39713042546655320a4d48336435396b45466a3534517562685739746942797669594d6e736633314f4537733744714f4278544342776a414f42674e56485138424166384542414d430a41715177457759445652306c42417777436759494b775942425155484177457744775944565230544151482f42415577417745422f7a416442674e56485134450a4667515572683771416c497875576e6a56536e4779352f4d4e77563454636f77617759445652305242475177596f4946595778705932574343577876593246730a6147397a644949465957787059325743446e4276624746794c5734304c57467361574e6c67675231626d6c3467677031626d6c346347466a61325630676764690a64575a6a623235756877522f4141414268784141414141414141414141414141414141414141414268775373464141454d416f4743437147534d343942414d430a41306b414d455943495143305536414d4a5a2b2f506c6859567a505736793637746877566b316743525243386d4c416c6e37752b4d514968414d675a6e4944370a7265727147474555386334622f6967697479776a36516737415a6e354c65306f696a6c450a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0a" }) lnd_rest = una.Node("LndRest", config_lnd_rest) print(await lnd_rest.get_info()) - print(await lnd_rest.create_invoice(invoice)) + newInvoice = await lnd_rest.create_invoice(invoice) + print(newInvoice) + print(await lnd_rest.get_invoice(newInvoice["payment_hash"])) print(await lnd_rest.pay_invoice(dict({ - "payment_request": "lnbcrt10u1p306998pp53jzmkeummuu0u6rfxpcgx7rk5adturte8mppr64032nek3jmjtvqdq4w3jhxapqvf5kuerfdenhxcqzpgxqrrsssp53nhngg8858l2ch63ks3yc2uetzf4gnctp9xccqxuchztxmahd2as9qyyssqzl6m9rwgwp0r5a6de7fj98k42sn7vvf30n6k2ymcq7wvmk4689ls7zewqq9x5maqa60tshdmhu3gx3dd243vh9h9xralrfrjpfwfn3gq6xml7k" + "payment_request": "lnbcrt500u1p30l86jsp5t8da6ptufsqmaeq82ggj459t0xaagr2zavd3rfjgq67ld2vxq70qpp59an0dyn45jp87ae8jkqxxmt5v3m2nlfvc274l097tehzeh5y06nsdpz2phkcctjypykuan0d93k2grxdaezqcn0vgxqyjw5qcqp2rzjqf6tlmcyzxx6j6td5scpr45cwjd850fyu5y9rqk3vfdygjsv8xxezqqqwgqqqqgqqqqqqqlgqqqqqqgq9q9qyysgqsclv524vlt3mumew6wsw25xszlr6zscn29w0g5ryhg67xvl89jsj9u4ylvqu65p7up07vuuee20hcfg2v5qfqzqk9f8vpwktuct6fwcq78fxyn" }))) async def cln_grpc(): config_cln_grpc = dict({ "url": "https://localhost:11002", - "tls_certificate": "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d494942636a434341526967417749424167494a414d466c546169526559526a4d416f4743437147534d343942414d434d4259784644415342674e5642414d4d0d0a43324e73626942536232393049454e424d434158445463314d4445774d5441774d4441774d466f59447a51774f5459774d5441784d4441774d444177576a41570d0a4d52517745675944565151444441746a62473467556d3976644342445154425a4d424d4742797147534d34394167454743437147534d343941774548413049410d0a424c4344514c387469663542445051643943715976776361756749752b757274616e554359536c6b4b714b3736562f4d66646b307372464c364c6d6e684b32720d0a61434c494b475841334f4f545038426e5a5a3144547a4b6a5454424c4d426b4741315564455151534d42434341324e73626f494a6247396a5957786f62334e300d0a4d42304741315564446751574242526a68486d527145316c775a56656b53735a374f56456d4a6c65736a415042674e5648524d4241663845425441444151482f0d0a4d416f4743437147534d343942414d43413067414d45554349474b772b784259364f656b334b6c675957693050346459525a57632b67537343616835513554620d0a4a575959416945413538316b475337347335694a58475950514351416d777531524b4577426139432b625552526e4569676b633d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", - "tls_client_certificate": "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d49494252544342374b41444167454341676b416a707851696b2f6852626b77436759494b6f5a497a6a304541774977466a45554d424947413155454177774c0d0a5932787549464a7662335167513045774942634e4e7a55774d5441784d4441774d444177576867504e4441354e6a41784d4445774d4441774d4442614d426f780d0a4744415742674e5642414d4d44324e736269426e636e426a49454e73615756756444425a4d424d4742797147534d34394167454743437147534d3439417745480d0a413049414247516a7057383170623545486749616878497165424e4d4138762f367070515761354f57366b33646e55484f434f465539686e72755630664d4a490d0a367444487363614a6c64327978666970575277712f2b6d32537a4f6a485441624d426b4741315564455151534d42434341324e73626f494a6247396a5957786f0d0a62334e304d416f4743437147534d343942414d43413067414d4555434951446e703555734f64457335304a6e3839596a5367456572635a4952314e70726831610d0a384e6b657736566d32514967523433303231333450654337617477363046524d3338414974433767672f686c78534c304f577a787833673d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", - "tls_client_key": "2d2d2d2d2d424547494e2050524956415445204b45592d2d2d2d2d0d0a4d494748416745414d424d4742797147534d34394167454743437147534d3439417745484247307761774942415151676c5a43666461766d53776b4939526c6a0d0a427062636e6f737757355351764348474b7346637744767642794b6852414e434141526b493656764e61572b52423443476f63534b6e67545441504c2f2b71610d0a55466d75546c75704e335a31427a676a685650595a36376c64487a43534f725178374847695a58647373583471566b634b762f70746b737a0d0a2d2d2d2d2d454e442050524956415445204b45592d2d2d2d2d0d0a", + "tls_certificate": "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d4949426354434341526967417749424167494a415065324934484e463673474d416f4743437147534d343942414d434d4259784644415342674e5642414d4d0d0a43324e73626942536232393049454e424d434158445463314d4445774d5441774d4441774d466f59447a51774f5459774d5441784d4441774d444177576a41570d0a4d52517745675944565151444441746a62473467556d3976644342445154425a4d424d4742797147534d34394167454743437147534d343941774548413049410d0a424e30454c4e62366a3477674d693761695455322b79334c444272754a71546d672f533361772f50756d58785a71674c6a746d6a654e746f6f6a44364474654d0d0a4931444a4877354366765777796a6d72496455587346616a5454424c4d426b4741315564455151534d42434341324e73626f494a6247396a5957786f62334e300d0a4d4230474131556444675157424251477178664e67534f32393055445254786a4a7a6a65774364534e44415042674e5648524d4241663845425441444151482f0d0a4d416f4743437147534d343942414d43413063414d4551434941765a4b39647a6344356a6f7a7347666473493346685032337a364754656773384a695a574b530d0a5479597a416941546f7970426f4c77684d33645443764f3679626248626375422f78532f62665458765336774749453774773d3d0d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", + "tls_client_certificate": "2d2d2d2d2d424547494e2043455254494649434154452d2d2d2d2d0d0a4d494942526a4342374b41444167454341676b4132595a375737573739526777436759494b6f5a497a6a304541774977466a45554d424947413155454177774c0d0a5932787549464a7662335167513045774942634e4e7a55774d5441784d4441774d444177576867504e4441354e6a41784d4445774d4441774d4442614d426f780d0a4744415742674e5642414d4d44324e736269426e636e426a49454e73615756756444425a4d424d4742797147534d34394167454743437147534d3439417745480d0a413049414248454b66516b6763733930516c36522f686e31305331482b676b6169455975646d327a6d647665374e494e51464d7179533879546b674c6a474c780d0a613072376e2b394e5a4351334a5041357a424e42646f6b3941586d6a485441624d426b4741315564455151534d42434341324e73626f494a6247396a5957786f0d0a62334e304d416f4743437147534d343942414d4341306b414d4559434951443462584675435832534f34744d2f4a4258376b32514a49494d3369726c533633550d0a46534475736272437777496841496c656435564854327547302b454135335a7a6677354a70477374563659526a52424e445a6d45783479340d0a2d2d2d2d2d454e442043455254494649434154452d2d2d2d2d0d0a", + "tls_client_key": "2d2d2d2d2d424547494e2050524956415445204b45592d2d2d2d2d0d0a4d494748416745414d424d4742797147534d34394167454743437147534d343941774548424730776177494241515167756c4e4532566247504a6a4c2b6b322b0d0a6f334249584b533032434657423663356f46363968516270566b796852414e4341415278436e304a49484c5064454a656b66345a39644574522f6f4a476f68470d0a4c6e5a7473356e6233757a53445542544b736b764d6b3549433478693857744b2b352f765457516b4e7954774f6377545158614a505146350d0a2d2d2d2d2d454e442050524956415445204b45592d2d2d2d2d0d0a", }) cln_grpc = una.Node("ClnGrpc", config_cln_grpc) print(await cln_grpc.get_info()) - print(await cln_grpc.create_invoice(invoice)) + newInvoice = await cln_grpc.create_invoice(invoice) + print(newInvoice) + print(await cln_grpc.get_invoice(newInvoice["payment_hash"])) print(await cln_grpc.pay_invoice(dict({ - "payment_request": "lnbcrt10u1p306998pp53jzmkeummuu0u6rfxpcgx7rk5adturte8mppr64032nek3jmjtvqdq4w3jhxapqvf5kuerfdenhxcqzpgxqrrsssp53nhngg8858l2ch63ks3yc2uetzf4gnctp9xccqxuchztxmahd2as9qyyssqzl6m9rwgwp0r5a6de7fj98k42sn7vvf30n6k2ymcq7wvmk4689ls7zewqq9x5maqa60tshdmhu3gx3dd243vh9h9xralrfrjpfwfn3gq6xml7k" + "payment_request": "lnbcrt500u1p30l8sqpp5w7lv678lvu6y79607slk7ucz9swnsr8hl0946nnpy6j5ey27xazsdqqcqzpgxqyz5vqsp5mtnhgzrvduh2dw6kvnrpa8asx2rdz6wqum9exla2nwfxmuqw2y6q9qyyssqtak8660yd9ne2u52tctnpsgyj97gsqt572sg6lp76dwanv0a43w3y9gavap4kkn4uzcedmjstachapkhuyex9ascy08wvx69v6xkrysq49fg6k" }))) async def eclair_rest(): @@ -44,11 +48,13 @@ async def eclair_rest(): eclair_rest = una.Node("EclairRest", config_eclair_rest) print(await eclair_rest.get_info()) - print(await eclair_rest.create_invoice(invoice)) + newInvoice = await eclair_rest.create_invoice(invoice) + print(newInvoice) + print(await eclair_rest.get_invoice(newInvoice["payment_hash"])) print(await eclair_rest.pay_invoice(dict({ - "payment_request": "lnbcrt10u1p30afdnsp5y05vz3g860fn8fy6fy2u9pr49ttnl6qq85v3mkmzz58cyqxmdpvspp52vy739gahycksqafupk4fw7mu0xjyf2l2e5exr64ycmjedzs3a5sdq4w3jhxapqvf5kuerfdenhxxqyjw5qcqp2rzjq25z6j80gkd8vyr5nptma4lnmhjvyq66eretzvy5a4gty72g8xpejqqqdsqqqqgqqyqqqqlgqqqqqqgq9q9qyysgqp0kpcx20yq5hftwguxfp0aka297g7kqplfl9ntc3rznkwnm9kf94ssq3qygjt2v0jrm95w2s590gc087vr6k3r9fvg9ey58et0dlcdcp978dh6" + "payment_request": "lnbcrt500u1p30l8ucsp5g2yz97eklymf2j5l6s0ukhn00xnkjh77ycjrmya0ve0k7yvfxu7spp5l33rnrfhrmlhe84theeu6kr5mjnntncewnzvdgctqfwnt9v4ky8qdpz2phkcctjypykuan0d93k2grxdaezqcn0vgxqyjw5qcqp2rzjqf6tlmcyzxx6j6td5scpr45cwjd850fyu5y9rqk3vfdygjsv8xxezqqqwgqqqqgqqqqqqqlgqqqqqqgq9q9qyysgqcv0etwph6zxa68rgezshmgy42z2f4e6xzdvjy64ayyeuy4e25u59gxtqsrftj9fq9k5vpcmurtgdq3x3d2chezl0g6cjg8v4g5th46sp23tz4q" }))) # asyncio.run(lnd_rest()) -asyncio.run(cln_grpc()) -# asyncio.run(eclair_rest()) \ No newline at end of file +# asyncio.run(cln_grpc()) +asyncio.run(eclair_rest()) \ No newline at end of file diff --git a/core/Cargo.toml b/core/Cargo.toml index e97e82b..2edd8b8 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,4 +17,5 @@ tonic = { version = "0.8.0", features = ["tls"] } prost = "0.11" cuid = "1.2.0" http = "0.2.8" +lightning-invoice = "0.18.0" regex = "1.6.0" diff --git a/core/src/backends/cln/grpc/node.rs b/core/src/backends/cln/grpc/node.rs index db3ee94..2d2d80f 100644 --- a/core/src/backends/cln/grpc/node.rs +++ b/core/src/backends/cln/grpc/node.rs @@ -3,11 +3,13 @@ use tonic::transport::{Certificate, Channel, ClientTlsConfig, Endpoint, Identity use crate::error::Error; use crate::node::NodeMethods; use crate::types::{ - CreateInvoiceParams, CreateInvoiceResult, NodeInfo, PayInvoiceParams, PayInvoiceResult, + CreateInvoiceParams, CreateInvoiceResult, Invoice, NodeInfo, PayInvoiceParams, PayInvoiceResult, }; use super::config::ClnGrpcConfig; -use super::pb::{node_client::NodeClient, GetinfoRequest, InvoiceRequest, PayRequest}; +use super::pb::{ + node_client::NodeClient, GetinfoRequest, InvoiceRequest, ListinvoicesRequest, PayRequest, +}; pub struct ClnGrpc { endpoint: Endpoint, @@ -68,6 +70,23 @@ impl NodeMethods for ClnGrpc { Ok(result) } + async fn get_invoice(&self, payment_hash: String) -> Result { + let mut client = self.get_client().await?; + + let payment_hash_hex = hex::decode(payment_hash) + .map_err(|_| Error::ApiError(String::from("Invalid payment_hash")))?; + + let request = ListinvoicesRequest { + payment_hash: Some(payment_hash_hex), + label: None, + invstring: None, + offer_id: None, + }; + let response = client.list_invoices(request).await?.into_inner(); + + Ok(response.try_into()?) + } + async fn pay_invoice(&self, invoice: PayInvoiceParams) -> Result { let mut client = self.get_client().await?; diff --git a/core/src/backends/cln/grpc/pb.rs b/core/src/backends/cln/grpc/pb.rs index 907803d..cfda456 100644 --- a/core/src/backends/cln/grpc/pb.rs +++ b/core/src/backends/cln/grpc/pb.rs @@ -1,6 +1,12 @@ #![allow(clippy::from_over_into)] -use crate::{types::*, utils}; +use std::time::UNIX_EPOCH; + +use crate::{ + error::Error, + types::*, + utils::{self, msat_to_sat}, +}; use cuid; include!(concat!(env!("PROTOBUFS_DIR"), "/cln.rs")); @@ -67,6 +73,66 @@ impl Into for GetinfoResponse { } } +impl TryInto for ListinvoicesResponse { + type Error = Error; + + fn try_into(self) -> Result { + let invoice: &ListinvoicesInvoices = self.invoices.get(0).expect("No invoice found"); + + let bolt11 = match &invoice.bolt11 { + Some(bolt11) => bolt11.as_ref(), + None => return Err(Error::ApiError(String::from("bolt11 missing"))), + }; + + let decoded_invoice = str::parse::(bolt11) + .expect("bolt11 is not a valid invoice"); + + let mut settle_date: Option = None; + let settled = match invoice.status { + 1 => match invoice.paid_at { + Some(e) => { + settle_date = Some(e); + true + } + None => true, + }, + _ => false, + }; + + let status = match invoice.status { + 0 => crate::types::InvoiceStatus::Pending, + 1 => crate::types::InvoiceStatus::Settled, + 2 => crate::types::InvoiceStatus::Cancelled, + _ => crate::types::InvoiceStatus::Accepted, + }; + + let amount_msat = &decoded_invoice + .amount_milli_satoshis() + .ok_or_else(|| Error::ApiError(String::from("amount_milli_satoshis missing")))?; + + Ok(Invoice { + bolt11: String::from(bolt11), + memo: match &invoice.description { + Some(description) => String::from(description), + None => return Err(Error::ApiError(String::from("description missing"))), + }, + amount: msat_to_sat(*amount_msat), + amount_msat: *amount_msat, + pre_image: invoice.payment_preimage.as_ref().map(hex::encode), + payment_hash: decoded_invoice.payment_hash().to_string(), + settled, + settle_date, + creation_date: decoded_invoice + .timestamp() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + expiry: decoded_invoice.expiry_time().as_secs(), + status, + }) + } +} + impl From for PayRequest { fn from(params: PayInvoiceParams) -> Self { let amount_msat = diff --git a/core/src/backends/eclair/rest/node.rs b/core/src/backends/eclair/rest/node.rs index 3782c6b..48f0fcd 100644 --- a/core/src/backends/eclair/rest/node.rs +++ b/core/src/backends/eclair/rest/node.rs @@ -1,13 +1,15 @@ +use std::collections::HashMap; + use crate::error::Error; use crate::node::NodeMethods; use crate::types::{ - CreateInvoiceParams, CreateInvoiceResult, NodeInfo, PayInvoiceParams, PayInvoiceResult, + CreateInvoiceParams, CreateInvoiceResult, Invoice, NodeInfo, PayInvoiceParams, PayInvoiceResult, }; use super::config::EclairRestConfig; use super::types::{ ApiError, ChannelState, CreateInvoiceRequest, CreateInvoiceResponse, GetChannelsResponse, - GetInfoResponse, PayInvoiceRequest, PayInvoiceResponse, + GetInfoResponse, InvoiceResponse, PayInvoiceRequest, PayInvoiceResponse, }; pub struct EclairRest { @@ -119,4 +121,19 @@ impl NodeMethods for EclairRest { Ok(data.try_into()?) } + + async fn get_invoice(&self, payment_hash: String) -> Result { + let url = format!("{}/getreceivedinfo", self.config.url); + + let mut params = HashMap::new(); + params.insert("paymentHash", &payment_hash); + + let mut response = self.client.post(&url).form(¶ms).send().await?; + + response = Self::on_response(response).await?; + + let data: InvoiceResponse = response.json().await?; + + Ok(data.into()) + } } diff --git a/core/src/backends/eclair/rest/types.rs b/core/src/backends/eclair/rest/types.rs index 57f12ab..25a4f72 100644 --- a/core/src/backends/eclair/rest/types.rs +++ b/core/src/backends/eclair/rest/types.rs @@ -1,10 +1,10 @@ #![allow(clippy::from_over_into)] +use crate::{types::*, utils}; use serde::{Deserialize, Serialize}; use serde_json::Value; use crate::error::Error; -use crate::{types::*, utils}; #[derive(Debug, Deserialize)] pub struct ApiError { @@ -84,6 +84,101 @@ pub enum ChannelState { Pending, } +#[derive(Debug, Deserialize)] +pub struct Chain { + pub chain: String, + pub network: String, +} + +#[derive(Debug, Deserialize)] +pub struct Feature { + pub name: String, + pub is_required: bool, + pub is_known: bool, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InvoiceResponse { + pub payment_request: PaymentRequestResponse, + pub payment_preimage: Option, + pub status: InvoiceStatusResponse, + pub created_at: InvoiceDateResponse, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct PaymentRequestResponse { + pub prefix: String, + pub timestamp: i64, + pub node_id: String, + pub serialized: String, + pub description: String, + pub payment_hash: String, + pub payment_metadata: String, + pub expiry: u64, + pub min_final_cltv_expiry: u32, + pub amount: u64, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "lowercase")] +pub enum InvoiceStatusTypeResponse { + Received, + Pending, + Expired, +} + +#[derive(Debug, Deserialize)] +pub struct InvoiceDateResponse { + pub unix: u64, +} + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct InvoiceStatusResponse { + #[serde(rename = "type")] + pub type_field: InvoiceStatusTypeResponse, + pub amount: Option, + pub received_at: Option, +} + +impl Into for InvoiceResponse { + fn into(self) -> Invoice { + let mut settle_date: Option = None; + let settled = match self.status.type_field { + InvoiceStatusTypeResponse::Received => match self.status.received_at { + Some(e) => { + settle_date = Some(e.unix); + true + } + None => true, + }, + _ => false, + }; + + let status = match self.status.type_field { + InvoiceStatusTypeResponse::Received => crate::types::InvoiceStatus::Settled, + InvoiceStatusTypeResponse::Pending => crate::types::InvoiceStatus::Pending, + InvoiceStatusTypeResponse::Expired => crate::types::InvoiceStatus::Cancelled, + }; + + Invoice { + bolt11: self.payment_request.serialized, + memo: self.payment_request.description, + amount: utils::msat_to_sat(self.payment_request.amount), + amount_msat: self.payment_request.amount, + pre_image: self.payment_preimage, + payment_hash: self.payment_request.payment_hash, + settled, + settle_date, + creation_date: self.created_at.unix, + expiry: self.payment_request.expiry, + status, + } + } +} + impl Into for GetInfoResponse { fn into(self) -> NodeInfo { let network = match self.network.as_ref() { diff --git a/core/src/backends/lnd/rest/node.rs b/core/src/backends/lnd/rest/node.rs index d972bad..e9216f1 100644 --- a/core/src/backends/lnd/rest/node.rs +++ b/core/src/backends/lnd/rest/node.rs @@ -1,13 +1,13 @@ use crate::error::Error; use crate::node::NodeMethods; use crate::types::{ - CreateInvoiceParams, CreateInvoiceResult, NodeInfo, PayInvoiceParams, PayInvoiceResult, + CreateInvoiceParams, CreateInvoiceResult, Invoice, NodeInfo, PayInvoiceParams, PayInvoiceResult, }; use super::config::LndRestConfig; use super::types::{ - ApiError, CreateInvoiceRequest, CreateInvoiceResponse, GetInfoResponse, SendPaymentSyncRequest, - SendPaymentSyncResponse, + ApiError, CreateInvoiceRequest, CreateInvoiceResponse, GetInfoResponse, InvoiceResponse, + SendPaymentSyncRequest, SendPaymentSyncResponse, }; pub struct LndRest { @@ -96,4 +96,16 @@ impl NodeMethods for LndRest { Ok(data.try_into()?) } + + async fn get_invoice(&self, payment_hash: String) -> Result { + let url = format!("{}/v1/invoice/{}", self.config.url, payment_hash); + + let mut response = self.client.get(&url).send().await?; + + response = Self::on_response(response).await?; + + let data: InvoiceResponse = response.json().await?; + + Ok(data.try_into()?) + } } diff --git a/core/src/backends/lnd/rest/types.rs b/core/src/backends/lnd/rest/types.rs index 7b6724e..4f626be 100644 --- a/core/src/backends/lnd/rest/types.rs +++ b/core/src/backends/lnd/rest/types.rs @@ -1,12 +1,12 @@ #![allow(clippy::from_over_into)] -use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use crate::error::Error; use crate::{types::*, utils}; pub type Base64String = String; +use crate::error::Error; +use serde::{Deserialize, Serialize}; #[derive(Debug, Deserialize)] pub struct ApiError { @@ -132,6 +132,66 @@ impl Into for GetInfoResponse { } } +#[derive(Debug, Deserialize)] +pub struct InvoiceResponse { + memo: String, + r_preimage: String, + r_hash: String, + value: String, + value_msat: String, + settled: bool, + creation_date: String, + settle_date: String, + payment_request: String, + expiry: String, + state: InvoiceStateResponse, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "UPPERCASE")] +pub enum InvoiceStateResponse { + Open, + Settled, + Cancelled, + Accepted, +} + +impl TryInto for InvoiceResponse { + type Error = Error; + + fn try_into(self) -> Result { + let mut settle_date: Option = None; + if self.settled { + settle_date = Some( + utils::parse_number(&self.settle_date).expect("settle_date should be a number"), + ); + } + + let status = match self.state { + InvoiceStateResponse::Open => crate::types::InvoiceStatus::Pending, + InvoiceStateResponse::Settled => crate::types::InvoiceStatus::Settled, + InvoiceStateResponse::Cancelled => crate::types::InvoiceStatus::Cancelled, + InvoiceStateResponse::Accepted => crate::types::InvoiceStatus::Accepted, + }; + + let invoice = Invoice { + bolt11: self.payment_request, + memo: self.memo, + amount: utils::parse_number(&self.value)?, + amount_msat: utils::parse_number(&self.value_msat)?, + pre_image: Some(utils::b64_to_hex(&self.r_preimage)?), + payment_hash: utils::b64_to_hex(&self.r_hash)?, + settled: self.settled, + settle_date, + creation_date: utils::parse_number(&self.creation_date)?, + expiry: utils::parse_number(&self.expiry)?, + status, + }; + + Ok(invoice) + } +} + #[derive(Debug, Serialize)] pub struct FeeLimit { pub fixed: Option, diff --git a/core/src/error.rs b/core/src/error.rs index e85b0ac..a707a31 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -33,6 +33,7 @@ pub enum Error { ApiError(String), UnknownError(String), ConversionError(String), + ParseNumberError(String), } impl Display for Error { @@ -47,6 +48,7 @@ impl Display for Error { Error::ApiError(err) => err.clone(), Error::ConversionError(err) => err.clone(), Error::UnknownError(err) => err.clone(), + Error::ParseNumberError(err) => err.clone(), }; write!(f, "{}", str) diff --git a/core/src/node.rs b/core/src/node.rs index fc5dab3..1619327 100644 --- a/core/src/node.rs +++ b/core/src/node.rs @@ -3,8 +3,8 @@ use crate::backends::eclair::rest::node::EclairRest; use crate::backends::lnd::rest::node::LndRest; use crate::error::Error; use crate::types::{ - Backend, CreateInvoiceParams, CreateInvoiceResult, NodeConfig, NodeInfo, PayInvoiceParams, - PayInvoiceResult, + Backend, CreateInvoiceParams, CreateInvoiceResult, Invoice, NodeConfig, NodeInfo, + PayInvoiceParams, PayInvoiceResult, }; #[async_trait::async_trait] @@ -15,6 +15,7 @@ pub trait NodeMethods { ) -> Result; async fn get_info(&self) -> Result; async fn pay_invoice(&self, invoice: PayInvoiceParams) -> Result; + async fn get_invoice(&self, payment_hash: String) -> Result; } pub struct Node { @@ -67,4 +68,8 @@ impl NodeMethods for Node { async fn pay_invoice(&self, invoice: PayInvoiceParams) -> Result { self.node.pay_invoice(invoice).await } + + async fn get_invoice(&self, payment_hash: String) -> Result { + self.node.get_invoice(payment_hash).await + } } diff --git a/core/src/types.rs b/core/src/types.rs index 49d0d86..a3042a7 100644 --- a/core/src/types.rs +++ b/core/src/types.rs @@ -87,9 +87,9 @@ pub struct Invoice { pub pre_image: Option, pub payment_hash: String, pub settled: bool, - pub settle_date: Option, - pub creation_date: i64, - pub expiry: i32, + pub settle_date: Option, + pub creation_date: u64, + pub expiry: u64, pub status: InvoiceStatus, } diff --git a/core/src/utils.rs b/core/src/utils.rs index 4b67c9c..4d04bf8 100644 --- a/core/src/utils.rs +++ b/core/src/utils.rs @@ -1,4 +1,7 @@ -use std::ops::{Div, Mul}; +use std::{ + ops::{Div, Mul}, + str::FromStr, +}; use crate::error::Error; @@ -42,3 +45,9 @@ pub fn b64_to_hex(b64: &str) -> Result { let bytes = base64::decode(b64)?; Ok(hex::encode(&bytes)) } + +pub fn parse_number(text: &str) -> Result { + text.trim() + .parse::() + .map_err(|_| Error::ParseNumberError(String::from("Could not parse number"))) +} diff --git a/schemas/src/main.rs b/schemas/src/main.rs index 2e04039..04284a8 100644 --- a/schemas/src/main.rs +++ b/schemas/src/main.rs @@ -2,8 +2,8 @@ use schemars::{schema::RootSchema, schema_for}; use std::env; use una_core::types::{ - Backend, ChannelStats, CreateInvoiceParams, CreateInvoiceResult, Network, NodeConfig, NodeInfo, - PayInvoiceParams, PayInvoiceResult, + Backend, ChannelStats, CreateInvoiceParams, CreateInvoiceResult, Invoice, Network, NodeConfig, + NodeInfo, PayInvoiceParams, PayInvoiceResult, }; fn write_schema(dir: &std::path::Path, name: &str, schema: &RootSchema) -> std::io::Result<()> { @@ -42,6 +42,9 @@ fn main() { let schema = schema_for!(CreateInvoiceResult); write_schema(&dir, "create_invoice_result", &schema).unwrap(); + let schema = schema_for!(Invoice); + write_schema(&dir, "invoice", &schema).unwrap(); + let schema = schema_for!(PayInvoiceParams); write_schema(&dir, "pay_invoice_params", &schema).unwrap(); diff --git a/src/cli.rs b/src/cli.rs index 1652d83..100d267 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -87,6 +87,16 @@ async fn main() -> Result<(), Box> { .help("description"), ), ) + .subcommand( + Command::new("getinvoice") + .about("get invoice infos from the node") + .arg( + Arg::new("payment_hash") + .required(true) + .index(1) + .help("payment hash in hex format"), + ), + ) .get_matches(); let backend: Backend = matches @@ -142,6 +152,16 @@ async fn main() -> Result<(), Box> { println!("{:}", serde_json::to_string_pretty(&invoice).unwrap()); } + "getinvoice" => { + let args = command_args; + let payment_hash: &str = args + .value_of("payment_hash") + .expect("payment_hash is a required field"); + + let invoice = node.get_invoice(String::from(payment_hash)).await.unwrap(); + + println!("{:}", serde_json::to_string_pretty(&invoice).unwrap()); + } _ => { println!("invalid command. use una-cli --help to see usage instructions.") }