Handling multiple assets

The Liquid sidechain can also be used to send and receive other assets registered on the Liquid Network. Using the SDK you can send and receive these assets by using a Liquid payment with an additional asset ID. By default the SDK includes the metadata for L-BTC and Tether USD. To include addition asset metadata, see Adding asset metadata.

Adding asset metadata API docs

You can add addition asset metadata to the SDK when you configure it on connect. In the example below we will add the PEGx EUR asset. Once the asset metadata is added, it can be used as an asset to send and receive. You can find the asset metadata for other assets in the Mainnet Liquid Asset Registry (Testnet).

Rust
// Create the default config
let mut config = LiquidSdk::default_config(
    LiquidNetwork::Mainnet,
    Some("<your-Breez-API-key>".to_string()),
)?;

// Configure asset metadata
config.asset_metadata = Some(vec![
    AssetMetadata {
        asset_id: "18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec".to_string(),
        name: "PEGx EUR".to_string(),
        ticker: "EURx".to_string(),
        precision: 8,
    },
]);
Swift
// Create the default config
var config = try defaultConfig(network: LiquidNetwork.mainnet, breezApiKey: "<your-Breez-API-key>")

// Configure asset metadata
config.assetMetadata = [
    AssetMetadata(
        assetId: "18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
        name: "PEGx EUR",
        ticker: "EURx",
        precision: 8
    )
]
Kotlin
// Create the default config
val config : Config = defaultConfig(LiquidNetwork.MAINNET, "<your Breez API key>")

// Configure asset metadata
config.assetMetadata = listOf(
    AssetMetadata(
        assetId = "18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
        name = "PEGx EUR",
        ticker = "EURx",
        precision = 8.toUByte()
    )
)
React Native
// Create the default config
const config = await defaultConfig(
  LiquidNetwork.MAINNET,
  '<your-Breez-API-key>'
)

// Configure asset metadata
config.assetMetadata = [
  {
    assetId: '18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec',
    name: 'PEGx EUR',
    ticker: 'EURx',
    precision: 8
  }
]
Dart
// Create the default config
Config config = defaultConfig(network: LiquidNetwork.mainnet, breezApiKey: "<your-Breez-API-key>");

// Configure asset metadata
config = config.copyWith(
  assetMetadata: [
    AssetMetadata(
      assetId: "18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
      name: "PEGx EUR",
      ticker: "EURx",
      precision: 8,
    ),
  ],
);
Python
# Create the default config
config = default_config(network=LiquidNetwork.MAINNET, breez_api_key="<your-Breez-API-key>")

# Configure asset metadata
config.asset_metadata = [
    AssetMetadata(
        asset_id="18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
        name="PEGx EUR",
        ticker="EURx",
        precision=8
    )
]
Go
// Create the default config
breezApiKey := "<your-Breez-API-key>"
config, err := breez_sdk_liquid.DefaultConfig(breez_sdk_liquid.LiquidNetworkMainnet, &breezApiKey)
if err != nil {
    return err
}

// Configure asset metadata
assetMetadata := []breez_sdk_liquid.AssetMetadata{
    {
        AssetId:   "18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
        Name:      "PEGx EUR",
        Ticker:    "EURx",
        Precision: 8,
    },
}
config.AssetMetadata = &assetMetadata
C#
// Create the default config
var config = BreezSdkLiquidMethods.DefaultConfig(
    LiquidNetwork.Mainnet,
    "<your-Breez-API-key>"
) with
{
    // Configure asset metadata
    assetMetadata = new List<AssetMetadata>
    {
        new(
            assetId: "18729918ab4bca843656f08d4dd877bed6641fbd596a0a963abbf199cfeb3cec",
            name: "PEGx EUR",
            ticker: "EURx",
            precision: 8
        )
    }
};

Default asset metadata

Mainnet

NameTickerAsset IDPrecision
BitcoinBTC6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d8
Tether USDUSDtce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd28

Testnet

NameTickerAsset IDPrecision
Testnet BitcoinBTC144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a498
Testnet Tether USDUSDtb612eb46313a2cd6ebabd8b7a8eed5696e29898b87a43bff41c94f51acef9d738

Fetching the asset balances API docs

Once connected, the asset balances can be retreived.

