Sending an on-chain transaction (Swap-Out)

You can send funds from the Breez SDK wallet to an on-chain address as follows.

Developer note

Consider implementing the Notification Plugin when using the Breez SDK in a mobile application. By registering a webhook the application can receive notifications to process the payment in the background.

Checking the limits

First, fetch the current Send Onchain limits:

Rust
let current_limits = sdk.fetch_onchain_limits().await?;

info!("Minimum amount: {} sats", current_limits.send.min_sat);
info!("Maximum amount: {} sats", current_limits.send.max_sat);
Swift
let currentLimits = try? sdk.fetchOnchainLimits()
if let limits = currentLimits {
    print("Minimum amount, in sats: \(limits.send.minSat)")
    print("Maximum amount, in sats: \(limits.send.maxSat)")
}
Kotlin
try {
    val currentLimits = sdk.fetchOnchainLimits()
    // Log.v("Breez", "Minimum amount, in sats: ${currentLimits.send.minSat}")
    // Log.v("Breez", "Maximum amount, in sats: ${currentLimits.send.maxSat}")
} catch (e: Exception) {
    // handle error
}
React Native
try {
  const currentLimits = await fetchOnchainLimits()

  console.log(`Minimum amount, in sats: ${currentLimits.send.minSat}`)
  console.log(`Maximum amount, in sats: ${currentLimits.send.maxSat}`)
} catch (err) {
  console.error(err)
}
Dart
OnchainPaymentLimitsResponse currentLimits = await breezSDKLiquid.instance!.fetchOnchainLimits();
print("Minimum amount: ${currentLimits.send.minSat} sats");
print("Maximum amount: ${currentLimits.send.maxSat} sats");
Python
try:
    current_limits = sdk.fetch_onchain_limits()
    logging.debug("Minimum amount, in sats ", current_limits.send.min_sat)
    logging.debug("Maximum amount, in sats ", current_limits.send.max_sat)
    return current_limits
except Exception as error:
    logging.error(error)
    raise
Go
if currentLimits, err := sdk.FetchOnchainLimits(); err == nil {
    log.Printf("Minimum amount, in sats: %v", currentLimits.Send.MinSat)
    log.Printf("Maximum amount, in sats: %v", currentLimits.Send.MaxSat)
}
C#
try
{
    var currentLimits = sdk.FetchOnchainLimits();
    Console.WriteLine($"Minimum amount, in sats: {currentLimits.send.minSat}");
    Console.WriteLine($"Maximum amount, in sats: {currentLimits.send.maxSat}");
}
catch (Exception)
{
    // Handle error
}

This represents the range of valid amounts that can be sent at this point in time. The range may change depending on the swap service parameters or mempool feerate fluctuations.

Developer note

It is best to fetch these limits just before your app shows the Pay Onchain (reverse swap) UI. You can then use these limits to validate the user input.

Preparing to send, checking fees

The next step is to find out the fees:

Rust
let prepare_res = sdk
    .prepare_pay_onchain(&PreparePayOnchainRequest {
        receiver_amount_sat: 5_000,
        sat_per_vbyte: None,
    })
    .await?;

// Check if the fees are acceptable before proceeding
let total_fees_sat = prepare_res.total_fees_sat;
Swift
let prepareRequest = PreparePayOnchainRequest(receiverAmountSat: 5_000)
let prepareResponse = try? sdk.preparePayOnchain(req: prepareRequest)

