From e03cde51f72e16464046473057fbb76df2831209 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Mon, 3 Jul 2023 20:41:22 +0200 Subject: [PATCH] Add Go examples --- src/guide/getting_started.md | 55 ++++++++++++++++++++++++++++++++++++ src/guide/install.md | 8 ++++++ src/guide/lnurl_auth.md | 23 +++++++++++++++ src/guide/lnurl_pay.md | 18 ++++++++++++ src/guide/lnurl_withdraw.md | 17 +++++++++++ src/guide/payments.md | 23 +++++++++++++++ src/guide/recieve_onchain.md | 38 ++++++++++++++++++++++++- src/guide/send_onchain.md | 46 ++++++++++++++++++++++++++++++ 8 files changed, 227 insertions(+), 1 deletion(-) diff --git a/src/guide/getting_started.md b/src/guide/getting_started.md index e15ccf5..4038858 100644 --- a/src/guide/getting_started.md +++ b/src/guide/getting_started.md @@ -195,6 +195,61 @@ try { } ``` +
Go
+
+ +The first step is to register a new node +## Registering a new node +```go +if seed, err := breez_sdk.MnemonicToSeed(""); err != nil { + inviteCode := "" + + // register_node takes either greenlight credentials (certifate & key) or invite code. + // At this example we are using the invite code option. + credentials, err = breez_sdk.RegisterNode(breez_sdk.NetworkBitcoin, seed, nil, &inviteCode) +} +``` + +## Recovering an existing node +```go +if seed, err := breez_sdk.MnemonicToSeed(""); err != nil { + credentials := breez_sdk.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 +```go +// SDK events listener +type BreezListener struct{} + +func (BreezListener) OnEvent(e breez_sdk.BreezEvent) { + log.Printf("received event %#v", e) +} + +// Create the default config +config := breez_sdk.DefaultConfig(breez_sdk.EnvironmentTypeProduction) + +// Customize the config object according to your needs +config.apiKey = "your API key" +config.workingDir = "path to an existing directory" + +if sdkServices, err := breez_sdk.InitServices(config, seed, credentials, BreezListener{}); err != nil { + sdkServices.Start() +} +``` + +At any point we can fetch our balance from the Greenlight node: + +```go +if nodeInfo, err := sdkServices.NodeInfo(); err != nil { + lnBalance := nodeInfo.ChannelsBalanceMsat + onchainBalance := nodeInfo.OnchainBalanceMsat +} +``` +
You are now ready to receive a Lightning [payment](payments.md). diff --git a/src/guide/install.md b/src/guide/install.md index ec1f936..3006644 100644 --- a/src/guide/install.md +++ b/src/guide/install.md @@ -36,6 +36,14 @@ or $ yarn add @breeztech/react-native-breez-sdk ``` +## Go + +We recommend using our official Go package: [breez/breez-sdk-go](https://github.com/breez/breez-sdk-go). + +```console +$ go get github.com/breez/breez-sdk-go +``` + ## C# Currently c# is built from source only. Please visit the [sdk-bindings](https://github.com/breez/breez-sdk/tree/main/libs/sdk-bindings#c) project for instructions. diff --git a/src/guide/lnurl_auth.md b/src/guide/lnurl_auth.md index 7d3c27d..0be2bca 100644 --- a/src/guide/lnurl_auth.md +++ b/src/guide/lnurl_auth.md @@ -73,6 +73,29 @@ try { } ``` + +
Go
+
+ +```go +// Endpoint can also be of the form: +// keyauth://domain.com/auth?key=val +lnurlAuthUrl := "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu" + +if input, err := breez_sdk.ParseInput(lnurlAuthUrl); err != nil { + switch input.Type { + case breez_sdk.InputTypeLnUrlAuth: + if result, err := sdkServices.LnurlAuth(input.Data); err != nil { + if (result.Status === "ok") { + log.Printf("Successfully authenticated") + } else { + log.Printf("Failed to authenticate") + } + } + } +} +``` +
diff --git a/src/guide/lnurl_pay.md b/src/guide/lnurl_pay.md index 1dada0e..4b9d9a1 100644 --- a/src/guide/lnurl_pay.md +++ b/src/guide/lnurl_pay.md @@ -61,6 +61,24 @@ try { } ``` +
Go
+
+ +```go +// Endpoint can also be of the form: +// lnurlp://domain.com/lnurl-pay?key=val +// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf +lnurlPayUrl := "lightning@address.com" + +if input, err := breez_sdk.ParseInput(lnurlPayUrl); err != nil { + switch input.Type { + case breez_sdk.InputTypeLnUrlPay: + amountsSats := input.MinSendable + result, err := sdkServices.PayLnurl(input.Data, amountsSats, "comment") + } +} +``` +
## Supported Specs diff --git a/src/guide/lnurl_withdraw.md b/src/guide/lnurl_withdraw.md index da7332f..3ca6f18 100644 --- a/src/guide/lnurl_withdraw.md +++ b/src/guide/lnurl_withdraw.md @@ -61,6 +61,23 @@ try { } ``` +
Go
+
+ +```go +// Endpoint can also be of the form: +// lnurlw://domain.com/lnurl-withdraw?key=val +lnurlWithdrawUrl := "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk" + +if input, err := breez_sdk.ParseInput(lnurlAuthUrl); err != nil { + switch input.Type { + case breez_sdk.InputTypeLnUrlWithdraw: + amountsSats := input.MinWithdrawable + result, err := sdkServices.WithdrawLnurl(input.Data, amountsSats, "comment") + } +} +``` +
## Supported Specs diff --git a/src/guide/payments.md b/src/guide/payments.md index 7ab47c6..5a49bee 100644 --- a/src/guide/payments.md +++ b/src/guide/payments.md @@ -95,4 +95,27 @@ try { } ``` +
Go
+
+ +## 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: + +```go +invoice, err := sdkServices.ReceivePayment(3000, "Invoice for 3000 sats") +``` + +## Sending Lightning Payments +```go +const bolt11 = "..."; +payment, err := sdkServices.SendPayment(bolt11, 3000) +``` + +## Sending Spontaneous Lightning Payments +```go +const nodeId = "..."; +payment, err := sdkServices.SendSpontaneousPayment(nodeId, 3000) +``` +
\ No newline at end of file diff --git a/src/guide/recieve_onchain.md b/src/guide/recieve_onchain.md index dd554fb..7a7ff0d 100644 --- a/src/guide/recieve_onchain.md +++ b/src/guide/recieve_onchain.md @@ -141,4 +141,40 @@ try { } ``` - \ No newline at end of file +
Go
+
+ +```go +if swapInfo, err := sdkServices.ReceiveOnchain(); err != nil { + // Send your funds to the below bitcoin address + address := swapInfo.BitcoinAddress +} +``` + +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: + +```go +swapInfo, err := sdkServices.InProgressSwap() +``` + +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: + +```go +refundables, err := sdkServices.ListRefundables() +``` + +Once you have a refundable swap in hand, use the follwing code to execute a refund: + +```go +destinationAddress := "..." +satPerVbyte := + +result, err := sdkServices.Refund(refundable.BitcoinAddress, destinationAddress, satPerVbyte) +``` +
+ diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index 7b4331f..b760b45 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -155,6 +155,52 @@ try { } ``` +
Go
+
+ +```go +if currentFees, err := sdkServices.FetchReverseSwapFees(); err != nil { + log.Printf("Percentage fee for the reverse swap service: %v", currentFees.FeesPercentage); + log.Printf("Estimated miner fees in sats for locking up funds: %v", currentFees.FeesLockup); + log.Printf("Estimated miner fees in sats for claiming funds: %v", currentFees.FeesClaim); +} +``` + +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: + +```go +log.Printf("Minimum amount, in sats: %v", currentFees.Min); +log.Printf("Maximum amount, in sats: %v", currentFees.Max); +``` + +Once you checked the fees are acceptable, you can start the reverse swap: + +```go +destinationAddress := "bc1.."; +amountSat := currentFees.Min; +satPerVbyte := + +reverseSwapInfo, err := sdkServices.SendOnchain(amountSat, destinationAddress, currentFees.FeesHash, satPerVbyte) +``` + +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: + +```go +if swaps, err := sdkServices.InProgressReverseSwaps(); err != nil { + for _, swap := range swaps { + log.Printf("Reverse swap %v in progress, status is %v", swap.Id, swap.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.