Rust
let info = sdk.get_info().await?;
let asset_balances = info.wallet_info.asset_balances;
Swift
if let info = try? sdk.getInfo() {
    let assetBalances = info.walletInfo.assetBalances
    
    print(assetBalances)
}
Kotlin
try {
    val info = sdk.getInfo()
    val assetBalances = info?.walletInfo?.assetBalances
} catch (e: Exception) {
    // handle error
}
React Native
const info = await getInfo()
const assetBalances = info.walletInfo.assetBalances
Dart
GetInfoResponse? info = await breezSDKLiquid.instance!.getInfo();
List<AssetBalance> assetBalances = info.walletInfo.assetBalances;
Python
try:
    info = sdk.get_info()
    asset_balances = info.wallet_info.asset_balances
except Exception as error:
    logging.error(error)
    raise
Go
if info, err := sdk.GetInfo(); err == nil {
    assetBalances := info.WalletInfo.AssetBalances
    log.Printf("Asset balances: %#v", assetBalances)
}
C#
try
{
    var info = sdk.GetInfo();
    var assetBalances = info?.walletInfo?.assetBalances;
}
catch (Exception)
{
    // Handle error
}

Receiving a non-Bitcoin asset API docs

When receiving an asset via Liquid, we can generate a BIP21 URI with information regarding the payment of a specific asset. The amount to receive is optional and omitting it will result in an amountless BIP21 URI.

In the example below we are using the Mainnet Tether USD asset.

Rust
// Create a Liquid BIP21 URI/address to receive an asset payment to.
// Note: Not setting the amount will generate an amountless BIP21 URI.
let usdt_asset_id = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2".to_string();
let optional_amount = Some(ReceiveAmount::Asset {
    asset_id: usdt_asset_id,
    payer_amount: Some(1.50),
});
let prepare_response = sdk
    .prepare_receive_payment(&PrepareReceiveRequest {
        payment_method: PaymentMethod::LiquidAddress,
        amount: optional_amount,
    })
    .await?;

// If the fees are acceptable, continue to create the Receive Payment
let receive_fees_sat = prepare_response.fees_sat;
info!("Fees: {} sats", receive_fees_sat);
Swift
// Create a Liquid BIP21 URI/address to receive an asset payment to.
// Note: Not setting the amount will generate an amountless BIP21 URI.
let usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
let optionalAmount = ReceiveAmount.asset(assetId: usdtAssetId, payerAmount: 1.50)
let prepareResponse = try? sdk
    .prepareReceivePayment(req: PrepareReceiveRequest(
        paymentMethod: PaymentMethod.liquidAddress,
        amount: optionalAmount
    ))

// If the fees are acceptable, continue to create the Receive Payment
let receiveFeesSat = prepareResponse!.feesSat;
print("Fees: {} sats", receiveFeesSat);
Kotlin
try {
    // Create a Liquid BIP21 URI/address to receive an asset payment to.
    // Note: Not setting the amount will generate an amountless BIP21 URI.
    val usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
    val optionalAmount = ReceiveAmount.Asset(usdtAssetId, 1.50)
    val prepareRequest = PrepareReceiveRequest(PaymentMethod.LIQUID_ADDRESS, optionalAmount)
    val prepareResponse = sdk.prepareReceivePayment(prepareRequest)

    // If the fees are acceptable, continue to create the Receive Payment
    val receiveFeesSat = prepareResponse.feesSat;
    // Log.v("Breez", "Fees: ${receiveFeesSat} sats")
} catch (e: Exception) {
    // handle error
}
React Native

// Create a Liquid BIP21 URI/address to receive an asset payment to.
// Note: Not setting the amount will generate an amountless BIP21 URI.
const usdtAssetId = 'ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2'
const optionalAmount: ReceiveAmount = {
  type: ReceiveAmountVariant.ASSET,
  assetId: usdtAssetId,
  payerAmount: 1.50
}

const prepareResponse = await prepareReceivePayment({
  paymentMethod: PaymentMethod.LIQUID_ADDRESS,
  amount: optionalAmount
})

// If the fees are acceptable, continue to create the Receive Payment
const receiveFeesSat = prepareResponse.feesSat
console.log(`Fees: ${receiveFeesSat} sats`)
Dart
// Create a Liquid BIP21 URI/address to receive an asset payment to.
// Note: Not setting the amount will generate an amountless BIP21 URI.
String usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2";
ReceiveAmount_Asset optionalAmount = ReceiveAmount_Asset(assetId: usdtAssetId, payerAmount: 1.50);
PrepareReceiveResponse prepareResponse = await breezSDKLiquid.instance!.prepareReceivePayment(
  req: PrepareReceiveRequest(
    paymentMethod: PaymentMethod.liquidAddress,
    amount: optionalAmount,
  ),
);