if let response = prepareResponse {
    // Check if the fees are acceptable before proceeding
    print("Payer fees, in sats: \(response.totalFeesSat)")
}
Kotlin
try {
    val prepareRequest = PreparePayOnchainRequest(5_000.toULong())
    val prepareResponse = sdk.preparePayOnchain(prepareRequest)

    // Check if the fees are acceptable before proceeding
    val totalFeesSat = prepareResponse.totalFeesSat;
} catch (e: Exception) {
    // handle error
}
React Native
try {
  const prepareResponse = await preparePayOnchain({
    receiverAmountSat: 5_000
  })

  // Check if the fees are acceptable before proceeding
  const totalFeesSat = prepareResponse.totalFeesSat
} catch (err) {
  console.error(err)
}
Dart
PreparePayOnchainRequest preparePayOnchainRequest = PreparePayOnchainRequest(
  receiverAmountSat: 5000 as BigInt,
);
PreparePayOnchainResponse prepareRes = await breezSDKLiquid.instance!.preparePayOnchain(
  req: preparePayOnchainRequest,
);

// Check if the fees are acceptable before proceeding
BigInt totalFeesSat = prepareRes.totalFeesSat;
Python
try:
    prepare_request = PreparePayOnchainRequest(5_000)
    prepare_response = sdk.prepare_pay_onchain(prepare_request)

    # Check if the fees are acceptable before proceeding
    total_fees_sat = prepare_response.total_fees_sat
except Exception as error:
    logging.error(error)
    raise
Go
prepareRequest := breez_sdk_liquid.PreparePayOnchainRequest{
    ReceiverAmountSat: 5_000,
}

if prepareResponse, err := sdk.PreparePayOnchain(prepareRequest); err == nil {
    // Check if the fees are acceptable before proceeding
    totalFeesSat := prepareResponse.TotalFeesSat
    log.Printf("Fees: %v sats", totalFeesSat)
}
C#
try
{
    var prepareRequest = new PreparePayOnchainRequest(5000);
    var prepareResponse = sdk.PreparePayOnchain(prepareRequest);

    // Check if the fees are acceptable before proceeding
    var totalFeesSat = prepareResponse.totalFeesSat;
}
catch (Exception)
{
    // Handle error
}

If you want to set a custom fee rate when the Bitcoin transaction is claimed:

Rust
let optional_sat_per_vbyte = Some(21);

let prepare_res = sdk
    .prepare_pay_onchain(&PreparePayOnchainRequest {
        receiver_amount_sat: 5_000,
        sat_per_vbyte: optional_sat_per_vbyte,
    })
    .await?;

// Check if the fees are acceptable before proceeding
let claim_fees_sat = prepare_res.claim_fees_sat;
let total_fees_sat = prepare_res.total_fees_sat;
Swift
let optionalSatPerVbyte = UInt32(21)

let prepareRequest = PreparePayOnchainRequest(receiverAmountSat: 5_000, satPerVbyte: optionalSatPerVbyte)
let prepareResponse = try? sdk.preparePayOnchain(req: prepareRequest)

if let response = prepareResponse {
    // Check if the fees are acceptable before proceeding
    print("Payer claim fees, in sats: \(response.claimFeesSat)")
    print("Payer total fees, in sats: \(response.totalFeesSat)")
}
Kotlin
try {
    val optionalSatPerVbyte = 21

    val prepareRequest = PreparePayOnchainRequest(5_000.toULong(), optionalSatPerVbyte.toUInt())
    val prepareResponse = sdk.preparePayOnchain(prepareRequest)

    // Check if the fees are acceptable before proceeding
    val claimFeesSat = prepareResponse.claimFeesSat;
    val totalFeesSat = prepareResponse.totalFeesSat;
} catch (e: Exception) {
    // handle error
}
React Native
try {
  const optionalSatPerVbyte = 21

  const prepareResponse = await preparePayOnchain({
    receiverAmountSat: 5_000,
    satPerVbyte: optionalSatPerVbyte
  })

  // Check if the fees are acceptable before proceeding
  const claimFeesSat = prepareResponse.claimFeesSat
  const totalFeesSat = prepareResponse.totalFeesSat
} catch (err) {
  console.error(err)
}
Dart
int optionalSatPerVbyte = 21;

