mirror of
https://github.com/aljazceru/breez-sdk-docs.git
synced 2025-12-17 22:04:21 +01:00
Merge branch 'main' into swift-docs-update
This commit is contained in:
17
README.md
17
README.md
@@ -1 +1,18 @@
|
||||
# Introduction
|
||||
|
||||
The SDK docs are live at [https://sdk-doc.breez.technology](https://sdk-doc.breez.technology).
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
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 --open
|
||||
```
|
||||
|
||||
@@ -6,8 +6,10 @@ src = "src"
|
||||
title = "Breez SDK"
|
||||
|
||||
[output.html]
|
||||
theme="theme"
|
||||
additional-js = ["tabs.js"]
|
||||
git-repository-url = "https://github.com/breez/breez-sdk-docs"
|
||||
edit-url-template = "https://github.com/breez/breez-sdk-docs/edit/main/{path}"
|
||||
|
||||
[output.html.print]
|
||||
enable = false
|
||||
enable = false
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
# Introduction
|
||||
@@ -5,7 +5,7 @@
|
||||
- [Installing](guide/install.md)
|
||||
- [Getting Started](guide/getting_started.md)
|
||||
- [Lightning payments](guide/payments.md)
|
||||
- [Receiving an on-chain transaction](guide/recieve_onchain.md)
|
||||
- [Receiving an on-chain transaction](guide/receive_onchain.md)
|
||||
- [Sending an on-chain transaction](guide/send_onchain.md)
|
||||
- [Connecting to an LSP](guide/connecting_lsp.md)
|
||||
- [Using LNURL](guide/lnurl.md)
|
||||
|
||||
@@ -1 +1,160 @@
|
||||
# Connecting to an LSP
|
||||
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
Based on the API key provided to the Breez SDK, a default LSP is selected for your node to provide liquidity to it. To get the information about the selected LSP you can do the following:
|
||||
|
||||
```swift
|
||||
do {
|
||||
let lspId = try sdk.lspId()
|
||||
let lspInfo = try sdk.fetchLspInfo(lspId: lspId!)
|
||||
} catch {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
When you have selected an LSP you may then connect to it.
|
||||
|
||||
```swift
|
||||
do {
|
||||
try sdk.connectLsp(lspId: lspId!)
|
||||
} catch {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
Based on the API key provided to the Breez SDK, a default LSP is selected for your node to provide liquidity to it. To get the information about the selected LSP you can do the following:
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const lspId = await lspId()
|
||||
const lspInfo = await fetchLspInfo(lspId)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
|
||||
When you have selected an LSP you may then connect to it.
|
||||
|
||||
```typescript
|
||||
try {
|
||||
await connectLsp(lspId)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
Based on the API key provided to the Breez SDK, a default LSP is selected for your node to provide liquidity to it. To get the information about the selected LSP you can do the following:
|
||||
|
||||
```dart
|
||||
try {
|
||||
List<LspInformation> lspList = await listLsps();
|
||||
// Select your desired LSP
|
||||
} catch (e) {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
When you have selected an LSP you may then connect to it.
|
||||
|
||||
```dart
|
||||
try {
|
||||
String lspId = await lspId();
|
||||
await connectLSP(lspId);
|
||||
} catch (e) {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
Based on the API key provided to the Breez SDK, a default LSP is selected for your node to provide liquidity to it. To get the information about the selected LSP you can do the following:
|
||||
|
||||
```python
|
||||
try:
|
||||
lsp_id = sdk_services.lsp_id()
|
||||
lsp_info = sdk_services.fetch_lsp_info(lsp_id)
|
||||
|
||||
except Exception as error:
|
||||
# Handle error
|
||||
```
|
||||
|
||||
When you have selected an LSP you may then connect to it.
|
||||
|
||||
```python
|
||||
try:
|
||||
sdk_services.connect_lsp(lsp_id)
|
||||
except Exception as error:
|
||||
# Handle error
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
Based on the API key provided to the Breez SDK, a default LSP is selected for your node to provide liquidity to it. To get the information about the selected LSP you can do the following:
|
||||
|
||||
|
||||
```go
|
||||
lspId, err := sdkServices.LspId()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
lspInfo, err := sdkServices.FetchLspInfo(*lspId)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
When you have selected an LSP you may then connect to it.
|
||||
|
||||
```go
|
||||
err = sdkServices.ConnectLsp(*lspId)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
Based on the API key provided to the Breez SDK, a default LSP is selected for your node to provide liquidity to it. To get the information about the selected LSP you can do the following:
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var lspId = sdk.LspId();
|
||||
var lspInfo = sdk.FetchLspInfo(lspId!);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
When you have selected an LSP you may then connect to it.
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
sdk.ConnectLsp(lspId!);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
@@ -1 +1,114 @@
|
||||
# Supporting fiat currencies
|
||||
# Supporting fiat currencies
|
||||
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
In order to list the availiable fiat currencies.
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const fiatCurrencyList = await listFiatCurrencies()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
|
||||
To get the current BTC rate for the currencies.
|
||||
|
||||
```typescript
|
||||
try {
|
||||
const fiatRatesMap = fetchFiatRates()
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
In order to list the availiable fiat currencies.
|
||||
|
||||
```dart
|
||||
try {
|
||||
List<FiatCurrency> fiatCurrencyList = await listFiatCurrencies();
|
||||
} catch(e) {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
To get the current BTC rate for the currencies.
|
||||
|
||||
```dart
|
||||
try {
|
||||
Map<String, Rate> fiatRatesMap = fetchFiatRates();
|
||||
// print your desired rate
|
||||
print(fiatRatesMap["USD"]?.value);
|
||||
} catch(e) {
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
In order to list the availiable fiat currencies.
|
||||
|
||||
```python
|
||||
try:
|
||||
fiat_currencies = sdk_services.list_fiat_currencies()
|
||||
|
||||
except Exception as error:
|
||||
#Handle error
|
||||
```
|
||||
|
||||
To get the current BTC rate for the currencies.
|
||||
|
||||
```python
|
||||
try:
|
||||
fiat_rates = sdk_services.fetch_fiat_rates()
|
||||
# print your desired rate
|
||||
except Exception as error:
|
||||
# Handle error
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
In order to list the availiable fiat currencies.
|
||||
|
||||
```go
|
||||
fiatCurrencies, err := sdkServices.ListFiatCurrencies()
|
||||
```
|
||||
|
||||
To get the current BTC rate for the currencies.
|
||||
|
||||
```go
|
||||
fiatRates, err := sdkServices.FetchFiatRates()
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
In order to list the availiable fiat currencies.
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var fiatCurrencies = sdk.ListFiatCurrencies();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
To get the current BTC rate for the currencies.
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var fiatRates = sdk.FetchFiatRates();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
@@ -9,57 +9,331 @@ 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
|
||||
|
||||
Breez SDK is available in several platforms. Follow the [Installing](install.md) page for instructions on how to install on your platform.
|
||||
|
||||
## Registering a new node
|
||||
```rust,no_run
|
||||
let seed = <your seed>;
|
||||
let invite_code = <your greenlight invite code>;
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
// 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?;
|
||||
```
|
||||
## Connecting
|
||||
```rust,ignore
|
||||
let mnemonic = Mnemonic::generate_in(Language::English, 12)?;
|
||||
let seed = mnemonic.to_seed("");
|
||||
let invite_code = Some("...".into());
|
||||
|
||||
## Recovering an existing node
|
||||
```rust,no_run
|
||||
let seed = <your seed>;
|
||||
let credentials = BreezServices::register_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
|
||||
```rust,no_run
|
||||
// Create the default config
|
||||
let config = BreezServices::default_config(EnvironmentType::Production)
|
||||
let mut config = BreezServices::default_config(
|
||||
EnvironmentType::Production,
|
||||
"your API key".into(),
|
||||
breez_sdk_core::NodeConfig::Greenlight {
|
||||
config: GreenlightNodeConfig {
|
||||
partner_credentials: None,
|
||||
invite_code
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// 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:
|
||||
|
||||
```rust,no_run
|
||||
```rust,ignore
|
||||
if let Some(node_state) = sdk.node_info()? {
|
||||
let balance_ln = node_state.channels_balance_msat;
|
||||
let balance_onchain = node_state.onchain_balance_msat;
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
## Connecting
|
||||
```swift
|
||||
|
||||
// SDK events listener
|
||||
class SDKListener: EventListener {
|
||||
func onEvent(e: BreezEvent) {
|
||||
print("received event ", e)
|
||||
}
|
||||
}
|
||||
|
||||
// Create the default config
|
||||
let seed = try mnemonicToSeed(phrase: "<mnemonics words>")
|
||||
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.workingDir = "path to an existing directory"
|
||||
|
||||
do {
|
||||
// Connect to the Breez SDK make it ready for use
|
||||
let sdk = try connect(config: config, seed: seed, listener: SDKListener());
|
||||
} catch{
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
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
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
## Connecting
|
||||
```typescript
|
||||
|
||||
// SDK events listener
|
||||
addEventListener((type, data) => {
|
||||
console.log(`received event ${type}`);
|
||||
})
|
||||
|
||||
// Create the default config
|
||||
const seed = await mnemonicToSeed("<mnemonics words>");
|
||||
const inviteCode = "<your greenlight invite code>";
|
||||
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.workingDir = "path to an existing directory";
|
||||
|
||||
try {
|
||||
// Connect to the Breez SDK make it ready for use
|
||||
const sdkServices = await connect(config, seed);
|
||||
} 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)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
## 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: "<mnemonic words>");
|
||||
String inviteCode = "<your greenlight invite code>";
|
||||
NodeConfg nodeConfig = NodeConfig.greenlight(config: GreenlightNodeConfig(partnerCredentials: null, inviteCode: inviteCode));
|
||||
Config config = await defaultConfig(configType: EnvironmentType.Production, apiKey: "<your API key>", 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
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
## 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("<mnemonics words>")
|
||||
invite_code = "<your greenlight 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
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
## Connecting
|
||||
```go
|
||||
// SDK events listener
|
||||
type BreezListener struct{}
|
||||
|
||||
func (BreezListener) OnEvent(e breez_sdk.BreezEvent) {
|
||||
log.Printf("received event %#v", e)
|
||||
}
|
||||
|
||||
// Create the default config
|
||||
seed, err := breez_sdk.MnemonicToSeed("<mnemonics words>")
|
||||
if err != nil {
|
||||
log.Fatalf("MnemonicToSeed failed: %#v", err)
|
||||
}
|
||||
|
||||
apiKey := "<your breez api key>"
|
||||
inviteCode := "<your greenlight invite code>"
|
||||
nodeConfig := breez_sdk.NodeConfigGreenlight{
|
||||
Config: breez_sdk.GreenlightNodeConfig{
|
||||
PartnerCredentials: nil,
|
||||
InviteCode: &inviteCode,
|
||||
},
|
||||
}
|
||||
|
||||
config, err := breez_sdk.DefaultConfig(breez_sdk.EnvironmentTypeProduction, apiKey, nodeConfig)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("DefaultConfig failed: %#v", err)
|
||||
}
|
||||
|
||||
// Customize the config object according to your needs
|
||||
config.workingDir = "path to an existing directory"
|
||||
|
||||
sdkServices, err := breez_sdk.Connect(config, seed, BreezListener{})
|
||||
if err != nil {
|
||||
log.Fatalf("Connect failed: %#v", err)
|
||||
}
|
||||
```
|
||||
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
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
## Connecting
|
||||
```cs
|
||||
using Breez.Sdk;
|
||||
|
||||
// Create the default config
|
||||
var seed = BreezSdkMethods.MnemonicToSeed("<mnemonics words>");
|
||||
var inviteCode = "<invite code>";
|
||||
var apiKey = "<api key>";
|
||||
var nodeConfig = new NodeConfig.Greenlight(
|
||||
new GreenlightNodeConfig(null, inviteCode)
|
||||
);
|
||||
var config = BreezSdkMethods.DefaultConfig(
|
||||
EnvironmentType.PRODUCTION,
|
||||
apiKey,
|
||||
nodeConfig
|
||||
) with {
|
||||
// Customize the config object according to your needs
|
||||
workingDir = "path to an existing directory"
|
||||
};
|
||||
|
||||
BlockingBreezServices sdk;
|
||||
try
|
||||
{
|
||||
// Connect to the Breez SDK make it ready for use
|
||||
sdk = BreezSdkMethods.Connect(config, seed, new SdkListener());
|
||||
} catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// SDK event listener
|
||||
class SdkListener : EventListener
|
||||
{
|
||||
public void OnEvent(BreezEvent e)
|
||||
{
|
||||
Console.WriteLine($"Received Breez event type {e.GetType().Name}");
|
||||
}
|
||||
}
|
||||
```
|
||||
At any point we can fetch our balance from the Greenlight node:
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var nodeInfo = sdk.NodeInfo();
|
||||
var lnBalance = nodeInfo?.channelsBalanceMsat;
|
||||
var onchainBalance = nodeInfo?.onchainBalanceMsat;
|
||||
}
|
||||
catch (Exception) {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
|
||||
You are now ready to receive a Lightning [payment](payments.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")
|
||||
@@ -61,17 +61,41 @@ end
|
||||
We recommmend using the official npm package:
|
||||
|
||||
```console
|
||||
$ npm install @breeztech/react-native-breez-sdk
|
||||
npm install https://github.com/breez/breez-sdk-react-native/releases/download/0.1.4/breeztech-react-native-breez-sdk-0.1.4.tgz
|
||||
```
|
||||
or
|
||||
```console
|
||||
$ yarn add @breeztech/react-native-breez-sdk
|
||||
yarn add https://github.com/breez/breez-sdk-react-native/releases/download/0.1.4/breeztech-react-native-breez-sdk-0.1.4.tgz
|
||||
```
|
||||
|
||||
## 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.
|
||||
We recommend using our official C# package: [Breez.Sdk](https://www.nuget.org/packages/Breez.Sdk).
|
||||
|
||||
```console
|
||||
dotnet add package Breez.Sdk
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
## 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: <relative-path-to>/breez-sdk/libs/sdk-flutter
|
||||
```
|
||||
## Python
|
||||
|
||||
Currently python is not acceable as a package and is needed to build it from source. Please visit [sdk-core](https://github.com/breez/breez-sdk/tree/main/libs/sdk-bindings#python) project for instructions.
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
# LNURL-Auth
|
||||
|
||||
## Usage
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
```rust,no_run
|
||||
```rust,ignore
|
||||
// Endpoint can also be of the form:
|
||||
// keyauth://domain.com/auth?key=val
|
||||
let lnurl_auth_url = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu";
|
||||
@@ -21,7 +24,150 @@ if let Ok(LnUrlAuth{data: ad}) = parse(lnurl_auth_url).await {
|
||||
}
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
```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(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")
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
```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)
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
```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 inputType := input.(type) {
|
||||
case breez_sdk.InputTypeLnUrlAuth:
|
||||
if result, err := sdkServices.LnurlAuth(inputType.Data); err != nil {
|
||||
if (result.Status === "ok") {
|
||||
log.Printf("Successfully authenticated")
|
||||
} else {
|
||||
log.Printf("Failed to authenticate")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
```cs
|
||||
// Endpoint can also be of the form:
|
||||
// keyauth://domain.com/auth?key=val
|
||||
var lnurlAuthUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttvdankjm3lw3skw0tvdankjm3xdvcn6vtp8q6n2dfsx5mrjwtrxdjnqvtzv56rzcnyv3jrxv3sxqmkyenrvv6kve3exv6nqdtyv43nqcmzvdsnvdrzx33rsenxx5unqc3cxgeqgntfgu";
|
||||
|
||||
try
|
||||
{
|
||||
var input = BreezSdkMethods.ParseInput(lnurlAuthUrl);
|
||||
if (input is InputType.LnUrlAuth lnurla) {
|
||||
var result = sdk.LnurlAuth(lnurla.data);
|
||||
if (result is LnUrlCallbackStatus.Ok) {
|
||||
Console.WriteLine("Successfully authenticated");
|
||||
} else {
|
||||
Console.WriteLine("Failed to authenticate");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
</custom-tabs>
|
||||
|
||||
## Supported Specs
|
||||
|
||||
|
||||
@@ -2,7 +2,11 @@
|
||||
|
||||
## Usage
|
||||
|
||||
```rust,no_run
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
```rust,ignore
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlp://domain.com/lnurl-pay?key=val
|
||||
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
|
||||
@@ -17,9 +21,133 @@ if let Ok(LnUrlPay{data: pd}) = parse(lnurl_pay_url).await {
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
```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: lnurlPayUrl)
|
||||
if case .lnUrlPay(let data) = inputType {
|
||||
let amountSats = data.minSendable;
|
||||
try sdk.payLnurl(reqData: data, amountSats: amountSats, comment: "comment")
|
||||
}
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
```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(lnurlPayUrl)
|
||||
if (input.type === InputType.LNURL_PAY) {
|
||||
const amountSats = input.data.minSendable;
|
||||
const result = await payLnurl(input.data, amountSats, "comment")
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
```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 inputType := input.(type) {
|
||||
case breez_sdk.InputTypeLnUrlPay:
|
||||
amountsSats := inputType.Data.MinSendable
|
||||
comment := "comment"
|
||||
result, err := sdkServices.PayLnurl(inputType.Data, amountsSats, &comment)
|
||||
}
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
```cs
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlp://domain.com/lnurl-pay?key=val
|
||||
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
|
||||
var lnurlPayUrl = "lightning@address.com";
|
||||
|
||||
try
|
||||
{
|
||||
var input = BreezSdkMethods.ParseInput(lnurlPayUrl);
|
||||
if (input is InputType.LnUrlPay lnurlp) {
|
||||
var amountSats = lnurlp.data.minSendable;
|
||||
var result = sdk.PayLnurl(lnurlp.data, amountSats, "comment");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
|
||||
## 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
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
|
||||
## Usage
|
||||
|
||||
```rust,no_run
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
```rust,ignore
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlw://domain.com/lnurl-withdraw?key=val
|
||||
let lnurl_withdraw_url = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk";
|
||||
@@ -16,7 +20,130 @@ if let Ok(LnUrlWithdraw{data: wd}) = parse(lnurl_withdraw_url).await {
|
||||
sdk.lnurl_withdraw(wd, amount_msat, Some(description)).await?;
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
```swift
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlw://domain.com/lnurl-withdraw?key=val
|
||||
let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"
|
||||
|
||||
do {
|
||||
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
|
||||
}
|
||||
|
||||
```
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
```typescript
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlw://domain.com/lnurl-withdraw?key=val
|
||||
let lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk";
|
||||
|
||||
try {
|
||||
const input = await parseInput(lnurlWithdrawUrl)
|
||||
if (input.type === InputType.LNURL_WITHDRAW) {
|
||||
const amountSats = input.data.minWithdrawable;
|
||||
const result = await withdrawLnurl(input.data, amountSats, "comment")
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
```go
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlw://domain.com/lnurl-withdraw?key=val
|
||||
lnurlWithdrawUrl := "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk"
|
||||
|
||||
if input, err := breez_sdk.ParseInput(lnurlWithdrawUrl); err != nil {
|
||||
switch inputType := input.(type) {
|
||||
case breez_sdk.InputTypeLnUrlWithdraw:
|
||||
amountsSats := inputType.Data.MinWithdrawable
|
||||
description := "comment"
|
||||
result, err := sdkServices.WithdrawLnurl(inputType.Data, amountsSats, &description)
|
||||
}
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
```cs
|
||||
// Endpoint can also be of the form:
|
||||
// lnurlw://domain.com/lnurl-withdraw?key=val
|
||||
var lnurlWithdrawUrl = "lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4exctthd96xserjv9mn7um9wdekjmmw843xxwpexdnxzen9vgunsvfexq6rvdecx93rgdmyxcuxverrvcursenpxvukzv3c8qunsdecx33nzwpnvg6ryc3hv93nzvecxgcxgwp3h33lxk";
|
||||
|
||||
try
|
||||
{
|
||||
var lnurlWithdrawUrl = "";
|
||||
var input = BreezSdkMethods.ParseInput(lnurlWithdrawUrl);
|
||||
if (input is InputType.LnUrlWithdraw lnurlw)
|
||||
{
|
||||
var amountSats = lnurlw.data.minWithdrawable;
|
||||
var result = sdk.WithdrawLnurl(lnurlw.data, amountSats, "comment");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
|
||||
## Supported Specs
|
||||
|
||||
|
||||
@@ -1,22 +1,241 @@
|
||||
# Sending and receiving Lightning payments
|
||||
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
## 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:
|
||||
|
||||
```rust,no_run
|
||||
```rust,ignore
|
||||
let invoice = sdk.receive_payment(3000, "Invoice for 3000 sats".into()).await?;
|
||||
```
|
||||
|
||||
## Sending Lightning Payments
|
||||
```rust,no_run
|
||||
```rust,ignore
|
||||
let bolt11 = "...";
|
||||
sdk.send_payment(bolt11.into(), Some(3000)).await?;
|
||||
```
|
||||
|
||||
## Sending Spontaneous Lightning Payments
|
||||
```rust,no_run
|
||||
```rust,ignore
|
||||
let node_id = "...";
|
||||
sdk.send_payment(node_id.into(), Some(3000)).await?;
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
## 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 {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
## Sending Lightning Payments
|
||||
```swift
|
||||
let bolt11 = "...";
|
||||
do {
|
||||
let payment = try sdk.sendPayment(bolt11: bolt11, amountSats: 3000)
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
## Sending Spontaneous Lightning Payments
|
||||
```swift
|
||||
let nodeId = "...";
|
||||
do {
|
||||
let payment = try sdk.sendSpontaneousPayment(nodeId: nodeId, amountSats: 3000)
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
## 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)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
## 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
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
## 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
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
## 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)
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
## 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:
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var invoice = sdk.ReceivePayment(3000, "Invoice for 3000 sats");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
## Sending Lightning Payments
|
||||
```cs
|
||||
const bolt11 = "...";
|
||||
try
|
||||
{
|
||||
var payment = sdk.SendPayment(bolt11, 3000);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
## Sending Spontaneous Lightning Payments
|
||||
```cs
|
||||
const nodeId = "...";
|
||||
try
|
||||
{
|
||||
var payment = sdk.SendSpontaneousPayment(nodeId, 3000);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
723
src/guide/receive_onchain.md
Normal file
723
src/guide/receive_onchain.md
Normal file
@@ -0,0 +1,723 @@
|
||||
# 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.
|
||||
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
```rust,ignore
|
||||
let swap_info = sdk.receive_onchain().await?;
|
||||
|
||||
// Send your funds to the below bitcoin address
|
||||
let address = swap_info.bitcoin_address;
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust,ignore
|
||||
let swap_info = sdk.in_progress_swap().await?
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust,ignore
|
||||
let refundables = sdk.list_refundables().await?
|
||||
```
|
||||
|
||||
Once you have a refundable swap in hand, use the following code to execute a refund:
|
||||
|
||||
```rust,ignore
|
||||
let destination_address = "...".into()
|
||||
let sat_per_vbyte = <refund tx fee rate>
|
||||
sdk.refund(refundable.bitcoin_address, destination_address, sat_per_vbyte).await?
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
```swift
|
||||
do {
|
||||
let swapInfo = try sdk.receiveOnchain()
|
||||
|
||||
// Send your funds to the bellow bitcoin address
|
||||
let address = swapInfo.bitcoinAddress;
|
||||
} catch {
|
||||
// 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:
|
||||
|
||||
```swift
|
||||
do {
|
||||
let swapInfo = try sdk.inProgressSwap()
|
||||
} catch {
|
||||
// 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:
|
||||
|
||||
```swift
|
||||
do {
|
||||
let refundables = try sdk.listRefundables()
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
|
||||
Once you have a refundable swap in hand, use the following code to execute a refund:
|
||||
|
||||
```swift
|
||||
let destinationAddress = "..."
|
||||
let satPerVbyte = <refund tx fee rate>
|
||||
|
||||
do {
|
||||
try sdk.refund(
|
||||
swapAddress: "",
|
||||
toAddress: destinationAddress,
|
||||
satPerVbyte: satPerVbyte)
|
||||
} catch {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
```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 following code to execute a refund:
|
||||
|
||||
```typescript
|
||||
const destinationAddress = "..."
|
||||
const satPerVbyte = <refund tx fee rate>
|
||||
try {
|
||||
const result = await refund(refundable.bitcoinAddress, destinationAddress, satPerVbyte)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
```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<SwapInfo> 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 = <refund tx fee rate>
|
||||
try {
|
||||
String result = await refund(
|
||||
swapAddress: refundable.bitcoinAddress,
|
||||
toAddress: destinationAddress,
|
||||
satPerVbyte: satPerVbyte,
|
||||
);
|
||||
} catch (error) {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
```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 = <refund tx fee rate>
|
||||
|
||||
try:
|
||||
sdk_services.refund(refundable.bitcoin_address, destination_address, sat_per_vbyte)
|
||||
except Exception as error:
|
||||
# Handle error
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
```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 := <refund tx fee rate>
|
||||
|
||||
result, err := sdkServices.Refund(refundable.BitcoinAddress, destinationAddress, satPerVbyte)
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var swapInfo = sdk.ReceiveOnchain();
|
||||
|
||||
// Send your funds to the below bitcoin address
|
||||
var address = swapInfo.bitcoinAddress;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 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:
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var swapInfo = sdk.InProgressSwap();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 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:
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var refundables = sdk.ListRefundables();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
|
||||
Once you have a refundable swap in hand, use the following code to execute a refund:
|
||||
|
||||
```cs
|
||||
var destinationAddress = "...";
|
||||
var satPerVbyte = <refund tx fee rate>;
|
||||
try
|
||||
{
|
||||
var result = sdk.Refund(refundable.bitcoinAddress, destinationAddress, satPerVbyte);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
|
||||
# Calculating fees
|
||||
|
||||
<custom-tabs category="lang">
|
||||
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```rust,ignore
|
||||
async fn calculate_channel_opening_fee(amount_msat: u64) -> Result<u64> {
|
||||
let channel_opening_fee_needed = is_channel_opening_fee_needed(amount_msat, sdk.clone())?;
|
||||
match channel_opening_fee_needed {
|
||||
true => calculate_fees_for_amount(amount_msat).await,
|
||||
false => Ok(0),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
```rust,ignore
|
||||
fn is_channel_opening_fee_needed(amount_msats: u64) -> Result<bool> {
|
||||
let node_info = sdk.node_info()?.ok_or(anyhow!("No node info found"))?;
|
||||
Ok(node_info.inbound_liquidity_msats <= amount_msats)
|
||||
}
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```rust,ignore
|
||||
async fn calculate_fees_for_amount(amount_msat: u64) -> Result<u64> {
|
||||
let lsp_id = sdk.lsp_id().await?.ok_or(anyhow!("No lsp id found"))?;
|
||||
let lsp_info = sdk
|
||||
.fetch_lsp_info(lsp_id)
|
||||
.await?
|
||||
.ok_or(anyhow!("No lsp id found"))?;
|
||||
|
||||
// We calculate the dynamic fees in millisatoshis rounded to satoshis.
|
||||
let channel_dynamic_fee_msat =
|
||||
amount_msat * lsp_info.channel_fee_permyriad as u64 / 10_000 / 1000 * 1000;
|
||||
let fee_msat = max(
|
||||
lsp_info.channel_minimum_fee_msat as u64,
|
||||
channel_dynamic_fee_msat,
|
||||
)
|
||||
Ok(fee_msat)
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```swift
|
||||
func calculateChannelOpeningFee(amountMsats: Int64) -> Int64? {
|
||||
var channelOpeningFeeNeeded = isChannelOpeningFeeNeeded(amountMsats: amountMsats)
|
||||
if channelOpeningFeeNeeded {
|
||||
return calculateFeesForAmount(amountMsats: amountMsats)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
```swift
|
||||
func isChannelOpeningFeeNeeded(amountMsats: Int64) -> Bool {
|
||||
do {
|
||||
let nodeInfo = try sdk.nodeInfo()
|
||||
|
||||
if let inboundLiquidityMsats = nodeInfo?.inboundLiquidityMsats {
|
||||
return inboundLiquidityMsats <= amountMsats
|
||||
}
|
||||
} catch {
|
||||
// Handle error
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```swift
|
||||
func calculateFeesForAmount(amountMsats: Int64) -> Int64? {
|
||||
do {
|
||||
if let lspId = try sdk.lspId() {
|
||||
let lspInfo = try sdk.fetchLspInfo(lspId: lspId)
|
||||
|
||||
// We calculate the dynamic fees in millisatoshis rounded to satoshis.
|
||||
let channelDynamicFeeMsat = amountMsats * lspInfo!.channelFeePermyriad / 10_000 / 1000 * 1000
|
||||
let feeMsat = max(lspInfo!.channelMinimumFeeMsat, channelDynamicFeeMsat)
|
||||
|
||||
return feeMsat
|
||||
}
|
||||
} catch {
|
||||
// Handle error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```typescript
|
||||
const calculateChannelOpeningFee = async (amountMsats: number): number => {
|
||||
const channelOpeningFeeNeeded = await isChannelOpeningFeeNeeded(amountMsats)
|
||||
if (channelOpeningFeeNeeded) {
|
||||
return calculateFeesForAmount(amountMsats)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
```typescript
|
||||
const isChannelOpeningFeeNeeded = async (amountMsats: number): boolean => {
|
||||
try {
|
||||
const nodeInfo = await nodeInfo()
|
||||
return nodeInfo.inboundLiquidityMsats <= amountMsats
|
||||
} catch (error) {
|
||||
// handle error
|
||||
}
|
||||
return false
|
||||
}
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```typescript
|
||||
const calculateFeesForAmount = async (amountMsats: number): number => {
|
||||
try {
|
||||
const id = await lspId()
|
||||
const lspInfo = await fetchLspInfo(id)
|
||||
|
||||
// We calculate the dynamic fees in millisatoshis rounded to satoshis.
|
||||
const channelDynamicFeeMsat = amountMsats * lspInfo.channelFeePermyriad / 10000 / 1000 * 1000
|
||||
const feeMsat = Math.max(lspInfo.channelMinimumFeeMsat, channelDynamicFeeMsat)
|
||||
|
||||
return feeMsat
|
||||
} catch (error) {
|
||||
// handle error
|
||||
}
|
||||
return 0
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```dart
|
||||
int calculateChannelOpeningFee(int amountMsat) async {
|
||||
bool isChannelOpeningFeeNeeded = await isChannelOpeningFeeNeeded(amountMsat);
|
||||
return isChannelOpeningFeeNeeded ? calculateFeesForAmount(amountMsat) : 0;
|
||||
}
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
|
||||
```dart
|
||||
// Assumes nodeState isn't empty
|
||||
bool isChannelOpeningFeeNeeded(int amountMsat) async {
|
||||
NodeState? nodeState = await getNodeState();
|
||||
return amountMsat >= nodeState.inboundLiquidityMsats;
|
||||
}
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```dart
|
||||
// Assumes lspId & lspInformation isn't empty
|
||||
int calculateFeesForAmount(int amountMsat) async {
|
||||
String? lspId = await getLspId();
|
||||
LSPInformation? lspInformation = await fetchLspInfo(lspId);
|
||||
|
||||
// We calculate the dynamic fees in millisatoshis rounded to satoshis.
|
||||
int channelFeesMsat = (amountMsat * lspInformation.channelFeePermyriad / 10000 / 1000 * 1000);
|
||||
return max(channelFeesMsat, lspInformation.channelMinimumFeeMsat);
|
||||
}
|
||||
```
|
||||
</section>
|
||||
|
||||
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```python
|
||||
def calculate_channel_opening_fees(amount_msats):
|
||||
is_channel_opening_fee_needed = is_channel_opening_fee_needed()
|
||||
|
||||
if is_channel_opening_fee_needed:
|
||||
return calculate_fees_for_amount(amount_msats)
|
||||
else:
|
||||
return None
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
|
||||
```python
|
||||
def is_channel_opening_fee_needed(amount_msats):
|
||||
return sdk_services.node_info().inbound_liquidity_msats <= amount_msats
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```python
|
||||
def calculate_fees_for_amount(amount_msats):
|
||||
# We need to open channel so we are calculating the fees for the LSP.
|
||||
lsp_id = sdk_services.lsp_id()
|
||||
lsp_info = sdk_services.fetch_lsp_info()
|
||||
|
||||
# We calculate the dynamic fees in millisatoshis rounded to satoshis.
|
||||
channel_dynamic_fee = amount_msats * lsp_info.channel_minimum_fee_msat * lsp_info.channel_fee_permyriad / 10000 // 10000 * 10000
|
||||
|
||||
fee_msat = max(lsp_info.channel_minimum_fee_msat, channel_dynamic_fee)
|
||||
|
||||
return fee_msat
|
||||
```
|
||||
</section>
|
||||
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```go
|
||||
func CalculateChannelOpeningFee(amountMsats uint64) (uint64, error) {
|
||||
isChannelOpeningFeeNeeded := isChannelOpeningFeeNeeded(amountMsats)
|
||||
if !isChannelOpeningFeeNeeded {
|
||||
return 0, fmt.Errorf("Channel not needed")
|
||||
}
|
||||
return calculateFeesForAmount(amountMsats), nil
|
||||
}
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
```go
|
||||
func isChannelOpeningFeeNeeded(amountMsats uint64) bool {
|
||||
nodeInfo, err := sdkServices.NodeInfo()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
return nodeInfo.InboundLiquidityMsats <= amountMsats
|
||||
}
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```go
|
||||
func calculateFeesForAmount(amountMsats uint64) uint64 {
|
||||
lspId, err := sdkServices.LspId()
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
lspInfo, err := sdkServices.FetchLspInfo(*lspId)
|
||||
if err != nil {
|
||||
// Handle error
|
||||
}
|
||||
|
||||
// We calculate the dynamic fees in millisatoshis rounded to satoshis
|
||||
channelDynamicFeeMsats := amountMsats * uint64(lspInfo.ChannelFeePermyriad) / 10000 / 1000 * 1000
|
||||
feeMsats := uint64(lspInfo.ChannelMinimumFeeMsat)
|
||||
|
||||
if channelDynamicFeeMsats >= feeMsats {
|
||||
feeMsats = channelDynamicFeeMsats
|
||||
}
|
||||
|
||||
return feeMsats
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
When the amount to be received exceeds the inbound liquidity of the node, a new channel will be opened by the LSP in order for the node to receive it. This can checked by retrieving the NodeState from the SDK and comparing the inbound liquidity to the amount to be received. If the amount is greater or equal to the inbound liquidity, a new channel opening is required.
|
||||
|
||||
To calculate the fees for a channel being opened by the LSP:
|
||||
|
||||
```cs
|
||||
ulong calculateChannelOpeningFee(ulong amountMsats)
|
||||
{
|
||||
var channelOpeningFeeNeeded = isChannelOpeningFeeNeeded(amountMsats);
|
||||
if (channelOpeningFeeNeeded)
|
||||
{
|
||||
return calculateFeesForAmount(amountMsats);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
How to detect if open channel fees are needed:
|
||||
```typescript
|
||||
bool isChannelOpeningFeeNeeded(ulong amountMsats)
|
||||
{
|
||||
try
|
||||
{
|
||||
var nodeInfo = sdk.NodeInfo();
|
||||
return nodeInfo.inboundLiquidityMsats <= amountMsats;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// handle error
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
```
|
||||
|
||||
LSP fees are calculated in two ways, either by a minimum fee set by the LSP or by a fee per myriad calculated based on the amount being received. If the fee calculated from the fee per myriad is less than the minimum fee, the minimum fee is used.
|
||||
|
||||
This information can be retrieved for each LSP and then calculated:
|
||||
|
||||
```typescript
|
||||
ulong calculateFeesForAmount(ulong amountMsats)
|
||||
{
|
||||
try
|
||||
{
|
||||
var id = sdk.LspId();
|
||||
var lspInfo = sdk.FetchLspInfo(id);
|
||||
|
||||
// We calculate the dynamic fees in millisatoshis rounded to satoshis.
|
||||
var channelDynamicFeeMsat = amountMsats * (ulong)lspInfo.channelFeePermyriad / 10000 / 1000 * 1000;
|
||||
var feeMsat = Math.Max((ulong)lspInfo.channelMinimumFeeMsat, channelDynamicFeeMsat);
|
||||
|
||||
return feeMsat;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
</section>
|
||||
</custom-tabs>
|
||||
@@ -1,34 +0,0 @@
|
||||
# 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,no_run
|
||||
let swap_info = sdk.receive_onchain().await?;
|
||||
|
||||
// Send your funds to the bellow bitcoin address
|
||||
let address = swap_info.bitcoin_address;
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust,no_run
|
||||
let swap_info = sdk.in_progress_swap().await?
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust,no_run
|
||||
let refundables = sdk.list_refundables().await?
|
||||
```
|
||||
|
||||
Once you have a refundable swap in hand, use the follwing code to execute a refund:
|
||||
|
||||
```rust,no_run
|
||||
let destination_address = "...".into()
|
||||
let sat_per_byte = <efund tx fee rate>
|
||||
sdk.refund(refundable.bitcoin_address, destination_address, sat_per_byte).await?
|
||||
```
|
||||
@@ -1 +1,382 @@
|
||||
# Sending an on-chain transaction (swap-out)
|
||||
|
||||
You can send funds from the Breez SDK wallet to an on-chain address as follows.
|
||||
|
||||
First, fetch the current reverse swap fees:
|
||||
|
||||
<custom-tabs category="lang">
|
||||
<div slot="title">Rust</div>
|
||||
<section>
|
||||
|
||||
```rust,ignore
|
||||
let current_fees = sdk.fetch_reverse_swap_fees().await?;
|
||||
|
||||
info!("Percentage fee for the reverse swap service: {}", current_fees.fees_percentage);
|
||||
info!("Estimated miner fees in sats for locking up funds: {}", current_fees.fees_lockup);
|
||||
info!("Estimated miner fees in sats for claiming funds: {}", current_fees.fees_claim);
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust,ignore
|
||||
info!("Minimum amount, in sats: {}", current_fees.min);
|
||||
info!("Maximum amount, in sats: {}", current_fees.max);
|
||||
```
|
||||
|
||||
Once you checked the fees are acceptable, you can start the reverse swap:
|
||||
|
||||
```rust,ignore
|
||||
let destination_address = String::from("bc1..");
|
||||
let amount_sat = current_fees.min;
|
||||
|
||||
sdk.send_onchain(amount_sat, destination_address, current_fees.fees_hash).await?;
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust,ignore
|
||||
for rs in sdk.in_progress_reverse_swaps().await? {
|
||||
info!("Reverse swap {} in progress, status is {}", rs.id, rs.status);
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Swift</div>
|
||||
<section>
|
||||
|
||||
```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 {
|
||||
// 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:
|
||||
|
||||
```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 = <fee rate>
|
||||
try {
|
||||
try sdk.sendOnchain(amountSat: amountSat, onchainRecipientAddress: destinationAddress, pairHash: currentFees.feesHash, satPerVbyte: satPerVbyte)
|
||||
} catch {
|
||||
// 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:
|
||||
|
||||
```swift
|
||||
for rs in sdk.inProgressReverseSwaps() {
|
||||
println("Reverse swap \(rs.id) in progress, status is \(rs.status)")
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">React Native</div>
|
||||
<section>
|
||||
|
||||
```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: ${currentFees.min}`);
|
||||
console.log(`Maximum amount, in sats: ${currentFees.max}`);
|
||||
```
|
||||
|
||||
Once you checked the fees are acceptable, you can start the reverse swap:
|
||||
|
||||
```typescript
|
||||
const destinationAddress = "bc1..";
|
||||
const amountSat = currentFees.min;
|
||||
const satPerVbyte = <fee rate>
|
||||
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.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Dart</div>
|
||||
<section>
|
||||
|
||||
```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 = <fee rate>
|
||||
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<ReverseSwapInfo> swaps = await inProgressReverseSwaps();
|
||||
for (swap in swaps) {
|
||||
print(`Reverse swap ${swap.id} in progress, status is ${swap.status}`);
|
||||
}
|
||||
} catch (error) {
|
||||
// handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Python</div>
|
||||
<section>
|
||||
|
||||
```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
|
||||
```
|
||||
</section>
|
||||
<div slot="title">Go</div>
|
||||
<section>
|
||||
|
||||
```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 := <fee rate>
|
||||
|
||||
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.Status)
|
||||
}
|
||||
}
|
||||
```
|
||||
</section>
|
||||
<div slot="title">C#</div>
|
||||
<section>
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var currentFees = sdk.FetchReverseSwapFees();
|
||||
Console.WriteLine($"Percentage fee for the reverse swap service: {currentFees.feesPercentage}");
|
||||
Console.WriteLine($"Estimated miner fees in sats for locking up funds: {currentFees.feesLockup}");
|
||||
Console.WriteLine($"Estimated miner fees in sats for claiming funds: {currentFees.feesClaim}");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 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:
|
||||
|
||||
```cs
|
||||
Console.WriteLine($"Minimum amount, in sats: {currentFees.min}");
|
||||
Console.WriteLine($"Maximum amount, in sats: {currentFees.max}");
|
||||
```
|
||||
|
||||
Once you checked the fees are acceptable, you can start the reverse swap:
|
||||
|
||||
```cs
|
||||
var destinationAddress = "bc1..";
|
||||
var amountSat = currentFees.min;
|
||||
var satPerVbyte = <fee rate>;
|
||||
try
|
||||
{
|
||||
var reverseSwapInfo = sdk.SendOnchain(amountSat, destinationAddress, currentFees.feesHash, satPerVbyte);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// 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:
|
||||
|
||||
```cs
|
||||
try
|
||||
{
|
||||
var swaps = sdk.InProgressReverseSwaps();
|
||||
foreach (var swap in swaps) {
|
||||
Console.WriteLine($"Reverse swap {swap.id} in progress, status is {swap.status}`");
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// Handle error
|
||||
}
|
||||
```
|
||||
</section>
|
||||
</custom-tabs>
|
||||
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.
|
||||
|
||||
If however something goes wrong at any point in the process, the initial HODL payment will be cancelled and the funds in
|
||||
your Breez SDK wallet will be unlocked.
|
||||
147
tabs.js
Normal file
147
tabs.js
Normal file
@@ -0,0 +1,147 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
let selected_ = null;
|
||||
|
||||
customElements.define('custom-tabs', class extends HTMLElement {
|
||||
|
||||
constructor() {
|
||||
super(); // always call super() first in the ctor.
|
||||
|
||||
// Create shadow DOM for the component.
|
||||
let shadowRoot = this.attachShadow({ mode: 'open' });
|
||||
shadowRoot.innerHTML = `
|
||||
<style>
|
||||
:host {
|
||||
display: inline-block;
|
||||
contain: content;
|
||||
border: 1px solid var(--quote-border);
|
||||
border-radius: 8px;
|
||||
width: 100%;
|
||||
}
|
||||
#panels {
|
||||
padding: 10px;
|
||||
}
|
||||
#tabs {
|
||||
border-bottom: 1px solid var(--quote-border);
|
||||
background-color: var(--sidebar-bg);
|
||||
}
|
||||
#tabs slot {
|
||||
display: inline-flex; /* Safari bug. Treats <slot> as a parent */
|
||||
}
|
||||
#tabs ::slotted(*) {
|
||||
color: var(--sidebar-fg);
|
||||
padding: 16px 8px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 3px;
|
||||
border: none; /* if the user users a <button> */
|
||||
}
|
||||
#tabs ::slotted([tabindex="0"]), #tabs ::slotted(*:hover) {
|
||||
color: var(--sidebar-active);
|
||||
}
|
||||
#panels ::slotted([aria-hidden="true"]) {
|
||||
display: none;
|
||||
}
|
||||
pre {
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
<div id="tabs">
|
||||
<slot id="tabsSlot" name="title"></slot>
|
||||
</div>
|
||||
<div id="panels">
|
||||
<slot id="panelsSlot"></slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
get selected() {
|
||||
return selected_;
|
||||
}
|
||||
|
||||
set selected(idx) {
|
||||
selected_ = idx;
|
||||
this._selectTab(idx);
|
||||
this.setAttribute('selected', idx);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.setAttribute('role', 'tablist');
|
||||
|
||||
const tabsSlot = this.shadowRoot.querySelector('#tabsSlot');
|
||||
const panelsSlot = this.shadowRoot.querySelector('#panelsSlot');
|
||||
|
||||
this.tabs = tabsSlot.assignedNodes({ flatten: true });
|
||||
this.panels = panelsSlot.assignedNodes({ flatten: true }).filter(el => {
|
||||
return el.nodeType === Node.ELEMENT_NODE;
|
||||
});
|
||||
|
||||
// Save refer to we can remove listeners later.
|
||||
this._boundOnTitleClick = this._onTitleClick.bind(this);
|
||||
|
||||
tabsSlot.addEventListener('click', this._boundOnTitleClick);
|
||||
|
||||
this.selected = this._findFirstSelectedTab() || this._findStoredSelectedTab() || 0;
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
const tabsSlot = this.shadowRoot.querySelector('#tabsSlot');
|
||||
tabsSlot.removeEventListener('click', this._boundOnTitleClick);
|
||||
}
|
||||
|
||||
_onTitleClick(e) {
|
||||
if (e.target.slot === 'title') {
|
||||
this.selected = this.tabs.indexOf(e.target);
|
||||
e.target.focus();
|
||||
}
|
||||
}
|
||||
|
||||
_findFirstSelectedTab() {
|
||||
let selectedIdx;
|
||||
for (let [i, tab] of this.tabs.entries()) {
|
||||
tab.setAttribute('role', 'tab');
|
||||
if (tab.hasAttribute('selected')) {
|
||||
selectedIdx = i;
|
||||
}
|
||||
}
|
||||
return selectedIdx;
|
||||
}
|
||||
|
||||
_findStoredSelectedTab() {
|
||||
let selectedIdx;
|
||||
if (this.getAttribute("category")) {
|
||||
let selectedText;
|
||||
try { selectedText = localStorage.getItem('mdbook-tabs-' + this.getAttribute("category")); } catch (e) { }
|
||||
if (selectedText) {
|
||||
for (let [i, tab] of this.tabs.entries()) {
|
||||
if (tab.textContent === selectedText) {
|
||||
selectedIdx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return selectedIdx;
|
||||
}
|
||||
|
||||
_selectTab(idx = null) {
|
||||
for (let i = 0, tab; tab = this.tabs[i]; ++i) {
|
||||
let select = i === idx;
|
||||
tab.setAttribute('tabindex', select ? 0 : -1);
|
||||
tab.setAttribute('aria-selected', select);
|
||||
this.panels[i].setAttribute('aria-hidden', !select);
|
||||
if (select && this.getAttribute("category") && tab.textContent) {
|
||||
try { localStorage.setItem('mdbook-tabs-' + this.getAttribute("category"), tab.textContent); } catch (e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
})();
|
||||
1471
theme/highlight.js
Normal file
1471
theme/highlight.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user