From 65815d5688408da84eb83c1948cf65d43f97e3c3 Mon Sep 17 00:00:00 2001 From: ok300 <106775972+ok300@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:07:57 +0000 Subject: [PATCH 01/37] Replace `fetchReverseSwapFees` with `onchainPaymentLimits` (#139) * Replace fetchReverseSwapFees with onchainPaymentLimits * Fix RN snippet imports --- .github/workflows/main.yml | 2 +- snippets/csharp/SendOnchain.cs | 22 +-- snippets/dart_snippets/lib/send_onchain.dart | 21 +-- snippets/go/send_onchain.go | 22 +-- .../com/example/kotlinmpplib/SendOnchain.kt | 18 +- snippets/python/src/send_onchain.py | 18 +- snippets/react-native/send_onchain.ts | 21 +-- snippets/rust/Cargo.lock | 175 ++++-------------- snippets/rust/Cargo.toml | 2 +- snippets/rust/src/send_onchain.rs | 28 +-- .../Sources/SendOnchain.swift | 19 +- src/guide/send_onchain.md | 95 ++-------- 12 files changed, 97 insertions(+), 346 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 76e1fc4b..c41da1c1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: name: setup runs-on: ubuntu-latest outputs: - sdk-ref: ${{ inputs.sdk-ref || '474ac7d4b5d19633dc851439b9ff7e159286fbd8' }} + sdk-ref: ${{ inputs.sdk-ref || '908bed466000617364047c103a8785222f8eedff' }} package-version: '0.3.1' steps: - run: echo "set pre-setup output variables" diff --git a/snippets/csharp/SendOnchain.cs b/snippets/csharp/SendOnchain.cs index 70dfc997..86b53dae 100644 --- a/snippets/csharp/SendOnchain.cs +++ b/snippets/csharp/SendOnchain.cs @@ -2,30 +2,20 @@ public class SendOnchainSnippets { - public void GetCurrentFees(BlockingBreezServices sdk) + public void GetCurrentLimits(BlockingBreezServices sdk) { - // ANCHOR: estimate-current-reverse-swap-total-fees + // ANCHOR: get-current-reverse-swap-limits try { - var currentFees = sdk.FetchReverseSwapFees( - new ReverseSwapFeesRequest(50000)); - Console.WriteLine( - $"Total estimated fees for reverse " + - $"swap: {currentFees.totalFees}"); + var currentLimits = sdk.OnchainPaymentLimits(); + Console.WriteLine($"Minimum amount, in sats: {currentLimits.minSat}"); + Console.WriteLine($"Maximum amount, in sats: {currentLimits.maxSat}"); } catch (Exception) { // Handle error } - // ANCHOR_END: estimate-current-reverse-swap-total-fees - } - - public void ListCurrentFees(BlockingBreezServices sdk, ReverseSwapPairInfo currentFees) - { - // ANCHOR: get-current-reverse-swap-min-max - Console.WriteLine($"Minimum amount, in sats: {currentFees.min}"); - Console.WriteLine($"Maximum amount, in sats: {currentFees.max}"); - // ANCHOR_END: get-current-reverse-swap-min-max + // ANCHOR_END: get-current-reverse-swap-limits } public void MaxReverseSwapAmount(BlockingBreezServices sdk) diff --git a/snippets/dart_snippets/lib/send_onchain.dart b/snippets/dart_snippets/lib/send_onchain.dart index 6785aa70..da95b7f0 100644 --- a/snippets/dart_snippets/lib/send_onchain.dart +++ b/snippets/dart_snippets/lib/send_onchain.dart @@ -1,20 +1,13 @@ import 'package:breez_sdk/breez_sdk.dart'; import 'package:breez_sdk/bridge_generated.dart'; -Future estimateCurrentFees() async { - // ANCHOR: estimate-current-reverse-swap-total-fees - ReverseSwapFeesRequest req = const ReverseSwapFeesRequest(sendAmountSat: 50000); - ReverseSwapPairInfo currentFees = await BreezSDK().fetchReverseSwapFees(req: req); - print("Total estimated fees for reverse swap: ${currentFees.totalFees}"); - // ANCHOR_END: estimate-current-reverse-swap-total-fees - return currentFees; -} - -void listCurrentFees({required ReverseSwapPairInfo currentFees}) { - // ANCHOR: get-current-reverse-swap-min-max - print("Minimum amount, in sats: ${currentFees.min}"); - print("Maximum amount, in sats: ${currentFees.max}"); - // ANCHOR_END: get-current-reverse-swap-min-max +Future getCurrentLimits() async { + // ANCHOR: get-current-reverse-swap-limits + OnchainPaymentLimitsResponse currentLimits = await BreezSDK().onchainPaymentLimits(); + print("Minimum amount, in sats: ${currentLimits.minSat}"); + print("Maximum amount, in sats: ${currentLimits.maxSat}"); + // ANCHOR_END: get-current-reverse-swap-limits + return currentLimits; } Future maxReverseSwapAmount() async { diff --git a/snippets/go/send_onchain.go b/snippets/go/send_onchain.go index 977b8cf9..81030ca3 100644 --- a/snippets/go/send_onchain.go +++ b/snippets/go/send_onchain.go @@ -6,23 +6,13 @@ import ( "github.com/breez/breez-sdk-go/breez_sdk" ) -func GetCurrentFees() { - // ANCHOR: estimate-current-reverse-swap-total-fees - sendAmountSat := uint64(50_000) - reverseSwapFeesRequest := breez_sdk.ReverseSwapFeesRequest{ - SendAmountSat: &sendAmountSat, - } - if currentFees, err := sdk.FetchReverseSwapFees(reverseSwapFeesRequest); err == nil { - log.Printf("Total estimated fees for reverse swap: %v", currentFees.TotalFees) +func GetCurrentLimits() { + // ANCHOR: get-current-reverse-swap-limits + if currentLimits, err := sdk.OnchainPaymentLimits(); err == nil { + log.Printf("Minimum amount, in sats: %v", currentLimits.MinSat) + log.Printf("Maximum amount, in sats: %v", currentLimits.MaxSat) } - // ANCHOR_END: estimate-current-reverse-swap-total-fees -} - -func ListCurrentFees(currentFees breez_sdk.ReverseSwapPairInfo) { - // ANCHOR: get-current-reverse-swap-min-max - log.Printf("Minimum amount, in sats: %v", currentFees.Min) - log.Printf("Maximum amount, in sats: %v", currentFees.Max) - // ANCHOR_END: get-current-reverse-swap-min-max + // ANCHOR_END: get-current-reverse-swap-limits } func MaxReverseSwapAmount() { diff --git a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt index 64248031..fcbf4988 100644 --- a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt +++ b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt @@ -2,22 +2,16 @@ package com.example.kotlinmpplib import breez_sdk.* class SendOnchain { - fun estimate_current_rev_swap_fees(sdk: BlockingBreezServices) { - // ANCHOR: estimate-current-reverse-swap-total-fees + fun get_current_rev_swap_limits(sdk: BlockingBreezServices) { + // ANCHOR: get-current-reverse-swap-limits try { - val fees = sdk.fetchReverseSwapFees(ReverseSwapFeesRequest(50_000_u)) - // Log.v("Breez", "Total estimated fees for reverse swap: ${fees.totalFees}") + val currentLimits = sdk.onchainPaymentLimits() + // Log.v("Breez", "Minimum amount, in sats: ${currentLimits.minSat}") + // Log.v("Breez", "Maximum amount, in sats: ${currentLimits.maxSat}") } catch (e: Exception) { // handle error } - // ANCHOR_END: estimate-current-reverse-swap-total-fees - } - - fun get_current_rev_swap_min_max(sdk: BlockingBreezServices, fees: ReverseSwapPairInfo) { - // ANCHOR: get-current-reverse-swap-min-max - // Log.v("Breez", "Minimum amount, in sats: ${fees.min}") - // Log.v("Breez", "Maximum amount, in sats: ${fees.max}") - // ANCHOR_END: get-current-reverse-swap-min-max + // ANCHOR_END: get-current-reverse-swap-limits } fun max_reverse_swap_amount(sdk: BlockingBreezServices) { diff --git a/snippets/python/src/send_onchain.py b/snippets/python/src/send_onchain.py index 91f0bc2c..b77c6754 100644 --- a/snippets/python/src/send_onchain.py +++ b/snippets/python/src/send_onchain.py @@ -1,23 +1,17 @@ import breez_sdk -def get_current_fees(sdk_services): +def get_current_limits(sdk_services): try: - # ANCHOR: estimate-current-reverse-swap-total-fees - req = breez_sdk.ReverseSwapFeesRequest(send_amount_sat=50000) - current_fees = sdk_services.fetch_reverse_swap_fees(req) - print("Total estimated fees for reverse swap: ", current_fees.total_fees) - # ANCHOR_END: estimate-current-reverse-swap-total-fees + # ANCHOR: get-current-reverse-swap-limits + current_limits = sdk_services.onchain_payment_limits() + print("Minimum amount, in sats: ", current_limits.min_sat) + print("Maximum amount, in sats: ", current_limits.max_sat) + # ANCHOR_END: get-current-reverse-swap-limits return current_fees except Exception as error: print(error) raise -def list_current_fees(current_fees): - # ANCHOR: get-current-reverse-swap-min-max - print("Minimum amount, in sats: ", current_fees.min) - print("Maximum amount, in sats: ", current_fees.max) - # ANCHOR_END: get-current-reverse-swap-min-max - def max_reverse_swap_amount(sdk_services): try: # ANCHOR: max-reverse-swap-amount diff --git a/snippets/react-native/send_onchain.ts b/snippets/react-native/send_onchain.ts index 20bf9085..d997f905 100644 --- a/snippets/react-native/send_onchain.ts +++ b/snippets/react-native/send_onchain.ts @@ -2,29 +2,22 @@ import { type ReverseSwapPairInfo, fetchReverseSwapFees, inProgressReverseSwaps, + onchainPaymentLimits, sendOnchain, maxReverseSwapAmount } from '@breeztech/react-native-breez-sdk' -const exampleFetchReverseSwapFees = async () => { - // ANCHOR: estimate-current-reverse-swap-total-fees +const exampleFetchReverseSwapLimits = async () => { + // ANCHOR: get-current-reverse-swap-limits try { - const currentFees = await fetchReverseSwapFees({ sendAmountSat: 50000 }) + const currentLimits = await onchainPaymentLimits() - console.log( - `Total estimated fees for reverse swap: ${currentFees.totalFees}` - ) + console.log(`Minimum amount, in sats: ${currentLimits.minSat}`) + console.log(`Maximum amount, in sats: ${currentLimits.maxSat}`) } catch (err) { console.error(err) } - // ANCHOR_END: estimate-current-reverse-swap-total-fees -} - -const exampleListCurrentFees = (currentFees: ReverseSwapPairInfo) => { - // ANCHOR: get-current-reverse-swap-min-max - console.log(`Minimum amount, in sats: ${currentFees.min}`) - console.log(`Maximum amount, in sats: ${currentFees.max}`) - // ANCHOR_END: get-current-reverse-swap-min-max + // ANCHOR_END: get-current-reverse-swap-limits } const maxAmount = async () => { diff --git a/snippets/rust/Cargo.lock b/snippets/rust/Cargo.lock index d1d91ef9..96e31595 100644 --- a/snippets/rust/Cargo.lock +++ b/snippets/rust/Cargo.lock @@ -306,12 +306,6 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" -[[package]] -name = "bech32" -version = "0.10.0-beta" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" - [[package]] name = "bip21" version = "0.2.0" @@ -347,7 +341,7 @@ version = "0.29.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0694ea59225b0c5f3cb405ff3f670e4828358ed26aec49dc352f730f0cb1a8a3" dependencies = [ - "bech32 0.9.1", + "bech32", "bitcoin_hashes 0.11.0", "bitcoinconsensus", "secp256k1 0.24.3", @@ -360,7 +354,7 @@ version = "0.30.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1945a5048598e4189e239d3f809b19bdad4845c4b2ba400d304d2dcf26d2c462" dependencies = [ - "bech32 0.9.1", + "bech32", "bitcoin-private", "bitcoin_hashes 0.12.0", "hex_lit", @@ -368,20 +362,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitcoin" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd00f3c09b5f21fb357abe32d29946eb8bb7a0862bae62c0b5e4a692acbbe73c" -dependencies = [ - "bech32 0.10.0-beta", - "bitcoin-internals", - "bitcoin_hashes 0.13.0", - "hex-conservative", - "hex_lit", - "secp256k1 0.28.2", -] - [[package]] name = "bitcoin-consensus-derive" version = "0.1.0" @@ -393,12 +373,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "bitcoin-internals" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" - [[package]] name = "bitcoin-private" version = "0.1.0" @@ -434,16 +408,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitcoin_hashes" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" -dependencies = [ - "bitcoin-internals", - "hex-conservative", -] - [[package]] name = "bitcoinconsensus" version = "0.20.2-0.5.0" @@ -497,8 +461,8 @@ dependencies = [ [[package]] name = "breez-sdk-core" -version = "0.3.1" -source = "git+https://github.com/breez/breez-sdk?tag=0.3.1#6fe250b2bad4109c7ed2ba75c552ab51e34b1fe4" +version = "0.3.2" +source = "git+https://github.com/breez/breez-sdk?branch=main#908bed466000617364047c103a8785222f8eedff" dependencies = [ "aes", "anyhow", @@ -514,8 +478,6 @@ dependencies = [ "gl-client", "hex", "lazy_static", - "lightning 0.0.118", - "lightning-invoice 0.26.0", "log", "miniz_oxide", "once_cell", @@ -530,7 +492,7 @@ dependencies = [ "rusqlite_migration", "serde", "serde_json", - "serde_with 3.6.1", + "serde_with", "strum", "strum_macros", "tempfile", @@ -1166,14 +1128,13 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "gl-client" -version = "0.1.9" -source = "git+https://github.com/Blockstream/greenlight.git?rev=556eedf47a837b71c4277ba6ee84322f5cbd80de#556eedf47a837b71c4277ba6ee84322f5cbd80de" +version = "0.1.11" +source = "git+https://github.com/Blockstream/greenlight.git?rev=1dbe06999bac216212124779c60006bd3d135ac7#1dbe06999bac216212124779c60006bd3d135ac7" dependencies = [ "anyhow", "async-trait", "base64 0.21.7", - "bech32 0.9.1", - "bitcoin 0.31.1", + "bech32", "bytes", "chacha20poly1305", "cln-grpc", @@ -1181,7 +1142,6 @@ dependencies = [ "hex", "http", "http-body", - "lightning-invoice 0.26.0", "log", "mockall", "pin-project", @@ -1292,12 +1252,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hex-conservative" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" - [[package]] name = "hex_lit" version = "0.1.1" @@ -1616,48 +1570,25 @@ dependencies = [ [[package]] name = "lightning" -version = "0.0.115" +version = "0.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e009e1c0c21f66378b491bb40f548682138c63e09db6f3a05af59f8804bb9f4a" +checksum = "90a0f2155316f1570446a0447c993480673f840748c8ed25bbc59dfc442ac770" dependencies = [ "bitcoin 0.29.2", "hex", "regex", ] -[[package]] -name = "lightning" -version = "0.0.118" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52cec5fa9382154fe9671e8df93095b800c7d77abc66e2a5ef839d672521c5e" -dependencies = [ - "bitcoin 0.29.2", -] - [[package]] name = "lightning-invoice" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e44b0e2822c8811470137d2339fdfe67a699b3248bb1606d1d02eb6a1e9f0a" +checksum = "1788c0158526ec27a502043c2911ea6ea58fdc656bdf8749484942c07b790d23" dependencies = [ - "bech32 0.9.1", + "bech32", "bitcoin 0.29.2", "bitcoin_hashes 0.11.0", - "lightning 0.0.115", - "num-traits", - "secp256k1 0.24.3", -] - -[[package]] -name = "lightning-invoice" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb24878b0f4ef75f020976c886d9ad1503867802329cc963e0ab4623ea3b25c" -dependencies = [ - "bech32 0.9.1", - "bitcoin 0.29.2", - "bitcoin_hashes 0.11.0", - "lightning 0.0.118", + "lightning", "num-traits", "secp256k1 0.24.3", ] @@ -2533,16 +2464,6 @@ dependencies = [ "serde", ] -[[package]] -name = "secp256k1" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10" -dependencies = [ - "bitcoin_hashes 0.13.0", - "secp256k1-sys 0.9.2", -] - [[package]] name = "secp256k1-sys" version = "0.6.1" @@ -2561,15 +2482,6 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-sys" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb" -dependencies = [ - "cc", -] - [[package]] name = "security-framework" version = "2.9.2" @@ -2659,21 +2571,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_with" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" -dependencies = [ - "base64 0.13.1", - "chrono", - "hex", - "serde", - "serde_json", - "serde_with_macros 2.3.3", - "time", -] - [[package]] name = "serde_with" version = "3.6.1" @@ -2688,22 +2585,10 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "serde_with_macros 3.6.1", + "serde_with_macros", "time", ] -[[package]] -name = "serde_with_macros" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "serde_with_macros" version = "3.6.1" @@ -3205,9 +3090,9 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "txoo" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67d7f813b11b656c950f66dd1ea293d147e2e2c3567d4246b3d682916dc19a5c" +checksum = "2d63e3a8a97175f205a3b101cb100568ce15e6b4e77d88207e9065da4a4e061e" dependencies = [ "bitcoin 0.29.2", "log", @@ -3304,9 +3189,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vls-core" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7465dd7f8cc004b67c52c6610ebf157695a93daf33f6a69c1b06b0f4e1fecbc0" +checksum = "1210aae1bc771b5ff39372466cf94ea23130a9d3ed0bbbafb6ee4443976de945" dependencies = [ "anyhow", "backtrace", @@ -3318,36 +3203,37 @@ dependencies = [ "hashbrown 0.8.2", "hex", "itertools", - "lightning 0.0.115", - "lightning-invoice 0.23.0", + "lightning", + "lightning-invoice", "log", "scopeguard", "serde", "serde_bolt 0.3.4", "serde_derive", - "serde_with 2.3.3", + "serde_with", "txoo", ] [[package]] name = "vls-persist" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86279e60e9dcdd3bcc135b7979655f1c80c6b99c38fee25d390725bfc5a24994" +checksum = "e8a9de079c84145fd4df1f826970d140f1a364fbd0f68f1944d16149988a3931" dependencies = [ "hex", "log", "serde", "serde_json", - "serde_with 2.3.3", + "serde_with", + "tempfile", "vls-core", ] [[package]] name = "vls-protocol" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55e525ef3cb95a27b240662fb518ea283d25b1f51afe899f0f253747acc284f4" +checksum = "e01ad8baa041296e8d715fd34d052d00ee5210038cc755e0f993c8c827935a85" dependencies = [ "as-any", "bitcoin-consensus-derive", @@ -3355,13 +3241,14 @@ dependencies = [ "hex", "log", "serde_bolt 0.3.4", + "txoo", ] [[package]] name = "vls-protocol-signer" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a766ac452520406eed1e7d8ad1c744156fc3ceaf6bdcefe3f3a44bd5f5ea0b29" +checksum = "a4435ed40d9bab3350f0caa305685bc3ac95e268e9c3b3f09bc08b002fac19ba" dependencies = [ "bit-vec", "log", diff --git a/snippets/rust/Cargo.toml b/snippets/rust/Cargo.toml index 71137fc4..fb1fcb30 100644 --- a/snippets/rust/Cargo.toml +++ b/snippets/rust/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] anyhow = "1" bip39 = { version = "2", features = ["rand"] } -breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.3.1" } +breez-sdk-core = { git = "https://github.com/breez/breez-sdk", branch = "main" } log = "0.4" tokio = "1.29" diff --git a/snippets/rust/src/send_onchain.rs b/snippets/rust/src/send_onchain.rs index 5377462e..7e0f1dd9 100644 --- a/snippets/rust/src/send_onchain.rs +++ b/snippets/rust/src/send_onchain.rs @@ -4,29 +4,13 @@ use anyhow::Result; use breez_sdk_core::*; use log::info; -async fn get_current_fees(sdk: Arc) -> Result<()> { - // ANCHOR: estimate-current-reverse-swap-total-fees - let current_fees = sdk - .fetch_reverse_swap_fees(ReverseSwapFeesRequest { - send_amount_sat: Some(50_000), - claim_tx_feerate: None, - }) - .await?; +async fn get_current_limits(sdk: Arc) -> Result<()> { + // ANCHOR: get-current-reverse-swap-limits + let current_limits = sdk.onchain_payment_limits().await?; - info!( - "Total estimated fees for reverse swap: {:?}", - current_fees.total_fees - ); - // ANCHOR_END: estimate-current-reverse-swap-total-fees - - Ok(()) -} - -async fn list_current_fees(current_fees: ReverseSwapPairInfo) -> Result<()> { - // ANCHOR: get-current-reverse-swap-min-max - info!("Minimum amount, in sats: {}", current_fees.min); - info!("Maximum amount, in sats: {}", current_fees.max); - // ANCHOR_END: get-current-reverse-swap-min-max + info!("Minimum amount, in sats: {}", current_limits.min_sat); + info!("Maximum amount, in sats: {}", current_limits.max_sat); + // ANCHOR_END: get-current-reverse-swap-limits Ok(()) } diff --git a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift index 0e106694..20513cc2 100644 --- a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift +++ b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift @@ -8,22 +8,15 @@ import BreezSDK import Foundation -func GetCurrentFees(sdk: BlockingBreezServices) -> ReverseSwapPairInfo? { - // ANCHOR: estimate-current-reverse-swap-total-fees - let sendAmountSat: UInt64 = 50_000 - let currentFees = try? sdk.fetchReverseSwapFees(req: ReverseSwapFeesRequest(sendAmountSat: sendAmountSat)) - print("Total estimated fees for reverse swap: \(String(describing: currentFees?.totalFees))") - // ANCHOR_END: estimate-current-reverse-swap-total-fees +func GetCurrentLimits(sdk: BlockingBreezServices) -> ReverseSwapPairInfo? { + // ANCHOR: get-current-reverse-swap-limits + let currentLimits = try? sdk.onchainPaymentLimits() + print("Minimum amount, in sats: \(currentLimits.minSat)") + print("Maximum amount, in sats: \(currentLimits.maxSat)") + // ANCHOR_END: get-current-reverse-swap-limits return currentFees } -func ListCurrentFees(currentFees: ReverseSwapPairInfo) { - // ANCHOR: get-current-reverse-swap-min-max - print("Minimum amount, in sats: \(currentFees.min)") - print("Maximum amount, in sats: \(currentFees.max)") - // ANCHOR_END: get-current-reverse-swap-min-max -} - func maxReverseSwapAmount(sdk: BlockingBreezServices) -> MaxReverseSwapAmountResponse? { // ANCHOR: max-reverse-swap-amount let maxAmount = try? sdk.maxReverseSwapAmount() diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index 3c654f2b..1c61f505 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -2,15 +2,15 @@ You can send funds from the Breez SDK wallet to an on-chain address as follows. -## Setting the fee -First, fetch the current reverse swap fees: +## Checking the limits +First, fetch the current reverse swap limits:
Rust
```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/rust/src/send_onchain.rs:get-current-reverse-swap-limits}} ```
@@ -18,7 +18,7 @@ First, fetch the current reverse swap fees:
```swift,ignore -{{#include ../../snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift:get-current-reverse-swap-limits}} ```
@@ -26,7 +26,7 @@ First, fetch the current reverse swap fees:
```kotlin,ignore -{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt:get-current-reverse-swap-limits}} ```
@@ -34,7 +34,7 @@ First, fetch the current reverse swap fees:
```typescript -{{#include ../../snippets/react-native/send_onchain.ts:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/react-native/send_onchain.ts:get-current-reverse-swap-limits}} ```
@@ -42,7 +42,7 @@ First, fetch the current reverse swap fees:
```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:get-current-reverse-swap-limits}} ```
@@ -50,7 +50,7 @@ First, fetch the current reverse swap fees:
```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/python/src/send_onchain.py:get-current-reverse-swap-limits}} ```
@@ -58,7 +58,7 @@ First, fetch the current reverse swap fees:
```go,ignore -{{#include ../../snippets/go/send_onchain.go:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/go/send_onchain.go:get-current-reverse-swap-limits}} ```
@@ -66,87 +66,20 @@ First, fetch the current reverse swap fees:
```cs,ignore -{{#include ../../snippets/csharp/SendOnchain.cs:estimate-current-reverse-swap-total-fees}} +{{#include ../../snippets/csharp/SendOnchain.cs:get-current-reverse-swap-limits}} ```
+This represents the range of valid amounts that can be sent at this point in time. The range may change depending on the wallet's liquidity, swap service parameters or mempool feerate fluctuations. +

Developer note

-The reverse swap will involve two on-chain transactions, for which the mining fees can only be estimated. They will happen -automatically once the process is started, but the last two values above are these estimates to help you get a picture -of the total costs. - -
- -Fetching the fees also tells you what is the range of amounts the service allows: - - -
Rust
-
- -```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:get-current-reverse-swap-min-max}} -``` -
-
Swift
-
+It is best to fetch these limits just before your app shows the Pay Onchain (reverse swap) UI. You can then use these limits to validate the user input. -```swift,ignore -{{#include ../../snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift:get-current-reverse-swap-min-max}} -``` -
- -
Kotlin
-
- -```kotlin,ignore -{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt:get-current-reverse-swap-min-max}} -``` -
- -
React Native
-
- -```typescript -{{#include ../../snippets/react-native/send_onchain.ts:get-current-reverse-swap-min-max}} -``` -
- -
Dart
-
- -```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:get-current-reverse-swap-min-max}} -``` -
- -
Python
-
- -```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:get-current-reverse-swap-min-max}} -``` -
- -
Go
-
- -```go,ignore -{{#include ../../snippets/go/send_onchain.go:get-current-reverse-swap-min-max}} -``` -
- -
C#
-
- -```cs,ignore -{{#include ../../snippets/csharp/SendOnchain.cs:get-current-reverse-swap-min-max}} -``` -
-
+ ## Sending all funds In case you want to drain your channels you need to know the maximum sendable amount to an on-chain address: From 0a1667986fbbfa114f61022191ecfa20d7137caa Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 13 Mar 2024 17:34:10 +0100 Subject: [PATCH 02/37] Adapt serviceHealthCheck usage --- .github/workflows/main.yml | 4 ++-- snippets/csharp/ServiceStatus.cs | 2 +- snippets/dart_snippets/lib/service_status.dart | 2 +- snippets/go/go.mod | 2 +- snippets/go/service_status.go | 2 +- snippets/kotlin_mpp_lib/shared/build.gradle.kts | 2 +- .../kotlin/com/example/kotlinmpplib/ServiceStatus.kt | 2 +- snippets/python/main.py | 2 +- snippets/python/src/service_status.py | 4 ++-- snippets/react-native/getting_started.ts | 9 ++++----- snippets/react-native/service_status.ts | 2 +- snippets/rust/Cargo.toml | 2 +- snippets/rust/src/service_status.rs | 4 +++- snippets/swift/BreezSDKExamples/Package.resolved | 4 ++-- snippets/swift/BreezSDKExamples/Package.swift | 2 +- .../swift/BreezSDKExamples/Sources/ServiceStatus.swift | 4 ++-- 16 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 76e1fc4b..2512a931 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,8 +25,8 @@ jobs: name: setup runs-on: ubuntu-latest outputs: - sdk-ref: ${{ inputs.sdk-ref || '474ac7d4b5d19633dc851439b9ff7e159286fbd8' }} - package-version: '0.3.1' + sdk-ref: ${{ inputs.sdk-ref || '16e70474937e3938563103adb463fb67c676415c' }} + package-version: '0.3.4' steps: - run: echo "set pre-setup output variables" diff --git a/snippets/csharp/ServiceStatus.cs b/snippets/csharp/ServiceStatus.cs index 70ab3c5e..d8e32a0e 100644 --- a/snippets/csharp/ServiceStatus.cs +++ b/snippets/csharp/ServiceStatus.cs @@ -7,7 +7,7 @@ public void HealthCheckStatus(BlockingBreezServices sdk) // ANCHOR: health-check-status try { - var healthCheck = sdk.ServiceHealthCheck(); + var healthCheck = BreezSdkMethods.ServiceHealthCheck(""); Console.WriteLine($"Current service status is: {healthCheck.status}"); } catch (Exception) diff --git a/snippets/dart_snippets/lib/service_status.dart b/snippets/dart_snippets/lib/service_status.dart index 7c32cf85..46d4ee29 100644 --- a/snippets/dart_snippets/lib/service_status.dart +++ b/snippets/dart_snippets/lib/service_status.dart @@ -3,7 +3,7 @@ import 'package:breez_sdk/bridge_generated.dart'; Future healthCheckStatus() async { // ANCHOR: health-check-status - ServiceHealthCheckResponse healthCheck = await BreezSDK().serviceHealthCheck(); + ServiceHealthCheckResponse healthCheck = await BreezSDK().serviceHealthCheck(""); print("Current service status is: ${healthCheck.status}"); // ANCHOR_END: health-check-status } diff --git a/snippets/go/go.mod b/snippets/go/go.mod index 6e80afd6..16b47bdc 100644 --- a/snippets/go/go.mod +++ b/snippets/go/go.mod @@ -2,6 +2,6 @@ module main go 1.19 -require github.com/breez/breez-sdk-go v0.3.1 +require github.com/breez/breez-sdk-go v0.3.4 replace github.com/breez/breez-sdk-go => ./packages/breez-sdk-go diff --git a/snippets/go/service_status.go b/snippets/go/service_status.go index 1d41408a..8b4a82c5 100644 --- a/snippets/go/service_status.go +++ b/snippets/go/service_status.go @@ -8,7 +8,7 @@ import ( func HealthCheckStatus() { // ANCHOR: health-check-status - if healthCheck, err := sdk.ServiceHealthCheck(); err != nil { + if healthCheck, err := breez_sdk.ServiceHealthCheck(""); err != nil { log.Printf("Current service status is: %v", healthCheck.Status) } // ANCHOR_END: health-check-status diff --git a/snippets/kotlin_mpp_lib/shared/build.gradle.kts b/snippets/kotlin_mpp_lib/shared/build.gradle.kts index 8a4a4c48..1c77626b 100644 --- a/snippets/kotlin_mpp_lib/shared/build.gradle.kts +++ b/snippets/kotlin_mpp_lib/shared/build.gradle.kts @@ -34,7 +34,7 @@ kotlin { } val commonMain by getting { dependencies { - implementation("technology.breez:breez-sdk-kmp:0.3.1") + implementation("technology.breez:breez-sdk-kmp:0.3.4") } } } diff --git a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/ServiceStatus.kt b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/ServiceStatus.kt index 1ed5f33d..896317db 100644 --- a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/ServiceStatus.kt +++ b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/ServiceStatus.kt @@ -5,7 +5,7 @@ class ServiceStatus { fun HealthCheckStatus(sdk: BlockingBreezServices) { // ANCHOR: health-check-status try { - val healthCheck = sdk.serviceHealthCheck() + val healthCheck = serviceHealthCheck("") // Log.v("Breez", "Current service status is: ${healthCheck.status}") } catch (e: Exception) { // Handle error diff --git a/snippets/python/main.py b/snippets/python/main.py index 50036a7a..d85c99fb 100755 --- a/snippets/python/main.py +++ b/snippets/python/main.py @@ -92,7 +92,7 @@ def main(): production_node_config() # service status - health_check_status(sdk_services) + health_check_status() report_payment_failure(sdk_services) # use temp_dir, and remove when done: diff --git a/snippets/python/src/service_status.py b/snippets/python/src/service_status.py index 18e11870..9f12f8be 100644 --- a/snippets/python/src/service_status.py +++ b/snippets/python/src/service_status.py @@ -1,9 +1,9 @@ import breez_sdk -def health_check_status(sdk_services): +def health_check_status(): try: # ANCHOR: health-check-status - health_check = sdk_services.service_health_check() + health_check = breez_sdk.service_health_check("") print("Current service status is: ", health_check.status) # ANCHOR_END: health-check-status except Exception as error: diff --git a/snippets/react-native/getting_started.ts b/snippets/react-native/getting_started.ts index 05ac853a..9c2f2690 100644 --- a/snippets/react-native/getting_started.ts +++ b/snippets/react-native/getting_started.ts @@ -44,12 +44,11 @@ const exampleGettingStarted = async () => { } // ANCHOR_END: init-sdk } - -const onBreezEvent = (e: BreezEvent) => { - console.log(`Received event ${e.type}`) -} - const exampleGettingRestoreOnly = async (config: Config, seed: number[]) => { + const onBreezEvent = (e: BreezEvent) => { + console.log(`Received event ${e.type}`) + } + try { // ANCHOR: init-sdk-restore-only const connectRequest: ConnectRequest = { config, seed, restoreOnly: true } diff --git a/snippets/react-native/service_status.ts b/snippets/react-native/service_status.ts index d52c592c..e63df583 100644 --- a/snippets/react-native/service_status.ts +++ b/snippets/react-native/service_status.ts @@ -3,7 +3,7 @@ import { serviceHealthCheck, reportIssue, ReportIssueRequestVariant } from '@bre const healthCheckStatus = async () => { // ANCHOR: health-check-status try { - const healthCheck = await serviceHealthCheck() + const healthCheck = await serviceHealthCheck('') console.log(`Current service status is: ${healthCheck.status}`) } catch (err) { console.error(err) diff --git a/snippets/rust/Cargo.toml b/snippets/rust/Cargo.toml index 71137fc4..2fdc652b 100644 --- a/snippets/rust/Cargo.toml +++ b/snippets/rust/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] anyhow = "1" bip39 = { version = "2", features = ["rand"] } -breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.3.1" } +breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.3.4" } log = "0.4" tokio = "1.29" diff --git a/snippets/rust/src/service_status.rs b/snippets/rust/src/service_status.rs index afe6eb58..698b4db6 100644 --- a/snippets/rust/src/service_status.rs +++ b/snippets/rust/src/service_status.rs @@ -6,7 +6,9 @@ use log::info; async fn health_check_status(sdk: Arc) -> Result<()> { // ANCHOR: health-check-status - let health_check = sdk.service_health_check().await?; + let api_key = "".into(); + + let health_check = BreezServices::service_health_check(api_key).await?; info!("Current service status is: {:?}", health_check.status); // ANCHOR_END: health-check-status diff --git a/snippets/swift/BreezSDKExamples/Package.resolved b/snippets/swift/BreezSDKExamples/Package.resolved index bad77204..73ef99b2 100644 --- a/snippets/swift/BreezSDKExamples/Package.resolved +++ b/snippets/swift/BreezSDKExamples/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/breez/breez-sdk-swift", "state" : { - "revision" : "a1b7c9065c2803d86d736850969dfe9fdbdde5b0", - "version" : "0.3.1" + "revision" : "eb6628730c88dc391ec62fb5a816686c51ad530f", + "version" : "0.3.4" } }, { diff --git a/snippets/swift/BreezSDKExamples/Package.swift b/snippets/swift/BreezSDKExamples/Package.swift index 43d177f7..b339ad1e 100644 --- a/snippets/swift/BreezSDKExamples/Package.swift +++ b/snippets/swift/BreezSDKExamples/Package.swift @@ -8,7 +8,7 @@ let package = Package( platforms: [.macOS(.v13)], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.3"), - .package(url: "https://github.com/breez/breez-sdk-swift", from:"0.3.1") + .package(url: "https://github.com/breez/breez-sdk-swift", from:"0.3.4") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/snippets/swift/BreezSDKExamples/Sources/ServiceStatus.swift b/snippets/swift/BreezSDKExamples/Sources/ServiceStatus.swift index 7edeec72..ab30a845 100644 --- a/snippets/swift/BreezSDKExamples/Sources/ServiceStatus.swift +++ b/snippets/swift/BreezSDKExamples/Sources/ServiceStatus.swift @@ -8,9 +8,9 @@ import BreezSDK import Foundation -func getServiceStatus(sdk: BlockingBreezServices) { +func getServiceStatus() { // ANCHOR: health-check-status - if let healthCheck = try? sdk.serviceHealthCheck() { + if let healthCheck = try? serviceHealthCheck("") { print("Current service status is: \(healthCheck.status)") } // ANCHOR_END: health-check-status From 939b5437eeb40d0934d9f8a53b0c30892dface11 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 13 Mar 2024 18:25:37 +0100 Subject: [PATCH 03/37] Fix dart snippet --- snippets/dart_snippets/lib/service_status.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snippets/dart_snippets/lib/service_status.dart b/snippets/dart_snippets/lib/service_status.dart index 46d4ee29..950c7de0 100644 --- a/snippets/dart_snippets/lib/service_status.dart +++ b/snippets/dart_snippets/lib/service_status.dart @@ -3,7 +3,7 @@ import 'package:breez_sdk/bridge_generated.dart'; Future healthCheckStatus() async { // ANCHOR: health-check-status - ServiceHealthCheckResponse healthCheck = await BreezSDK().serviceHealthCheck(""); + ServiceHealthCheckResponse healthCheck = await BreezSDK().serviceHealthCheck(apiKey: ""); print("Current service status is: ${healthCheck.status}"); // ANCHOR_END: health-check-status } From d92f5e14e88e12a912f035d418526e90ec969981 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 13 Mar 2024 20:27:49 +0100 Subject: [PATCH 04/37] Fix RN snippet --- snippets/react-native/getting_started.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snippets/react-native/getting_started.ts b/snippets/react-native/getting_started.ts index 9c2f2690..97f2d137 100644 --- a/snippets/react-native/getting_started.ts +++ b/snippets/react-native/getting_started.ts @@ -44,11 +44,12 @@ const exampleGettingStarted = async () => { } // ANCHOR_END: init-sdk } + const exampleGettingRestoreOnly = async (config: Config, seed: number[]) => { const onBreezEvent = (e: BreezEvent) => { console.log(`Received event ${e.type}`) } - + try { // ANCHOR: init-sdk-restore-only const connectRequest: ConnectRequest = { config, seed, restoreOnly: true } From 3bbb393ca0caf15a81df513147ec89d16724bafc Mon Sep 17 00:00:00 2001 From: ok300 <106775972+ok300@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:58:39 +0000 Subject: [PATCH 05/37] Add `prepareOnchainPayment` snippets (#141) Add prepareOnchainPayment snippets --- snippets/csharp/SendOnchain.cs | 25 ++++++ snippets/dart_snippets/lib/send_onchain.dart | 18 +++++ snippets/go/send_onchain.go | 19 +++++ .../com/example/kotlinmpplib/SendOnchain.kt | 16 ++++ snippets/python/src/send_onchain.py | 16 ++++ snippets/react-native/send_onchain.ts | 23 ++++++ snippets/rust/src/send_onchain.rs | 29 ++++++- .../Sources/SendOnchain.swift | 15 ++++ src/guide/send_onchain.md | 79 +++++++++++++++++++ 9 files changed, 238 insertions(+), 2 deletions(-) diff --git a/snippets/csharp/SendOnchain.cs b/snippets/csharp/SendOnchain.cs index 86b53dae..34e5a618 100644 --- a/snippets/csharp/SendOnchain.cs +++ b/snippets/csharp/SendOnchain.cs @@ -34,6 +34,31 @@ public void MaxReverseSwapAmount(BlockingBreezServices sdk) // ANCHOR_END: max-reverse-swap-amount } + public void PreparePayOnchain(BlockingBreezServices sdk, OnchainPaymentLimitsResponse currentLimits, uint feeRate) + { + // ANCHOR: prepare-pay-onchain + var amountSat = currentLimits.minSat; + var claimTxFeerate = feeRate; + + try + { + var resp = sdk.PrepareOnchainPayment( + new PrepareOnchainPaymentRequest( + amountSat, + SwapAmountType.SEND, + claimTxFeerate)); + + Console.WriteLine($"Sender amount, in sats: {resp.senderAmountSat}"); + Console.WriteLine($"Recipient amount, in sats: {resp.recipientAmountSat}"); + Console.WriteLine($"Total fees, in sats: {resp.totalFees}"); + } + catch (Exception) + { + // Handle error + } + // ANCHOR_END: prepare-pay-onchain + } + public void StartReverseSwap(BlockingBreezServices sdk, ReverseSwapPairInfo currentFees, uint feeRate) { // ANCHOR: start-reverse-swap diff --git a/snippets/dart_snippets/lib/send_onchain.dart b/snippets/dart_snippets/lib/send_onchain.dart index da95b7f0..61804eb9 100644 --- a/snippets/dart_snippets/lib/send_onchain.dart +++ b/snippets/dart_snippets/lib/send_onchain.dart @@ -18,6 +18,24 @@ Future maxReverseSwapAmount() async { return maxAmount; } +Future preparePayOnchain({ + required int amountSat, + required int satPerVbyte, +}) async { + // ANCHOR: prepare-pay-onchain + PrepareOnchainPaymentRequest req = PrepareOnchainPaymentRequest( + amountSat: amountSat, + amountType: SwapAmountType.Send, + claimTxFeerate: satPerVbyte, + ); + PrepareOnchainPaymentResponse resp = await BreezSDK().prepareOnchainPayment(req: req); + print("Sender amount: ${resp.senderAmountSat} sats"); + print("Recipient amount: ${resp.recipientAmountSat} sats"); + print("Total fees: ${resp.totalFees} sats"); + // ANCHOR_END: prepare-pay-onchain + return resp; +} + Future startReverseSwap({ required int amountSat, required String onchainRecipientAddress, diff --git a/snippets/go/send_onchain.go b/snippets/go/send_onchain.go index 81030ca3..090cd545 100644 --- a/snippets/go/send_onchain.go +++ b/snippets/go/send_onchain.go @@ -23,6 +23,25 @@ func MaxReverseSwapAmount() { // ANCHOR_END: max-reverse-swap-amount } +func PreparePayOnchain(currentLimits breez_sdk.OnchainPaymentLimitsResponse) { + // ANCHOR: prepare-pay-onchain + sendAmountSat := currentLimits.MinSat + satPerVbyte := uint32(10) + + req := breez_sdk.PrepareOnchainPaymentRequest{ + AmountSat: sendAmountSat, + AmountType: breez_sdk.SwapAmountTypeSend, + ClaimTxFeerate: satPerVbyte, + } + + if prepareResp, err := sdk.PrepareOnchainPayment(req); err == nil { + log.Printf("Sender amount, in sats: %v", prepareResp.SenderAmountSat) + log.Printf("Recipient amount, in sats: %v", prepareResp.RecipientAmountSat) + log.Printf("Total fees, in sats: %v", prepareResp.TotalFees) + } + // ANCHOR_END: prepare-pay-onchain +} + func StartReverseSwap() { // ANCHOR: start-reverse-swap destinationAddress := "bc1.." diff --git a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt index fcbf4988..de4de38e 100644 --- a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt +++ b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt @@ -25,6 +25,22 @@ class SendOnchain { // ANCHOR_END: max-reverse-swap-amount } + fun prepare_pay_onchain(sdk: BlockingBreezServices, currentLimits: OnchainPaymentLimitsResponse) { + // ANCHOR: prepare-pay-onchain + val amountSat = currentLimits.minSat + val satPerVbyte = 10.toUInt() + try { + val prepareRequest = PrepareOnchainPaymentRequest(amountSat, SwapAmountType.SEND, satPerVbyte) + val prepareRes = sdk.prepareOnchainPayment(prepareRequest) + // Log.v("Breez", "Sender amount: ${prepareRes.senderAmountSat} sats") + // Log.v("Breez", "Recipient amount: ${prepareRes.recipientAmountSat} sats") + // Log.v("Breez", "Total fees: ${prepareRes.totalFees} sats") + } catch (e: Exception) { + // handle error + } + // ANCHOR_END: prepare-pay-onchain + } + fun start_reverse_swap(sdk: BlockingBreezServices, fees: ReverseSwapPairInfo) { // ANCHOR: start-reverse-swap val address = "bc1.." diff --git a/snippets/python/src/send_onchain.py b/snippets/python/src/send_onchain.py index b77c6754..508a7247 100644 --- a/snippets/python/src/send_onchain.py +++ b/snippets/python/src/send_onchain.py @@ -23,6 +23,22 @@ def max_reverse_swap_amount(sdk_services): print(error) raise +def prepare_pay_onchain(sdk_services, current_limits, fee_rate): + amount_sat = current_limits.min_sat + claim_tx_feerate = fee_rate + try: + # ANCHOR: prepare-pay-onchain + req = breez_sdk.PrepareOnchainPaymentRequest(amount_sat, breez_sdk.SwapAmountType.SEND, claim_tx_feerate) + resp = sdk_services.prepare_onchain_payment(req) + + print("Sender amount, in sats: ", resp.sender_amount_sat) + print("Recipient amount, in sats: ", resp.recipient_amount_sat) + print("Total fees, in sats: ", resp.total_fees) + # ANCHOR_END: prepare-pay-onchain + except Exception as error: + print(error) + raise + def start_reverse_swap(sdk_services, current_fees,fee_rate): # ANCHOR: start-reverse-swap destination_address = "bc1.." diff --git a/snippets/react-native/send_onchain.ts b/snippets/react-native/send_onchain.ts index d997f905..156e1087 100644 --- a/snippets/react-native/send_onchain.ts +++ b/snippets/react-native/send_onchain.ts @@ -1,9 +1,12 @@ import { type ReverseSwapPairInfo, + type OnchainPaymentLimitsResponse, fetchReverseSwapFees, inProgressReverseSwaps, onchainPaymentLimits, + prepareOnchainPayment, sendOnchain, + SwapAmountType, maxReverseSwapAmount } from '@breeztech/react-native-breez-sdk' @@ -34,6 +37,26 @@ const maxAmount = async () => { // ANCHOR_END: max-reverse-swap-amount } +const examplePreparePayOnchain = async (currentLimits: OnchainPaymentLimitsResponse) => { + // ANCHOR: prepare-pay-onchain + try { + const amountSat = currentLimits.minSat + const satPerVbyte = 10 + + const prepareResponse = await prepareOnchainPayment({ + amountSat, + amountType: SwapAmountType.SEND, + claimTxFeerate: satPerVbyte + }) + console.log(`Sender amount: ${prepareResponse.senderAmountSat} sats`) + console.log(`Recipient amount: ${prepareResponse.recipientAmountSat} sats`) + console.log(`Total fees: ${prepareResponse.totalFees} sats`) + } catch (err) { + console.error(err) + } + // ANCHOR_END: prepare-pay-onchain +} + const exampleSendOnchain = async (currentFees: ReverseSwapPairInfo) => { // ANCHOR: start-reverse-swap try { diff --git a/snippets/rust/src/send_onchain.rs b/snippets/rust/src/send_onchain.rs index 7e0f1dd9..606f17c7 100644 --- a/snippets/rust/src/send_onchain.rs +++ b/snippets/rust/src/send_onchain.rs @@ -8,8 +8,8 @@ async fn get_current_limits(sdk: Arc) -> Result<()> { // ANCHOR: get-current-reverse-swap-limits let current_limits = sdk.onchain_payment_limits().await?; - info!("Minimum amount, in sats: {}", current_limits.min_sat); - info!("Maximum amount, in sats: {}", current_limits.max_sat); + info!("Minimum amount: {} sats", current_limits.min_sat); + info!("Maximum amount: {} sats", current_limits.max_sat); // ANCHOR_END: get-current-reverse-swap-limits Ok(()) @@ -25,6 +25,31 @@ async fn max_reverse_swap_amount(sdk: Arc) -> Result<()> { Ok(()) } +async fn prepare_pay_onchain( + sdk: Arc, + current_limits: OnchainPaymentLimitsResponse, + fee_rate: u32, +) -> Result<()> { + // ANCHOR: prepare-pay-onchain + let amount_sat = current_limits.min_sat; + let claim_tx_feerate = fee_rate; + + let prepare_res = sdk + .prepare_onchain_payment(PrepareOnchainPaymentRequest { + amount_sat, + amount_type: SwapAmountType::Send, + claim_tx_feerate, + }) + .await?; + + info!("Sender amount: {} sats", prepare_res.sender_amount_sat); + info!("Recipient amount: {} sats", prepare_res.recipient_amount_sat); + info!("Total fees: {} sats", prepare_res.total_fees); + // ANCHOR_END: prepare-pay-onchain + + Ok(()) +} + async fn start_reverse_swap( sdk: Arc, current_fees: ReverseSwapPairInfo, diff --git a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift index 20513cc2..ff7ee873 100644 --- a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift +++ b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift @@ -25,6 +25,21 @@ func maxReverseSwapAmount(sdk: BlockingBreezServices) -> MaxReverseSwapAmountRes return maxAmount } +func PreparePayOnchain(sdk: BlockingBreezServices, currentLimits: OnchainPaymentLimitsResponse) -> PrepareOnchainPaymentResponse? { + // ANCHOR: prepare-pay-onchain + let amountSat = currentLimits.minSat + let satPerVbyte: UInt32 = 5 + + let prepareRequest = PrepareOnchainPaymentRequest(amountSat: amountSat, amountType: .send, claimTxFeerate: satPerVbyte); + let prepareResponse = try? sdk.prepareOnchainPayment(req: prepareRequest) + + print("Sender amount, in sats: \(prepareResponse.senderAmountSat)") + print("Recipient amount, in sats: \(prepareResponse.recipientAmountSat)") + print("Total fees, in sats: \(prepareResponse.totalFees)") + // ANCHOR_END: prepare-pay-onchain + return prepareResponse +} + func StartReverseSwap(sdk: BlockingBreezServices, currentFees: ReverseSwapPairInfo) -> SendOnchainResponse? { // ANCHOR: start-reverse-swap let destinationAddress = "bc1.." diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index 1c61f505..b8e00ffb 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -81,6 +81,85 @@ It is best to fetch these limits just before your app shows the Pay Onchain (rev +## Preparing to send, checking fees +The next step is to get an overview of the exact amount that will be sent, the amount that will be received, and the fees. + +There are two ways to do this: +- you can set the sender amount, then the recipient amount will be your input minus the fees +- you can set the recipient amount, in which case the sender amount will be your input plus the fees + +Assuming you'd like to specify the sender amount, the snippet is as follows: + + +
Rust
+
+ +```rust,ignore +{{#include ../../snippets/rust/src/send_onchain.rs:prepare-pay-onchain}} +``` +
+ +
Swift
+
+ +```swift,ignore +{{#include ../../snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift:prepare-pay-onchain}} +``` +
+ +
Kotlin
+
+ +```kotlin,ignore +{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt:prepare-pay-onchain}} +``` +
+ +
React Native
+
+ +```typescript +{{#include ../../snippets/react-native/send_onchain.ts:prepare-pay-onchain}} +``` +
+ +
Dart
+
+ +```dart,ignore +{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:prepare-pay-onchain}} +``` +
+ +
Python
+
+ +```python,ignore +{{#include ../../snippets/python/src/send_onchain.py:prepare-pay-onchain}} +``` +
+ +
Go
+
+ +```go,ignore +{{#include ../../snippets/go/send_onchain.go:prepare-pay-onchain}} +``` +
+ +
C#
+
+ +```cs,ignore +{{#include ../../snippets/csharp/SendOnchain.cs:prepare-pay-onchain}} +``` +
+
+ +If instead you'd like to specify the recipient amount, simply change the `SwapAmountType` from `Send` to `Receive`. + +Once you checked the amounts and the fees are acceptable, you can continue with sending the payment. + ## Sending all funds In case you want to drain your channels you need to know the maximum sendable amount to an on-chain address: From 088678777264f7040b20fe06a89bbbfc1d08b310 Mon Sep 17 00:00:00 2001 From: ok300 <106775972+ok300@users.noreply.github.com> Date: Fri, 15 Mar 2024 09:40:45 +0000 Subject: [PATCH 06/37] Consolidate send-all snippet (#142) --- snippets/csharp/SendOnchain.cs | 16 ----- snippets/dart_snippets/lib/send_onchain.dart | 8 --- snippets/go/send_onchain.go | 8 --- .../com/example/kotlinmpplib/SendOnchain.kt | 11 --- snippets/python/src/send_onchain.py | 11 --- snippets/react-native/send_onchain.ts | 14 ---- snippets/rust/src/send_onchain.rs | 10 --- .../Sources/SendOnchain.swift | 8 --- src/guide/send_onchain.md | 70 +------------------ 9 files changed, 2 insertions(+), 154 deletions(-) diff --git a/snippets/csharp/SendOnchain.cs b/snippets/csharp/SendOnchain.cs index 34e5a618..2afdc3f4 100644 --- a/snippets/csharp/SendOnchain.cs +++ b/snippets/csharp/SendOnchain.cs @@ -18,22 +18,6 @@ public void GetCurrentLimits(BlockingBreezServices sdk) // ANCHOR_END: get-current-reverse-swap-limits } - public void MaxReverseSwapAmount(BlockingBreezServices sdk) - { - // ANCHOR: max-reverse-swap-amount - try - { - var maxAmountResponse = sdk.MaxReverseSwapAmount(); - Console.WriteLine( - $"Max reverse swap amount {maxAmountResponse.totalSat}"); - } - catch (Exception) - { - // Handle error - } - // ANCHOR_END: max-reverse-swap-amount - } - public void PreparePayOnchain(BlockingBreezServices sdk, OnchainPaymentLimitsResponse currentLimits, uint feeRate) { // ANCHOR: prepare-pay-onchain diff --git a/snippets/dart_snippets/lib/send_onchain.dart b/snippets/dart_snippets/lib/send_onchain.dart index 61804eb9..cf0c3a92 100644 --- a/snippets/dart_snippets/lib/send_onchain.dart +++ b/snippets/dart_snippets/lib/send_onchain.dart @@ -10,14 +10,6 @@ Future getCurrentLimits() async { return currentLimits; } -Future maxReverseSwapAmount() async { - // ANCHOR: max-reverse-swap-amount - MaxReverseSwapAmountResponse maxAmount = await BreezSDK().maxReverseSwapAmount(); - print("Max reverse swap amount: ${maxAmount.totalSat}"); - // ANCHOR_END: max-reverse-swap-amount - return maxAmount; -} - Future preparePayOnchain({ required int amountSat, required int satPerVbyte, diff --git a/snippets/go/send_onchain.go b/snippets/go/send_onchain.go index 090cd545..c294e25a 100644 --- a/snippets/go/send_onchain.go +++ b/snippets/go/send_onchain.go @@ -15,14 +15,6 @@ func GetCurrentLimits() { // ANCHOR_END: get-current-reverse-swap-limits } -func MaxReverseSwapAmount() { - // ANCHOR: max-reverse-swap-amount - if maxAmount, err := sdk.MaxReverseSwapAmount(); err == nil { - log.Printf("Max reverse swap amount: %v", maxAmount.TotalSat) - } - // ANCHOR_END: max-reverse-swap-amount -} - func PreparePayOnchain(currentLimits breez_sdk.OnchainPaymentLimitsResponse) { // ANCHOR: prepare-pay-onchain sendAmountSat := currentLimits.MinSat diff --git a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt index de4de38e..65cac079 100644 --- a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt +++ b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt @@ -14,17 +14,6 @@ class SendOnchain { // ANCHOR_END: get-current-reverse-swap-limits } - fun max_reverse_swap_amount(sdk: BlockingBreezServices) { - // ANCHOR: max-reverse-swap-amount - try { - val maxAmount = sdk.maxReverseSwapAmount() - // Log.v("Breez", "Max reverse swap amount: ${maxAmount.totalSat}") - } catch (e: Exception) { - // handle error - } - // ANCHOR_END: max-reverse-swap-amount - } - fun prepare_pay_onchain(sdk: BlockingBreezServices, currentLimits: OnchainPaymentLimitsResponse) { // ANCHOR: prepare-pay-onchain val amountSat = currentLimits.minSat diff --git a/snippets/python/src/send_onchain.py b/snippets/python/src/send_onchain.py index 508a7247..c7ff4859 100644 --- a/snippets/python/src/send_onchain.py +++ b/snippets/python/src/send_onchain.py @@ -12,17 +12,6 @@ def get_current_limits(sdk_services): print(error) raise -def max_reverse_swap_amount(sdk_services): - try: - # ANCHOR: max-reverse-swap-amount - max_amount = sdk_services.max_reverse_swap_amount() - print("Max reverse swap amount: ", max_amount.totalSat) - # ANCHOR_END: max-reverse-swap-amount - return max_amount - except Exception as error: - print(error) - raise - def prepare_pay_onchain(sdk_services, current_limits, fee_rate): amount_sat = current_limits.min_sat claim_tx_feerate = fee_rate diff --git a/snippets/react-native/send_onchain.ts b/snippets/react-native/send_onchain.ts index 156e1087..96abbfc0 100644 --- a/snippets/react-native/send_onchain.ts +++ b/snippets/react-native/send_onchain.ts @@ -23,20 +23,6 @@ const exampleFetchReverseSwapLimits = async () => { // ANCHOR_END: get-current-reverse-swap-limits } -const maxAmount = async () => { - // ANCHOR: max-reverse-swap-amount - try { - const maxAmount = await maxReverseSwapAmount() - - console.log( - `Max reverse swap amount: ${maxAmount.totalSat}` - ) - } catch (err) { - console.error(err) - } - // ANCHOR_END: max-reverse-swap-amount -} - const examplePreparePayOnchain = async (currentLimits: OnchainPaymentLimitsResponse) => { // ANCHOR: prepare-pay-onchain try { diff --git a/snippets/rust/src/send_onchain.rs b/snippets/rust/src/send_onchain.rs index 606f17c7..41dde37d 100644 --- a/snippets/rust/src/send_onchain.rs +++ b/snippets/rust/src/send_onchain.rs @@ -15,16 +15,6 @@ async fn get_current_limits(sdk: Arc) -> Result<()> { Ok(()) } -async fn max_reverse_swap_amount(sdk: Arc) -> Result<()> { - // ANCHOR: max-reverse-swap-amount - let max_amount = sdk.max_reverse_swap_amount().await?; - - info!("Max reverse swap amount: {:?}", max_amount.total_sat); - // ANCHOR_END: max-reverse-swap-amount - - Ok(()) -} - async fn prepare_pay_onchain( sdk: Arc, current_limits: OnchainPaymentLimitsResponse, diff --git a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift index ff7ee873..a0faba39 100644 --- a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift +++ b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift @@ -17,14 +17,6 @@ func GetCurrentLimits(sdk: BlockingBreezServices) -> ReverseSwapPairInfo? { return currentFees } -func maxReverseSwapAmount(sdk: BlockingBreezServices) -> MaxReverseSwapAmountResponse? { - // ANCHOR: max-reverse-swap-amount - let maxAmount = try? sdk.maxReverseSwapAmount() - print("Max reverse swap amount: \(String(describing: maxAmount?.totalSat))") - // ANCHOR_END: max-reverse-swap-amount - return maxAmount -} - func PreparePayOnchain(sdk: BlockingBreezServices, currentLimits: OnchainPaymentLimitsResponse) -> PrepareOnchainPaymentResponse? { // ANCHOR: prepare-pay-onchain let amountSat = currentLimits.minSat diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index b8e00ffb..2a0e8acb 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -158,76 +158,10 @@ Assuming you'd like to specify the sender amount, the snippet is as follows: If instead you'd like to specify the recipient amount, simply change the `SwapAmountType` from `Send` to `Receive`. -Once you checked the amounts and the fees are acceptable, you can continue with sending the payment. - -## Sending all funds -In case you want to drain your channels you need to know the maximum sendable amount to an on-chain address: - - -
Rust
-
- -```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:max-reverse-swap-amount}} -``` -
- -
Swift
-
- -```swift,ignore -{{#include ../../snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift:max-reverse-swap-amount}} -``` -
- -
Kotlin
-
+In case you want to drain your channels and send the maximum amount possible, you can use the above snippet with `amount_sat` set to `current_limits.max_sat` and `amount_type` as `Send`. -```kotlin,ignore -{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt:max-reverse-swap-amount}} -``` -
- -
React Native
-
- -```typescript -{{#include ../../snippets/react-native/send_onchain.ts:max-reverse-swap-amount}} -``` -
- -
Dart
-
- -```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:max-reverse-swap-amount}} -``` -
- -
Python
-
- -```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:max-reverse-swap-amount}} -``` -
- -
Go
-
- -```go,ignore -{{#include ../../snippets/go/send_onchain.go:max-reverse-swap-amount}} -``` -
- -
C#
-
+Once you checked the amounts and the fees are acceptable, you can continue with sending the payment. -```cs,ignore -{{#include ../../snippets/csharp/SendOnchain.cs:max-reverse-swap-amount}} -``` -
-
## Executing the Swap From 3c655c1459c5e67d9edc66268ebbbd4ef21c5c7e Mon Sep 17 00:00:00 2001 From: ok300 <106775972+ok300@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:06:52 +0000 Subject: [PATCH 07/37] Replace `send_onchain` snippets with `pay_onchain` (#144) Replace send_onchain snippets with pay_onchain --- snippets/csharp/SendOnchain.cs | 20 +++++-------- snippets/dart_snippets/lib/send_onchain.dart | 28 ++++++++--------- snippets/go/send_onchain.go | 30 ++++++++----------- .../com/example/kotlinmpplib/SendOnchain.kt | 6 ++-- snippets/python/src/send_onchain.py | 18 +++++------ snippets/react-native/send_onchain.ts | 16 ++++------ snippets/rust/src/send_onchain.rs | 18 +++++------ .../Sources/SendOnchain.swift | 6 ++-- src/guide/send_onchain.md | 12 ++++---- 9 files changed, 64 insertions(+), 90 deletions(-) diff --git a/snippets/csharp/SendOnchain.cs b/snippets/csharp/SendOnchain.cs index 2afdc3f4..bb23dee8 100644 --- a/snippets/csharp/SendOnchain.cs +++ b/snippets/csharp/SendOnchain.cs @@ -26,15 +26,15 @@ public void PreparePayOnchain(BlockingBreezServices sdk, OnchainPaymentLimitsRes try { - var resp = sdk.PrepareOnchainPayment( + var prepareRes = sdk.PrepareOnchainPayment( new PrepareOnchainPaymentRequest( amountSat, SwapAmountType.SEND, claimTxFeerate)); - Console.WriteLine($"Sender amount, in sats: {resp.senderAmountSat}"); - Console.WriteLine($"Recipient amount, in sats: {resp.recipientAmountSat}"); - Console.WriteLine($"Total fees, in sats: {resp.totalFees}"); + Console.WriteLine($"Sender amount, in sats: {prepareRes.senderAmountSat}"); + Console.WriteLine($"Recipient amount, in sats: {prepareRes.recipientAmountSat}"); + Console.WriteLine($"Total fees, in sats: {prepareRes.totalFees}"); } catch (Exception) { @@ -43,20 +43,14 @@ public void PreparePayOnchain(BlockingBreezServices sdk, OnchainPaymentLimitsRes // ANCHOR_END: prepare-pay-onchain } - public void StartReverseSwap(BlockingBreezServices sdk, ReverseSwapPairInfo currentFees, uint feeRate) + public void StartReverseSwap(BlockingBreezServices sdk, PrepareOnchainPaymentResponse prepareRes) { // ANCHOR: start-reverse-swap var destinationAddress = "bc1.."; - var amountSat = currentFees.min; - var satPerVbyte = feeRate; try { - var reverseSwapInfo = sdk.SendOnchain( - new SendOnchainRequest( - amountSat, - destinationAddress, - currentFees.feesHash, - satPerVbyte)); + var reverseSwapInfo = sdk.PayOnchain( + new PayOnchainRequest(destinationAddress, prepareRes)); } catch (Exception) { diff --git a/snippets/dart_snippets/lib/send_onchain.dart b/snippets/dart_snippets/lib/send_onchain.dart index cf0c3a92..c6536732 100644 --- a/snippets/dart_snippets/lib/send_onchain.dart +++ b/snippets/dart_snippets/lib/send_onchain.dart @@ -20,30 +20,26 @@ Future preparePayOnchain({ amountType: SwapAmountType.Send, claimTxFeerate: satPerVbyte, ); - PrepareOnchainPaymentResponse resp = await BreezSDK().prepareOnchainPayment(req: req); - print("Sender amount: ${resp.senderAmountSat} sats"); - print("Recipient amount: ${resp.recipientAmountSat} sats"); - print("Total fees: ${resp.totalFees} sats"); + PrepareOnchainPaymentResponse prepareRes = await BreezSDK().prepareOnchainPayment(req: req); + print("Sender amount: ${prepareRes.senderAmountSat} sats"); + print("Recipient amount: ${prepareRes.recipientAmountSat} sats"); + print("Total fees: ${prepareRes.totalFees} sats"); // ANCHOR_END: prepare-pay-onchain - return resp; + return prepareRes; } -Future startReverseSwap({ - required int amountSat, +Future startReverseSwap({ required String onchainRecipientAddress, - required String pairHash, - required int satPerVbyte, + required PrepareOnchainPaymentResponse prepareRes, }) async { // ANCHOR: start-reverse-swap - SendOnchainRequest req = SendOnchainRequest( - amountSat: amountSat, - onchainRecipientAddress: onchainRecipientAddress, - pairHash: pairHash, - satPerVbyte: satPerVbyte, + PayOnchainRequest req = PayOnchainRequest( + recipientAddress: onchainRecipientAddress, + prepareRes: prepareRes, ); - SendOnchainResponse resp = await BreezSDK().sendOnchain(req: req); + PayOnchainResponse res = await BreezSDK().payOnchain(req: req); // ANCHOR_END: start-reverse-swap - return resp; + return res; } Future> checkReverseSwapStatus() async { diff --git a/snippets/go/send_onchain.go b/snippets/go/send_onchain.go index c294e25a..3dd676c9 100644 --- a/snippets/go/send_onchain.go +++ b/snippets/go/send_onchain.go @@ -26,29 +26,25 @@ func PreparePayOnchain(currentLimits breez_sdk.OnchainPaymentLimitsResponse) { ClaimTxFeerate: satPerVbyte, } - if prepareResp, err := sdk.PrepareOnchainPayment(req); err == nil { - log.Printf("Sender amount, in sats: %v", prepareResp.SenderAmountSat) - log.Printf("Recipient amount, in sats: %v", prepareResp.RecipientAmountSat) - log.Printf("Total fees, in sats: %v", prepareResp.TotalFees) + if prepareRes, err := sdk.PrepareOnchainPayment(req); err == nil { + log.Printf("Sender amount, in sats: %v", prepareRes.SenderAmountSat) + log.Printf("Recipient amount, in sats: %v", prepareRes.RecipientAmountSat) + log.Printf("Total fees, in sats: %v", prepareRes.TotalFees) } // ANCHOR_END: prepare-pay-onchain } -func StartReverseSwap() { +func StartReverseSwap(prepareRes breez_sdk.PrepareOnchainPaymentResponse) { // ANCHOR: start-reverse-swap destinationAddress := "bc1.." - sendAmountSat := uint64(50_000) - satPerVbyte := uint32(5) - if currentFees, err := sdk.FetchReverseSwapFees(breez_sdk.ReverseSwapFeesRequest{SendAmountSat: &sendAmountSat}); err == nil { - sendOnchainRequest := breez_sdk.SendOnchainRequest{ - AmountSat: sendAmountSat, - OnchainRecipientAddress: destinationAddress, - PairHash: currentFees.FeesHash, - SatPerVbyte: satPerVbyte, - } - if reverseSwapInfo, err := sdk.SendOnchain(sendOnchainRequest); err == nil { - log.Printf("%#v", reverseSwapInfo) - } + + payOnchainRequest := breez_sdk.PayOnchainRequest{ + RecipientAddress: destinationAddress, + PrepareRes: prepareRes, + } + + if reverseSwapInfo, err := sdk.PayOnchain(payOnchainRequest); err == nil { + log.Printf("%#v", reverseSwapInfo) } // ANCHOR_END: start-reverse-swap } diff --git a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt index 65cac079..684e5a20 100644 --- a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt +++ b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt @@ -30,13 +30,11 @@ class SendOnchain { // ANCHOR_END: prepare-pay-onchain } - fun start_reverse_swap(sdk: BlockingBreezServices, fees: ReverseSwapPairInfo) { + fun start_reverse_swap(sdk: BlockingBreezServices, prepareRes: PrepareOnchainPaymentResponse) { // ANCHOR: start-reverse-swap val address = "bc1.." - val amountSat = 123.toULong() - val satPerVbyte = 1.toUInt() try { - sdk.sendOnchain(SendOnchainRequest(amountSat, address, fees.feesHash, satPerVbyte)) + sdk.payOnchain(PayOnchainRequest(address, prepareRes)) } catch (e: Exception) { // handle error } diff --git a/snippets/python/src/send_onchain.py b/snippets/python/src/send_onchain.py index c7ff4859..6347ebb4 100644 --- a/snippets/python/src/send_onchain.py +++ b/snippets/python/src/send_onchain.py @@ -7,7 +7,7 @@ def get_current_limits(sdk_services): print("Minimum amount, in sats: ", current_limits.min_sat) print("Maximum amount, in sats: ", current_limits.max_sat) # ANCHOR_END: get-current-reverse-swap-limits - return current_fees + return current_limits except Exception as error: print(error) raise @@ -18,24 +18,22 @@ def prepare_pay_onchain(sdk_services, current_limits, fee_rate): try: # ANCHOR: prepare-pay-onchain req = breez_sdk.PrepareOnchainPaymentRequest(amount_sat, breez_sdk.SwapAmountType.SEND, claim_tx_feerate) - resp = sdk_services.prepare_onchain_payment(req) + prepare_res = sdk_services.prepare_onchain_payment(req) - print("Sender amount, in sats: ", resp.sender_amount_sat) - print("Recipient amount, in sats: ", resp.recipient_amount_sat) - print("Total fees, in sats: ", resp.total_fees) + print("Sender amount, in sats: ", prepare_res.sender_amount_sat) + print("Recipient amount, in sats: ", prepare_res.recipient_amount_sat) + print("Total fees, in sats: ", prepare_res.total_fees) # ANCHOR_END: prepare-pay-onchain except Exception as error: print(error) raise -def start_reverse_swap(sdk_services, current_fees,fee_rate): +def start_reverse_swap(sdk_services, prepare_res): # ANCHOR: start-reverse-swap destination_address = "bc1.." - amount_sat = 50000 - sat_per_vbyte = fee_rate try: - req = breez_sdk.SendOnchainRequest(amount_sat, destination_address, current_fees.fees_hash, sat_per_vbyte) - sdk_services.send_onchain(req) + req = breez_sdk.PayOnchainRequest(destination_address, prepare_res) + sdk_services.pay_onchain(req) # ANCHOR_END: start-reverse-swap except Exception as error: print(error) diff --git a/snippets/react-native/send_onchain.ts b/snippets/react-native/send_onchain.ts index 96abbfc0..76606abd 100644 --- a/snippets/react-native/send_onchain.ts +++ b/snippets/react-native/send_onchain.ts @@ -1,11 +1,11 @@ import { - type ReverseSwapPairInfo, type OnchainPaymentLimitsResponse, + type PrepareOnchainPaymentResponse, fetchReverseSwapFees, inProgressReverseSwaps, onchainPaymentLimits, + payOnchain, prepareOnchainPayment, - sendOnchain, SwapAmountType, maxReverseSwapAmount } from '@breeztech/react-native-breez-sdk' @@ -43,18 +43,14 @@ const examplePreparePayOnchain = async (currentLimits: OnchainPaymentLimitsRespo // ANCHOR_END: prepare-pay-onchain } -const exampleSendOnchain = async (currentFees: ReverseSwapPairInfo) => { +const examplePayOnchain = async (prepareRes: PrepareOnchainPaymentResponse) => { // ANCHOR: start-reverse-swap try { const onchainRecipientAddress = 'bc1..' - const amountSat = currentFees.min - const satPerVbyte = 5 - const reverseSwapInfo = await sendOnchain({ - amountSat, - onchainRecipientAddress, - pairHash: currentFees.feesHash, - satPerVbyte + const reverseSwapInfo = await payOnchain({ + recipientAddress: onchainRecipientAddress, + prepareRes }) } catch (err) { console.error(err) diff --git a/snippets/rust/src/send_onchain.rs b/snippets/rust/src/send_onchain.rs index 41dde37d..4384d3ce 100644 --- a/snippets/rust/src/send_onchain.rs +++ b/snippets/rust/src/send_onchain.rs @@ -33,7 +33,10 @@ async fn prepare_pay_onchain( .await?; info!("Sender amount: {} sats", prepare_res.sender_amount_sat); - info!("Recipient amount: {} sats", prepare_res.recipient_amount_sat); + info!( + "Recipient amount: {} sats", + prepare_res.recipient_amount_sat + ); info!("Total fees: {} sats", prepare_res.total_fees); // ANCHOR_END: prepare-pay-onchain @@ -42,19 +45,14 @@ async fn prepare_pay_onchain( async fn start_reverse_swap( sdk: Arc, - current_fees: ReverseSwapPairInfo, - fee_rate: u32, + prepare_res: PrepareOnchainPaymentResponse, ) -> Result<()> { // ANCHOR: start-reverse-swap let destination_address = String::from("bc1.."); - let amount_sat = current_fees.min; - let sat_per_vbyte = fee_rate; - sdk.send_onchain(SendOnchainRequest { - pair_hash: current_fees.fees_hash, - amount_sat, - sat_per_vbyte, - onchain_recipient_address: destination_address, + sdk.pay_onchain(PayOnchainRequest { + recipient_address: destination_address, + prepare_res, }) .await?; // ANCHOR_END: start-reverse-swap diff --git a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift index a0faba39..468de849 100644 --- a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift +++ b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift @@ -32,13 +32,11 @@ func PreparePayOnchain(sdk: BlockingBreezServices, currentLimits: OnchainPayment return prepareResponse } -func StartReverseSwap(sdk: BlockingBreezServices, currentFees: ReverseSwapPairInfo) -> SendOnchainResponse? { +func StartReverseSwap(sdk: BlockingBreezServices, prepareResponse: PrepareOnchainPaymentRequest) -> SendOnchainResponse? { // ANCHOR: start-reverse-swap let destinationAddress = "bc1.." - let amountSat = currentFees.min - let satPerVbyte: UInt32 = 5 - let response = try? sdk.sendOnchain(req: SendOnchainRequest(amountSat: amountSat, onchainRecipientAddress: destinationAddress, pairHash: currentFees.feesHash, satPerVbyte: satPerVbyte)) + let response = try? sdk.payOnchain(req: PayOnchainRequest(recipientAddress: destinationAddress, prepareRes: prepareResponse)) // ANCHOR_END: start-reverse-swap return response } diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index 2a0e8acb..ceb7ecb4 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -158,14 +158,14 @@ Assuming you'd like to specify the sender amount, the snippet is as follows: If instead you'd like to specify the recipient amount, simply change the `SwapAmountType` from `Send` to `Receive`. -In case you want to drain your channels and send the maximum amount possible, you can use the above snippet with `amount_sat` set to `current_limits.max_sat` and `amount_type` as `Send`. - -Once you checked the amounts and the fees are acceptable, you can continue with sending the payment. +In case you want to drain your channels and send the maximum amount possible, you can use the above snippet with `amount_sat` set to `current_limits.max_sat` and `amount_type` as `Send`. ## Executing the Swap -Once you decided about the amount and checked the fees are acceptable, you can start the reverse swap: +Once you checked the amounts and the fees are acceptable, you can continue with sending the payment. + +Note that one of the arguments will be the result from the `prepare` call above.
Rust
@@ -233,13 +233,13 @@ Once you decided about the amount and checked the fees are acceptable, you can s
-Starting the reverse swap will trigger a HODL invoice payment, which will only be settled if the entire swap completes. +Starting the onchain payment (reverse swap) will trigger a HODL invoice payment, which will only be settled if the entire swap completes. This means you will see an outgoing pending payment in your list of payments, which locks those funds until the invoice is either settled or cancelled. This will happen automatically at the end of the reverse swap. ## List in-progress Swaps -You can check its status with: +You can check the ongoing onchain payments (reverse swaps) and their status with:
Rust
From 278fb4ce59ab0ca837cd053d6f016998d30333a6 Mon Sep 17 00:00:00 2001 From: ok300 <106775972+ok300@users.noreply.github.com> Date: Sat, 16 Mar 2024 06:58:17 +0000 Subject: [PATCH 08/37] Rename send_onchain snippets to pay_onchain (#146) --- .../{send_onchain.dart => pay_onchain.dart} | 0 .../go/{send_onchain.go => pay_onchain.go} | 0 .../src/{send_onchain.py => pay_onchain.py} | 0 .../{send_onchain.ts => pay_onchain.ts} | 0 snippets/rust/src/main.rs | 2 +- .../src/{send_onchain.rs => pay_onchain.rs} | 0 src/SUMMARY.md | 2 +- src/guide/{send_onchain.md => pay_onchain.md} | 40 +++++++++---------- 8 files changed, 22 insertions(+), 22 deletions(-) rename snippets/dart_snippets/lib/{send_onchain.dart => pay_onchain.dart} (100%) rename snippets/go/{send_onchain.go => pay_onchain.go} (100%) rename snippets/python/src/{send_onchain.py => pay_onchain.py} (100%) rename snippets/react-native/{send_onchain.ts => pay_onchain.ts} (100%) rename snippets/rust/src/{send_onchain.rs => pay_onchain.rs} (100%) rename src/guide/{send_onchain.md => pay_onchain.md} (79%) diff --git a/snippets/dart_snippets/lib/send_onchain.dart b/snippets/dart_snippets/lib/pay_onchain.dart similarity index 100% rename from snippets/dart_snippets/lib/send_onchain.dart rename to snippets/dart_snippets/lib/pay_onchain.dart diff --git a/snippets/go/send_onchain.go b/snippets/go/pay_onchain.go similarity index 100% rename from snippets/go/send_onchain.go rename to snippets/go/pay_onchain.go diff --git a/snippets/python/src/send_onchain.py b/snippets/python/src/pay_onchain.py similarity index 100% rename from snippets/python/src/send_onchain.py rename to snippets/python/src/pay_onchain.py diff --git a/snippets/react-native/send_onchain.ts b/snippets/react-native/pay_onchain.ts similarity index 100% rename from snippets/react-native/send_onchain.ts rename to snippets/react-native/pay_onchain.ts diff --git a/snippets/rust/src/main.rs b/snippets/rust/src/main.rs index 3cd3df29..5961e66d 100644 --- a/snippets/rust/src/main.rs +++ b/snippets/rust/src/main.rs @@ -7,10 +7,10 @@ mod list_payments; mod lnurl_auth; mod lnurl_pay; mod lnurl_withdraw; +mod pay_onchain; mod production; mod receive_onchain; mod receive_payment; -mod send_onchain; mod send_payment; mod send_spontaneous_payment; mod service_status; diff --git a/snippets/rust/src/send_onchain.rs b/snippets/rust/src/pay_onchain.rs similarity index 100% rename from snippets/rust/src/send_onchain.rs rename to snippets/rust/src/pay_onchain.rs diff --git a/src/SUMMARY.md b/src/SUMMARY.md index f77f7a96..fdef4191 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -15,7 +15,7 @@ - [Adding and filtering for payment metadata](guide/payment_metadata.md) - [Connecting to an LSP](guide/connecting_lsp.md) - [Receiving an On-Chain Transaction](guide/receive_onchain.md) -- [Sending an On-Chain Transaction](guide/send_onchain.md) +- [Sending an On-Chain Transaction](guide/pay_onchain.md) - [Using LNURL & Lightning addresses](guide/lnurl.md) - [Sending payments using LNURL-Pay/Lightning address](guide/lnurl_pay.md) - [Receiving payments using LNURL-Pay/Lightning address](guide/lnurlpay.md) diff --git a/src/guide/send_onchain.md b/src/guide/pay_onchain.md similarity index 79% rename from src/guide/send_onchain.md rename to src/guide/pay_onchain.md index ceb7ecb4..9f337baf 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/pay_onchain.md @@ -10,7 +10,7 @@ First, fetch the current reverse swap limits:
```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:get-current-reverse-swap-limits}} +{{#include ../../snippets/rust/src/pay_onchain.rs:get-current-reverse-swap-limits}} ```
@@ -34,7 +34,7 @@ First, fetch the current reverse swap limits:
```typescript -{{#include ../../snippets/react-native/send_onchain.ts:get-current-reverse-swap-limits}} +{{#include ../../snippets/react-native/pay_onchain.ts:get-current-reverse-swap-limits}} ```
@@ -42,7 +42,7 @@ First, fetch the current reverse swap limits:
```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:get-current-reverse-swap-limits}} +{{#include ../../snippets/dart_snippets/lib/pay_onchain.dart:get-current-reverse-swap-limits}} ```
@@ -50,7 +50,7 @@ First, fetch the current reverse swap limits:
```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:get-current-reverse-swap-limits}} +{{#include ../../snippets/python/src/pay_onchain.py:get-current-reverse-swap-limits}} ```
@@ -58,7 +58,7 @@ First, fetch the current reverse swap limits:
```go,ignore -{{#include ../../snippets/go/send_onchain.go:get-current-reverse-swap-limits}} +{{#include ../../snippets/go/pay_onchain.go:get-current-reverse-swap-limits}} ```
@@ -95,7 +95,7 @@ Assuming you'd like to specify the sender amount, the snippet is as follows:
```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:prepare-pay-onchain}} +{{#include ../../snippets/rust/src/pay_onchain.rs:prepare-pay-onchain}} ```
@@ -119,7 +119,7 @@ Assuming you'd like to specify the sender amount, the snippet is as follows:
```typescript -{{#include ../../snippets/react-native/send_onchain.ts:prepare-pay-onchain}} +{{#include ../../snippets/react-native/pay_onchain.ts:prepare-pay-onchain}} ```
@@ -127,7 +127,7 @@ Assuming you'd like to specify the sender amount, the snippet is as follows:
```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:prepare-pay-onchain}} +{{#include ../../snippets/dart_snippets/lib/pay_onchain.dart:prepare-pay-onchain}} ```
@@ -135,7 +135,7 @@ Assuming you'd like to specify the sender amount, the snippet is as follows:
```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:prepare-pay-onchain}} +{{#include ../../snippets/python/src/pay_onchain.py:prepare-pay-onchain}} ```
@@ -143,7 +143,7 @@ Assuming you'd like to specify the sender amount, the snippet is as follows:
```go,ignore -{{#include ../../snippets/go/send_onchain.go:prepare-pay-onchain}} +{{#include ../../snippets/go/pay_onchain.go:prepare-pay-onchain}} ```
@@ -172,7 +172,7 @@ Note that one of the arguments will be the result from the `prepare` call above.
```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:start-reverse-swap}} +{{#include ../../snippets/rust/src/pay_onchain.rs:start-reverse-swap}} ```
@@ -196,7 +196,7 @@ Note that one of the arguments will be the result from the `prepare` call above.
```typescript -{{#include ../../snippets/react-native/send_onchain.ts:start-reverse-swap}} +{{#include ../../snippets/react-native/pay_onchain.ts:start-reverse-swap}} ```
@@ -204,7 +204,7 @@ Note that one of the arguments will be the result from the `prepare` call above.
```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:start-reverse-swap}} +{{#include ../../snippets/dart_snippets/lib/pay_onchain.dart:start-reverse-swap}} ```
@@ -212,7 +212,7 @@ Note that one of the arguments will be the result from the `prepare` call above.
```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:start-reverse-swap}} +{{#include ../../snippets/python/src/pay_onchain.py:start-reverse-swap}} ```
@@ -220,7 +220,7 @@ Note that one of the arguments will be the result from the `prepare` call above.
```go,ignore -{{#include ../../snippets/go/send_onchain.go:start-reverse-swap}} +{{#include ../../snippets/go/pay_onchain.go:start-reverse-swap}} ```
@@ -246,7 +246,7 @@ You can check the ongoing onchain payments (reverse swaps) and their status with
```rust,ignore -{{#include ../../snippets/rust/src/send_onchain.rs:check-reverse-swaps-status}} +{{#include ../../snippets/rust/src/pay_onchain.rs:check-reverse-swaps-status}} ```
@@ -270,7 +270,7 @@ You can check the ongoing onchain payments (reverse swaps) and their status with
```typescript -{{#include ../../snippets/react-native/send_onchain.ts:check-reverse-swaps-status}} +{{#include ../../snippets/react-native/pay_onchain.ts:check-reverse-swaps-status}} ```
@@ -278,7 +278,7 @@ You can check the ongoing onchain payments (reverse swaps) and their status with
```dart,ignore -{{#include ../../snippets/dart_snippets/lib/send_onchain.dart:check-reverse-swaps-status}} +{{#include ../../snippets/dart_snippets/lib/pay_onchain.dart:check-reverse-swaps-status}} ```
@@ -286,7 +286,7 @@ You can check the ongoing onchain payments (reverse swaps) and their status with
```python,ignore -{{#include ../../snippets/python/src/send_onchain.py:check-reverse-swaps-status}} +{{#include ../../snippets/python/src/pay_onchain.py:check-reverse-swaps-status}} ```
@@ -294,7 +294,7 @@ You can check the ongoing onchain payments (reverse swaps) and their status with
```go,ignore -{{#include ../../snippets/go/send_onchain.go:check-reverse-swaps-status}} +{{#include ../../snippets/go/pay_onchain.go:check-reverse-swaps-status}} ```
From 894a487a4b95dd685ed11c71b57547a4025a3683 Mon Sep 17 00:00:00 2001 From: ok300 <106775972+ok300@users.noreply.github.com> Date: Thu, 21 Mar 2024 08:26:55 +0000 Subject: [PATCH 09/37] Replace in_progress_reverse_swaps snippets with v2 version (#148) * Replace in_progress_reverse_swaps snippets with v2 * RN snippet: fix imports --- .github/workflows/main.yml | 2 +- snippets/csharp/SendOnchain.cs | 4 ++-- snippets/dart_snippets/lib/pay_onchain.dart | 8 ++++---- snippets/go/pay_onchain.go | 4 ++-- .../kotlin/com/example/kotlinmpplib/SendOnchain.kt | 4 ++-- snippets/python/src/pay_onchain.py | 4 ++-- snippets/react-native/pay_onchain.ts | 6 +++--- snippets/rust/src/pay_onchain.rs | 4 ++-- snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift | 4 ++-- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2512a931..0f8c3fe7 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,7 +25,7 @@ jobs: name: setup runs-on: ubuntu-latest outputs: - sdk-ref: ${{ inputs.sdk-ref || '16e70474937e3938563103adb463fb67c676415c' }} + sdk-ref: ${{ inputs.sdk-ref || 'f02e3e8fbd9b480c0a21e094d06888f54a3a108c' }} package-version: '0.3.4' steps: - run: echo "set pre-setup output variables" diff --git a/snippets/csharp/SendOnchain.cs b/snippets/csharp/SendOnchain.cs index bb23dee8..0ab9d030 100644 --- a/snippets/csharp/SendOnchain.cs +++ b/snippets/csharp/SendOnchain.cs @@ -64,11 +64,11 @@ public void CheckReverseSwapStatus(BlockingBreezServices sdk) // ANCHOR: check-reverse-swaps-status try { - var swaps = sdk.InProgressReverseSwaps(); + var swaps = sdk.InProgressOnchainPayments(); foreach (var swap in swaps) { Console.WriteLine( - $"Reverse swap {swap.id} in progress, " + + $"Onchain payment {swap.id} in progress, " + $"status is {swap.status}`"); } } diff --git a/snippets/dart_snippets/lib/pay_onchain.dart b/snippets/dart_snippets/lib/pay_onchain.dart index c6536732..b1c36ded 100644 --- a/snippets/dart_snippets/lib/pay_onchain.dart +++ b/snippets/dart_snippets/lib/pay_onchain.dart @@ -44,10 +44,10 @@ Future startReverseSwap({ Future> checkReverseSwapStatus() async { // ANCHOR: check-reverse-swaps-status - List inProgRevSwapList = await BreezSDK().inProgressReverseSwaps(); - for (var inProgRevSwap in inProgRevSwapList) { - print("Reverse swap ${inProgRevSwap.id} in progress, status is ${inProgRevSwap.status.name}"); + List inProgOnchainPaymentList = await BreezSDK().inProgressOnchainPayments(); + for (var inProgOnchainPayment in inProgOnchainPaymentList) { + print("Onchain payment ${inProgOnchainPayment.id} in progress, status is ${inProgOnchainPayment.status.name}"); } // ANCHOR_END: check-reverse-swaps-status - return inProgRevSwapList; + return inProgOnchainPaymentList; } diff --git a/snippets/go/pay_onchain.go b/snippets/go/pay_onchain.go index 3dd676c9..9cd525f7 100644 --- a/snippets/go/pay_onchain.go +++ b/snippets/go/pay_onchain.go @@ -51,9 +51,9 @@ func StartReverseSwap(prepareRes breez_sdk.PrepareOnchainPaymentResponse) { func CheckReverseSwapStatus() { // ANCHOR: check-reverse-swaps-status - if swaps, err := sdk.InProgressReverseSwaps(); err == nil { + if swaps, err := sdk.InProgressOnchainPayments(); err == nil { for _, swap := range swaps { - log.Printf("Reverse swap %v in progress, status is %v", swap.Id, swap.Status) + log.Printf("Onchain payment %v in progress, status is %v", swap.Id, swap.Status) } } // ANCHOR_END: check-reverse-swaps-status diff --git a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt index 684e5a20..9ac61b1a 100644 --- a/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt +++ b/snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/SendOnchain.kt @@ -43,8 +43,8 @@ class SendOnchain { fun check_rev_swap_status(sdk: BlockingBreezServices) { // ANCHOR: check-reverse-swaps-status - for (rs in sdk.inProgressReverseSwaps()) { - // Log.v("Breez", "Reverse swap ${rs.id} in progress, status is ${rs.status}") + for (rs in sdk.inProgressOnchainPayments()) { + // Log.v("Breez", "Onchain payment ${rs.id} in progress, status is ${rs.status}") } // ANCHOR_END: check-reverse-swaps-status } diff --git a/snippets/python/src/pay_onchain.py b/snippets/python/src/pay_onchain.py index 6347ebb4..8f8bf450 100644 --- a/snippets/python/src/pay_onchain.py +++ b/snippets/python/src/pay_onchain.py @@ -42,9 +42,9 @@ def start_reverse_swap(sdk_services, prepare_res): def check_reverse_swap_status(sdk_services): try: # ANCHOR: check-reverse-swaps-status - reverse_swaps = sdk_services.in_progress_reverse_swaps() + reverse_swaps = sdk_services.in_progress_onchain_payments() for rs in reverse_swaps: - print("Reverse swap ",rs.id , " in progress, status is ", rs.status) + print("Onchain payment ",rs.id , " in progress, status is ", rs.status) # ANCHOR_END: check-reverse-swaps-status except Exception as error: print(error) diff --git a/snippets/react-native/pay_onchain.ts b/snippets/react-native/pay_onchain.ts index 76606abd..2080b1ec 100644 --- a/snippets/react-native/pay_onchain.ts +++ b/snippets/react-native/pay_onchain.ts @@ -2,7 +2,7 @@ import { type OnchainPaymentLimitsResponse, type PrepareOnchainPaymentResponse, fetchReverseSwapFees, - inProgressReverseSwaps, + inProgressOnchainPayments, onchainPaymentLimits, payOnchain, prepareOnchainPayment, @@ -61,10 +61,10 @@ const examplePayOnchain = async (prepareRes: PrepareOnchainPaymentResponse) => { const exampleInProgressReverseSwaps = async () => { // ANCHOR: check-reverse-swaps-status try { - const swaps = await inProgressReverseSwaps() + const swaps = await inProgressOnchainPayments() for (const swap of swaps) { console.log( - `Reverse swap ${swap.id} in progress, status is ${swap.status}` + `Onchain payment ${swap.id} in progress, status is ${swap.status}` ) } } catch (err) { diff --git a/snippets/rust/src/pay_onchain.rs b/snippets/rust/src/pay_onchain.rs index 4384d3ce..26c80769 100644 --- a/snippets/rust/src/pay_onchain.rs +++ b/snippets/rust/src/pay_onchain.rs @@ -62,9 +62,9 @@ async fn start_reverse_swap( async fn check_reverse_swap_status(sdk: Arc) -> Result<()> { // ANCHOR: check-reverse-swaps-status - for rs in sdk.in_progress_reverse_swaps().await? { + for rs in sdk.in_progress_onchain_payments().await? { info!( - "Reverse swap {} in progress, status is {:?}", + "Onchain payment {} in progress, status is {:?}", rs.id, rs.status ); } diff --git a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift index 468de849..5463eeea 100644 --- a/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift +++ b/snippets/swift/BreezSDKExamples/Sources/SendOnchain.swift @@ -43,9 +43,9 @@ func StartReverseSwap(sdk: BlockingBreezServices, prepareResponse: PrepareOnchai func checkReverseSwap(sdk: BlockingBreezServices) { // ANCHOR: check-reverse-swaps-status - if let inProgressReverseSwaps = try? sdk.inProgressReverseSwaps() { + if let inProgressOnchainPayments = try? sdk.inProgressOnchainPayments() { for rs in inProgressReverseSwaps { - print("Reverse swap \(rs.id) in progress, status is \(rs.status)") + print("Onchain payment \(rs.id) in progress, status is \(rs.status)") } } // ANCHOR_END: check-reverse-swaps-status From e743521e28247338a99dcbacc4cc3f0c99f0f3ab Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Tue, 26 Mar 2024 22:51:05 +0100 Subject: [PATCH 10/37] Add docs for iOS implementation of the notification plugin --- src/SUMMARY.md | 18 +++- src/guide/receive_onchain.md | 4 + src/guide/receive_payment.md | 4 + src/notifications/android_service.md | 0 src/notifications/android_setup.md | 1 + src/notifications/changing_strings.md | 31 ++++++ src/notifications/custom_notifications.md | 115 +++++++++++++++++++++ src/notifications/getting_started.md | 14 +++ src/notifications/ios_plugin.md | 82 +++++++++++++++ src/notifications/ios_service.md | 56 ++++++++++ src/notifications/ios_setup.md | 7 ++ src/notifications/logging.md | 100 ++++++++++++++++++ src/notifications/receive_payment.md | 1 + src/notifications/register_webhook.md | 71 +++++++++++++ src/notifications/service_configuration.md | 34 ++++++ src/notifications/setup_nds.md | 26 +++++ src/notifications/setup_plugin.md | 7 ++ 17 files changed, 568 insertions(+), 3 deletions(-) create mode 100644 src/notifications/android_service.md create mode 100644 src/notifications/android_setup.md create mode 100644 src/notifications/changing_strings.md create mode 100644 src/notifications/custom_notifications.md create mode 100644 src/notifications/getting_started.md create mode 100644 src/notifications/ios_plugin.md create mode 100644 src/notifications/ios_service.md create mode 100644 src/notifications/ios_setup.md create mode 100644 src/notifications/logging.md create mode 100644 src/notifications/receive_payment.md create mode 100644 src/notifications/register_webhook.md create mode 100644 src/notifications/service_configuration.md create mode 100644 src/notifications/setup_nds.md create mode 100644 src/notifications/setup_plugin.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index f77f7a96..00a80b2a 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -9,9 +9,6 @@ - [Sending payments](guide/send_payment.md) - [Sending spontaneous payments](guide/send_spontaneous_payment.md) - [Listing payments](guide/list_payments.md) - - [Receiving payments via mobile notifications](guide/payment_notification.md) - - [iOS](guide/ios_notification_service_extension.md) - - [Android](guide/android_notification_foreground_service.md) - [Adding and filtering for payment metadata](guide/payment_metadata.md) - [Connecting to an LSP](guide/connecting_lsp.md) - [Receiving an On-Chain Transaction](guide/receive_onchain.md) @@ -28,3 +25,18 @@ - [Retrieving service status](guide/service_status.md) - [Reporting payment failures](guide/failure_report.md) - [Moving to production](guide/production.md) + +# Notifications + +- [Getting Started](notifications/getting_started.md) +- [Setup an NDS](notifications/setup_nds.md) +- [Register a webhook](notifications/register_webhook.md) +- [Project Integration](notifications/setup_plugin.md) + - [Android](notifications/android_setup.md) + - [iOS](notifications/ios_setup.md) + - [Notification Service Extension](notifications/ios_service.md) + - [Notification Plugin](notifications/ios_plugin.md) +- [Logging](notifications/logging.md) +- [Service Configuration](notifications/service_configuration.md) +- [Changing Default Strings](notifications/changing_strings.md) +- [Custom Notification Handling](notifications/custom_notifications.md) diff --git a/src/guide/receive_onchain.md b/src/guide/receive_onchain.md index 6e1a9ed5..8668f2b0 100644 --- a/src/guide/receive_onchain.md +++ b/src/guide/receive_onchain.md @@ -155,6 +155,10 @@ The process of receiving funds via an on-chain address is trustless and uses a s 1. Either by a preimage that is exposed when the Lightning payment is completed - this is the positive case where the swap was successful. 2. Or by your node when the swap didn't complete within a certain timeout (216 blocks) - this is the negative case where your node will execute a refund (funds become refundable after 288 blocks). Refund will also be available in case the amount sent wasn't within the limits. +
+

Developer note

+Consider implementing the Notification Plugin when using the Breez SDK in a mobile application. By registering a webhook the application can receive a transaction confirmation notification to redeem the swap in the background. +
## Refund a Swap diff --git a/src/guide/receive_payment.md b/src/guide/receive_payment.md index b479b4d8..95cca9c4 100644 --- a/src/guide/receive_payment.md +++ b/src/guide/receive_payment.md @@ -68,6 +68,10 @@ The Breez SDK automatically connects your node to the LSP peer and you can now r ```
+
+

Developer note

+Consider implementing the Notification Plugin when using the Breez SDK in a mobile application. By registering a webhook the application can receive a payment notification to process the payment in the background. +
# Calculating fees diff --git a/src/notifications/android_service.md b/src/notifications/android_service.md new file mode 100644 index 00000000..e69de29b diff --git a/src/notifications/android_setup.md b/src/notifications/android_setup.md new file mode 100644 index 00000000..f5aec8a3 --- /dev/null +++ b/src/notifications/android_setup.md @@ -0,0 +1 @@ +# Android diff --git a/src/notifications/changing_strings.md b/src/notifications/changing_strings.md new file mode 100644 index 00000000..09fd20f0 --- /dev/null +++ b/src/notifications/changing_strings.md @@ -0,0 +1,31 @@ +# Changing Default Strings + +The Notification Plugin uses a set of identifiers and default strings to display messages when processing push notifications. These default strings can be customised by the application. For example, if you wanted to change the `lnurl_pay_metadata_plain_text`, which sets the LNURL-pay text/plain metadata. + +## Android + +In the `string.xml` file of the application's `res/values` directory, add the key/value: + +``` + + + Pay to Custom App + +``` +You can find the current identifiers and default strings [here](https://github.com/breez/breez-sdk/blob/main/libs/sdk-bindings/bindings-android/lib/src/main/kotlin/breez_sdk_notification/Constants.kt) + +## iOS + +In the `Info.plist` file of the `NotificationService` target, add the key/value: + +``` + + + + + lnurl_pay_metadata_plain_text + Pay to Custom App + + +``` +You can find the current identifiers and default strings [here](https://github.com/breez/breez-sdk/blob/main/libs/sdk-bindings/bindings-swift/Sources/BreezSDKNotification/Constants.swift) \ No newline at end of file diff --git a/src/notifications/custom_notifications.md b/src/notifications/custom_notifications.md new file mode 100644 index 00000000..fa801a96 --- /dev/null +++ b/src/notifications/custom_notifications.md @@ -0,0 +1,115 @@ +# Custom Notification Handling + +You can customise the Notification Plugin even further by handling your own notification types sent to the application via push notification. Follow the code example below for adding these to iOS and Android. + + +
Swift
+
+ +```swift,ignore +class NotificationService: SDKNotificationService { + // Override the `getTaskFromNotification` function + override func getTaskFromNotification() -> TaskProtocol? { + if let task = super.getTaskFromNotification() { + // Return the task if it can already be handled by the notification plugin + return task + } + + guard let content = bestAttemptContent else { return nil } + guard let notificationType = content.userInfo[Constants.MESSAGE_DATA_TYPE] as? String else { return nil } + guard let payload = content.userInfo[Constants.MESSAGE_DATA_PAYLOAD] as? String else { return nil } + + switch(notificationType) { + case "custom_type": + return CustomTask(payload: payload, logger: self.logger, contentHandler: contentHandler, bestAttemptContent: bestAttemptContent) + default: + return nil + } + } +} +``` + +
+
Kotlin
+
+ +```kotlin,ignore +``` + +
+
+ + +You can customise the Notification Plugin even further by handling your own notification types sent to the application via push notification. Follow the code example below for adding these to iOS and Android. + + +
Swift
+
+ +```swift,ignore +import UserNotifications +import Foundation + +// Use a codeable struct to decode the notification payload +struct CustomRequest: Codable { +} + +class CustomTask : TaskProtocol { + fileprivate let TAG = "CustomTask" + + internal var payload: String + internal var contentHandler: ((UNNotificationContent) -> Void)? + internal var bestAttemptContent: UNMutableNotificationContent? + internal var logger: ServiceLogger + internal var receivedPayment: Payment? = nil + + init(payload: String, logger: ServiceLogger, contentHandler: ((UNNotificationContent) -> Void)? = nil, bestAttemptContent: UNMutableNotificationContent? = nil) { + self.payload = payload + self.contentHandler = contentHandler + self.bestAttemptContent = bestAttemptContent + self.logger = logger + } + + // Use the `onEvent` function to handle events from the Breez SDK + // that can be used in your task + public func onEvent(e: BreezEvent) {} + + // The `start` function is called once the SDK instance is connected + func start(breezSDK: BlockingBreezServices) throws { + var customRequest: CustomRequest? = nil + do { + customRequest = try JSONDecoder().decode(CustomRequest.self, from: self.payload.data(using: .utf8)!) + } catch let e { + self.logger.log(tag: TAG, line: "failed to decode payload: \(e)", level: "ERROR") + self.onShutdown() + throw e + } + + do { + // Do something with the SDK, then once finished call 'displayPushNotification' with a success + // or failure message. The 'onShutdown' function can also be called to show the failure message + self.displayPushNotification(title: "Success", logger: self.logger) + } catch let e { + self.logger.log(tag: TAG, line: "Failed to process notification: \(e)", level: "ERROR") + self.onShutdown() + } + } + + // The 'onShutdown' function can be called when the notification service extension is about to be + // shutdown by the OS, here you can cleanup and display the failed push notification message + func onShutdown() { + self.displayPushNotification(title: "Failed", logger: self.logger) + } +} +``` + +
+
Kotlin
+
+ +```kotlin,ignore +``` + +
+
+ diff --git a/src/notifications/getting_started.md b/src/notifications/getting_started.md new file mode 100644 index 00000000..4537b91b --- /dev/null +++ b/src/notifications/getting_started.md @@ -0,0 +1,14 @@ +# Introduction + +The Breez SDK Notification Plugin provides vendors the ability to receive events via mobile notifications even while the application is in the background or closed. This plugin processes several different notification types like receiving payments, LNURL-pay flows and swap confirmations. Within your application you can even extend the functionality to handle your own notification types. + +![receive via notifications_2](https://github.com/breez/breez-sdk-docs/assets/31890660/75e7cac6-4480-453d-823b-f52bd6757ce9) + +## How it works + +This process involves using a Notification Delivery Service (NDS) acting as an intermediary host by the application developer. The NDS must provide a public facing webhook URL where a POST request can be sent to when a notification needs to be delivered to the application. The NDS then forwards the data sent in the webhook POST request via push notification to the application. When the application then receives the push notification then Breez SDK Notification Plugin can be used to process the event. + +## Next Steps +- **[Setup an NDS](setup_nds.md)** to receive webhook requests +- **[Register a webhook](register_webhook.md)** in your main application +- **[Project integration](setup_plugin.md)** using a notification service extension or foreground service diff --git a/src/notifications/ios_plugin.md b/src/notifications/ios_plugin.md new file mode 100644 index 00000000..a2098e8b --- /dev/null +++ b/src/notifications/ios_plugin.md @@ -0,0 +1,82 @@ +# Add the iOS Notification Plugin + +Add the `BreezSDK` cocoapod to your iOS Podfile, with the target `NotificationService`. You can add any other dependencies your require here also, for example `KeychainAccess` to read the saved mnemonic from the keychain. + +``` +target 'NotificationService' do + pod 'BreezSDK' + pod 'KeychainAccess' +end +``` + +Once added to the Podfile, run `pod install` to install the dependencies. + +## Integrate the Notification Plugin + +You're ready to add some Swift code to implement the Notification Plugin in your NotificationService target. In Xcode, in the `NotificationService` folder, open the Swift file named `NotificationService.swift`. + +This Swift file should implement the Notification Plugin's `SDKNotificationService` class. The `SDKNotificationService` class handles the incoming notification content and processes the event. To properly implement this class the NotificationService needs to override at least the `getConnectRequest` function. The `getConnectRequest` function is called by the `SDKNotificationService` to get a BreezSDK `ConnectRequest` which contains the data necessary to connect the SDK to the node. This data includes the Breez API key, the `Config` with it's workingDir and the node seed. + +
+

Developer note

+When using the Notification Plugin in iOS, it is important to note that the Config workingDir needs to be set to the app group's shared directory in both the NotificationService target and in the main application target, wheather that is a Swift, Flutter or React Native based application. +
+
+

Developer note

+When accessing the Keychain using the Keychain Group, the AppIdentifierPrefix needs to be prepended to the configured identifier, like <TEAM_ID>.com.example.SharedKeychain. This Keychain Group needs to be used in the main application target as the accessGroup when you want to store anything on the keychain that later needs to be accessed by the notification service. +
+ +```swift +import UserNotifications +import KeychainAccess +import BreezSDK + +fileprivate let logger = OSLog( + subsystem: Bundle.main.bundleIdentifier!, + category: "NotificationService" +) + +fileprivate let appGroup = "group.com.example.application" +fileprivate let keychainGroup = "A352BFE4OR.com.example.SharedKeychain" +fileprivate let accountMnemonic: String = "BREEZ_SDK_SEED_MNEMONIC" +fileprivate let accountApiKey: String = "BREEZ_SDK_API_KEY" + +class NotificationService: SDKNotificationService { + override func getConnectRequest() -> ConnectRequest? { + // Get the Breez API key from the target bundle's Info.plist + guard let apiKey = Bundle.main.object(forInfoDictionaryKey: accountApiKey) as? String else { + os_log(.error, "API key not found") + return nil + } + var config = defaultConfig(envType: EnvironmentType.production, + apiKey: apiKey, + nodeConfig: NodeConfig.greenlight( + config: GreenlightNodeConfig(partnerCredentials: nil, + inviteCode: nil))) + // Set the workingDir as the app group's shared directory, + // this should be the same directory as the main application uses + config.workingDir = FileManager + .default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)! + .appendingPathComponent("breezSdk", isDirectory: true) + .absoluteString + + // Get the mnemonic from the shared keychain using the same + // service name as the main application + let service = Bundle.main.bundleIdentifier!.replacingOccurrences(of: ".NotificationService", with: "") + let keychain = Keychain(service: service, accessGroup: keychainGroup) + guard let mnemonic = try? keychain.getString(accountMnemonic) else { + os_log(.error, "Mnemonic not found") + return nil + } + // Convert the mnenonic to a seed + guard let seed = try? mnemonicToSeed(phrase: mnemonic) else { + os_log(.error, "Invalid seed") + return nil + } + return ConnectRequest(config: config, seed: seed) + } +} +``` + +## Reference implementation +For a complete reference, see how we implemented it in c-breez wallet: [NotificationService.swift](https://github.com/breez/c-breez/blob/main/ios/Breez%20Notification%20Service%20Extension/NotificationService.swift). \ No newline at end of file diff --git a/src/notifications/ios_service.md b/src/notifications/ios_service.md new file mode 100644 index 00000000..074975b0 --- /dev/null +++ b/src/notifications/ios_service.md @@ -0,0 +1,56 @@ +# iOS Notfication Service Extension +## Add a Notfication Service Extension target + +In Xcode add a new Target to your application: +1. In the menu `File > New > Target...` +2. Select `Notification Service Extension` +3. Give the name `NotificationExtension` + +This should create a new target with a bundle identifier like `com.example.application.NotificationExtension` and a folder in your application called `NotificationExtension`. + +## Identifiers + +To share data between the main application and service extension targets, you need to add a common `app group` to the main application identifier and new service extension identifier. Go the [Apple Developer](https://developer.apple.com/account/resources/identifiers/list/applicationGroup) portal, in the Identifiers section select the App Groups dropdown to the right, then: +1. Click `+` to add an App Group +2. Select `App Groups` from the list +3. Give the App Group a description and identifier, like `group.com.example.application` + +### Update Identifiers +Now add the App Group to your existing main application release and debug Identifiers, in the Identifiers section select the App IDs dropdown to the right, then: +1. Click the Identifier to edit +2. Enable the `App Groups` app service +3. Click `Edit` and select the created app group + +### Create Service Extension Identifiers +Create new release and debug Identifiers for the new service extension. +1. Click `+` to add an Identifier +2. Select `App IDs` from the list +3. Give the Identifier a description and identifier the same as the service extension, like `com.example.application.NotificationExtension` +4. Enable the `App Groups` app service +5. Save the Identifier, then edit again it to add the created app group as above + +## Provisioning Profiles + +Once you've updated and created the application Identifiers, you need to create new Provisioning Profiles for the main application and service extension that include the app group service. Go the [Apple Developer](https://developer.apple.com/account/resources/profiles/list) portal, in the Profiles section, then: +1. Click `+` to add a Provisioning Profile +2. Select the Development or Distribution type depending if its for release or debug building +3. Select the App ID +4. Select the Certificate, then generate the Provisioning Profile making a note of the name + +## Configure Notification Service Extension + +Back in Xcode you need to configure for each of your projects's targets, updating the Provisioning Profiles then adding capabilities for App Groups and Keychain Sharing. First for each target: +1. Select the `Signing & Capabilities` tab +2. Update the Provisioning Profile to the newly created ones + +### Add an App Group Capability +Then add an App Group capability still in the `Signing & Capabilities` tab for each target: +1. Click `+ Capability` to add a capability +2. Select `App Groups` from the list +3. In the capability with the title `App Groups`, enable the created app group, like `group.com.example.application` + +### Add an Keychain Sharing Capability +Then add a Keychain Sharing capability still in the `Signing & Capabilities` tab for each target: +1. Click `+ Capability` to add a capability +2. Select `Keychain Sharing` from the list +3. In the capability with the title `Keychain Sharing`, add a name for the Keychain Group, like `com.example.SharedKeychain` \ No newline at end of file diff --git a/src/notifications/ios_setup.md b/src/notifications/ios_setup.md new file mode 100644 index 00000000..fead5dfc --- /dev/null +++ b/src/notifications/ios_setup.md @@ -0,0 +1,7 @@ +# Setup the iOS Notification Plugin + +In order to add the Notification Plugin to your iOS application, first you need to setup the Notification Service Extension, then add the Notification Plugin dependency and integrate it: + +## Next Steps +- **[Setup the Notification Service Extension](ios_service.md)** +- **[Add the Notification Plugin](ios_plugin.md)** diff --git a/src/notifications/logging.md b/src/notifications/logging.md new file mode 100644 index 00000000..de44347d --- /dev/null +++ b/src/notifications/logging.md @@ -0,0 +1,100 @@ +# Logging + +You can override the default logger used by the Notification Plugin to use your own logging implementation or dependency. Lets look at an example of a file logger. + + +
Swift
+
+ +```swift,ignore +import BreezSDK +import XCGLogger + +class NotificationService: SDKNotificationService { + // Override the `init` function + override init() { + // Initialize XCGLogger + let logsDir = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: accessGroup)!.appendingPathComponent("logs") + let extensionLogFile = logsDir.appendingPathComponent("\(Date().timeIntervalSince1970).ios-extension.log") + + xcgLogger = { + let log = XCGLogger.default + log.setup(level: .info, showThreadName: true, showLevel: true, showFileNames: true, showLineNumbers: true, writeToFile: extensionLogFile.path) + return log + + }() + + super.init() + // Set NotificationService logger that utilizes the XCGLogger library + let logger = CustomLogListener(logger: xcgLogger) + setLogger(logger: logger) + // Use the same logger to listen in on BreezSDK logs + do { + try setLogStream(logStream: logger) + } catch let e { + self.logger.log(tag: TAG, line:"Failed to set log stream: \(e)", level: "ERROR") + } + } +} +``` + +
+
Kotlin
+
+ +```kotlin,ignore +``` + +
+
+ +Implement a custom LogStream listener, this can be used to listen to log entries from both the Notification Plugin and Breez SDK. + + +
Swift
+
+ +```swift,ignore +import XCGLogger + +class CustomLogListener : LogStream { + private var logger: XCGLogger + + init(logger: XCGLogger) { + self.logger = logger + } + + func log(l: LogEntry) { + switch(l.level) { + case "ERROR": + logger.error { l.line } + break + case "WARN": + logger.warning { l.line } + break + case "INFO": + logger.info { l.line } + break + case "DEBUG": + logger.debug { l.line } + break + case "TRACE": + logger.verbose { l.line } + break + default: + return + } + } +} +``` + +
+
Kotlin
+
+ +```kotlin,ignore +``` + +
+
+ diff --git a/src/notifications/receive_payment.md b/src/notifications/receive_payment.md new file mode 100644 index 00000000..dbe9e690 --- /dev/null +++ b/src/notifications/receive_payment.md @@ -0,0 +1 @@ +# Setup an NDS diff --git a/src/notifications/register_webhook.md b/src/notifications/register_webhook.md new file mode 100644 index 00000000..6c645b31 --- /dev/null +++ b/src/notifications/register_webhook.md @@ -0,0 +1,71 @@ +# Register a webhook + +Once your vendor [NDS is setup](setup_nds.md) and can accept POST requests from the SDK services, you can within your mail application register the webhook URL with the Breez SDK by calling the register webhook API as follows: + + +
Rust
+
+ +```rust,ignore +{{#include ../../snippets/rust/src/webhook.rs:register-payment-webook}} +``` +
+ +
Swift
+
+ +```swift,ignore +{{#include ../../snippets/swift/BreezSDKExamples/Sources/Webhook.swift:register-payment-webook}} +``` +
+ +
Kotlin
+
+ +```kotlin,ignore +{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/Webhook.kt:register-payment-webook}} +``` +
+ +
React Native
+
+ +```typescript +{{#include ../../snippets/react-native/webhook.ts:register-payment-webook}} +``` +
+ +
Dart
+
+ +```dart,ignore +{{#include ../../snippets/dart_snippets/lib/webhook.dart:register-payment-webook}} +``` +
+ +
Python
+
+ +```python,ignore +{{#include ../../snippets/python/src/webhook.py:register-payment-webook}} +``` +
+ +
Go
+
+ +```go,ignore +{{#include ../../snippets/go/webhook.go:register-payment-webook}} +``` +
+ +
C#
+
+ +```cs,ignore +{{#include ../../snippets/csharp/Webhook.cs:register-payment-webook}} +``` +
+
+ +Now when the NDS receives a POST request for this webhook URL, it will forward the request data via push notification to the applications Service Extension (iOS) or Foreground Service (Android) to be handled by the [Notification Plugin](setup_plugin.md). \ No newline at end of file diff --git a/src/notifications/service_configuration.md b/src/notifications/service_configuration.md new file mode 100644 index 00000000..7fdbfb5c --- /dev/null +++ b/src/notifications/service_configuration.md @@ -0,0 +1,34 @@ +# Service Configuration + +You can override the default Notification Plugin config to set values used to process certain notification events. For example, the `channelFeeLimitMsat` value can be set to limit the maximum fee paid in the case where a channel will be opened during receiving a payment with LNURL-pay. + + +
Swift
+
+ +```swift,ignore +import BreezSDK + +fileprivate let appGroup = "group.com.example.application" + +class NotificationService: SDKNotificationService { + private let channelSetupFeeLimit: String = "CHANNEL_SETUP_FEE_LIMIT" + + // Override the `getServiceConfig` function + override func getServiceConfig() -> ServiceConfig? { + // Get the fee limit for opening a new channel from the `UserDefaults` + let channelFeeLimitMsat = UInt64(UserDefaults(suiteName: appGroup)!.integer(forKey: channelSetupFeeLimit)) + return ServiceConfig.init(channelFeeLimitMsat: UInt64(channelFeeLimitMsat)) + } +} +``` + +
+
Kotlin
+
+ +```kotlin,ignore +``` + +
+
diff --git a/src/notifications/setup_nds.md b/src/notifications/setup_nds.md new file mode 100644 index 00000000..08afeb0c --- /dev/null +++ b/src/notifications/setup_nds.md @@ -0,0 +1,26 @@ +# Setup a Notification Delivery Service (NDS) + +Receiving push notifications involves using a NDS as an intermediary to receive the webhook event from one of the SDK services. These can be currently one of several services that provide information about events that the Breez SDK registers for. For example, payment events from the LSP or swap transaction confirmation events from the chain service. The NDS then processes this information and dispatches a push notification to the intended mobile device, ensuring the user receives timely updates about incoming events. This architecture necessitates vendors setup up and maintain their own NDS, tailored to handle and forward these notifications efficiently. An example payload when a `payment_received` POST request to the webhook URL contains the following JSON formatted structure: + +``` +{ + "template": "payment_received", + "data": { + "payment_hash": [payment hash] + } +} +``` + +The vendor needs to run their own NDS because it is configured to send push notifications to your application users and therefore should be configured with the required keys and certificates. You can use our [reference NDS implementation](https://github.com/breez/notify) as an implementation starting point or as is. Our implementation of the NDS expects URLs in the following format: +``` +https://your-nds-service.com/notify?platform=&token=[PUSH_TOKEN] +``` + + + +This is the same format used when [registering a webhook](register_webhook.md) in the Breez SDK, replacing the `PUSH_TOKEN` with the mobile push token. Once the NDS has received such request it will send a push notification to the corresponding device. + +## Mobile push token +Ensure that your mobile application is set up to receive push notifications and can generate a push token. This token uniquely identifies the device for push notifications. +* For iOS, use [Apple Push Notification Service (APNs)](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns) to get the token. +* For Android, use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging/manage-tokens) to obtain the token. diff --git a/src/notifications/setup_plugin.md b/src/notifications/setup_plugin.md new file mode 100644 index 00000000..ae2ce90a --- /dev/null +++ b/src/notifications/setup_plugin.md @@ -0,0 +1,7 @@ +# Notification Integration + +The Notification Plugin is designed to be used when the application isn't running. For this to be acheived reliably and to ensure that the notification is processed, specific implementations are required for both Android and iOS platforms to handle the incoming push notifications. + +* For Android, the application requires a [Foreground Service](android_setup.md) to handle the notification intent. + +* For iOS, the application requires a [Notification Service Extension](ios_setup.md) to handle the notification request. From 4647cabc100fda1e1b47b1f9278c47fe356970af Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 27 Mar 2024 11:13:40 +0100 Subject: [PATCH 11/37] Add advanced Android notification plugin docs --- src/notifications/custom_notifications.md | 107 ++++++++++++++++++++- src/notifications/logging.md | 107 ++++++++++++++++++++- src/notifications/service_configuration.md | 33 +++++++ 3 files changed, 241 insertions(+), 6 deletions(-) diff --git a/src/notifications/custom_notifications.md b/src/notifications/custom_notifications.md index fa801a96..bf5910e5 100644 --- a/src/notifications/custom_notifications.md +++ b/src/notifications/custom_notifications.md @@ -5,6 +5,7 @@ You can customise the Notification Plugin even further by handling your own noti
Swift
+First you need to override the getTaskFromNotification function in the implementation of the SDKNotificationService class. ```swift,ignore class NotificationService: SDKNotificationService { @@ -32,15 +33,53 @@ class NotificationService: SDKNotificationService {
Kotlin
+First you need to override the getJobFromIntent function in the implementation of the ForegroundService class. ```kotlin,ignore +package com.example.application + +import android.content.Intent +import breez_sdk_notification.ForegroundService +import breez_sdk_notification.job.Job +import breez_sdk_notification.Message +import breez_sdk_notification.NotificationHelper.Companion.registerNotificationChannels + +class ExampleForegroundService : ForegroundService() { + // Override the `onCreate` function and register custom notification channels if needed + override fun onCreate() { + super.onCreate() + // First register the default notification channels + registerNotificationChannels(applicationContext, DEFAULT_CLICK_ACTION) + // Then register any additional notification channels + } + + // Override the `getJobFromIntent` function + override fun getJobFromIntent(intent: Intent?): Job? { + return super.getJobFromIntent(intent) ?: run { + // If the job cannot be handled by the notification plugin + Message.createFromIntent(intent)?.let { message -> + message.payload?.let { payload -> + when (message.type) { + "custom_type" -> CustomJob( + applicationContext, + this, + payload, + logger + ) + + else -> null + } + } + } + } + } +} ```
- -You can customise the Notification Plugin even further by handling your own notification types sent to the application via push notification. Follow the code example below for adding these to iOS and Android. +Then add a class that encapsulates the handling of the custom push notification type.
Swift
@@ -76,6 +115,7 @@ class CustomTask : TaskProtocol { // The `start` function is called once the SDK instance is connected func start(breezSDK: BlockingBreezServices) throws { + // Decode the `CustomRequest` from the payload var customRequest: CustomRequest? = nil do { customRequest = try JSONDecoder().decode(CustomRequest.self, from: self.payload.data(using: .utf8)!) @@ -85,9 +125,9 @@ class CustomTask : TaskProtocol { throw e } + // Do something with the SDK, then once finished call 'displayPushNotification' with a success + // or failure message. The 'onShutdown' function can also be called to show the failure message do { - // Do something with the SDK, then once finished call 'displayPushNotification' with a success - // or failure message. The 'onShutdown' function can also be called to show the failure message self.displayPushNotification(title: "Success", logger: self.logger) } catch let e { self.logger.log(tag: TAG, line: "Failed to process notification: \(e)", level: "ERROR") @@ -108,6 +148,65 @@ class CustomTask : TaskProtocol {
```kotlin,ignore +package com.example.application + +import android.content.Context +import breez_sdk.BlockingBreezServices +import breez_sdk.BreezEvent +import breez_sdk_notification.NotificationHelper.Companion.notifyChannel +import breez_sdk_notification.SdkForegroundService +import breez_sdk_notification.ServiceLogger +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json + +// Use a `Serializable` data class to decode the notification payload +@Serializable +data class CustomRequest( +) + +class CustomJob( + private val context: Context, + private val fgService: SdkForegroundService, + private val payload: String, + private val logger: ServiceLogger, +) : Job { + companion object { + private const val TAG = "CustomJob" + } + + // Use the `onEvent` function to handle events from the Breez SDK + // that can be used in your task + override fun onEvent(e: BreezEvent) {} + + // The `start` function is called once the SDK instance is connected + override fun start(breezSDK: BlockingBreezServices) { + // Remember if you are using a custom notification channel, you have to register it first + val applicationId = context.applicationContext.packageName + val notificationChannel = "${applicationId}.CUSTOM_JOB" + try { + // Decode the `CustomRequest` from the payload + val request = Json.decodeFromString(CustomRequest.serializer(), payload) + // Do something with the SDK. Once finished call 'notifyChannel' + // with a success or failure message + notifyChannel( + context, + notificationChannel, + "Success", + ) + } catch (e: Exception) { + logger.log(TAG, "Failed to process notification: ${e.message}", "WARN") + notifyChannel( + context, + notificationChannel, + "Failed", + ) + } + + // Shutdown the foreground service once finished + fgService.shutdown() + } + +} ```
diff --git a/src/notifications/logging.md b/src/notifications/logging.md index de44347d..ae143978 100644 --- a/src/notifications/logging.md +++ b/src/notifications/logging.md @@ -5,16 +5,19 @@ You can override the default logger used by the Notification Plugin to use your
Swift
+In iOS lets use the XCGLogger to handle logging to a seperate log file in the app group's shared directory. ```swift,ignore import BreezSDK import XCGLogger +fileprivate let appGroup = "group.com.example.application" + class NotificationService: SDKNotificationService { // Override the `init` function override init() { // Initialize XCGLogger - let logsDir = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: accessGroup)!.appendingPathComponent("logs") + let logsDir = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroup)!.appendingPathComponent("logs") let extensionLogFile = logsDir.appendingPathComponent("\(Date().timeIntervalSince1970).ios-extension.log") xcgLogger = { @@ -25,7 +28,7 @@ class NotificationService: SDKNotificationService { }() super.init() - // Set NotificationService logger that utilizes the XCGLogger library + // Set notification plugin logger that utilizes the XCGLogger library let logger = CustomLogListener(logger: xcgLogger) setLogger(logger: logger) // Use the same logger to listen in on BreezSDK logs @@ -41,8 +44,91 @@ class NotificationService: SDKNotificationService {
Kotlin
+In Android lets use the tinylog to handle logging to a file. First create a utility class to configure tinylog. + +```kotlin,ignore +package com.example.application + +import android.content.Context +import java.io.File +import org.tinylog.kotlin.Logger + +class LogHelper { + companion object { + private const val TAG = "LogHelper" + private var isInit: Boolean? = null + + internal fun configureLogger(applicationContext: Context): Boolean? { + synchronized(this) { + // Get `/logs` folder from app data directory + val loggingDir = + File(applicationContext.applicationInfo.dataDir, "/logs").apply { + mkdirs() + } + + System.setProperty("tinylog.directory", loggingDir.absolutePath) + System.setProperty("tinylog.timestamp", System.currentTimeMillis().toString()) + + if (isInit == false) { + Logger.tag(TAG).debug { "Starting ${BuildConfig.APPLICATION_ID}..." } + Logger.tag(TAG).debug { "Logs directory: '$loggingDir'" } + isInit = true + } + return isInit + } + } + } +} +``` + +When a message is received by the messaging service, configure the logger. + +```kotlin,ignore +package com.example.application + +import breez_sdk_notification.MessagingService +import com.example.application.LogHelper.Companion.configureLogger +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage + +class ExampleFcmService : MessagingService, FirebaseMessagingService() { + override fun onMessageReceived(remoteMessage: RemoteMessage) { + super.onMessageReceived(remoteMessage) + // Initialise the logger + configureLogger(applicationContext) + Logger.tag(TAG).debug { "FCM message received!" } + + // Go on to call `startServiceIfNeeded` + } +} +``` + +When the foreground service is created, initialise the Breek SDK log stream and subscribe to log entries ```kotlin,ignore +package com.example.application + +import breez_sdk.setLogStream +import breez_sdk_notification.ForegroundService +import breez_sdk_notification.NotificationHelper.Companion.registerNotificationChannels +import org.tinylog.kotlin.Logger + +class ExampleForegroundService : ForegroundService() { + // Override the `onCreate` function + override fun onCreate() { + super.onCreate() + registerNotificationChannels(applicationContext, DEFAULT_CLICK_ACTION) + // Set notification plugin logger that utilizes the tinylog library + val logger = CustomLogListener() + setLogger(logger) + // Use the same logger to listen in on BreezSDK logs + try { + setLogStream(logger) + } catch (e: Exception) { + Logger.tag(TAG).error { "Failed to set log stream: ${e.message}" } + } + } +} ```
@@ -93,6 +179,23 @@ class CustomLogListener : LogStream {
```kotlin,ignore +package com.example.application + +import breez_sdk.LogEntry +import breez_sdk.LogStream +import org.tinylog.kotlin.Logger + +class CustomLogListener : LogStream { + override fun log(l: LogEntry) { + when (l.level) { + "ERROR" -> Logger.tag(TAG).error { l.line } + "WARN" -> Logger.tag(TAG).warn { l.line } + "INFO" -> Logger.tag(TAG).info { l.line } + "DEBUG" -> Logger.tag(TAG).debug { l.line } + "TRACE" -> Logger.tag(TAG).trace { l.line } + } + } +} ```
diff --git a/src/notifications/service_configuration.md b/src/notifications/service_configuration.md index 7fdbfb5c..b2b3bf15 100644 --- a/src/notifications/service_configuration.md +++ b/src/notifications/service_configuration.md @@ -28,6 +28,39 @@ class NotificationService: SDKNotificationService {
```kotlin,ignore +package com.example.application + +import android.content.SharedPreferences +import breez_sdk_notification.ForegroundService +import breez_sdk_notification.ServiceConfig +import org.tinylog.kotlin.Logger + +class ExampleForegroundService : ForegroundService() { + companion object { + // Your own shared preferences name or `FlutterSharedPreferences` for Flutter + private const val SHARED_PREFERENCES_NAME = "group.com.example.application" + private const val CHANNEL_SETUP_FEE_LIMIT = "CHANNEL_SETUP_FEE_LIMIT" + } + + // Override the `getServiceConfig` function + override fun getServiceConfig(): ServiceConfig? { + try { + val sharedPreferences: SharedPreferences = applicationContext.getSharedPreferences( + SHARED_PREFERENCES_NAME, + MODE_PRIVATE + ) + // Get the fee limit for opening a new channel from the shared preferences + val channelFeeLimitMsat = + sharedPreferences.getLong(CHANNEL_SETUP_FEE_LIMIT, 0).toULong() + return ServiceConfig(channelFeeLimitMsat = channelFeeLimitMsat) + } catch (e: Exception) { + Logger.tag(TAG).error { "Failed to get service config: ${e.message}" } + } + + return ServiceConfig.default() + } +} + ```
From 6213ebb45a9b74d6710c525b1dec111517436161 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 27 Mar 2024 13:20:53 +0100 Subject: [PATCH 12/37] Add Android notification plugin setup --- src/SUMMARY.md | 2 + src/notifications/android_plugin.md | 145 ++++++++++++++++++++++++++ src/notifications/android_service.md | 37 +++++++ src/notifications/android_setup.md | 8 +- src/notifications/changing_strings.md | 4 +- src/notifications/ios_plugin.md | 3 +- 6 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 src/notifications/android_plugin.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 00a80b2a..fc669612 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -33,6 +33,8 @@ - [Register a webhook](notifications/register_webhook.md) - [Project Integration](notifications/setup_plugin.md) - [Android](notifications/android_setup.md) + - [Foreground Service](notifications/android_service.md) + - [Notification Plugin](notifications/android_plugin.md) - [iOS](notifications/ios_setup.md) - [Notification Service Extension](notifications/ios_service.md) - [Notification Plugin](notifications/ios_plugin.md) diff --git a/src/notifications/android_plugin.md b/src/notifications/android_plugin.md new file mode 100644 index 00000000..2ec2319e --- /dev/null +++ b/src/notifications/android_plugin.md @@ -0,0 +1,145 @@ +# Add the Android Notification Plugin + +Add the `breez-sdk` dependency to your application's `build.gradle` file in the `app` directory. + +```gradle +android { + defaultConfig { + // Add a build config field to read the Breez API key + // from a git ignored `gradle.properties` file + buildConfigField "String", "BREEZ_SDK_API_KEY", project.property('BREEZ_SDK_API_KEY') + } + + // This might help building if duplicate libraries are found + packagingOptions { + pickFirst "lib/armeabi-v7a/libc++_shared.so" + pickFirst "lib/arm64-v8a/libc++_shared.so" + pickFirst "lib/x86/libc++_shared.so" + pickFirst "lib/x86_64/libc++_shared.so" + exclude "META-INF/*" + } +} + +dependencies { + // Add the breez-sdk dependency + implementation "com.github.breez:breez-sdk" +} +``` + +## Integrate the Notification Plugin + +You're ready to add some Kotlin code to implement the Notification Plugin in your application. In the example below we are using the `FirebaseMessagingService` to receive the message intents. First lets implement the Notification Plugin's `MessagingService` class along with `FirebaseMessagingService`. + +```kotlin +package com.example.application + +import android.annotation.SuppressLint +import android.content.Intent +import androidx.core.content.ContextCompat +import breez_sdk_notification.Constants +import breez_sdk_notification.Message +import breez_sdk_notification.MessagingService +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage + +@SuppressLint("MissingFirebaseInstanceTokenRefresh") +class ExampleFcmService : MessagingService, FirebaseMessagingService() { + companion object { + private const val TAG = "FcmService" + } + + // Override the `onMessageReceived` to handle the remote message + override fun onMessageReceived(remoteMessage: RemoteMessage) { + super.onMessageReceived(remoteMessage) + + // Check if the message is high priority and can be handled + if (remoteMessage.priority == RemoteMessage.PRIORITY_HIGH) { + remoteMessage.asMessage()?.also { message -> + // Call `startServiceIfNeeded` to check if the foreground + // service is needed depending on the message type and + // foreground state of the application + startServiceIfNeeded(applicationContext, message) + } + } + } + + // A helper function the convert the `RemoteMessage` + // to a notification plugin 'Message' + private fun RemoteMessage.asMessage(): Message? { + return data[Constants.MESSAGE_DATA_TYPE]?.let { + Message( + data[Constants.MESSAGE_DATA_TYPE], data[Constants.MESSAGE_DATA_PAYLOAD] + ) + } + } + + // Override the `startForegroundService` function to start the foreground service + // using the `ExampleForegroundService` handler + override fun startForegroundService(message: Message) { + val intent = Intent(applicationContext, ExampleForegroundService::class.java) + intent.putExtra(Constants.EXTRA_REMOTE_MESSAGE, message) + ContextCompat.startForegroundService(applicationContext, intent) + } +} +``` + +Now lets add the foreground service implementation. This should implement the notification plugin `ForegroundService` class, which handles the incoming notification intent and processes the event. To properly implement this, your class needs to override the `onCreate`, `getConnectRequest` and `getServiceConfig` functions. The `getConnectRequest` function is called by the `ForegroundService` to get a BreezSDK `ConnectRequest` which contains the data necessary to connect the SDK to the node. This data includes the Breez API key, the `Config` with it's workingDir and the node seed. + +
+

Developer note

+In Android reading from secured storage can vary a lot depending if it is a Kotlin, Flutter or React Native based application and the dependencies used to write to the secured storage. Consult the dependency used to write to the secured storage on how to read data back from them. +
+ +```kotlin +package com.example.application + +import breez_sdk.ConnectRequest +import breez_sdk.EnvironmentType +import breez_sdk.GreenlightNodeConfig +import breez_sdk.NodeConfig +import breez_sdk.defaultConfig +import breez_sdk.mnemonicToSeed +import breez_sdk_notification.ForegroundService +import breez_sdk_notification.NotificationHelper.Companion.registerNotificationChannels +import breez_sdk_notification.ServiceConfig + +class ExampleForegroundService : ForegroundService() { + companion object { + private const val TAG = "ForegroundService" + private const val ACCOUNT_MNEMONIC = "BREEZ_SDK_SEED_MNEMONIC" + } + + // Override the `onCreate` function + override fun onCreate() { + super.onCreate() + // Register the default notification channels + registerNotificationChannels(applicationContext, DEFAULT_CLICK_ACTION) + } + + // Override the `getConnectRequest` function + override fun getConnectRequest(): ConnectRequest? { + // Get the Breez API key from the build config + val apiKey = BuildConfig.BREEZ_SDK_API_KEY + val glNodeConf = GreenlightNodeConfig(null, null) + val nodeConf = NodeConfig.Greenlight(glNodeConf) + val config = defaultConfig(EnvironmentType.PRODUCTION, apiKey, nodeConf) + + // Set the workingDir as the same directory as the main application + config.workingDir = "${applicationContext.applicationInfo.dataDir}/breezSdk" + + // Get the mnemonic from secured storage using an implementation of + // `readSecuredValue` depending on how data is written to secured storage. + // See Developer Note + return readSecuredValue(applicationContext, ACCOUNT_MNEMONIC) + ?.let { mnemonic -> + ConnectRequest(config, mnemonicToSeed(mnemonic)) + } + } + + // Override the `getServiceConfig` function + override fun getServiceConfig(): ServiceConfig? { + // For now just return the default config + return ServiceConfig.default() + } +} +``` diff --git a/src/notifications/android_service.md b/src/notifications/android_service.md index e69de29b..8a8189bd 100644 --- a/src/notifications/android_service.md +++ b/src/notifications/android_service.md @@ -0,0 +1,37 @@ +# Android Foreground Service + +In the `AndroidManifest.xml` file of the application's `app/src/main` directory, add the user permissions necessary to handle notifications `POST_NOTIFICATIONS` as a foreground service `FOREGROUND_SERVICE`. Then to your main application add two services, one to handle messaging events and one to handle the foreground service. + +```xml + + + + + + + + + + + + + + + + + + + + +``` diff --git a/src/notifications/android_setup.md b/src/notifications/android_setup.md index f5aec8a3..ab24ebab 100644 --- a/src/notifications/android_setup.md +++ b/src/notifications/android_setup.md @@ -1 +1,7 @@ -# Android +# Setup the Android Notification Plugin + +In order to add the Notification Plugin to your Android application, first you need to setup the Foreground Service, then add the Notification Plugin dependency and integrate it: + +## Next Steps +- **[Setup the Foreground Service](android_service.md)** +- **[Add the Notification Plugin](android_plugin.md)** diff --git a/src/notifications/changing_strings.md b/src/notifications/changing_strings.md index 09fd20f0..8de4a3fe 100644 --- a/src/notifications/changing_strings.md +++ b/src/notifications/changing_strings.md @@ -6,7 +6,7 @@ The Notification Plugin uses a set of identifiers and default strings to display In the `string.xml` file of the application's `res/values` directory, add the key/value: -``` +```xml Pay to Custom App @@ -18,7 +18,7 @@ You can find the current identifiers and default strings [here](https://github.c In the `Info.plist` file of the `NotificationService` target, add the key/value: -``` +```xml diff --git a/src/notifications/ios_plugin.md b/src/notifications/ios_plugin.md index a2098e8b..252d60de 100644 --- a/src/notifications/ios_plugin.md +++ b/src/notifications/ios_plugin.md @@ -2,7 +2,7 @@ Add the `BreezSDK` cocoapod to your iOS Podfile, with the target `NotificationService`. You can add any other dependencies your require here also, for example `KeychainAccess` to read the saved mnemonic from the keychain. -``` +```podfile target 'NotificationService' do pod 'BreezSDK' pod 'KeychainAccess' @@ -42,6 +42,7 @@ fileprivate let accountMnemonic: String = "BREEZ_SDK_SEED_MNEMONIC" fileprivate let accountApiKey: String = "BREEZ_SDK_API_KEY" class NotificationService: SDKNotificationService { + // Override the `getConnectRequest` function override func getConnectRequest() -> ConnectRequest? { // Get the Breez API key from the target bundle's Info.plist guard let apiKey = Bundle.main.object(forInfoDictionaryKey: accountApiKey) as? String else { From 2e19b2a3f248a95a72184cdba6705c24bf2b4cba Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 27 Mar 2024 13:25:24 +0100 Subject: [PATCH 13/37] Remove empty file --- src/notifications/receive_payment.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 src/notifications/receive_payment.md diff --git a/src/notifications/receive_payment.md b/src/notifications/receive_payment.md deleted file mode 100644 index dbe9e690..00000000 --- a/src/notifications/receive_payment.md +++ /dev/null @@ -1 +0,0 @@ -# Setup an NDS From e553d1c0f8ffe085deaa81f57947c17d6214f42e Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Wed, 27 Mar 2024 14:51:15 +0100 Subject: [PATCH 14/37] Register additional notification group/channel in example --- src/notifications/custom_notifications.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/notifications/custom_notifications.md b/src/notifications/custom_notifications.md index bf5910e5..1df9d6cd 100644 --- a/src/notifications/custom_notifications.md +++ b/src/notifications/custom_notifications.md @@ -38,10 +38,13 @@ First you need to override the getJobFromIntent function in the imp ```kotlin,ignore package com.example.application +import android.app.NotificationManager import android.content.Intent import breez_sdk_notification.ForegroundService import breez_sdk_notification.job.Job import breez_sdk_notification.Message +import breez_sdk_notification.NotificationHelper.Companion.createNotificationChannel +import breez_sdk_notification.NotificationHelper.Companion.createNotificationChannelGroup import breez_sdk_notification.NotificationHelper.Companion.registerNotificationChannels class ExampleForegroundService : ForegroundService() { @@ -51,6 +54,20 @@ class ExampleForegroundService : ForegroundService() { // First register the default notification channels registerNotificationChannels(applicationContext, DEFAULT_CLICK_ACTION) // Then register any additional notification channels + createNotificationChannelGroup( + applicationContext, + "custom_job_group", + "Custom Job Group", + "Required to handle custom job requests when the application is in the background" + ) + createNotificationChannel( + applicationContext, + "CUSTOM_JOB", + "Custom Job", + "Notifications for custom job when the application is in the background", + "custom_job_group", + NotificationManager.IMPORTANCE_DEFAULT + ) } // Override the `getJobFromIntent` function @@ -181,8 +198,7 @@ class CustomJob( // The `start` function is called once the SDK instance is connected override fun start(breezSDK: BlockingBreezServices) { // Remember if you are using a custom notification channel, you have to register it first - val applicationId = context.applicationContext.packageName - val notificationChannel = "${applicationId}.CUSTOM_JOB" + val notificationChannel = "CUSTOM_JOB" try { // Decode the `CustomRequest` from the payload val request = Json.decodeFromString(CustomRequest.serializer(), payload) From aac93f6efe04e5b23b0f9a05874aac19af51e57b Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Thu, 28 Mar 2024 16:34:16 +0100 Subject: [PATCH 15/37] Change the job finishing call --- src/notifications/custom_notifications.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/notifications/custom_notifications.md b/src/notifications/custom_notifications.md index 1df9d6cd..4da5ce85 100644 --- a/src/notifications/custom_notifications.md +++ b/src/notifications/custom_notifications.md @@ -218,10 +218,9 @@ class CustomJob( ) } - // Shutdown the foreground service once finished - fgService.shutdown() + // Tell the foreground service the job is finished + fgService.onFinished(this) } - } ``` From 3c3b1fda0a612197c1e47d0ef3c968fb442dcc39 Mon Sep 17 00:00:00 2001 From: Ross Savage <551697+dangeross@users.noreply.github.com> Date: Thu, 28 Mar 2024 20:54:50 +0100 Subject: [PATCH 16/37] Apply suggestions from code review Co-authored-by: Erdem Yerebasmaz --- src/notifications/android_plugin.md | 2 +- src/notifications/getting_started.md | 2 +- src/notifications/register_webhook.md | 4 ++-- src/notifications/setup_nds.md | 4 ++-- src/notifications/setup_plugin.md | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/notifications/android_plugin.md b/src/notifications/android_plugin.md index 2ec2319e..c6edb171 100644 --- a/src/notifications/android_plugin.md +++ b/src/notifications/android_plugin.md @@ -28,7 +28,7 @@ dependencies { ## Integrate the Notification Plugin -You're ready to add some Kotlin code to implement the Notification Plugin in your application. In the example below we are using the `FirebaseMessagingService` to receive the message intents. First lets implement the Notification Plugin's `MessagingService` class along with `FirebaseMessagingService`. +You're ready to add some Kotlin code to implement the Notification Plugin in your application. In the example below, we are using the `FirebaseMessagingService` to receive the message intents. First, let's implement the Notification Plugin's `MessagingService` class along with `FirebaseMessagingService`. ```kotlin package com.example.application diff --git a/src/notifications/getting_started.md b/src/notifications/getting_started.md index 4537b91b..d5c745e6 100644 --- a/src/notifications/getting_started.md +++ b/src/notifications/getting_started.md @@ -1,6 +1,6 @@ # Introduction -The Breez SDK Notification Plugin provides vendors the ability to receive events via mobile notifications even while the application is in the background or closed. This plugin processes several different notification types like receiving payments, LNURL-pay flows and swap confirmations. Within your application you can even extend the functionality to handle your own notification types. +The Breez SDK Notification Plugin provides vendors the ability to receive events via mobile notifications even while the application is in the background or closed. This plugin processes several different notification types like receiving payments, LNURL-pay flows and swap confirmations. You can even extend the functionality to handle your own notification types within your application. ![receive via notifications_2](https://github.com/breez/breez-sdk-docs/assets/31890660/75e7cac6-4480-453d-823b-f52bd6757ce9) diff --git a/src/notifications/register_webhook.md b/src/notifications/register_webhook.md index 6c645b31..1bc389b5 100644 --- a/src/notifications/register_webhook.md +++ b/src/notifications/register_webhook.md @@ -1,6 +1,6 @@ # Register a webhook -Once your vendor [NDS is setup](setup_nds.md) and can accept POST requests from the SDK services, you can within your mail application register the webhook URL with the Breez SDK by calling the register webhook API as follows: +Once your vendor [NDS is set up](setup_nds.md) and can accept POST requests from the SDK services, you can within your mail application register the webhook URL with the Breez SDK by calling the register webhook API as follows:
Rust
@@ -68,4 +68,4 @@ Once your vendor [NDS is setup](setup_nds.md) and can accept POST requests from
-Now when the NDS receives a POST request for this webhook URL, it will forward the request data via push notification to the applications Service Extension (iOS) or Foreground Service (Android) to be handled by the [Notification Plugin](setup_plugin.md). \ No newline at end of file +When the NDS receives a POST request for the registered webhook URL, it will forward the request data via push notification to the applications Service Extension (iOS) or Foreground Service (Android) to be handled by the [Notification Plugin](setup_plugin.md). \ No newline at end of file diff --git a/src/notifications/setup_nds.md b/src/notifications/setup_nds.md index 08afeb0c..db49d111 100644 --- a/src/notifications/setup_nds.md +++ b/src/notifications/setup_nds.md @@ -1,6 +1,6 @@ # Setup a Notification Delivery Service (NDS) -Receiving push notifications involves using a NDS as an intermediary to receive the webhook event from one of the SDK services. These can be currently one of several services that provide information about events that the Breez SDK registers for. For example, payment events from the LSP or swap transaction confirmation events from the chain service. The NDS then processes this information and dispatches a push notification to the intended mobile device, ensuring the user receives timely updates about incoming events. This architecture necessitates vendors setup up and maintain their own NDS, tailored to handle and forward these notifications efficiently. An example payload when a `payment_received` POST request to the webhook URL contains the following JSON formatted structure: +Receiving push notifications involves using an NDS as an intermediary to receive the webhook event from one of the SDK services. These can be currently one of several services that provide information about events that the Breez SDK registers for. For example, payment events from the LSP or swap transaction confirmation events from the chain service. The NDS then processes this information and dispatches a push notification to the intended mobile device, ensuring the user receives timely updates about incoming events. This architecture necessitates vendors set up and maintain their own NDS, tailored to handle and forward these notifications efficiently. An example payload when a `payment_received` POST request to the webhook URL contains the following JSON formatted structure: ``` { @@ -11,7 +11,7 @@ Receiving push notifications involves using a NDS as an intermediary to receive } ``` -The vendor needs to run their own NDS because it is configured to send push notifications to your application users and therefore should be configured with the required keys and certificates. You can use our [reference NDS implementation](https://github.com/breez/notify) as an implementation starting point or as is. Our implementation of the NDS expects URLs in the following format: +The vendor needs to run their own NDS because it is configured to send push notifications to your application users and therefore should be configured with the required keys and certificates. You can use our [reference NDS implementation](https://github.com/breez/notify) as a starting point or as is. Our implementation of the NDS expects URLs in the following format: ``` https://your-nds-service.com/notify?platform=&token=[PUSH_TOKEN] ``` diff --git a/src/notifications/setup_plugin.md b/src/notifications/setup_plugin.md index ae2ce90a..ceac024d 100644 --- a/src/notifications/setup_plugin.md +++ b/src/notifications/setup_plugin.md @@ -1,6 +1,6 @@ # Notification Integration -The Notification Plugin is designed to be used when the application isn't running. For this to be acheived reliably and to ensure that the notification is processed, specific implementations are required for both Android and iOS platforms to handle the incoming push notifications. +The Notification Plugin is designed to be used when the application isn't running. For this to be achieved reliably and to ensure that the notification is processed, specific implementations are required for both Android and iOS platforms to handle the incoming push notifications. * For Android, the application requires a [Foreground Service](android_setup.md) to handle the notification intent. From fef0ff7e99bc8235fee212ad63a21a282250bfba Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Thu, 28 Mar 2024 21:16:54 +0100 Subject: [PATCH 17/37] Add hidden links for previously shared urls, link to breez-sdk-swift repo, add android reference implementation link --- src/SUMMARY.md | 3 + src/guide/payment_notification.md | 116 ++-------------------------- src/notifications/android_plugin.md | 3 + src/notifications/ios_plugin.md | 2 + 4 files changed, 16 insertions(+), 108 deletions(-) diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 3d624c96..9c6e0402 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -42,3 +42,6 @@ - [Service Configuration](notifications/service_configuration.md) - [Changing Default Strings](notifications/changing_strings.md) - [Custom Notification Handling](notifications/custom_notifications.md) + + +[](guide/payment_notification.md) diff --git a/src/guide/payment_notification.md b/src/guide/payment_notification.md index 54fba4cc..2a166c74 100644 --- a/src/guide/payment_notification.md +++ b/src/guide/payment_notification.md @@ -1,114 +1,14 @@ -# Receiving payments via mobile notifications +# Introduction -The Breez SDK provides users the ability to receive Lightning payments via mobile notifications. It uses a webhook that allows your application to be notified (via a pre-specified URL) when a payment is about to be received. To use this feature, you need to set up a webhook that an LSP can call when a payment is received and [register it in the Breez SDK](payment_notification.html#step-3-register-a-webhook). This webhook, a URL endpoint in your application, will handle incoming payment notifications. This URL should be capable of receiving POST requests. The payment received webhook payload is json formatted and contains the following structure: - -
-
-{
- "template": "payment_received",
- "data": {  
-  "payment_hash": [payment hash]
- }
-}
-
-
- -## Webhook integration for receiving payments while the app isn't running -You can use this webhook to allow mobile users to receive Lightning payments even if they aren't running the app at the time of the payment. This process involves using a Notification Delivery Service (NDS) acting as an intermediary. When a payment is made to a user, the LSP sends a notification to the NDS configured with a specific webhook URL. The NDS then processes this information and dispatches a push notification to the intended mobile device, ensuring the user receives timely updates about incoming payments. This architecture necessitates vendors setting up and maintaining their own NDS, tailored to handle and forward these notifications efficiently. +The Breez SDK Notification Plugin provides vendors the ability to receive events via mobile notifications even while the application is in the background or closed. This plugin processes several different notification types like receiving payments, LNURL-pay flows and swap confirmations. You can even extend the functionality to handle your own notification types within your application. ![receive via notifications_2](https://github.com/breez/breez-sdk-docs/assets/31890660/75e7cac6-4480-453d-823b-f52bd6757ce9) -### Step 1: Run your own NDS -You will need to run your own NDS because the NDS is configured to send push notifications to your app users and therefore should be configured with the required keys and certificates. - -You can use our [reference NDS implementation](https://github.com/breez/notify). - -Our NDS implementation expects URLs in the following format: -
-
- https://your-nds-service.com/notify?platform=&token=[PUSH_TOKEN]
-
-
- -Once the NDS has received such request it will send a push notification to the corresponding devices. - -### Step 2: Obtain a mobile push token -Ensure that your mobile application is set up to receive push notifications and can generate a push token. This token uniquely identifies the device for push notifications. -* For iOS, use [Apple Push Notification Service (APNs)](https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns) to get the token. -* For Android, use [Firebase Cloud Messaging (FCM)](https://firebase.google.com/docs/cloud-messaging/manage-tokens) to obtain the token. - -### Step 3: Register a webhook -Register the constructed URL with the Breez SDK By calling the register-payment-webook API as follows: - - -
Rust
-
- -```rust,ignore -{{#include ../../snippets/rust/src/webhook.rs:register-payment-webook}} -``` -
- -
Swift
-
- -```swift,ignore -{{#include ../../snippets/swift/BreezSDKExamples/Sources/Webhook.swift:register-payment-webook}} -``` -
- -
Kotlin
-
- -```kotlin,ignore -{{#include ../../snippets/kotlin_mpp_lib/shared/src/commonMain/kotlin/com/example/kotlinmpplib/Webhook.kt:register-payment-webook}} -``` -
- -
React Native
-
- -```typescript -{{#include ../../snippets/react-native/webhook.ts:register-payment-webook}} -``` -
- -
Dart
-
- -```dart,ignore -{{#include ../../snippets/dart_snippets/lib/webhook.dart:register-payment-webook}} -``` -
- -
Python
-
- -```python,ignore -{{#include ../../snippets/python/src/webhook.py:register-payment-webook}} -``` -
- -
Go
-
- -```go,ignore -{{#include ../../snippets/go/webhook.go:register-payment-webook}} -``` -
- -
C#
-
- -```cs,ignore -{{#include ../../snippets/csharp/Webhook.cs:register-payment-webook}} -``` -
- -
+## How it works -### Step 4: Handling notifications when the app isn't running -To ensure that your mobile application can handle payment notifications even when it is not actively running, specific implementations are required for both iOS and Android platforms. This involves waking up the app upon receiving a push notification, connecting with the Breez SDK, and then waiting for the payment to be fully received. -* For iOS, please follow the steps in [iOS NotificationServiceExtension](ios_notification_service_extension.md). +This process involves using a Notification Delivery Service (NDS) acting as an intermediary host by the application developer. The NDS must provide a public facing webhook URL where a POST request can be sent to when a notification needs to be delivered to the application. The NDS then forwards the data sent in the webhook POST request via push notification to the application. When the application then receives the push notification then Breez SDK Notification Plugin can be used to process the event. -* For Android, please follow the steps in [Android foreground service](android_notification_foreground_service.md). +## Next Steps +- **[Setup an NDS](/notifications/setup_nds.md)** to receive webhook requests +- **[Register a webhook](/notifications/register_webhook.md)** in your main application +- **[Project integration](/notifications/setup_plugin.md)** using a notification service extension or foreground service diff --git a/src/notifications/android_plugin.md b/src/notifications/android_plugin.md index c6edb171..493f69a5 100644 --- a/src/notifications/android_plugin.md +++ b/src/notifications/android_plugin.md @@ -143,3 +143,6 @@ class ExampleForegroundService : ForegroundService() { } } ``` + +## Reference implementation +For a complete reference, see how we implemented it in c-breez wallet: [BreezFcmService.kt](https://github.com/breez/c-breez/blob/main/android/app/src/main/kotlin/com/cBreez/client/BreezFcmService.kt). \ No newline at end of file diff --git a/src/notifications/ios_plugin.md b/src/notifications/ios_plugin.md index 252d60de..99fe4506 100644 --- a/src/notifications/ios_plugin.md +++ b/src/notifications/ios_plugin.md @@ -11,6 +11,8 @@ end Once added to the Podfile, run `pod install` to install the dependencies. +More installation methods, including with the Swift Package Manager, can be found in the [breez-sdk-swift](https://github.com/breez/breez-sdk-swift/blob/main/README.md) repository. + ## Integrate the Notification Plugin You're ready to add some Swift code to implement the Notification Plugin in your NotificationService target. In Xcode, in the `NotificationService` folder, open the Swift file named `NotificationService.swift`. From 553c50003146738dd0198faba92794eb19428b1c Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Fri, 29 Mar 2024 04:09:37 +0100 Subject: [PATCH 18/37] Fix the NotificationService name --- src/notifications/ios_service.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/notifications/ios_service.md b/src/notifications/ios_service.md index 074975b0..11900641 100644 --- a/src/notifications/ios_service.md +++ b/src/notifications/ios_service.md @@ -4,9 +4,9 @@ In Xcode add a new Target to your application: 1. In the menu `File > New > Target...` 2. Select `Notification Service Extension` -3. Give the name `NotificationExtension` +3. Give the name `NotificationService` -This should create a new target with a bundle identifier like `com.example.application.NotificationExtension` and a folder in your application called `NotificationExtension`. +This should create a new target with a bundle identifier like `com.example.application.NotificationService` and a folder in your application called `NotificationService`. ## Identifiers @@ -25,7 +25,7 @@ Now add the App Group to your existing main application release and debug Identi Create new release and debug Identifiers for the new service extension. 1. Click `+` to add an Identifier 2. Select `App IDs` from the list -3. Give the Identifier a description and identifier the same as the service extension, like `com.example.application.NotificationExtension` +3. Give the Identifier a description and identifier the same as the service extension, like `com.example.application.NotificationService` 4. Enable the `App Groups` app service 5. Save the Identifier, then edit again it to add the created app group as above From 989e6b6ff95e4a3f4b15a76bafa58f8464615d68 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Thu, 4 Apr 2024 17:26:11 +0200 Subject: [PATCH 19/37] Add descriptions of handled notification types --- src/notifications/getting_started.md | 51 ++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/notifications/getting_started.md b/src/notifications/getting_started.md index d5c745e6..8615826b 100644 --- a/src/notifications/getting_started.md +++ b/src/notifications/getting_started.md @@ -8,6 +8,57 @@ The Breez SDK Notification Plugin provides vendors the ability to receive events This process involves using a Notification Delivery Service (NDS) acting as an intermediary host by the application developer. The NDS must provide a public facing webhook URL where a POST request can be sent to when a notification needs to be delivered to the application. The NDS then forwards the data sent in the webhook POST request via push notification to the application. When the application then receives the push notification then Breez SDK Notification Plugin can be used to process the event. +## Handled Types + +The following notification types are handled by default by the Notification Plugin. + +#### Payment Received + +When an LSP intercepts a payment on the way to the user's node, the LSP will call the webhook with the POST data: +```json +{ + "template": "payment_received", + "data": { + "payment_hash": "" // The payment hash that is in progress + } +} +``` + +#### Swap Confirmed + +When the chain service confirms that there are funds available at the swap address when receiving a onchain payment, the chain service will call the webhook with the POST data: +```json +{ + "template": "address_txs_confirmed", + "data": { + "address": "" // The address of the swap with confirmed funds + } +} +``` + +#### LNURL-pay + +When an LNURL service receives a request for LNURL-pay info or an invoice, the LNURL service will first call the webhook with the POST data: +```json +{ + "template": "lnurlpay_info", + "data": { + "callback_url": "", // The URL of the LNURL service + "reply_url": "" // The URL to reply to this request + } +} +``` +Then to get an invoice with the POST data: +```json +{ + "template": "lnurlpay_invoice", + "data": { + "amount": 0, // The amount in millisatoshis within the min/max sendable range + "reply_url": "" // The URL to reply to this request + } +} +``` + ## Next Steps - **[Setup an NDS](setup_nds.md)** to receive webhook requests - **[Register a webhook](register_webhook.md)** in your main application From ab0fcf3bc27989972353cd487d214e27b4b20d25 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Thu, 11 Apr 2024 16:43:14 +0200 Subject: [PATCH 20/37] Add optional payment label to snippets --- snippets/csharp/LnurlPay.cs | 6 ++-- snippets/csharp/SendPayment.cs | 7 ++-- snippets/csharp/SendSpontaneousPayment.cs | 8 +++-- snippets/dart_snippets/lib/lnurl_pay.dart | 5 ++- snippets/dart_snippets/lib/send_payment.dart | 4 ++- .../lib/send_spontaneous_payment.dart | 7 ++-- snippets/go/lnurl_pay.go | 10 +++--- snippets/go/send_payment.go | 6 ++-- snippets/go/send_spontaneous_payment.go | 6 ++-- .../com/example/kotlinmpplib/LnurlPay.kt | 5 ++- .../com/example/kotlinmpplib/SendPayment.kt | 5 +-- .../kotlinmpplib/SendSpontaneousPayment.kt | 11 ++++--- snippets/python/src/closed_channel.py | 1 - snippets/python/src/getting_started.py | 2 +- snippets/python/src/lnurl_pay.py | 8 +++-- snippets/python/src/lnurl_withdraw.py | 4 +-- snippets/python/src/receive_onchain.py | 32 +++++++++---------- snippets/python/src/send_payment.py | 17 ++++++++++ .../python/src/send_spontaneous_payment.py | 21 ++++++------ snippets/react-native/lnurl_pay.ts | 5 ++- snippets/react-native/send_payment.ts | 9 ++++-- .../react-native/send_spontaneous_payment.ts | 8 +++-- snippets/rust/src/lnurl_pay.rs | 6 ++-- snippets/rust/src/send_payment.rs | 7 ++-- snippets/rust/src/send_spontaneous_payment.rs | 9 ++++-- snippets/rust/src/service_status.rs | 2 +- .../BreezSDKExamples/Sources/LnurlPay.swift | 7 ++-- .../Sources/SendPayment.swift | 4 ++- .../Sources/SendSpontaneous.swift | 17 ++++------ src/guide/send_payment.md | 9 +----- 30 files changed, 150 insertions(+), 98 deletions(-) create mode 100644 snippets/python/src/send_payment.py diff --git a/snippets/csharp/LnurlPay.cs b/snippets/csharp/LnurlPay.cs index c63d71ca..965e4827 100644 --- a/snippets/csharp/LnurlPay.cs +++ b/snippets/csharp/LnurlPay.cs @@ -16,8 +16,10 @@ public void LnurlPay(BlockingBreezServices sdk) if (input is InputType.LnUrlPay lnurlp) { var amountMsat = lnurlp.data.minSendable; - var result = sdk.PayLnurl( - new LnUrlPayRequest(lnurlp.data, amountMsat, "comment")); + var optionalComment = ""; + var optionalPaymentLabel = "
-### Receive onchain +### Receiving an on-chain transaction For receiving onchain, there is a minimum and a maximum amount the user can receive. The fees are made up of the same components as receiving a lightning payment. The user gets an onchain address from `receive_onchain`. There is no way to know ahead of time exactly the amount that will be received on this address, so it is recommended to show the user the receivable boundaries and the fees involved: From e98cc6fcf35b7a58697e4f9ef3d2b64fd0834c76 Mon Sep 17 00:00:00 2001 From: Jesse de Wit Date: Fri, 3 May 2024 15:12:47 +0200 Subject: [PATCH 35/37] allow prerelease C# packages --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a663537a..508b98f2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -151,7 +151,7 @@ jobs: - name: Add nuget dependency working-directory: snippets/csharp run: | - dotnet add package Breez.Sdk -s ./packages + dotnet add package Breez.Sdk -s ./packages --prerelease - name: Build the csharp project working-directory: snippets/csharp From dc8e183106bb7c3126807428e4580fc60da7b090 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Fri, 3 May 2024 16:25:17 +0200 Subject: [PATCH 36/37] Clarify when to register a webhook URL --- src/notifications/register_webhook.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/notifications/register_webhook.md b/src/notifications/register_webhook.md index d196cb93..d06056a2 100644 --- a/src/notifications/register_webhook.md +++ b/src/notifications/register_webhook.md @@ -1,6 +1,6 @@ # Registering a webhook -Once your [NDS is set up](setup_nds.md) and can accept POST requests from the SDK services, you can within your mail application register the webhook URL with the Breez SDK by calling the register webhook API as follows: +Once your [NDS is set up](setup_nds.md) and can accept POST requests from the SDK services, you can within your main application register the webhook URL with the Breez SDK. The registration of the webhook URL should be done **every time** the application is started and when the webhook URL changes. This can be done by calling the register webhook API as follows:
Rust
From d38f9f30fdae3120771ac5f54a6b6866c59df0cc Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Mon, 6 May 2024 10:50:30 +0200 Subject: [PATCH 37/37] Update to 0.4.0 --- .github/workflows/main.yml | 4 ++-- snippets/dart_snippets/pubspec.lock | 2 +- snippets/kotlin_mpp_lib/shared/build.gradle.kts | 2 +- snippets/react-native/yarn.lock | 8 ++++---- snippets/rust/Cargo.toml | 2 +- snippets/swift/BreezSDKExamples/Package.resolved | 4 ++-- snippets/swift/BreezSDKExamples/Package.swift | 2 +- src/guide/install.md | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f4918629..11d0c06b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -25,8 +25,8 @@ jobs: name: setup runs-on: ubuntu-latest outputs: - sdk-ref: ${{ inputs.sdk-ref || '0.4.0-rc5' }} - package-version: '0.4.0-rc5' + sdk-ref: ${{ inputs.sdk-ref || '0.4.0' }} + package-version: '0.4.0' steps: - run: echo "set pre-setup output variables" diff --git a/snippets/dart_snippets/pubspec.lock b/snippets/dart_snippets/pubspec.lock index 219d2f72..1bc6990b 100644 --- a/snippets/dart_snippets/pubspec.lock +++ b/snippets/dart_snippets/pubspec.lock @@ -55,7 +55,7 @@ packages: path: "packages/breez-sdk-flutter" relative: true source: path - version: "0.4.0-rc5" + version: "0.4.0" build: dependency: transitive description: diff --git a/snippets/kotlin_mpp_lib/shared/build.gradle.kts b/snippets/kotlin_mpp_lib/shared/build.gradle.kts index 104de5da..e4fc42e8 100644 --- a/snippets/kotlin_mpp_lib/shared/build.gradle.kts +++ b/snippets/kotlin_mpp_lib/shared/build.gradle.kts @@ -34,7 +34,7 @@ kotlin { } val commonMain by getting { dependencies { - implementation("technology.breez:breez-sdk-kmp:0.4.0-rc5") + implementation("technology.breez:breez-sdk-kmp:0.4.0") } } } diff --git a/snippets/react-native/yarn.lock b/snippets/react-native/yarn.lock index aad1bf87..b7761575 100644 --- a/snippets/react-native/yarn.lock +++ b/snippets/react-native/yarn.lock @@ -714,10 +714,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@breeztech/react-native-breez-sdk@0.4.0-rc5": - version "0.4.0-rc5" - resolved "https://registry.yarnpkg.com/@breeztech/react-native-breez-sdk/-/react-native-breez-sdk-0.4.0-rc5.tgz#764329fe2482f553b4d8be57b6f65c111d9fdd47" - integrity sha512-HMAd+vUKLIJt8vjbBpKEV1y07sktb4prpQRiKSuGsKlrchlanE4OgnC+OeejrwvraiQgC/UoyISW6C3VN2IF8A== +"@breeztech/react-native-breez-sdk@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@breeztech/react-native-breez-sdk/-/react-native-breez-sdk-0.4.0.tgz#986136d9414ff9fb5d67c1b005b966c0b4440637" + integrity sha512-9OGmYUIxfhFUTbvnRXKG551xM77bAW4Fb4SgKa7KieFI3oytFR5xPl3OHU1baUqAUqB86QEAVxljYMA+YUR4gA== "@esbuild/android-arm64@0.18.20": version "0.18.20" diff --git a/snippets/rust/Cargo.toml b/snippets/rust/Cargo.toml index 7e806c0c..8142d9d4 100644 --- a/snippets/rust/Cargo.toml +++ b/snippets/rust/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] anyhow = "1" bip39 = { version = "2", features = ["rand"] } -breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.4.0-rc5" } +breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.4.0" } log = "0.4" tokio = "1.29" diff --git a/snippets/swift/BreezSDKExamples/Package.resolved b/snippets/swift/BreezSDKExamples/Package.resolved index 13c23e1d..74b6379e 100644 --- a/snippets/swift/BreezSDKExamples/Package.resolved +++ b/snippets/swift/BreezSDKExamples/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/breez/breez-sdk-swift", "state" : { - "revision" : "7431e35877003a310da3871cccd0048c5f233bab", - "version" : "0.4.0-rc5" + "revision" : "687a6a0c50ac966e55fbc24c2a717e484bb0d962", + "version" : "0.4.0" } }, { diff --git a/snippets/swift/BreezSDKExamples/Package.swift b/snippets/swift/BreezSDKExamples/Package.swift index b7ee45eb..42c9cdc3 100644 --- a/snippets/swift/BreezSDKExamples/Package.swift +++ b/snippets/swift/BreezSDKExamples/Package.swift @@ -8,7 +8,7 @@ let package = Package( platforms: [.macOS(.v13)], dependencies: [ .package(url: "https://github.com/apple/swift-argument-parser", from: "1.2.3"), - .package(url: "https://github.com/breez/breez-sdk-swift", from:"0.4.0-rc5") + .package(url: "https://github.com/breez/breez-sdk-swift", from: "0.4.0") ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/src/guide/install.md b/src/guide/install.md index febe84b3..23ee788a 100644 --- a/src/guide/install.md +++ b/src/guide/install.md @@ -93,7 +93,7 @@ Check https://github.com/breez/breez-sdk/releases for the latest version. ```toml [dependencies] -breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.4.0-rc5" } +breez-sdk-core = { git = "https://github.com/breez/breez-sdk", tag = "0.4.0" } ``` ## Flutter/Dart