From 34e338d13a2008566b35d1f0b7a3ab18bf14edbb Mon Sep 17 00:00:00 2001 From: Roei Erez Date: Sun, 2 Jul 2023 00:46:15 +0300 Subject: [PATCH] Add swift examples --- src/guide/getting_started.md | 46 +++++++++++++++++++++++--- src/guide/lnurl_auth.md | 29 ++++++++++++++++ src/guide/lnurl_pay.md | 25 ++++++++++++++ src/guide/lnurl_withdraw.md | 26 +++++++++++++++ src/guide/payments.md | 42 +++++++++++++++++++++++ src/guide/recieve_onchain.md | 64 ++++++++++++++++++++++++++++++++++-- src/guide/send_onchain.md | 56 +++++++++++++++++++++++++++++++ 7 files changed, 281 insertions(+), 7 deletions(-) diff --git a/src/guide/getting_started.md b/src/guide/getting_started.md index 4c6bcb8..b2fb59e 100644 --- a/src/guide/getting_started.md +++ b/src/guide/getting_started.md @@ -74,12 +74,22 @@ if let Some(node_state) = sdk.node_info()? { The first step is to register a new node ## Registering a new node ```swift -// TODO +do { + let seed = try mnemonicToSeed(phrase: ""); + let invite_code = ; + + // register_node takes either greenlight credentials (certifate & key) or invite code. + // At this example we are using the invite code option. + let credentials = try registerNode(network: Network.bitcoin, seed: seed, inviteCode: inviteCode); +} catch SdkError.Error(let message) { + print(message) +} ``` ## Recovering an existing node ```swift -// TODO + let seed = try mnemonicToSeed(phrase: ""); + let credentials = try recoverNode(network: Network.bitcoin, seed: seed); ``` Once the credentials are retrieved they should be saved in a secured storage. @@ -87,15 +97,41 @@ The next step is to initialize the SDK and start the node: ## Initializing the SDK ```swift -/* TODO -*/ + +// SDK events listener +class SDKListener: EventListener { + func onEvent(e: BreezEvent) { + print("received event ", e); + } +} + +// Create the default config +let config = breez_sdk.defaultConfig(envType: EnvironmentType.production) + +// Customize the config object according to your needs +config.apiKey = "your API key"; +config.workingDir = "path to an existing directory"; + +do { + let sdkServices = try initServices(config: config, seed: seed, creds: credentials, listener: SDKListener()); + try sdkServices.start(); +} catch SdkError.Error(let message) { + print(message) +} ``` At any point we can fetch our balance from the Greenlight node: ```swift -// TODO +do { + let nodeInfo = try sdkServices.nodeInfo(); + let lnBalance = nodeInfo.channelsBalanceMsat; + let onchainBalance = nodeInfo.onchainBalanceMsat; +} catch SdkError.Error(let message) { + print(message) +} ``` + diff --git a/src/guide/lnurl_auth.md b/src/guide/lnurl_auth.md index 0a7ea4a..7c94489 100644 --- a/src/guide/lnurl_auth.md +++ b/src/guide/lnurl_auth.md @@ -1,6 +1,9 @@ # LNURL-Auth ## Usage + +
Rust
+
```rust,no_run // Endpoint can also be of the form: @@ -21,7 +24,33 @@ if let Ok(LnUrlAuth{data: ad}) = parse(lnurl_auth_url).await { } } ``` +
+
Swift
+
+```swift +// Endpoint can also be of the form: +// keyauth://domain.com/auth?key=val +let lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu"; + +do { + let inputType = try parseInput(s: lnurlAuthUrl) + if case .lnUrlAuth(data) = inputType { + let result = try sdk.lnurlAuth(data) + switch result { + case .ok: + print("Successfully authenticated") + case .errorStatus(data): + print("Failed to authenticate") + } + } +} catch SdkError.Error(let message) { + print(message) +} +``` + +
+ ## Supported Specs diff --git a/src/guide/lnurl_pay.md b/src/guide/lnurl_pay.md index 1019d92..732dd1d 100644 --- a/src/guide/lnurl_pay.md +++ b/src/guide/lnurl_pay.md @@ -2,6 +2,10 @@ ## Usage + +
Rust
+
+ ```rust,no_run // Endpoint can also be of the form: // lnurlp://domain.com/lnurl-pay?key=val @@ -17,6 +21,27 @@ if let Ok(LnUrlPay{data: pd}) = parse(lnurl_pay_url).await { } ``` +
+
Swift
+
+ +```swift +// Endpoint can also be of the form: +// lnurlp://domain.com/lnurl-pay?key=val +// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf +let lnurlPayUrl = "lightning@address.com"; +do { + let inputType = try parseInput(s: input) + if case .lnUrlPay(data) = inputType { + let amountSats = inputType.minSendable; + try sdk.payLnurl(amountSats: amountSats, "comment", reqData: data) + } +} catch SdkError.Error(let message) { + print(message) +} +``` +
+ ## Supported Specs diff --git a/src/guide/lnurl_withdraw.md b/src/guide/lnurl_withdraw.md index 869e833..1677f0c 100644 --- a/src/guide/lnurl_withdraw.md +++ b/src/guide/lnurl_withdraw.md @@ -3,6 +3,10 @@ ## Usage + +
Rust
+
+ ```rust,no_run // Endpoint can also be of the form: // lnurlw://domain.com/lnurl-withdraw?key=val @@ -16,7 +20,29 @@ if let Ok(LnUrlWithdraw{data: wd}) = parse(lnurl_withdraw_url).await { sdk.lnurl_withdraw(wd, amount_msat, Some(description)).await?; } ``` +
+
Swift
+
+```swift +// Endpoint can also be of the form: +// lnurlw://domain.com/lnurl-withdraw?key=val +let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"; + +do { + let inputType = try parseInput(s: input) + if case .lnUrlWithdraw(data) = inputType { + let amountSat = data.minWithdrawable; + let description = "Test withdraw" + try sdk.withdrawLnurl(amountSats: amountSat, description: "comment", reqData: data) + } +} catch SdkError.Error(let message) { + print(message) +} + +``` +
+ ## Supported Specs diff --git a/src/guide/payments.md b/src/guide/payments.md index 96faf60..303848b 100644 --- a/src/guide/payments.md +++ b/src/guide/payments.md @@ -1,5 +1,8 @@ # Sending and receiving Lightning payments + +
Rust
+
## Receiving Lightning Payments Breez SDK doesn't require you to open a channel and set up your inbound liquidity. Breez SDK automatically connects your node to the LSP peer and you can now receive payments: @@ -20,3 +23,42 @@ let node_id = "..."; sdk.send_payment(node_id.into(), Some(3000)).await?; ``` +
+
Swift
+ +## Receiving Lightning Payments +Breez SDK doesn't require you to open a channel and set up your inbound liquidity. +Breez SDK automatically connects your node to the LSP peer and you can now receive payments: + +```swift +do { + let invoice = try sdk.receivePayment(amountSats: 3000, description: "Invoice for 3000 sats") +} catch SdkError.Error(let message) { + print(message) +} +``` + +## Sending Lightning Payments +```swift +let bolt11 = "..."; +do { + let payment = try sdk.sendPayment(bolt11: bolt11, amountSats: 3000) +} catch SdkError.Error(let message) { + print(message) +} +``` + +## Sending Spontaneous Lightning Payments +```swift +let nodeId = "..."; +do { + let payment = try sdk.sendSpontaneousPayment(nodeId: nodeId, amountSats: 3000) +} catch SdkError.Error(let message) { + print(message) +} +``` + +
+ +
+
\ No newline at end of file diff --git a/src/guide/recieve_onchain.md b/src/guide/recieve_onchain.md index 7c9fb04..1d6cd84 100644 --- a/src/guide/recieve_onchain.md +++ b/src/guide/recieve_onchain.md @@ -1,6 +1,10 @@ # Receiving an on-chain transaction (swap-in) There are cases when you have funds in some bitcoin address and you would like to send those to your lightning node. + +
Rust
+
+ ```rust,no_run let swap_info = sdk.receive_onchain().await?; @@ -29,6 +33,62 @@ Once you have a refundable swap in hand, use the follwing code to execute a refu ```rust,no_run let destination_address = "...".into() -let sat_per_byte = -sdk.refund(refundable.bitcoin_address, destination_address, sat_per_byte).await? +let sat_per_vbyte = +sdk.refund(refundable.bitcoin_address, destination_address, sat_per_vbyte).await? ``` +
+
Swift
+
+ +```swift +do { + let swapInfo = try sdk.receiveOnchain(); + + // Send your funds to the bellow bitcoin address + let address = swapInfo.bitcoinAddress; +} catch SdkError.Error(let message) { + print(message) +} +``` + +Once you've sent the funds to the above address, the SDK will monitor this address for unspent confirmed outputs and use a trustless submarine swap to receive these into your Lightning node. You can always monitor the status of the current in-progress swap using the following code: + +```swift +do { + let swapInfo = try sdk.inProgressSwap() +} catch SdkError.Error(let message) { + print(message) +} +``` + +The process of receiving funds via an on-chain address is trustless and uses a submarine swap. This means there are two ways to spend the sent funds: + +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 - this is the negative case where your node will execute a refund. + +In order to execute a refund, you need to supply an on-chain address to where the refunded amount will be sent. The following code will retrieve the refundable swaps: + +```swift +do { + let refundables = try sdk.listRefundables() +} catch SdkError.Error(let message) { + print(message) +} +``` + +Once you have a refundable swap in hand, use the follwing code to execute a refund: + +```swift +let destinationAddress = "..." +let satPerVbyte = +do { + try sdk.refund( + swapAddress: refundable.bitcoinAddress, + toAddress: destinationAddress, + satPerVbyte: satPerVbyte) +} catch SdkError.Error(let message) { + print(message) +} +``` +
+
\ No newline at end of file diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index 340cd03..eb9207d 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -4,6 +4,10 @@ You can send funds from the Breez SDK wallet to an on-chain address as follows. First, fetch the current reverse swap fees: + +
Rust
+
+ ```rust,no_run let current_fees = sdk.fetch_reverse_swap_fees().await?; @@ -43,7 +47,59 @@ for rs in sdk.in_progress_reverse_swaps().await? { info!("Reverse swap {} in progress, status is {}", rs.id, rs.breez_status); } ``` +
+
Swift
+
+```swift +try { + let currentFees = try sdk.fetchReverseSwapFees() + + println("Percentage fee for the reverse swap service: \(currentFees.feesPercentage))"); + println("Estimated miner fees in sats for locking up funds: \(currentFees.feesLockup)"); + println("Estimated miner fees in sats for claiming funds: \(currentFees.feesClaim)"); +} catch { + print(error) +} +``` + +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 you can send: + +```swift +println("Minimum amount, in sats: \(current_fees.min)"); +println("Maximum amount, in sats: \(current_fees.max)"); +``` + +Once you checked the fees are acceptable, you can start the reverse swap: + +```swift +let destinationAddress = "bc1.."; +let amountSat = currentFees.min; +let satPerVbyte = +try { + try sdk.sendOnchain(amountSat: amountSat, onchainRecipientAddress: destinationAddress, pairHash: currentFees.feesHash, satPerVbyte: satPerVbyte) +} catch { + print(error) +} +``` + +Starting the 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. + +You can check its status with: + +```swift +for rs in sdk.inProgressReverseSwaps() { + println("Reverse swap \(rs.id) in progress, status is \(rs.breezStatus)"); +} +``` +
+
If the reverse swap is successful, you'll get the on-chain payment on your destination address and the HODL invoice will change from pending to settled.