mirror of
https://github.com/aljazceru/breez-sdk-docs.git
synced 2025-12-17 22:04:21 +01:00
add documentation for C#
This commit is contained in:
@@ -126,4 +126,35 @@ if err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
</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>
|
||||
@@ -83,4 +83,32 @@ To get the current BTC rate for the currencies.
|
||||
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>
|
||||
@@ -271,6 +271,63 @@ 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>
|
||||
|
||||
@@ -62,4 +62,4 @@ dependencies:
|
||||
```
|
||||
## Python
|
||||
|
||||
Currently python is not acceable as a package and is needed to build it from soruce. Please visit [sdk-core](https://github.com/breez/breez-sdk/tree/main/libs/sdk-bindings#python) project for instructions.
|
||||
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.
|
||||
|
||||
@@ -139,6 +139,33 @@ if input, err := breez_sdk.ParseInput(lnurlAuthUrl); err != nil {
|
||||
}
|
||||
}
|
||||
```
|
||||
</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>
|
||||
|
||||
|
||||
@@ -122,6 +122,29 @@ if input, err := breez_sdk.ParseInput(lnurlPayUrl); err != nil {
|
||||
}
|
||||
```
|
||||
</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-tab>
|
||||
|
||||
## Supported Specs
|
||||
|
||||
@@ -119,6 +119,30 @@ if input, err := breez_sdk.ParseInput(lnurlWithdrawUrl); err != nil {
|
||||
}
|
||||
```
|
||||
</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-tab>
|
||||
|
||||
## Supported Specs
|
||||
|
||||
@@ -193,5 +193,49 @@ 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>
|
||||
@@ -282,6 +282,69 @@ 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
|
||||
@@ -592,5 +655,69 @@ func calculateFeesForAmount(amountMsats uint64) uint64 {
|
||||
```
|
||||
|
||||
</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>
|
||||
@@ -310,6 +310,70 @@ if swaps, err := sdkServices.InProgressReverseSwaps(); err != nil {
|
||||
}
|
||||
```
|
||||
</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.
|
||||
|
||||
Reference in New Issue
Block a user