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).
// 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,
},
]);
// 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
)
]
// 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()
)
)
// 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
}
]
// 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,
),
],
);
# 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
)
]
// 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
// 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
Name | Ticker | Asset ID | Precision |
---|---|---|---|
Bitcoin | BTC | 6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d | 8 |
Tether USD | USDt | ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2 | 8 |
Testnet
Name | Ticker | Asset ID | Precision |
---|---|---|---|
Testnet Bitcoin | BTC | 144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49 | 8 |
Testnet Tether USD | USDt | b612eb46313a2cd6ebabd8b7a8eed5696e29898b87a43bff41c94f51acef9d73 | 8 |
Fetching the asset balances API docs
Once connected, the asset balances can be retreived.
let info = sdk.get_info().await?;
let asset_balances = info.wallet_info.asset_balances;
if let info = try? sdk.getInfo() {
let assetBalances = info.walletInfo.assetBalances
print(assetBalances)
}
try {
val info = sdk.getInfo()
val assetBalances = info?.walletInfo?.assetBalances
} catch (e: Exception) {
// handle error
}
const info = await getInfo()
const assetBalances = info.walletInfo.assetBalances
GetInfoResponse? info = await breezSDKLiquid.instance!.getInfo();
List<AssetBalance> assetBalances = info.walletInfo.assetBalances;
try:
info = sdk.get_info()
asset_balances = info.wallet_info.asset_balances
except Exception as error:
logging.error(error)
raise
if info, err := sdk.GetInfo(); err == nil {
assetBalances := info.WalletInfo.AssetBalances
log.Printf("Asset balances: %#v", assetBalances)
}
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.
// 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);
// 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);
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
}
// 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`)
// 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");
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
// 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)
}
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.
// 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);
// 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);
// 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
}
// 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`)
// 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");
# 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
// 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)
// 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
}