PreparePayOnchainRequest preparePayOnchainRequest = PreparePayOnchainRequest(
  receiverAmountSat: 5000 as BigInt,
  satPerVbyte: optionalSatPerVbyte,
);
PreparePayOnchainResponse prepareRes = await breezSDKLiquid.instance!.preparePayOnchain(
  req: preparePayOnchainRequest,
);

// Check if the fees are acceptable before proceeding
BigInt claimFeesSat = prepareRes.claimFeesSat;
BigInt totalFeesSat = prepareRes.totalFeesSat;
Python
try:
    optional_sat_per_vbyte = 21

    prepare_request = PreparePayOnchainRequest(5_000, optional_sat_per_vbyte)
    prepare_response = sdk.prepare_pay_onchain(prepare_request)

    # Check if the fees are acceptable before proceeding
    claim_fees_sat = prepare_response.claim_fees_sat
    total_fees_sat = prepare_response.total_fees_sat
except Exception as error:
    logging.error(error)
    raise
Go
optionalSatPerVbyte := uint32(21)
prepareRequest := breez_sdk_liquid.PreparePayOnchainRequest{
    ReceiverAmountSat: 5_000,
    SatPerVbyte:       &optionalSatPerVbyte,
}

if prepareResponse, err := sdk.PreparePayOnchain(prepareRequest); err == nil {
    // Check if the fees are acceptable before proceeding
    claimFeesSat := prepareResponse.ClaimFeesSat
    totalFeesSat := prepareResponse.TotalFeesSat
    log.Printf("Claim fees: %v sats, total fees: %v sats", claimFeesSat, totalFeesSat)
}
C#
try
{
    uint optionalSatPerVbyte = 21;

    var prepareRequest = new PreparePayOnchainRequest(5000, optionalSatPerVbyte);
    var prepareResponse = sdk.PreparePayOnchain(prepareRequest);

    // Check if the fees are acceptable before proceeding
    var claimFeesSat = prepareResponse.claimFeesSat;
    var totalFeesSat = prepareResponse.totalFeesSat;
}
catch (Exception)
{
    // Handle error
}

Executing the Swap

Once you checked the amounts and the fees are acceptable, you can continue with sending the payment.

Note that one of the arguments will be the result from the prepare call above.

Rust
let destination_address = String::from("bc1..");

sdk.pay_onchain(&PayOnchainRequest {
    address: destination_address,
    prepare_response,
})
.await?;
Swift
let destinationAddress = "bc1.."

let response = try? sdk.payOnchain(req: PayOnchainRequest(
    address: destinationAddress,
    prepareResponse: prepareResponse))
Kotlin
val address = "bc1.."
try {
    sdk.payOnchain(PayOnchainRequest(address, prepareResponse))
} catch (e: Exception) {
    // handle error
}
React Native
try {
  const destinationAddress = 'bc1..'

  const payOnchainRes = await payOnchain({
    address: destinationAddress,
    prepareResponse
  })
} catch (err) {
  console.error(err)
}
Dart
String destinationAddress = "bc1..";

PayOnchainRequest req = PayOnchainRequest(
  address: destinationAddress,
  prepareResponse: prepareRes,
);
SendPaymentResponse res = await breezSDKLiquid.instance!.payOnchain(req: req);
Python
address = "bc1.."
try:
    sdk.pay_onchain(PayOnchainRequest(address, prepare_response))
except Exception as error:
    logging.error(error)
    raise
Go
address := "bc1.."
payOnchainRequest := breez_sdk_liquid.PayOnchainRequest{
    Address:         address,
    PrepareResponse: prepareResponse,
}

if reverseSwapInfo, err := sdk.PayOnchain(payOnchainRequest); err == nil {
    log.Printf("%#v", reverseSwapInfo)
}
C#
var address = "bc1..";
try
{
    var reverseSwapInfo = sdk.PayOnchain(
        new PayOnchainRequest(address, prepareResponse));
}
catch (Exception)
{
    // Handle error
}