diff --git a/src/guide/getting_started.md b/src/guide/getting_started.md index b82a30c..0645dd5 100644 --- a/src/guide/getting_started.md +++ b/src/guide/getting_started.md @@ -80,7 +80,7 @@ do { // 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, registerCredentials: nil, inviteCode: inviteCode); + let credentials = try registerNode(network: Network.bitcoin, seed: seed, registerCredentials: nil, inviteCode: inviteCode); } catch { // handle error } @@ -89,8 +89,8 @@ do { ## Recovering an existing node ```swift do { - let seed = try mnemonicToSeed(phrase: ""); - let credentials = try recoverNode(network: Network.bitcoin, seed: seed); + let seed = try mnemonicToSeed(phrase: ""); + let credentials = try recoverNode(network: Network.bitcoin, seed: seed); } catch { // handle error } @@ -104,9 +104,9 @@ The next step is to initialize the SDK and start the node: // SDK events listener class SDKListener: EventListener { - func onEvent(e: BreezEvent) { - print("received event ", e); - } + func onEvent(e: BreezEvent) { + print("received event ", e); + } } // Create the default config @@ -117,8 +117,8 @@ config.apiKey = "your API key"; config.workingDir = "path to an existing directory"; do { - let sdk = try initServices(config: config, seed: seed, creds: credentials, listener: SDKListener()); - try sdk.start(); + let sdk = try initServices(config: config, seed: seed, creds: credentials, listener: SDKListener()); + try sdk.start(); } catch{ // handle error } @@ -127,15 +127,77 @@ do { At any point we can fetch our balance from the Greenlight node: ```swift - do { - let nodeInfo = try sdk.nodeInfo(); - let lnBalance = nodeInfo?.channelsBalanceMsat; - let onchainBalance = nodeInfo?.onchainBalanceMsat; +do { + let nodeInfo = try sdk.nodeInfo(); + let lnBalance = nodeInfo?.channelsBalanceMsat; + let onchainBalance = nodeInfo?.onchainBalanceMsat; } catch { // handle error } ``` + +
React Native
+
+ +The first step is to register a new node +## Registering a new node +```typescript +try { + const seed = await mnemonicToSeed(""); + const invite_code = ""; + + // register_node takes either greenlight credentials (certifate & key) or invite code. + // At this example we are using the invite code option. + const credentials = await registerNode(Network.BITCOIN, seed, inviteCode); +} catch (error) { + console.log(error) +} +``` + +## Recovering an existing node +```typescript + const seed = await mnemonicToSeed(""); + const credentials = await recoverNode(Network.BITCOIN, seed); +``` + +Once the credentials are retrieved they should be saved in a secured storage. +The next step is to initialize the SDK and start the node: + +## Initializing the SDK +```typescript + +// SDK events listener +addEventListener((type, data) => { + console.log(`received event ${type}`); +}) + +// Create the default config +let config = defaultConfig(EnvironmentType.PRODUCTION) + +// Customize the config object according to your needs +config.apiKey = "your API key"; +config.workingDir = "path to an existing directory"; + +try { + const sdkServices = await initServices(config, credentials.deviceKey, credentials.deviceCert, seed); + await start(); +} catch (error) { + console.log(error); +} +``` + +At any point we can fetch our balance from the Greenlight node: + +```typescript +try { + const nodeInfo = await nodeInfo(); + const lnBalance = nodeInfo.channelsBalanceMsat; + const onchainBalance = nodeInfo.onchainBalanceMsat; +} catch (error) { + console.log(error); +} +```
diff --git a/src/guide/lnurl_auth.md b/src/guide/lnurl_auth.md index 7c6adbc..6ef2c8b 100644 --- a/src/guide/lnurl_auth.md +++ b/src/guide/lnurl_auth.md @@ -36,19 +36,43 @@ let lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0 do { let inputType = try parseInput(s: lnurlAuthUrl) if case .lnUrlAuth(let data) = inputType { - let result = try sdk.lnurlAuth(reqData: data) - switch result { - case .ok: - print("Successfully authenticated") - case .errorStatus(let data): - print("Failed to authenticate") - } + let result = try sdk.lnurlAuth(reqData: data) + switch result { + case .ok: + print("Successfully authenticated") + case .errorStatus(let data): + print("Failed to authenticate") + } } } catch { // handle error } ``` + +
React Native
+
+ +```typescript +// Endpoint can also be of the form: +// keyauth://domain.com/auth?key=val +let lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu"; + +try { + const input = await parseInput(lnurlAuthUrl) + if (input.type === InputType.LNURL_AUTH) { + const result = await lnurlAuth(input.data) + if (result.status === "ok") { + print("Successfully authenticated") + } else { + print("Failed to authenticate") + } + } +} catch (error) { + console.log(error) +} +``` +
diff --git a/src/guide/lnurl_pay.md b/src/guide/lnurl_pay.md index 1f40f75..85b088b 100644 --- a/src/guide/lnurl_pay.md +++ b/src/guide/lnurl_pay.md @@ -31,16 +31,36 @@ if let Ok(LnUrlPay{data: pd}) = parse(lnurl_pay_url).await { // lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf let lnurlPayUrl = "lightning@address.com"; do { - let inputType = try parseInput(s: lnurlPayUrl) + let inputType = try parseInput(s: lnurlPayUrl) if case .lnUrlPay(let data) = inputType { let amountSats = data.minSendable; try sdk.payLnurl(reqData: data, amountSats: amountSats, comment: "comment") - } + } } catch { // handle error } ``` +
React Native
+
+ +```typescript +// Endpoint can also be of the form: +// lnurlp://domain.com/lnurl-pay?key=val +// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf +let lnurlPayUrl = "lightning@address.com"; + +try { + const input = await parseInput(lnurlAuthUrl) + if (input.type === InputType.LNURL_PAY) { + const amountSats = input.minSendable; + const result = await payLnurl(input.data, amountSats, "comment") + } +} catch (error) { + console.log(error) +} +``` +
## Supported Specs diff --git a/src/guide/lnurl_withdraw.md b/src/guide/lnurl_withdraw.md index cdb473f..b458239 100644 --- a/src/guide/lnurl_withdraw.md +++ b/src/guide/lnurl_withdraw.md @@ -30,16 +30,35 @@ if let Ok(LnUrlWithdraw{data: wd}) = parse(lnurl_withdraw_url).await { let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"; do { - let inputType = try parseInput(s: lnurlWithdrawUrl) - if case .lnUrlWithdraw(let data) = inputType { + let inputType = try parseInput(s: lnurlWithdrawUrl) + if case .lnUrlWithdraw(let data) = inputType { let amountSat = data.minWithdrawable; let description = "Test withdraw" try sdk.withdrawLnurl(reqData: data, amountSats: amountSat, description: "comment") - } + } } catch { // handle error } +``` + +
React Native
+
+ +```typescript +// Endpoint can also be of the form: +// lnurlw://domain.com/lnurl-withdraw?key=val +let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"; + +try { + const input = await parseInput(lnurlAuthUrl) + if (input.type === InputType.LNURL_WITHDRAW) { + const amountSats = input.minWithdrawable; + const result = await withdrawLnurl(input.data, amountSats, "comment") + } +} catch (error) { + console.log(error) +} ```
diff --git a/src/guide/payments.md b/src/guide/payments.md index cd40456..70aacd5 100644 --- a/src/guide/payments.md +++ b/src/guide/payments.md @@ -25,14 +25,14 @@ 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") + let invoice = try sdk.receivePayment(amountSats: 3000, description: "Invoice for 3000 sats") } catch { // handle error } @@ -42,7 +42,7 @@ do { ```swift let bolt11 = "..."; do { - let payment = try sdk.sendPayment(bolt11: bolt11, amountSats: 3000) + let payment = try sdk.sendPayment(bolt11: bolt11, amountSats: 3000) } catch { // handle error } @@ -52,13 +52,44 @@ do { ```swift let nodeId = "..."; do { - let payment = try sdk.sendSpontaneousPayment(nodeId: nodeId, amountSats: 3000) + let payment = try sdk.sendSpontaneousPayment(nodeId: nodeId, amountSats: 3000) } catch { // handle error } ``` - +
+
React Native
+## 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: +```typescript +try { + const invoice = await receivePayment(3000, "Invoice for 3000 sats") +} catch (error) { + console.log(error) +} +``` + +## Sending Lightning Payments +```typescript +const bolt11 = "..."; +try { + const payment = await sendPayment(bolt11, 3000) +} catch (error) { + console.log(error) +} +``` + +## Sending Spontaneous Lightning Payments +```typescript +const nodeId = "..."; +try { + const payment = await sendSpontaneousPayment(nodeId, 3000) +} catch (error) { + console.log(error) +} +```
\ No newline at end of file diff --git a/src/guide/recieve_onchain.md b/src/guide/recieve_onchain.md index ebe420b..f024021 100644 --- a/src/guide/recieve_onchain.md +++ b/src/guide/recieve_onchain.md @@ -8,7 +8,7 @@ There are cases when you have funds in some bitcoin address and you would like t ```rust,no_run let swap_info = sdk.receive_onchain().await?; -// Send your funds to the bellow bitcoin address +// Send your funds to the below bitcoin address let address = swap_info.bitcoin_address; ``` @@ -42,10 +42,10 @@ sdk.refund(refundable.bitcoin_address, destination_address, sat_per_vbyte).await ```swift do { - let swapInfo = try sdk.receiveOnchain(); + let swapInfo = try sdk.receiveOnchain(); - // Send your funds to the bellow bitcoin address - let address = swapInfo.bitcoinAddress; + // Send your funds to the bellow bitcoin address + let address = swapInfo.bitcoinAddress; } catch { // handle error } @@ -55,7 +55,7 @@ Once you've sent the funds to the above address, the SDK will monitor this addre ```swift do { - let swapInfo = try sdk.inProgressSwap() + let swapInfo = try sdk.inProgressSwap() } catch { // handle error } @@ -70,7 +70,7 @@ In order to execute a refund, you need to supply an on-chain address to where th ```swift do { - let refundables = try sdk.listRefundables() + let refundables = try sdk.listRefundables() } catch { // handle error } @@ -83,13 +83,64 @@ let destinationAddress = "..." let satPerVbyte = do { - try sdk.refund( - swapAddress: "", - toAddress: destinationAddress, - satPerVbyte: satPerVbyte) + try sdk.refund( + swapAddress: "", + toAddress: destinationAddress, + satPerVbyte: satPerVbyte) } catch { // handle error } ``` +
React Native
+
+ +```typescript +try { + const swapInfo = await receiveOnchain(); + + // Send your funds to the below bitcoin address + const address = swapInfo.bitcoinAddress; +} catch (error) { + console.log(error) +} +``` + +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: + +```typescript +try { + const swapInfo = await inProgressSwap() +} catch (error) { + console.log(error) +} +``` + +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: + +```typescript +try { + const refundables = await listRefundables() +} catch (error) { + console.log(error) +} +``` + +Once you have a refundable swap in hand, use the follwing code to execute a refund: + +```typescript +const destinationAddress = "..." +const satPerVbyte = +try { + const result = await refund(refundable.bitcoinAddress, destinationAddress, satPerVbyte) +} catch (error) { + console.log(error) +} +``` +
\ No newline at end of file diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index eb9207d..ce1a4f9 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -53,13 +53,13 @@ for rs in sdk.in_progress_reverse_swaps().await? { ```swift try { - let currentFees = try sdk.fetchReverseSwapFees() + 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) + 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 SdkError.Error(let message) { + print(message) } ``` @@ -81,9 +81,9 @@ 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) + try sdk.sendOnchain(amountSat: amountSat, onchainRecipientAddress: destinationAddress, pairHash: currentFees.feesHash, satPerVbyte: satPerVbyte) +} catch SdkError.Error(let message) { + print(message) } ``` @@ -95,7 +95,63 @@ You can check its status with: ```swift for rs in sdk.inProgressReverseSwaps() { - println("Reverse swap \(rs.id) in progress, status is \(rs.breezStatus)"); + println("Reverse swap \(rs.id) in progress, status is \(rs.breezStatus)"); +} +``` + +
React Native
+
+ +```typescript +try { + const currentFees = await fetchReverseSwapFees() + + console.log(`Percentage fee for the reverse swap service: ${currentFees.feesPercentage}`); + console.log(`Estimated miner fees in sats for locking up funds: ${currentFees.feesLockup}`); + console.log(`Estimated miner fees in sats for claiming funds: ${currentFees.feesClaim}`); +} catch (error) { + console.log(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: + +```typescript +console.log(`Minimum amount, in sats: ${current_fees.min}`); +console.log(`Maximum amount, in sats: ${current_fees.max}`); +``` + +Once you checked the fees are acceptable, you can start the reverse swap: + +```typescript +const destinationAddress = "bc1.."; +const amountSat = currentFees.min; +const satPerVbyte = +try { + const reverseSwapInfo = sendOnchain(amountSat, destinationAddress, currentFees.feesHash, satPerVbyte) +} catch (error) { + console.log(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: + +```typescript +try { + const swaps = await inProgressReverseSwaps() + for (const swap in swaps) { + println(`Reverse swap ${swap.id} in progress, status is ${swap.breezStatus}`); + } +} catch (error) { + console.log(error) } ```