Open warrenpuffett opened 2 days ago
Here's how I approached this problem:
I've made it so you have to select an asset before you can compose a message, where you're shown the balance as the sum of utxo and non-utxo amounts. And then it you click into the send experience, you're only shown what's non-utxo. And if you want to interact with the utxo you click into that. This works pretty well.
And then in my application, I have:
/**
* Fetches the balance of a specific token for a given address.
*
* @param address - The Bitcoin address to fetch the token balance for.
* @param asset - The asset (token) name to fetch the balance of.
* @param excludeUtxos - Whether to exclude balances associated with UTXOs (default is false).
* @returns A promise that resolves to a TokenBalance object or null if not found.
*/
export async function fetchTokenBalance(
address: string,
asset: string,
excludeUtxos: boolean = false
): Promise<TokenBalance | null> {
try {
const response = await axios.get(
`/v2/addresses/${address}/balances/${asset}?verbose=true`
);
const data = response.data;
if (!data.result) {
return null;
}
if (Array.isArray(data.result) && data.result.length === 0) {
// Return a zero balance if the asset is not held by the address.
return {
asset: asset,
quantity: 0,
quantity_normalized: '0',
asset_info: {
asset_longname: null,
description: '',
issuer: '',
divisible: true,
locked: false,
},
};
}
let balances = data.result;
if (excludeUtxos) {
// Filter out balances that have utxo information
balances = balances.filter((balance: TokenBalance) => !balance.utxo);
}
if (balances.length === 0) {
// After filtering, if no balances are left, return zero balance
return {
asset: asset,
quantity: 0,
quantity_normalized: '0',
asset_info: {
asset_longname: null,
description: '',
issuer: '',
divisible: true,
locked: false,
},
};
}
// Aggregate the quantities
const totalQuantity = balances.reduce(
(sum: number, entry: TokenBalance) => sum + (entry.quantity || 0),
0
);
const totalQuantityNormalized = balances
.reduce(
(sum: number, entry: TokenBalance) =>
sum + parseFloat(entry.quantity_normalized),
0
)
.toString();
const firstEntry = balances[0];
return {
asset: asset,
quantity: totalQuantity,
asset_info: firstEntry.asset_info,
quantity_normalized: totalQuantityNormalized,
};
} catch (error) {
console.error('Error fetching token balance:', error);
return null;
}
}
/**
* Fetches token balances that are locked in UTXOs for a given address and asset.
*
* @param address - The Bitcoin address to fetch UTXO balances for
* @param asset - The asset name to fetch UTXOs for
* @returns A promise that resolves to an array of TokenBalance objects with UTXO information
*/
export async function fetchTokenUtxos(
address: string,
asset: string
): Promise<TokenBalance[]> {
try {
const response = await axios.get(
`/v2/addresses/${address}/balances/${asset}?verbose=true`
);
const data = response.data;
if (!data.result || !Array.isArray(data.result)) {
return [];
}
// Filter to only include balances with UTXO information
return data.result.filter((balance: TokenBalance) => balance.utxo !== null);
} catch (error) {
console.error('Error fetching token UTXOs:', error);
return [];
}
}
(I'd name the route /addresses/<address>/balances?type=utxo
)
@ouziel-slama Currently the only way to do this is with
GET /addresses/balances?address={address}
. This gives back an inconvenient shape that incurs a compute performance penalty when filtering O(n*m). Additionally it is bandwidth inefficient as many of the assets will not be UTXO attached.Maybe an endpoint like
GET /addresses/{address}/utxo-assets
?