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.

Preparing Payments

When sending an onchain payment, the swap limits for sending onchain need to be first checked.

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.

Setting the receiver amount

When you want the payment receipient to receive a specific amount.

Rust
let prepare_res = sdk
    .prepare_pay_onchain(&PreparePayOnchainRequest {
        amount: PayOnchainAmount.Receiver {
            amount_sat: 5_000,
        },
        fee_rate_sat_per_vbyte: None,
    })
    .await?;

// Check if the fees are acceptable before proceeding
let total_fees_sat = prepare_res.total_fees_sat;
Swift
let amount = PayOnchainAmount.receiver(amountSat: 5_000)
let prepareRequest = PreparePayOnchainRequest(amount: amount)
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 amount = PayOnchainAmount.Receiver(5_000.toULong())
    val prepareRequest = PreparePayOnchainRequest(amount)
    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({
    amount: {
      type: PayOnchainAmountVariant.RECEIVER,
      amountSat: 5_000
    }
  })

  // Check if the fees are acceptable before proceeding
  const totalFeesSat = prepareResponse.totalFeesSat
} catch (err) {
  console.error(err)
}
Dart
PreparePayOnchainRequest preparePayOnchainRequest = PreparePayOnchainRequest(
  amount: PayOnchainAmount_Receiver(amountSat: 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:
    amount = PayOnchainAmount.RECEIVER(5_000)
    prepare_request = PreparePayOnchainRequest(amount)
    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
amount := breez_sdk_liquid.PayOnchainAmountReceiver{AmountSat: 5_000}
prepareRequest := breez_sdk_liquid.PreparePayOnchainRequest{
    Amount: amount,
}

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 amount = new PayOnchainAmount.Receiver(5000);
    var prepareRequest = new PreparePayOnchainRequest(amount);
    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 {
        amount: PayOnchainAmount.Receiver {
            amount_sat: 5_000,
        },
        fee_rate_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 amount = PayOnchainAmount.receiver(amountSat: 5_000)
let optionalSatPerVbyte = UInt32(21)

let prepareRequest = PreparePayOnchainRequest(amount: amount, feeRateSatPerVbyte: 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 amount = PayOnchainAmount.Receiver(5_000.toULong())
    val optionalSatPerVbyte = 21

    val prepareRequest = PreparePayOnchainRequest(amount, 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({
    amount: {
      type: PayOnchainAmountVariant.RECEIVER,
      amountSat: 5_000
    },
    feeRateSatPerVbyte: 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(
  amount: PayOnchainAmount_Receiver(amountSat: 5000 as BigInt),
  feeRateSatPerVbyte: 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:
    amount = PayOnchainAmount.RECEIVER(5_000)
    optional_sat_per_vbyte = 21

    prepare_request = PreparePayOnchainRequest(amount, 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
amount := breez_sdk_liquid.PayOnchainAmountReceiver{AmountSat: 5_000}
optionalSatPerVbyte := uint32(21)
prepareRequest := breez_sdk_liquid.PreparePayOnchainRequest{
    Amount:             amount,
    FeeRateSatPerVbyte: &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
{
    var amount = new PayOnchainAmount.Receiver(5000);
    uint optionalSatPerVbyte = 21;

    var prepareRequest = new PreparePayOnchainRequest(amount, 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
}

Draining all funds

When you want send all funds from your wallet to another address.

Rust
let prepare_res = sdk
    .prepare_pay_onchain(&PreparePayOnchainRequest {
        amount: PayOnchainAmount.Drain,
        fee_rate_sat_per_vbyte: None,
    })
    .await?;

// Check if the fees are acceptable before proceeding
let total_fees_sat = prepare_res.total_fees_sat;
Swift
let amount = PayOnchainAmount.drain
let prepareRequest = PreparePayOnchainRequest(amount: amount)
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 amount = PayOnchainAmount.Drain
    val prepareRequest = PreparePayOnchainRequest(amount)
    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({
    amount: {
      type: PayOnchainAmountVariant.DRAIN
    }
  })

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

// Check if the fees are acceptable before proceeding
BigInt totalFeesSat = prepareRes.totalFeesSat;
Python
try:
    amount = PayOnchainAmount.DRAIN
    prepare_request = PreparePayOnchainRequest(amount)
    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
amount := breez_sdk_liquid.PayOnchainAmountDrain{}
prepareRequest := breez_sdk_liquid.PreparePayOnchainRequest{
    Amount: amount,
}

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 amount = new PayOnchainAmount.Drain();
    var prepareRequest = new PreparePayOnchainRequest(amount);
    var prepareResponse = sdk.PreparePayOnchain(prepareRequest);

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

Sending Payments

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
}