diff --git a/README.md b/README.md index 47f9969..adaadd7 100644 --- a/README.md +++ b/README.md @@ -5,4 +5,14 @@ The SDK docs are live at [https://sdk-doc.breez.technology](https://sdk-doc.bree ## Contributions -For syntax and supported features, see [https://rust-lang.github.io/mdBook](https://rust-lang.github.io/mdBook). \ No newline at end of file +For syntax and supported features, see [https://rust-lang.github.io/mdBook](https://rust-lang.github.io/mdBook). + +## Develop + +To locally serve the docs run: + +```bash +cargo install mdbook +mdbook build +mdbook serve +``` diff --git a/src/guide/getting_started.md b/src/guide/getting_started.md index 0ee470b..5ff25bc 100644 --- a/src/guide/getting_started.md +++ b/src/guide/getting_started.md @@ -9,7 +9,7 @@ The Breez SDK provides the following services: * Fetching node status (e.g. balance, max allow to pay, max allow to receive, on-chain balance, etc.) * Connecting to a new or existing node. -Connecting to a node requires a seed (your master key) and credentials. The seed is a bip39 mnemonic and the credentials are retrieved by registering a new node or recovering an existing one. +Connecting to a node requires a seed (your master key). The seed is a bip39 mnemonic. ## Installing @@ -19,44 +19,30 @@ Breez SDK is available in several platforms. Follow the [Installing](install.md)
Rust
-The first step is to register a new node. In order to do that a seed is needed. -## Registering a new node -```rust,no_run -let seed = ; -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 = BreezServices::register_node(Network::Bitcoin, seed, None, Some(invite_code)).await?; -``` - -## Recovering an existing node -```rust,no_run -let seed = ; -let credentials = BreezServices::recover_node(Network::Bitcoin, seed).await?; -``` - -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 +## Connecting ```rust,no_run // Create the default config -let mut config = BreezServices::default_config(EnvironmentType::Production); +let config = BreezServices::default_config( + EnvironmentType::Production, + "your API key".into(), + breez_sdk_core::NodeConfig::Greenlight { + config: GreenlightNodeConfig { + partner_credentials: None, + invite_code: None, + }, + }, +); // Customize the config object according to your needs -config.api_key = Some("your API key".into()); config.working_dir = "path to an existing directory".into(); -let sdk = BreezServices::init_services( +// Connect to the Breez SDK make it ready for use +let sdk = BreezServices::connect( config, - seed.to_vec(), - credentials.clone(), + seed.to_vec(), Box::new(AppEventListener {}), ) .await?; - -BreezServices::start(rt(), &sdk).await?; ``` At any point we can fetch our balance from the Greenlight node: @@ -71,35 +57,7 @@ if let Some(node_state) = sdk.node_info()? {
Swift
-The first step is to register a new node -## Registering a new node -```swift -do { - let seed = try mnemonicToSeed(phrase: "") - let inviteCode = "" - - // 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) -} catch { - // handle error -} -``` - -## Recovering an existing node -```swift -do { - let seed = try mnemonicToSeed(phrase: "") - let credentials = try recoverNode(network: Network.bitcoin, seed: seed) -} catch { - // handle error -} -``` - -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 +## Connecting ```swift // SDK events listener @@ -110,15 +68,18 @@ class SDKListener: EventListener { } // Create the default config -var config = defaultConfig(envType: EnvironmentType.production) +let seed = try mnemonicToSeed(phrase: "") +let inviteCode = "your invite code" +let config = breez_sdk.defaultConfig(envType: EnvironmentType.production, apiKey: "", + nodeConfig: NodeConfig.greenlight( + config: GreenlightNodeConfig(partnerCredentials: nil,inviteCode: inviteCode))); // Customize the config object according to your needs -config.apiKey = "your API key"; -config.workingDir = "path to an existing directory"; +config.workingDir = "path to an existing directory" -do { - let sdk = try initServices(config: config, seed: seed, creds: credentials, listener: SDKListener()); - try sdk.start(); +do { + // Connect to the Breez SDK make it ready for use + let sdk = try connect(config: config, seed: seed, listener: SDKListener()); } catch{ // handle error } @@ -140,31 +101,7 @@ do {
React Native
-The first step is to register a new node -## Registering a new node -```typescript -try { - const seed = await mnemonicToSeed(""); - const inviteCode = ""; - - // 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, null, 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 +## Connecting ```typescript // SDK events listener @@ -173,15 +110,22 @@ addEventListener((type, data) => { }) // Create the default config -let config = defaultConfig(EnvironmentType.PRODUCTION) +const seed = await mnemonicToSeed(""); +const inviteCode = ""; +const nodeConfig : NodeConfig = { + type: NodeConfigType.GREENLIGHT, + config: { + inviteCode: "your invite code" + } +} +let config = defaultConfig(EnvironmentType.PRODUCTION, "api key", nodeConfig); // 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(); + // Connect to the Breez SDK make it ready for use + const sdkServices = await connect(config, seed); } catch (error) { console.log(error); } @@ -199,32 +143,90 @@ try { } ```
+
Dart
+
+ +## Connecting +```dart +// SDK events listener +breezEventsStream().listen((event) { + print("Received Breez event: $event"); +} + +// SDK logs listener +breezLogStream().listen((log) { + print("Received Breez log entry: $log"); +} + +// Create the default config +Uint8List seed = await mnemonicToSeed(phrase: ""); +String inviteCode = ""; +NodeConfg nodeConfig = NodeConfig.greenlight(config: GreenlightNodeConfig(partnerCredentials: null, inviteCode: inviteCode)); +Config config = await defaultConfig(configType: EnvironmentType.Production, apiKey: "", nodeConfig: nodeConfig); + +// Customize the config object according to your needs +config.workingDir = "path to an existing directory"; + +try { + // Connect to the Breez SDK make it ready for use + await connect(config: config, seed: seed); +} catch (error) { + // handle error +} +``` +At any point we can fetch our balance from the Greenlight node: + +```dart +try { + NodeState? nodeInfo = await nodeInfo(); + int lnBalance = nodeInfo?.channelsBalanceMsat; + int onchainBalance = nodeInfo?.onchainBalanceMsat; +} catch (error) { + // handle error +} +``` +
+
Python
+
+ +## Connecting +```python +# SDK events listener +class SDKListener(breez_sdk.EventListener): + def on_event(self, event): + print(event) + +# Create the default config +seed = mnemonic_to_seed("") +invite_code = "" +config = breez_sdk.default_config(breez_sdk.EnvironmentType.PRODUCTION, "api key", + breez_sdk.NodeConfig.GREENLIGHT(breez_sdk.GreenlightNodeConfig(None, invite_code))) + +# Customize the config object according to your needs +config.working_dir = "path to an existing directory" + +try: + # Connect to the Breez SDK make it ready for use + sdk_services = breez_sdk.connect(config, seed, SDKListener()) +except Exception as error: + # Handle error +``` + +At any point we can fetch our balance from the Greenlight node: + +```python +try: + node_info = node_info() + ln_balance = node_info.channels_balance_msat + onchain_balance = node_info.onchain_balance_msat +except Exception as error: + # Handle error +``` +
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 +## Connecting ```go // SDK events listener type BreezListener struct{} @@ -234,17 +236,24 @@ func (BreezListener) OnEvent(e breez_sdk.BreezEvent) { } // Create the default config -config := breez_sdk.DefaultConfig(breez_sdk.EnvironmentTypeProduction) +apiKey := "" +inviteCode := "" +nodeConfig := breez_sdk.NodeConfigGreenlight{ + Config: breez_sdk.GreenlightNodeConfig{ + PartnerCredentials: nil, + InviteCode: &inviteCode, + }, +} + +config := breez_sdk.DefaultConfig(breez_sdk.EnvironmentTypeProduction, apiKey, nodeConfig) // 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 { +if sdkServices, err := breez_sdk.Connect(config, seed, BreezListener{}); err != nil { sdkServices.Start() } ``` - At any point we can fetch our balance from the Greenlight node: ```go diff --git a/src/guide/install.md b/src/guide/install.md index 3006644..559bb04 100644 --- a/src/guide/install.md +++ b/src/guide/install.md @@ -8,7 +8,7 @@ We recommend integrating the Breez SDK as Gradle dependency from [our Maven repo To do so, add the following to your Gradle dependencies: -``` groovy +```gradle repositories { maven { url("https://mvn.breez.technology/releases") @@ -50,4 +50,16 @@ Currently c# is built from source only. Please visit the [sdk-bindings](https:// ## rust -Currently rust is still not accessible via cargo and is needed to be built from source. Please visit the [sdk-core](https://github.com/breez/breez-sdk/tree/main/libs/sdk-core) project for instructions. \ No newline at end of file +Currently rust is still not accessible via cargo and is needed to be built from source. Please visit the [sdk-core](https://github.com/breez/breez-sdk/tree/main/libs/sdk-core) project for instructions. + +## Dart/Flutter +Currently Dart is built from source only. Please visit the [sdk-flutter](https://github.com/breez/breez-sdk/tree/main/libs/sdk-flutter#readme) project for instructions. We're planning to publish this package to [pub.dev](https://pub.dev/), until then it needs to be specified as a local directory dependency. + +```yaml +dependencies: + breez_sdk: + path: /breez-sdk/libs/sdk-flutter +``` +## Python + +Currently python is not acceable as a package and is needed to build it from soruce. Please visit [sdk-core](https://github.com/breez/breez-sdk/tree/main/libs/sdk-bindings#python) project for instructions. diff --git a/src/guide/lnurl_auth.md b/src/guide/lnurl_auth.md index f89e743..bcb90ef 100644 --- a/src/guide/lnurl_auth.md +++ b/src/guide/lnurl_auth.md @@ -73,6 +73,51 @@ try { } ``` +
+
Dart
+
+ +```dart +// Endpoint can also be of the form: +// keyauth://domain.com/auth?key=val +String lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu"; + +try { + InputType inputType = await parse(s: lnurlAuthUrl); + if (inputType is InputType_LnUrlAuth) { + LnUrlCallbackStatus result = await lnurlAuth(reqData: inputType.data); + if (result is LnUrlCallbackStatus_Ok) { + print("Successfully authenticated"); + } else { + print("Failed to authenticate"); + } + } +} catch (error) { + // handle error +} +``` + +
+
Python
+
+ +```python +# Endpoint can also be of the form: +# keyauth://domain.com/auth?key=val +lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu" + +try: + parsed_input = breez_sdk.parse_input(lnurl_auth_url) + if isinstance(parsed_input, breez_sdk.InputType.LN_URL_AUTH): + result = sdk_services.lnurl_auth(parsed_input.data) + if result.is_ok(): + print("Successfully authenticated") + else: + print("Failed to authenticate") +except Exception as error: + # Handle error +``` +
Go
@@ -93,11 +138,9 @@ if input, err := breez_sdk.ParseInput(lnurlAuthUrl); err != nil { } } } -} ``` -
- + ## Supported Specs diff --git a/src/guide/lnurl_pay.md b/src/guide/lnurl_pay.md index acadc65..75cd867 100644 --- a/src/guide/lnurl_pay.md +++ b/src/guide/lnurl_pay.md @@ -61,6 +61,48 @@ try { } ```
+
Dart
+
+ +```dart +// Endpoint can also be of the form: +// lnurlp://domain.com/lnurl-pay?key=val +// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf +String lnurlPayUrl = "lightning@address.com"; + +try { + InputType inputType = await parseInput(s: lnurlPayUrl); + if (inputType is InputType_LnUrlPay) { + int amountSats = inputType.data.minSendable; + LnUrlCallbackStatus result = await lnurlPay( + reqData: inputType.data, + userAmountSat: amountSats, + comment: "comment", + ); + } +} catch (error) { + // handle error +} +``` +
+
Python
+
+ +```python +# Endpoint can also be of the form: +# lnurlp://domain.com/lnurl-pay?key=val +# lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf +lnurl_pay_url = "lightning@address.com" + +try: + parsed_input = breez_sdk.parse_input(lnurl_pay_url) + if isinstance(parsed_input, breez_sdk.InputType.LN_URL_PAY): + amount_sats = parsed_input.data.min_sendable + result = sdk_service.pay_lnurl(parsed_input.data, amount_sats, "comment") +except Exception as error: + # Handle error +``` +
Go
@@ -83,7 +125,6 @@ if input, err := breez_sdk.ParseInput(lnurlPayUrl); err != nil { ## Supported Specs - - [LUD-01](https://github.com/lnurl/luds/blob/luds/01.md) LNURL bech32 encoding - [LUD-06](https://github.com/lnurl/luds/blob/luds/06.md) `payRequest` spec - [LUD-16](https://github.com/lnurl/luds/blob/luds/16.md) LN Address diff --git a/src/guide/lnurl_withdraw.md b/src/guide/lnurl_withdraw.md index 84b8eb7..c3fbe79 100644 --- a/src/guide/lnurl_withdraw.md +++ b/src/guide/lnurl_withdraw.md @@ -61,6 +61,46 @@ try { } ```
+
Dart
+
+ +```dart +// Endpoint can also be of the form: +// lnurlw://domain.com/lnurl-withdraw?key=val +String lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"; + +try { + InputType inputType = await parseInput(s: lnurlWithdrawUrl); + if (inputType is InputType_LnUrlWithdraw) { + int amountSats = inputType.data.minWithdrawable; + LnUrlCallbackStatus result = await lnurlWithdraw( + reqData: inputType.data, + amountSats: amountSats, + description: "comment", + ); + } +} catch (error) { + // handle error +} +``` +
+
Python
+
+ +```python +# Endpoint can also be of the form: +# lnurlw://domain.com/lnurl-withdraw?key=val +lnurl_withdraw_url = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk" + +try: + parsed_input = parse_input(lnurl_withdraw_url) + if isinstance(parsed_input, breez_sdk.InputType.LN_URL_WITHDRAW): + amount_sats = parsed_input.data.min_withdrawable + result = sdk_services.withdraw_lnurl(parsed_input.data, amount_sats, "comment") +except Exception as error: + # Handle error +``` +
Go
diff --git a/src/guide/payments.md b/src/guide/payments.md index f5da6e7..39dde1e 100644 --- a/src/guide/payments.md +++ b/src/guide/payments.md @@ -94,6 +94,81 @@ try { console.log(error) } ``` +
+
Dart
+
+ +## 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: + +```dart +try { + ReceivePaymentRequestData requestData = ReceivePaymentRequestData(amountSats: 3000, description: "Invoice for 3000 sats"); + ReceivePaymentResponse invoice = await receivePayment(reqData: requestData); +} catch (error) { + // handle error +} +``` + +## Sending Lightning Payments +```dart +String bolt11 = "..."; +try { + Payment payment = await sendPayment( + bolt11: bolt11, + amountSats: 3000, + ); +} catch (error) { + // handle error +} +``` + +## Sending Spontaneous Lightning Payments +```dart +String nodeId = "..."; +try { + Payment payment = await sendSpontaneousPayment( + nodeId: nodeId, + amountSats: 3000, + ); +} catch (error) { + // handle error +} +``` +
+
Python
+
+ +## 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: + +```python +try: + invoice = sdk_services.receive_payment(3000, "Invoice for 3000 sats") +except Exception as error: + # Handle error +``` + +## Sending Lightning Payments +```python +bolt11 = "..." +try: + sdk_services.send_payment(bolt11, 3000) +except Exception as error: + # Handle error +``` + +## Sending Spontaneous Lightning Payments +```python +let node_id = "..." +try: + sdk_services.send_spontaneous_payment(node_id, 3000) +except Exception as error: + # Handle error +``` +
Go
@@ -117,5 +192,6 @@ payment, err := sdkServices.SendPayment(bolt11, 3000) const nodeId = "..."; payment, err := sdkServices.SendSpontaneousPayment(nodeId, 3000) ``` +
\ No newline at end of file diff --git a/src/guide/receive_onchain.md b/src/guide/receive_onchain.md index a8f167a..1adea6a 100644 --- a/src/guide/receive_onchain.md +++ b/src/guide/receive_onchain.md @@ -29,7 +29,7 @@ In order to execute a refund, you need to supply an on-chain address to where th let refundables = sdk.list_refundables().await? ``` -Once you have a refundable swap in hand, use the follwing code to execute a refund: +Once you have a refundable swap in hand, use the following code to execute a refund: ```rust,no_run let destination_address = "...".into() @@ -76,7 +76,7 @@ do { } ``` -Once you have a refundable swap in hand, use the follwing code to execute a refund: +Once you have a refundable swap in hand, use the following code to execute a refund: ```swift let destinationAddress = "..." @@ -131,7 +131,7 @@ try { } ``` -Once you have a refundable swap in hand, use the follwing code to execute a refund: +Once you have a refundable swap in hand, use the following code to execute a refund: ```typescript const destinationAddress = "..." @@ -143,6 +143,109 @@ try { } ```
+
Dart
+
+ +```dart +try { + SwapInfo swapInfo = await receiveOnchain(); + + // Send your funds to the below bitcoin address + String address = swapInfo.bitcoinAddress; +} catch (error) { + // handle 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: + +```dart +try { + SwapInfo? swapInfo = await inProgressSwap() +} catch (error) { + // handle 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: + +```dart +try { + List refundables = await listRefundables() +} catch (error) { + // handle error +} +``` + +Once you have a refundable swap in hand, use the following code to execute a refund: + +```dart +String destinationAddress = "..." +int satPerVbyte = +try { + String result = await refund( + swapAddress: refundable.bitcoinAddress, + toAddress: destinationAddress, + satPerVbyte: satPerVbyte, + ); +} catch (error) { + // handle error +} +``` +
+
Python
+
+ +```python +try: + swap_info = sdk_services.receive_onchain() + # Send your funds to the below bitcoin address + address = sdk_services.swap_info.bitcoin_address +except Exception as error: + # Handle 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: + +```python +try: + swap_info = sdk_services.in_progress_swap() +except Exception as error: + # Handle 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: + + +Once you have a refundable swap in hand, use the following code to execute a refund: + +```python +try: + refundables = sdk_services.list_refundables() +except Exception as error: + # Handle error +``` + +Once you have a refundable swap in hand, use the follwing code to execute a refund: + +```python +destination_address = "..." +sat_per_vbyte = + +try: + sdk_services.refund(refundable.bitcoin_address, destination_address, sat_per_vbyte) +except Exception as error: + # Handle error +``` +
Go
diff --git a/src/guide/send_onchain.md b/src/guide/send_onchain.md index c9a313d..bb8918d 100644 --- a/src/guide/send_onchain.md +++ b/src/guide/send_onchain.md @@ -155,6 +155,115 @@ try { } ```
+
Dart
+
+ +```dart +try { + ReverseSwapPairInfo currentFees = await fetchReverseSwapFees(); + + print(`Percentage fee for the reverse swap service: ${currentFees.feesPercentage}`); + print(`Estimated miner fees in sats for locking up funds: ${currentFees.feesLockup}`); + print(`Estimated miner fees in sats for claiming funds: ${currentFees.feesClaim}`); +} catch (error) { + // handle 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: + +```dart +print(`Minimum amount, in sats: ${currentFees.min}`); +print(`Maximum amount, in sats: ${currentFees.max}`); +``` +Once you checked the fees are acceptable, you can start the reverse swap: + +```dart +String destinationAddress = "bc1.."; +int amountSat = currentFees.min; +int satPerVbyte = +try { + ReverseSwapInfo reverseSwapInfo = await sendOnchain( + amountSat: amountSat, + onchainRecipientAddress: destinationAddress, + pairHash: currentFees.feesHash, + satPerVbyte: satPerVbyte, + ); +} catch (error) { + // handle 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: + +```dart +try { + List swaps = await inProgressReverseSwaps(); + for (swap in swaps) { + print(`Reverse swap ${swap.id} in progress, status is ${swap.status}`); + } +} catch (error) { + // handle error +} +``` +
+
Python
+
+ +```python +try: + current_fees = sdk_services.fetch_reverse_swap_fees() + print("Percentage fee for the reverse swap service: ", current_fees.fees_percentage) + print("Estimated miner fees in sats for locking up funds: ", current_fees.fees_lockup) + print("Estimated miner fees in sats for claiming funds: ", current_fees.fees_claim) +except Exception as error: + # Handle 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: + +```python +print("Minimum amount, in sats: ", current_fees.min) +print("Maximum amount, in sats: ", current_fees.max) +``` + +Once you checked the fees are acceptable, you can start the reverse swap: + +```python +destination_address = "bc1.." +amount_sat = current_fees.min + +try: + sdk.send_onchain(amount_sat, destination_address, current_fees.fees_hash) +except Exception as error: + # Handle erorr +``` + +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: + +```python +try: + reverse_swaps = sdk_services.in_progress_reverse_swaps() + for rs in reverse_swaps: + print("Reverse swap ",rs.id , " in progress, status is ", rs.status) +except Exception as error: + # Handle erorr +``` +
Go