From 7fa5044aee2131aa7690caa8dd337a2da77c91a2 Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 22 Mar 2024 10:57:26 -0700 Subject: [PATCH 1/2] feat: add external-ln-receive-pubkey --- Cargo.lock | 462 ++---------------- fedimint-clientd/Cargo.toml | 12 +- fedimint-clientd/src/main.rs | 11 + .../fedimint/ln/claim_external_receive.rs | 81 +++ .../fedimint/ln/invoice_external_pubkey.rs | 95 ++++ .../src/router/handlers/fedimint/ln/mod.rs | 2 + fedimint-clientd/src/router/ws.rs | 10 + 7 files changed, 249 insertions(+), 424 deletions(-) create mode 100644 fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive.rs create mode 100644 fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey.rs diff --git a/Cargo.lock b/Cargo.lock index 00e3f6f..a4ee5c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,18 +984,6 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d79878f18e518d77cfb3126939d0e63a62cad845d51a3266f4ac866f2efe57f" -[[package]] -name = "fedimint-aead" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "argon2", - "hex", - "rand", - "ring 0.17.8", -] - [[package]] name = "fedimint-aead" version = "0.3.0-rc.1" @@ -1008,27 +996,6 @@ dependencies = [ "ring 0.17.8", ] -[[package]] -name = "fedimint-bitcoind" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "async-trait", - "bitcoin 0.29.2", - "bitcoin_hashes 0.11.0", - "bitcoincore-rpc", - "esplora-client", - "fedimint-core 0.3.0-rc.0", - "fedimint-logging 0.3.0-rc.0", - "lazy_static", - "rand", - "serde", - "serde_json", - "tracing", - "url", -] - [[package]] name = "fedimint-bitcoind" version = "0.3.0-rc.1" @@ -1040,8 +1007,8 @@ dependencies = [ "bitcoin_hashes 0.11.0", "bitcoincore-rpc", "esplora-client", - "fedimint-core 0.3.0-rc.1", - "fedimint-logging 0.3.0-rc.1", + "fedimint-core", + "fedimint-logging", "lazy_static", "rand", "serde", @@ -1050,14 +1017,6 @@ dependencies = [ "url", ] -[[package]] -name = "fedimint-build" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "serde_json", -] - [[package]] name = "fedimint-build" version = "0.3.0-rc.1" @@ -1066,37 +1025,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "fedimint-client" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "aquamarine", - "async-stream", - "async-trait", - "bitcoin 0.29.2", - "bitcoin_hashes 0.11.0", - "fedimint-aead 0.3.0-rc.0", - "fedimint-build 0.3.0-rc.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-derive-secret 0.3.0-rc.0", - "fedimint-logging 0.3.0-rc.0", - "futures", - "itertools 0.12.1", - "rand", - "ring 0.17.8", - "secp256k1-zkp", - "serde", - "serde_json", - "strum", - "strum_macros", - "thiserror", - "tokio", - "tokio-stream", - "tracing", -] - [[package]] name = "fedimint-client" version = "0.3.0-rc.1" @@ -1108,11 +1036,11 @@ dependencies = [ "async-trait", "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", - "fedimint-aead 0.3.0-rc.1", - "fedimint-build 0.3.0-rc.1", - "fedimint-core 0.3.0-rc.1", - "fedimint-derive-secret 0.3.0-rc.1", - "fedimint-logging 0.3.0-rc.1", + "fedimint-aead", + "fedimint-build", + "fedimint-core", + "fedimint-derive-secret", + "fedimint-logging", "futures", "itertools 0.12.1", "rand", @@ -1143,12 +1071,12 @@ dependencies = [ "clap", "dotenv", "fedimint", - "fedimint-client 0.3.0-rc.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-ln-client 0.3.0-rc.0", - "fedimint-mint-client 0.3.0-rc.0", - "fedimint-rocksdb 0.3.0-rc.0", - "fedimint-wallet-client 0.3.0-rc.0", + "fedimint-client", + "fedimint-core", + "fedimint-ln-client", + "fedimint-mint-client", + "fedimint-rocksdb", + "fedimint-wallet-client", "futures-util", "itertools 0.12.1", "lazy_static", @@ -1166,59 +1094,6 @@ dependencies = [ "url", ] -[[package]] -name = "fedimint-core" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "async-lock", - "async-recursion", - "async-trait", - "backtrace", - "bech32", - "bincode", - "bitcoin 0.29.2", - "bitcoin 0.30.2", - "bitcoin_hashes 0.11.0", - "bitvec", - "erased-serde", - "fedimint-derive 0.3.0-rc.0", - "fedimint-logging 0.3.0-rc.0", - "fedimint-tbs 0.3.0-rc.0", - "fedimint-threshold-crypto", - "futures", - "getrandom", - "gloo-timers 0.3.0", - "hex", - "imbl", - "itertools 0.12.1", - "js-sys", - "jsonrpsee-core", - "jsonrpsee-types", - "jsonrpsee-wasm-client", - "jsonrpsee-ws-client", - "lightning", - "lightning-invoice", - "lru", - "macro_rules_attribute", - "miniscript 10.0.0", - "parity-scale-codec", - "rand", - "secp256k1-zkp", - "serde", - "serde_json", - "sha3", - "strum", - "strum_macros", - "thiserror", - "tokio", - "tokio-rustls 0.23.4", - "tracing", - "url", - "wasm-bindgen-futures", -] - [[package]] name = "fedimint-core" version = "0.3.0-rc.1" @@ -1236,9 +1111,9 @@ dependencies = [ "bitcoin_hashes 0.11.0", "bitvec", "erased-serde", - "fedimint-derive 0.3.0-rc.1", - "fedimint-logging 0.3.0-rc.1", - "fedimint-tbs 0.3.0-rc.1", + "fedimint-derive", + "fedimint-logging", + "fedimint-tbs", "fedimint-threshold-crypto", "futures", "getrandom", @@ -1272,17 +1147,6 @@ dependencies = [ "wasm-bindgen-futures", ] -[[package]] -name = "fedimint-derive" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "itertools 0.12.1", - "proc-macro2", - "quote", - "syn 2.0.53", -] - [[package]] name = "fedimint-derive" version = "0.3.0-rc.1" @@ -1294,40 +1158,19 @@ dependencies = [ "syn 2.0.53", ] -[[package]] -name = "fedimint-derive-secret" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "fedimint-core 0.3.0-rc.0", - "fedimint-hkdf 0.3.0-rc.0", - "fedimint-tbs 0.3.0-rc.0", - "ring 0.17.8", - "secp256k1-zkp", -] - [[package]] name = "fedimint-derive-secret" version = "0.3.0-rc.1" source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.1#c51ea0c85576008dcbf9d94e2fe994dfa34bca61" dependencies = [ "anyhow", - "fedimint-core 0.3.0-rc.1", - "fedimint-hkdf 0.3.0-rc.1", - "fedimint-tbs 0.3.0-rc.1", + "fedimint-core", + "fedimint-hkdf", + "fedimint-tbs", "ring 0.17.8", "secp256k1-zkp", ] -[[package]] -name = "fedimint-hkdf" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "bitcoin_hashes 0.11.0", -] - [[package]] name = "fedimint-hkdf" version = "0.3.0-rc.1" @@ -1336,40 +1179,6 @@ dependencies = [ "bitcoin_hashes 0.11.0", ] -[[package]] -name = "fedimint-ln-client" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "aquamarine", - "async-stream", - "async-trait", - "bincode", - "bitcoin 0.29.2", - "bitcoin_hashes 0.11.0", - "erased-serde", - "fedimint-client 0.3.0-rc.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-ln-common 0.3.0-rc.0", - "fedimint-threshold-crypto", - "futures", - "itertools 0.12.1", - "lightning-invoice", - "rand", - "reqwest", - "secp256k1 0.24.3", - "secp256k1-zkp", - "serde", - "serde_json", - "strum", - "strum_macros", - "thiserror", - "tokio", - "tracing", - "url", -] - [[package]] name = "fedimint-ln-client" version = "0.3.0-rc.1" @@ -1383,9 +1192,9 @@ dependencies = [ "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", "erased-serde", - "fedimint-client 0.3.0-rc.1", - "fedimint-core 0.3.0-rc.1", - "fedimint-ln-common 0.3.0-rc.1", + "fedimint-client", + "fedimint-core", + "fedimint-ln-common", "fedimint-threshold-crypto", "futures", "itertools 0.12.1", @@ -1404,36 +1213,6 @@ dependencies = [ "url", ] -[[package]] -name = "fedimint-ln-common" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "aquamarine", - "async-trait", - "bitcoin 0.29.2", - "bitcoin_hashes 0.11.0", - "erased-serde", - "fedimint-client 0.3.0-rc.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-threshold-crypto", - "futures", - "itertools 0.12.1", - "lightning", - "lightning-invoice", - "rand", - "secp256k1 0.24.3", - "serde", - "serde-big-array", - "serde_json", - "strum", - "strum_macros", - "thiserror", - "tracing", - "url", -] - [[package]] name = "fedimint-ln-common" version = "0.3.0-rc.1" @@ -1445,8 +1224,8 @@ dependencies = [ "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", "erased-serde", - "fedimint-client 0.3.0-rc.1", - "fedimint-core 0.3.0-rc.1", + "fedimint-client", + "fedimint-core", "fedimint-threshold-crypto", "futures", "itertools 0.12.1", @@ -1464,15 +1243,6 @@ dependencies = [ "url", ] -[[package]] -name = "fedimint-logging" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "tracing-subscriber", -] - [[package]] name = "fedimint-logging" version = "0.3.0-rc.1" @@ -1482,41 +1252,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "fedimint-mint-client" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "aquamarine", - "async-stream", - "async-trait", - "base64 0.22.0", - "bincode", - "bitcoin_hashes 0.11.0", - "erased-serde", - "fedimint-client 0.3.0-rc.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-derive-secret 0.3.0-rc.0", - "fedimint-logging 0.3.0-rc.0", - "fedimint-mint-common 0.3.0-rc.0", - "fedimint-tbs 0.3.0-rc.0", - "fedimint-threshold-crypto", - "futures", - "itertools 0.12.1", - "rand", - "secp256k1 0.24.3", - "secp256k1-zkp", - "serde", - "serde-big-array", - "serde_json", - "strum", - "strum_macros", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "fedimint-mint-client" version = "0.3.0-rc.1" @@ -1530,12 +1265,12 @@ dependencies = [ "bincode", "bitcoin_hashes 0.11.0", "erased-serde", - "fedimint-client 0.3.0-rc.1", - "fedimint-core 0.3.0-rc.1", - "fedimint-derive-secret 0.3.0-rc.1", - "fedimint-logging 0.3.0-rc.1", - "fedimint-mint-common 0.3.0-rc.1", - "fedimint-tbs 0.3.0-rc.1", + "fedimint-client", + "fedimint-core", + "fedimint-derive-secret", + "fedimint-logging", + "fedimint-mint-common", + "fedimint-tbs", "fedimint-threshold-crypto", "futures", "itertools 0.12.1", @@ -1552,30 +1287,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "fedimint-mint-common" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "async-trait", - "bincode", - "bitcoin_hashes 0.11.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-tbs 0.3.0-rc.0", - "fedimint-threshold-crypto", - "futures", - "itertools 0.12.1", - "rand", - "secp256k1 0.24.3", - "secp256k1-zkp", - "serde", - "strum", - "strum_macros", - "thiserror", - "tracing", -] - [[package]] name = "fedimint-mint-common" version = "0.3.0-rc.1" @@ -1585,8 +1296,8 @@ dependencies = [ "async-trait", "bincode", "bitcoin_hashes 0.11.0", - "fedimint-core 0.3.0-rc.1", - "fedimint-tbs 0.3.0-rc.1", + "fedimint-core", + "fedimint-tbs", "fedimint-threshold-crypto", "futures", "itertools 0.12.1", @@ -1600,20 +1311,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "fedimint-rocksdb" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "async-trait", - "fedimint-core 0.3.0-rc.0", - "futures", - "rocksdb", - "tokio", - "tracing", -] - [[package]] name = "fedimint-rocksdb" version = "0.3.0-rc.1" @@ -1621,28 +1318,13 @@ source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.1#c51ea0c855760 dependencies = [ "anyhow", "async-trait", - "fedimint-core 0.3.0-rc.1", + "fedimint-core", "futures", "rocksdb", "tokio", "tracing", ] -[[package]] -name = "fedimint-tbs" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "bitcoin_hashes 0.11.0", - "bls12_381", - "ff", - "group", - "rand", - "rand_chacha", - "serde", - "sha3", -] - [[package]] name = "fedimint-tbs" version = "0.3.0-rc.1" @@ -1680,37 +1362,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "fedimint-wallet-client" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "aquamarine", - "async-stream", - "async-trait", - "bitcoin 0.29.2", - "erased-serde", - "fedimint-bitcoind 0.3.0-rc.0", - "fedimint-client 0.3.0-rc.0", - "fedimint-core 0.3.0-rc.0", - "fedimint-wallet-common 0.3.0-rc.0", - "futures", - "impl-tools", - "miniscript 10.0.0", - "rand", - "secp256k1 0.24.3", - "serde", - "serde_json", - "strum", - "strum_macros", - "thiserror", - "tokio", - "tracing", - "url", - "validator", -] - [[package]] name = "fedimint-wallet-client" version = "0.3.0-rc.1" @@ -1722,10 +1373,10 @@ dependencies = [ "async-trait", "bitcoin 0.29.2", "erased-serde", - "fedimint-bitcoind 0.3.0-rc.1", - "fedimint-client 0.3.0-rc.1", - "fedimint-core 0.3.0-rc.1", - "fedimint-wallet-common 0.3.0-rc.1", + "fedimint-bitcoind", + "fedimint-client", + "fedimint-core", + "fedimint-wallet-common", "futures", "impl-tools", "miniscript 10.0.0", @@ -1742,31 +1393,6 @@ dependencies = [ "validator", ] -[[package]] -name = "fedimint-wallet-common" -version = "0.3.0-rc.0" -source = "git+https://github.com/fedimint/fedimint?tag=v0.3.0-rc.0#45c945d6307f440fd18d1fde3331fc681e0b5d1c" -dependencies = [ - "anyhow", - "async-trait", - "bitcoin 0.29.2", - "erased-serde", - "fedimint-core 0.3.0-rc.0", - "futures", - "impl-tools", - "miniscript 10.0.0", - "miniscript 9.0.2", - "rand", - "secp256k1 0.24.3", - "serde", - "strum", - "strum_macros", - "thiserror", - "tracing", - "url", - "validator", -] - [[package]] name = "fedimint-wallet-common" version = "0.3.0-rc.1" @@ -1776,7 +1402,7 @@ dependencies = [ "async-trait", "bitcoin 0.29.2", "erased-serde", - "fedimint-core 0.3.0-rc.1", + "fedimint-core", "futures", "impl-tools", "miniscript 10.0.0", @@ -2823,12 +2449,12 @@ name = "multimint" version = "0.1.12" dependencies = [ "anyhow", - "fedimint-client 0.3.0-rc.1", - "fedimint-core 0.3.0-rc.1", - "fedimint-ln-client 0.3.0-rc.1", - "fedimint-mint-client 0.3.0-rc.1", - "fedimint-rocksdb 0.3.0-rc.1", - "fedimint-wallet-client 0.3.0-rc.1", + "fedimint-client", + "fedimint-core", + "fedimint-ln-client", + "fedimint-mint-client", + "fedimint-rocksdb", + "fedimint-wallet-client", "futures-util", "hex", "rand", diff --git a/fedimint-clientd/Cargo.toml b/fedimint-clientd/Cargo.toml index 47e97a5..b6a9728 100644 --- a/fedimint-clientd/Cargo.toml +++ b/fedimint-clientd/Cargo.toml @@ -20,12 +20,12 @@ serde_json = "1.0.108" tokio = { version = "1.34.0", features = ["full"] } tracing = "0.1.40" tracing-subscriber = "0.3.18" -fedimint-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.0" } -fedimint-core = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.0" } -fedimint-wallet-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.0" } -fedimint-mint-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.0" } -fedimint-ln-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.0" } -fedimint-rocksdb = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.0" } +fedimint-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.1" } +fedimint-core = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.1" } +fedimint-wallet-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.1" } +fedimint-mint-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.1" } +fedimint-ln-client = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.1" } +fedimint-rocksdb = { git = "https://github.com/fedimint/fedimint", tag = "v0.3.0-rc.1" } url = "2.5.0" lazy_static = "1.4.0" async-utility = "0.2.0" diff --git a/fedimint-clientd/src/main.rs b/fedimint-clientd/src/main.rs index 9681507..142a645 100644 --- a/fedimint-clientd/src/main.rs +++ b/fedimint-clientd/src/main.rs @@ -182,7 +182,10 @@ async fn main() -> Result<()> { /// Lightning network related commands: /// - `/fedimint/v2/ln/invoice`: Create a lightning invoice to receive payment /// via gateway. +/// - `/fedimint/v2/ln/invoice-external-pubkey`: Create a lightning invoice to +/// receive payment via gateway with external pubkey. /// - `/fedimint/v2/ln/await-invoice`: Wait for incoming invoice to be paid. +/// - `/fedimint/v2/ln/claim-external-receive`: Claim an external receive. /// - `/fedimint/v2/ln/pay`: Pay a lightning invoice or lnurl via a gateway. /// - `/fedimint/v2/ln/await-pay`: Wait for a lightning payment to complete. /// - `/fedimint/v2/ln/list-gateways`: List registered gateways. @@ -204,10 +207,18 @@ fn fedimint_v2_rest() -> Router { let ln_router = Router::new() .route("/invoice", post(fedimint::ln::invoice::handle_rest)) + .route( + "/invoice-external-pubkey", + post(fedimint::ln::invoice_external_pubkey::handle_rest), + ) .route( "/await-invoice", post(fedimint::ln::await_invoice::handle_rest), ) + .route( + "/claim-external-receive", + post(fedimint::ln::claim_external_receive::handle_rest), + ) .route("/pay", post(fedimint::ln::pay::handle_rest)) .route( "/list-gateways", diff --git a/fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive.rs b/fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive.rs new file mode 100644 index 0000000..18e0417 --- /dev/null +++ b/fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive.rs @@ -0,0 +1,81 @@ +use anyhow::anyhow; +use axum::extract::State; +use axum::http::StatusCode; +use axum::Json; +use bitcoin::secp256k1::{Secp256k1, SecretKey}; +use bitcoin::util::key::KeyPair; +use fedimint_client::ClientHandleArc; +use fedimint_core::config::FederationId; +use fedimint_ln_client::{LightningClientModule, LnReceiveState}; +use futures_util::StreamExt; +use serde::Deserialize; +use serde_json::{json, Value}; +use tracing::info; + +use crate::error::AppError; +use crate::router::handlers::fedimint::admin::get_note_summary; +use crate::router::handlers::fedimint::admin::info::InfoResponse; +use crate::state::AppState; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ClaimExternalReceiveRequest { + pub private_key: SecretKey, + pub federation_id: FederationId, +} + +async fn _await_claim_external_receive( + client: ClientHandleArc, + req: ClaimExternalReceiveRequest, +) -> Result { + let secp = Secp256k1::new(); + let key_pair = KeyPair::from_secret_key(&secp, &req.private_key); + let lightning_module = &client.get_first_module::(); + let operation_id = lightning_module.scan_receive_for_user(key_pair, ()).await?; + let mut updates = lightning_module + .subscribe_ln_claim(operation_id) + .await? + .into_stream(); + + while let Some(update) = updates.next().await { + info!("Update: {update:?}"); + match update { + LnReceiveState::Claimed => { + return Ok(get_note_summary(&client).await?); + } + LnReceiveState::Canceled { reason } => { + return Err(AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!(reason), + )) + } + _ => {} + } + + info!("Update: {update:?}"); + } + + Err(AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!("Unexpected end of stream"), + )) +} + +pub async fn handle_ws(state: AppState, v: Value) -> Result { + let v = serde_json::from_value::(v) + .map_err(|e| AppError::new(StatusCode::BAD_REQUEST, anyhow!("Invalid request: {}", e)))?; + let client = state.get_client(v.federation_id).await?; + let invoice = _await_claim_external_receive(client, v).await?; + let invoice_json = json!(invoice); + Ok(invoice_json) +} + +#[axum_macros::debug_handler] +pub async fn handle_rest( + State(state): State, + Json(req): Json, +) -> Result, AppError> { + let client = state.get_client(req.federation_id).await?; + let invoice = _await_claim_external_receive(client, req).await?; + Ok(Json(invoice)) +} diff --git a/fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey.rs b/fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey.rs new file mode 100644 index 0000000..0dac00c --- /dev/null +++ b/fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey.rs @@ -0,0 +1,95 @@ +use anyhow::anyhow; +use axum::extract::State; +use axum::http::StatusCode; +use axum::Json; +use bitcoin::secp256k1::PublicKey; +use fedimint_client::ClientHandleArc; +use fedimint_core::config::FederationId; +use fedimint_core::core::OperationId; +use fedimint_core::Amount; +use fedimint_ln_client::LightningClientModule; +use lightning_invoice::{Bolt11InvoiceDescription, Description}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use tracing::error; + +use crate::error::AppError; +use crate::state::AppState; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LnInvoiceExternalPubkeyRequest { + pub amount_msat: Amount, + pub description: String, + pub expiry_time: Option, + pub external_pubkey: PublicKey, + pub federation_id: FederationId, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LnInvoiceExternalPubkeyResponse { + pub operation_id: OperationId, + pub invoice: String, +} + +async fn _invoice( + client: ClientHandleArc, + req: LnInvoiceExternalPubkeyRequest, +) -> Result { + let lightning_module = client.get_first_module::(); + let gateway_id = match lightning_module.list_gateways().await.first() { + Some(gateway_announcement) => gateway_announcement.info.gateway_id, + None => { + error!("No gateways available"); + return Err(AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!("No gateways available"), + )); + } + }; + let gateway = lightning_module + .select_gateway(&gateway_id) + .await + .ok_or_else(|| { + error!("Failed to select gateway"); + AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!("Failed to select gateway"), + ) + })?; + + let (operation_id, invoice, _) = lightning_module + .create_bolt11_invoice_for_user( + req.amount_msat, + Bolt11InvoiceDescription::Direct(&Description::new(req.description)?), + req.expiry_time, + req.external_pubkey.clone(), + (), + Some(gateway), + ) + .await?; + Ok(LnInvoiceExternalPubkeyResponse { + operation_id, + invoice: invoice.to_string(), + }) +} + +pub async fn handle_ws(state: AppState, v: Value) -> Result { + let v = serde_json::from_value::(v) + .map_err(|e| AppError::new(StatusCode::BAD_REQUEST, anyhow!("Invalid request: {}", e)))?; + let client = state.get_client(v.federation_id).await?; + let invoice = _invoice(client, v).await?; + let invoice_json = json!(invoice); + Ok(invoice_json) +} + +#[axum_macros::debug_handler] +pub async fn handle_rest( + State(state): State, + Json(req): Json, +) -> Result, AppError> { + let client = state.get_client(req.federation_id).await?; + let invoice = _invoice(client, req).await?; + Ok(Json(invoice)) +} diff --git a/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs b/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs index 0050a27..97109f3 100644 --- a/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs +++ b/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs @@ -11,7 +11,9 @@ use tracing::{debug, info}; use self::pay::{LnPayRequest, LnPayResponse}; pub mod await_invoice; +pub mod claim_external_receive; pub mod invoice; +pub mod invoice_external_pubkey; pub mod list_gateways; pub mod pay; diff --git a/fedimint-clientd/src/router/ws.rs b/fedimint-clientd/src/router/ws.rs index 934edb9..5f17e8b 100644 --- a/fedimint-clientd/src/router/ws.rs +++ b/fedimint-clientd/src/router/ws.rs @@ -60,7 +60,9 @@ pub enum JsonRpcMethod { MintSplit, MintCombine, LnInvoice, + LnInvoiceExternalPubkey, LnAwaitInvoice, + LnClaimExternalReceive, LnPay, LnListGateways, WalletDepositAddress, @@ -182,9 +184,17 @@ async fn match_method(req: JsonRpcRequest, state: AppState) -> Result { handlers::fedimint::ln::invoice::handle_ws(state.clone(), req.params).await } + JsonRpcMethod::LnInvoiceExternalPubkey => { + handlers::fedimint::ln::invoice_external_pubkey::handle_ws(state.clone(), req.params) + .await + } JsonRpcMethod::LnAwaitInvoice => { handlers::fedimint::ln::await_invoice::handle_ws(state.clone(), req.params).await } + JsonRpcMethod::LnClaimExternalReceive => { + handlers::fedimint::ln::claim_external_receive::handle_ws(state.clone(), req.params) + .await + } JsonRpcMethod::LnPay => { handlers::fedimint::ln::pay::handle_ws(state.clone(), req.params).await } From 959dc51997938ebcb400056a45add3071727728b Mon Sep 17 00:00:00 2001 From: "kody.low" Date: Fri, 22 Mar 2024 11:13:01 -0700 Subject: [PATCH 2/2] feat: claim external pubkey tweaked --- fedimint-clientd/src/main.rs | 8 ++ .../ln/claim_external_receive_tweaked.rs | 85 ++++++++++++++++ .../ln/invoice_external_pubkey_tweaked.rs | 97 +++++++++++++++++++ .../src/router/handlers/fedimint/ln/mod.rs | 2 + fedimint-clientd/src/router/ws.rs | 16 +++ 5 files changed, 208 insertions(+) create mode 100644 fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive_tweaked.rs create mode 100644 fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey_tweaked.rs diff --git a/fedimint-clientd/src/main.rs b/fedimint-clientd/src/main.rs index 142a645..9375363 100644 --- a/fedimint-clientd/src/main.rs +++ b/fedimint-clientd/src/main.rs @@ -211,6 +211,10 @@ fn fedimint_v2_rest() -> Router { "/invoice-external-pubkey", post(fedimint::ln::invoice_external_pubkey::handle_rest), ) + .route( + "/invoice-external-pubkey-tweaked", + post(fedimint::ln::invoice_external_pubkey_tweaked::handle_rest), + ) .route( "/await-invoice", post(fedimint::ln::await_invoice::handle_rest), @@ -219,6 +223,10 @@ fn fedimint_v2_rest() -> Router { "/claim-external-receive", post(fedimint::ln::claim_external_receive::handle_rest), ) + .route( + "/claim-external-receive-tweaked", + post(fedimint::ln::claim_external_receive_tweaked::handle_rest), + ) .route("/pay", post(fedimint::ln::pay::handle_rest)) .route( "/list-gateways", diff --git a/fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive_tweaked.rs b/fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive_tweaked.rs new file mode 100644 index 0000000..4affc3a --- /dev/null +++ b/fedimint-clientd/src/router/handlers/fedimint/ln/claim_external_receive_tweaked.rs @@ -0,0 +1,85 @@ +use anyhow::anyhow; +use axum::extract::State; +use axum::http::StatusCode; +use axum::Json; +use bitcoin::secp256k1::{Secp256k1, SecretKey}; +use bitcoin::util::key::KeyPair; +use fedimint_client::ClientHandleArc; +use fedimint_core::config::FederationId; +use fedimint_ln_client::{LightningClientModule, LnReceiveState}; +use futures_util::StreamExt; +use serde::Deserialize; +use serde_json::{json, Value}; +use tracing::info; + +use crate::error::AppError; +use crate::router::handlers::fedimint::admin::get_note_summary; +use crate::router::handlers::fedimint::admin::info::InfoResponse; +use crate::state::AppState; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ClaimExternalReceiveTweakedRequest { + pub tweaks: Vec, + pub private_key: SecretKey, + pub federation_id: FederationId, +} + +async fn _await_claim_external_receive_tweaked( + client: ClientHandleArc, + req: ClaimExternalReceiveTweakedRequest, +) -> Result { + let secp = Secp256k1::new(); + let key_pair = KeyPair::from_secret_key(&secp, &req.private_key); + let lightning_module = &client.get_first_module::(); + let operation_id = lightning_module + .scan_receive_for_user_tweaked(key_pair, req.tweaks, ()) + .await; + + let mut final_response = get_note_summary(&client).await?; + for operation_id in operation_id { + let mut updates = lightning_module + .subscribe_ln_claim(operation_id) + .await? + .into_stream(); + + while let Some(update) = updates.next().await { + info!("Update: {update:?}"); + match update { + LnReceiveState::Claimed => { + final_response = get_note_summary(&client).await?; + } + LnReceiveState::Canceled { reason } => { + return Err(AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!(reason), + )) + } + _ => {} + } + + info!("Update: {update:?}"); + } + } + + Ok(final_response) +} + +pub async fn handle_ws(state: AppState, v: Value) -> Result { + let v = serde_json::from_value::(v) + .map_err(|e| AppError::new(StatusCode::BAD_REQUEST, anyhow!("Invalid request: {}", e)))?; + let client = state.get_client(v.federation_id).await?; + let invoice = _await_claim_external_receive_tweaked(client, v).await?; + let invoice_json = json!(invoice); + Ok(invoice_json) +} + +#[axum_macros::debug_handler] +pub async fn handle_rest( + State(state): State, + Json(req): Json, +) -> Result, AppError> { + let client = state.get_client(req.federation_id).await?; + let invoice = _await_claim_external_receive_tweaked(client, req).await?; + Ok(Json(invoice)) +} diff --git a/fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey_tweaked.rs b/fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey_tweaked.rs new file mode 100644 index 0000000..6fad6c4 --- /dev/null +++ b/fedimint-clientd/src/router/handlers/fedimint/ln/invoice_external_pubkey_tweaked.rs @@ -0,0 +1,97 @@ +use anyhow::anyhow; +use axum::extract::State; +use axum::http::StatusCode; +use axum::Json; +use bitcoin::secp256k1::PublicKey; +use fedimint_client::ClientHandleArc; +use fedimint_core::config::FederationId; +use fedimint_core::core::OperationId; +use fedimint_core::Amount; +use fedimint_ln_client::LightningClientModule; +use lightning_invoice::{Bolt11InvoiceDescription, Description}; +use serde::{Deserialize, Serialize}; +use serde_json::{json, Value}; +use tracing::error; + +use crate::error::AppError; +use crate::state::AppState; + +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct LnInvoiceExternalPubkeyTweakedRequest { + pub amount_msat: Amount, + pub description: String, + pub expiry_time: Option, + pub external_pubkey: PublicKey, + pub tweak: u64, + pub federation_id: FederationId, +} + +#[derive(Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LnInvoiceExternalPubkeyTweakedResponse { + pub operation_id: OperationId, + pub invoice: String, +} + +async fn _invoice( + client: ClientHandleArc, + req: LnInvoiceExternalPubkeyTweakedRequest, +) -> Result { + let lightning_module = client.get_first_module::(); + let gateway_id = match lightning_module.list_gateways().await.first() { + Some(gateway_announcement) => gateway_announcement.info.gateway_id, + None => { + error!("No gateways available"); + return Err(AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!("No gateways available"), + )); + } + }; + let gateway = lightning_module + .select_gateway(&gateway_id) + .await + .ok_or_else(|| { + error!("Failed to select gateway"); + AppError::new( + StatusCode::INTERNAL_SERVER_ERROR, + anyhow!("Failed to select gateway"), + ) + })?; + + let (operation_id, invoice, _) = lightning_module + .create_bolt11_invoice_for_user_tweaked( + req.amount_msat, + Bolt11InvoiceDescription::Direct(&Description::new(req.description)?), + req.expiry_time, + req.external_pubkey.clone(), + req.tweak, + (), + Some(gateway), + ) + .await?; + Ok(LnInvoiceExternalPubkeyTweakedResponse { + operation_id, + invoice: invoice.to_string(), + }) +} + +pub async fn handle_ws(state: AppState, v: Value) -> Result { + let v = serde_json::from_value::(v) + .map_err(|e| AppError::new(StatusCode::BAD_REQUEST, anyhow!("Invalid request: {}", e)))?; + let client = state.get_client(v.federation_id).await?; + let invoice = _invoice(client, v).await?; + let invoice_json = json!(invoice); + Ok(invoice_json) +} + +#[axum_macros::debug_handler] +pub async fn handle_rest( + State(state): State, + Json(req): Json, +) -> Result, AppError> { + let client = state.get_client(req.federation_id).await?; + let invoice = _invoice(client, req).await?; + Ok(Json(invoice)) +} diff --git a/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs b/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs index 97109f3..41ccb05 100644 --- a/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs +++ b/fedimint-clientd/src/router/handlers/fedimint/ln/mod.rs @@ -12,8 +12,10 @@ use self::pay::{LnPayRequest, LnPayResponse}; pub mod await_invoice; pub mod claim_external_receive; +pub mod claim_external_receive_tweaked; pub mod invoice; pub mod invoice_external_pubkey; +pub mod invoice_external_pubkey_tweaked; pub mod list_gateways; pub mod pay; diff --git a/fedimint-clientd/src/router/ws.rs b/fedimint-clientd/src/router/ws.rs index 5f17e8b..65129a8 100644 --- a/fedimint-clientd/src/router/ws.rs +++ b/fedimint-clientd/src/router/ws.rs @@ -61,8 +61,10 @@ pub enum JsonRpcMethod { MintCombine, LnInvoice, LnInvoiceExternalPubkey, + LnInvoiceExternalPubkeyTweaked, LnAwaitInvoice, LnClaimExternalReceive, + LnClaimExternalReceiveTweaked, LnPay, LnListGateways, WalletDepositAddress, @@ -188,6 +190,13 @@ async fn match_method(req: JsonRpcRequest, state: AppState) -> Result { + handlers::fedimint::ln::invoice_external_pubkey_tweaked::handle_ws( + state.clone(), + req.params, + ) + .await + } JsonRpcMethod::LnAwaitInvoice => { handlers::fedimint::ln::await_invoice::handle_ws(state.clone(), req.params).await } @@ -195,6 +204,13 @@ async fn match_method(req: JsonRpcRequest, state: AppState) -> Result { + handlers::fedimint::ln::claim_external_receive_tweaked::handle_ws( + state.clone(), + req.params, + ) + .await + } JsonRpcMethod::LnPay => { handlers::fedimint::ln::pay::handle_ws(state.clone(), req.params).await }