// If the fees are acceptable, continue to create the Receive Payment
BigInt receiveFeesSat = prepareResponse.feesSat;
print("Fees: $receiveFeesSat sats");
Python
try:
    # Create a Liquid BIP21 URI/address to receive an asset payment to.
    # Note: Not setting the amount will generate an amountless BIP21 URI.
    usdt_asset_id = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
    optional_amount = ReceiveAmount.ASSET(usdt_asset_id, 1.50)
    prepare_request = PrepareReceiveRequest(PaymentMethod.LIQUID_ADDRESS, optional_amount)
    prepare_response = sdk.prepare_receive_payment(prepare_request)

    # If the fees are acceptable, continue to create the Receive Payment
    receive_fees_sat = prepare_response.fees_sat
    logging.debug("Fees: ", receive_fees_sat, " sats")
    return prepare_response
except Exception as error:
    logging.error(error)
    raise
Go
// Create a Liquid BIP21 URI/address to receive an asset payment to.
// Note: Not setting the amount will generate an amountless BIP21 URI.
usdtAssetId := "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
payerAmount := float64(1.50)
var optionalAmount breez_sdk_liquid.ReceiveAmount = breez_sdk_liquid.ReceiveAmountAsset{
    AssetId:     usdtAssetId,
    PayerAmount: &payerAmount,
}
prepareRequest := breez_sdk_liquid.PrepareReceiveRequest{
    PaymentMethod: breez_sdk_liquid.PaymentMethodLiquidAddress,
    Amount:        &optionalAmount,
}
if prepareResponse, err := sdk.PrepareReceivePayment(prepareRequest); err == nil {
    // If the fees are acceptable, continue to create the Receive Payment
    receiveFeesSat := prepareResponse.FeesSat
    log.Printf("Fees: %v sats", receiveFeesSat)
}
C#
try
{
    // Create a Liquid BIP21 URI/address to receive an asset payment to.
    // Note: Not setting the amount will generate an amountless BIP21 URI.
    var usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2";
    var optionalAmount = new ReceiveAmount.Asset(usdtAssetId, 1.50);
    var prepareRequest = new PrepareReceiveRequest(PaymentMethod.LiquidAddress, optionalAmount);
    var prepareResponse = sdk.PrepareReceivePayment(prepareRequest);

    // If the fees are acceptable, continue to create the Receive Payment
    var receiveFeesSat = prepareResponse.feesSat;
    Console.WriteLine($"Fees: {receiveFeesSat} sats");
}
catch (Exception)
{
    // Handle error
}

Sending a non-Bitcoin asset API docs

When sending an asset via Liquid, a BIP21 URI or Liquid address can be used as the destination. If a Liquid address is used, the optional prepare request amount must be set. If a BIP21 URI is used, either the BIP21 URI amount or optional prepare request amount must be set. When both amounts are set, the SDK will prioritize the request amount over the BIP21 amount.

In the example below we are using the Mainnet Tether USD asset.

Rust
// Set the Liquid BIP21 or Liquid address you wish to pay
let destination = "<Liquid BIP21 or address>".to_string();
// If the destination is an address or an amountless BIP21 URI,
// you must specifiy an asset amount
let usdt_asset_id = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2".to_string();
let optional_amount = Some(PayAmount::Asset {
    asset_id: usdt_asset_id,
    receiver_amount: Some(1.50),
});
let prepare_response = sdk
    .prepare_send_payment(&PrepareSendRequest {
        destination,
        amount: optional_amount,
    })
    .await?;

// If the fees are acceptable, continue to create the Send Payment
let send_fees_sat = prepare_response.fees_sat;
info!("Fees: {} sats", send_fees_sat);
Swift
// Set the Liquid BIP21 or Liquid address you wish to pay
let destination = "<Liquid BIP21 or address>"
// If the destination is an address or an amountless BIP21 URI,
// you must specifiy an asset amount
let usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
let optionalAmount = PayAmount.asset(assetId: usdtAssetId, receiverAmount: 1.50)
let prepareResponse = try? sdk
    .prepareSendPayment(req: PrepareSendRequest (
        destination: destination,
        amount: optionalAmount
    ))

