Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions README-liquid.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Interface to access Liquid APIs.
- [Get Address Txs Chain](#get-address-txs-chain)
- [Get Address Txs Mempool](#get-address-txs-mempool)
- [Get Address Txs Utxo](#get-address-txs-utxo)
- [Get Address Asset Balances](#get-address-asset-balances)
- Assets
- [Get Asset](#get-asset)
- [Get Assets](#get-assets)
Expand Down Expand Up @@ -158,12 +159,37 @@ Get the list of unspent transaction outputs associated with the `address/scripth
[ [NodeJS Example](examples/nodejs/liquid/addresses.ts) ] [ [HTML Example](examples/html/liquid/addresses.html) ] [ [Top](#features) ]

```js
const { addresses } = mempoolJS();
const {
liquid: { addresses },
} = mempoolJS();

const addressTxsUtxo = await addresses.getAddressTxsUtxo('15e10745f15593a...');
const address = 'Go65t19hP2FuhBMYtgbdMDgdmEzNwh1i48';

const addressTxsUtxo = await addresses.getAddressTxsUtxo({ address });
console.log(addressTxsUtxo);
```

### **Get Address Asset Balances**

Returns Liquid asset balances for an address by grouping its unspent outputs by asset id.

**Parameters:**

- {string} address

[ [NodeJS Example](examples/nodejs/liquid/addresses.ts) ] [ [HTML Example](examples/html/liquid/addresses.html) ] [ [Top](#features) ]

```js
const {
liquid: { addresses },
} = mempoolJS();

const address = 'Go65t19hP2FuhBMYtgbdMDgdmEzNwh1i48';

const addressAssetBalances = await addresses.getAddressAssetBalances({ address });
console.log(addressAssetBalances);
```

### **Get Asset**

Returns information about a Liquid asset.
Expand Down
5 changes: 5 additions & 0 deletions examples/html/liquid/addresses.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@

const addressTxsUtxo = await addresses.getAddressTxsUtxo({ address });
console.log(addressTxsUtxo);

const addressAssetBalances = await addresses.getAddressAssetBalances({
address,
});
console.log(addressAssetBalances);
} catch (error) {
console.log(error);
}
Expand Down
5 changes: 5 additions & 0 deletions examples/nodejs/liquid/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ const init = async () => {

const addressTxsUtxo = await addresses.getAddressTxsUtxo({ address });
console.log(addressTxsUtxo);

const addressAssetBalances = await addresses.getAddressAssetBalances({
address,
});
console.log(addressAssetBalances);
} catch (error) {
console.log(error);
}
Expand Down
61 changes: 57 additions & 4 deletions src/app/liquid/addresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { AxiosInstance } from 'axios';
import {
Address,
AddressTxsUtxo,
AddressInstance,
} from '../../interfaces/bitcoin/addresses';
import { Tx } from '../../interfaces/bitcoin/transactions';
AddressLiquidInstance,
AddressAssetBalance,
} from '../../interfaces/liquid/addresses';
import { Tx } from '../../interfaces/liquid/transactions';

export const useAddresses = (api: AxiosInstance): AddressInstance => {
export const useAddresses = (api: AxiosInstance): AddressLiquidInstance => {
const getAddress = async (params: { address: string }) => {
const { data } = await api.get<Address>(`/address/${params.address}`);
return data;
Expand Down Expand Up @@ -42,11 +43,63 @@ export const useAddresses = (api: AxiosInstance): AddressInstance => {
return data;
};

const getAddressAssetBalances = async (params: { address: string }) => {
const utxos = await getAddressTxsUtxo(params);

if (utxos.length === 0) {
return [];
}

const uniqueTxids = utxos.reduce((txids, { txid }) => {
if (txids.indexOf(txid) === -1) {
txids.push(txid);
}
return txids;
}, [] as string[]);

const transactions = await Promise.all(
uniqueTxids.map(async (txid) => {
const { data } = await api.get<Tx>(`/tx/${txid}`);
return [txid, data] as const;
})
);

const transactionMap = new Map<string, Tx>(transactions);
const balances = new Map<string, AddressAssetBalance>();

utxos.forEach((utxo) => {
const tx = transactionMap.get(utxo.txid);
const txOutput = tx?.vout[utxo.vout];
const asset_id = utxo.asset || txOutput?.asset;

if (!asset_id) {
throw new Error(`Asset id not found for Liquid UTXO ${utxo.txid}:${utxo.vout}`);
}

const currentBalance = balances.get(asset_id);

if (currentBalance) {
currentBalance.value += utxo.value;
currentBalance.utxo_count += 1;
return;
}

balances.set(asset_id, {
asset_id,
value: utxo.value,
utxo_count: 1,
});
});

return Array.from(balances.values()).sort((a, b) => b.value - a.value);
};

return {
getAddress,
getAddressTxs,
getAddressTxsChain,
getAddressTxsMempool,
getAddressTxsUtxo,
getAddressAssetBalances,
};
};
3 changes: 2 additions & 1 deletion src/interfaces/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { TxInstance } from './bitcoin/transactions';
import { WsInstance } from './bitcoin/websockets';

import { AssetsInstance } from './liquid/assets';
import { AddressLiquidInstance } from './liquid/addresses';
import { BlockLiquidInstance } from './liquid/blocks';
import { TxLiquidInstance } from './liquid/transactions';
import { WsLiquidInstance } from './liquid/websockets';
Expand All @@ -32,7 +33,7 @@ export interface MempoolReturn {
};
liquid: {
assets: AssetsInstance;
addresses: AddressInstance;
addresses: AddressLiquidInstance;
blocks: BlockLiquidInstance;
fees: FeeInstance;
mempool: MempoolInstance;
Expand Down
38 changes: 38 additions & 0 deletions src/interfaces/liquid/addresses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { Tx, TxStatus } from './transactions';

export interface Address {
address: string;
chain_stats: StatsInfo;
mempool_stats: StatsInfo;
}

export interface StatsInfo {
funded_txo_count: number;
funded_txo_sum: number;
spent_txo_count: number;
spent_txo_sum: number;
tx_count: number;
}

export interface AddressTxsUtxo {
txid: string;
vout: number;
status: TxStatus;
value: number;
asset?: string;
}

export interface AddressAssetBalance {
asset_id: string;
value: number;
utxo_count: number;
}

export interface AddressLiquidInstance {
getAddress: (params: { address: string }) => Promise<Address>;
getAddressTxs: (params: { address: string, after_txid?: string }) => Promise<Tx[]>;
getAddressTxsChain: (params: { address: string }) => Promise<Tx[]>;
getAddressTxsMempool: (params: { address: string }) => Promise<Tx[]>;
getAddressTxsUtxo: (params: { address: string }) => Promise<AddressTxsUtxo[]>;
getAddressAssetBalances: (params: { address: string }) => Promise<AddressAssetBalance[]>;
}
1 change: 1 addition & 0 deletions src/interfaces/liquid/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export interface Vout {
scriptpubkey_asm: string;
scriptpubkey_type: string;
scriptpubkey_address: string;
asset: string;
value: number;
}

Expand Down
Loading