// If the fees are acceptable, continue to create the Send Payment
let sendFeesSat = prepareResponse!.feesSat
print("Fees: {} sats", sendFeesSat);
Kotlin
// Set the Liquid BIP21 or Liquid address you wish to pay
val destination = "<Liquid BIP21 or address>"
try {
    // Create a Liquid BIP21 URI/address to receive an asset payment to.
    // Note: Not setting the amount will generate an amountless BIP21 URI.
    val usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
    val optionalAmount = PayAmount.Asset(usdtAssetId, 1.50)
    val prepareResponse = sdk.prepareSendPayment(PrepareSendRequest(destination, optionalAmount))

    // If the fees are acceptable, continue to create the Send Payment
    val sendFeesSat = prepareResponse.feesSat;
    // Log.v("Breez", "Fees: ${sendFeesSat} sats")
} catch (e: Exception) {
    // handle error
}
React Native
// Set the Liquid BIP21 or Liquid address you wish to pay
const destination = '<Liquid BIP21 or address>'
// If the destination is an address or an amountless BIP21 URI,
// you must specifiy an asset amount

const usdtAssetId = 'ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2'
const optionalAmount: PayAmount = {
  type: PayAmountVariant.ASSET,
  assetId: usdtAssetId,
  receiverAmount: 1.50
}

const prepareResponse = await prepareSendPayment({
  destination,
  amount: optionalAmount
})

// If the fees are acceptable, continue to create the Send Payment
const sendFeesSat = prepareResponse.feesSat
console.log(`Fees: ${sendFeesSat} sats`)
Dart
// Set the Liquid BIP21 or Liquid address you wish to pay
String destination = "<Liquid BIP21 or address>";
// If the destination is an address or an amountless BIP21 URI,
// you must specifiy an asset amount
String usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2";
PayAmount_Asset optionalAmount = PayAmount_Asset(assetId: usdtAssetId, receiverAmount: 1.50);
PrepareSendRequest prepareSendRequest = PrepareSendRequest(
  destination: destination,
  amount: optionalAmount,
);

PrepareSendResponse prepareSendResponse = await breezSDKLiquid.instance!.prepareSendPayment(
  req: prepareSendRequest,
);

// If the fees are acceptable, continue to create the Send Payment
BigInt sendFeesSat = prepareSendResponse.feesSat;
print("Fees: $sendFeesSat sats");
Python
# Set the Liquid BIP21 or Liquid address you wish to pay
destination = "<Liquid BIP21 or address>"
try:
    # If the destination is an address or an amountless BIP21 URI,
    # you must specifiy an asset amount
    usdt_asset_id = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
    optional_amount = PayAmount.ASSET(usdt_asset_id, 1.50)
    prepare_response = sdk.prepare_send_payment(PrepareSendRequest(destination, optional_amount))

    # If the fees are acceptable, continue to create the Send Payment
    send_fees_sat = prepare_response.fees_sat
    logging.debug("Fees: ", send_fees_sat, " sats")
    return prepare_response
except Exception as error:
    logging.error(error)
    raise
Go
// Set the Liquid BIP21 or Liquid address you wish to pay
destination := "<Liquid BIP21 or address>"
// If the destination is an address or an amountless BIP21 URI,
// you must specifiy an asset amount
usdtAssetId := "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2"
receiverAmount := float64(1.50)
var optionalAmount breez_sdk_liquid.PayAmount = breez_sdk_liquid.PayAmountAsset{
    AssetId:        usdtAssetId,
    ReceiverAmount: receiverAmount,
}

prepareRequest := breez_sdk_liquid.PrepareSendRequest{
    Destination: destination,
    Amount:      &optionalAmount,
}
prepareResponse, err := sdk.PrepareSendPayment(prepareRequest)
if err != nil {
    log.Printf("Error: %#v", err)
    return
}

sendFeesSat := prepareResponse.FeesSat
log.Printf("Fees: %v sats", sendFeesSat)
C#
// Set the Liquid BIP21 or address you wish to pay
var destination = "<Liquid BIP21 or address>";
try
{
    // If the destination is an address or an amountless BIP21 URI,
    // you must specifiy an asset amount
    var usdtAssetId = "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2";
    var optionalAmount = new PayAmount.Asset(usdtAssetId, 1.50);
    var prepareResponse = sdk.PrepareSendPayment(new PrepareSendRequest(destination, optionalAmount));

    // If the fees are acceptable, continue to create the Send Payment
    var sendFeesSat = prepareResponse.feesSat;
    Console.WriteLine($"Fees: {sendFeesSat} sats");
}
catch (Exception)
{
    // Handle error
}