Skip to content

Commit cde3d51

Browse files
committed
feat: browser compatible BlockfrostUtxoProvider
1 parent 2bf86df commit cde3d51

File tree

7 files changed

+102
-170
lines changed

7 files changed

+102
-170
lines changed
Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
import { BlockfrostProvider } from '../../util/BlockfrostProvider/BlockfrostProvider';
2-
import {
3-
BlockfrostToCore,
4-
blockfrostToProviderError,
5-
fetchByAddressSequentially
6-
} from '@cardano-sdk/cardano-services-client';
1+
import { BlockfrostProvider, BlockfrostToCore, fetchByAddressSequentially } from '../blockfrost';
72
import { Cardano, Serialization, UtxoByAddressesArgs, UtxoProvider } from '@cardano-sdk/core';
83
import { PaginationOptions } from '@blockfrost/blockfrost-js/lib/types';
94
import { Responses } from '@blockfrost/blockfrost-js';
10-
import { Schemas } from '@blockfrost/blockfrost-js/lib/types/open-api';
115

126
export class BlockfrostUtxoProvider extends BlockfrostProvider implements UtxoProvider {
13-
protected async fetchUtxos(addr: Cardano.PaymentAddress, pagination: PaginationOptions): Promise<Cardano.Utxo[]> {
14-
const utxos: Responses['address_utxo_content'] = (await this.blockfrost.addressesUtxos(
15-
addr.toString(),
16-
pagination
17-
)) as Responses['address_utxo_content'];
7+
protected async fetchUtxos(
8+
addr: Cardano.PaymentAddress,
9+
{ page, count, order }: PaginationOptions
10+
): Promise<Cardano.Utxo[]> {
11+
let queryString = `addresses/${addr.toString()}/utxo`;
12+
if (page) queryString += `?page=${page}`;
13+
if (count) queryString += `?count=${count}`;
14+
if (order) queryString += `?order=${order}`;
15+
const utxos = await this.request<Responses['address_utxo_content']>(queryString);
1816

1917
const utxoPromises = utxos.map((utxo) =>
2018
this.fetchDetailsFromCBOR(utxo.tx_hash).then((tx) => {
@@ -26,10 +24,9 @@ export class BlockfrostUtxoProvider extends BlockfrostProvider implements UtxoPr
2624
}
2725

2826
async fetchCBOR(hash: string): Promise<string> {
29-
return this.blockfrost
30-
.instance<Schemas['script_cbor']>(`txs/${hash}/cbor`)
27+
return this.request<Responses['tx_content_cbor']>(`txs/${hash}/cbor`)
3128
.then((response) => {
32-
if (response.body.cbor) return response.body.cbor;
29+
if (response.cbor) return response.cbor;
3330
throw new Error('CBOR is null');
3431
})
3532
.catch((_error) => {
@@ -54,13 +51,14 @@ export class BlockfrostUtxoProvider extends BlockfrostProvider implements UtxoPr
5451
addresses.map(async (address) =>
5552
fetchByAddressSequentially<Cardano.Utxo, Cardano.Utxo>({
5653
address,
57-
request: async (addr: Cardano.PaymentAddress, pagination) => await this.fetchUtxos(addr, pagination)
54+
request: async (addr: Cardano.PaymentAddress, pagination: PaginationOptions) =>
55+
await this.fetchUtxos(addr, pagination)
5856
})
5957
)
6058
);
6159
return utxoResults.flat(1);
6260
} catch (error) {
63-
throw blockfrostToProviderError(error);
61+
throw this.toProviderError(error);
6462
}
6563
}
6664
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export * from './BlockfrostUtxoProvider';
12
export * from './utxoHttpProvider';
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { BlockfrostClient, BlockfrostUtxoProvider } from '../../src';
2+
import { Cardano } from '@cardano-sdk/core';
3+
import { Responses } from '@blockfrost/blockfrost-js';
4+
import { logger } from '@cardano-sdk/util-dev';
5+
import { mockResponses } from '../AssetInfoProvider/util';
6+
jest.mock('@blockfrost/blockfrost-js');
7+
8+
const generateUtxoResponseMock = (qty: number) =>
9+
[...Array.from({ length: qty }).keys()].map((num) => ({
10+
amount: [
11+
{
12+
quantity: String(50_928_877 + num),
13+
unit: 'lovelace'
14+
},
15+
{
16+
quantity: num + 1,
17+
unit: 'b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'
18+
}
19+
],
20+
block: 'b1b23210b9de8f3edef233f21f7d6e1fb93efe124ba126ba924edec3043e75b46',
21+
output_index: num,
22+
tx_hash: '0f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5',
23+
tx_index: num
24+
})) as Responses['address_utxo_content'];
25+
26+
describe('blockfrostUtxoProvider', () => {
27+
let request: jest.Mock;
28+
let provider: BlockfrostUtxoProvider;
29+
let address: Cardano.PaymentAddress;
30+
31+
beforeEach(async () => {
32+
request = jest.fn();
33+
const client = { request } as unknown as BlockfrostClient;
34+
provider = new BlockfrostUtxoProvider(client, logger);
35+
address = Cardano.PaymentAddress(
36+
'addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3jcu5d8ps7zex2k2xt3uqxgjqnnj83ws8lhrn648jjxtwq2ytjqp'
37+
);
38+
});
39+
40+
describe('utxoByAddresses', () => {
41+
test('used addresses', async () => {
42+
mockResponses(request, [
43+
[`addresses/${address.toString()}/utxo?page=1?count=100`, generateUtxoResponseMock(100)],
44+
[`addresses/${address.toString()}/utxo?page=2?count=100`, generateUtxoResponseMock(100)],
45+
[`addresses/${address.toString()}/utxo?page=3?count=100`, generateUtxoResponseMock(0)]
46+
]);
47+
const response = await provider.utxoByAddresses({
48+
addresses: [address]
49+
});
50+
51+
expect(response).toBeTruthy();
52+
expect(response[0]).toHaveLength(2);
53+
expect(response[0][0]).toMatchObject<Cardano.TxIn>({
54+
index: 0,
55+
txId: Cardano.TransactionId('0f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5')
56+
});
57+
expect(response[0][1]).toMatchObject<Cardano.TxOut>({
58+
address,
59+
value: {
60+
assets: new Map([
61+
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 1n]
62+
]),
63+
coins: 50_928_877n
64+
}
65+
});
66+
67+
expect(response[1]).toHaveLength(2);
68+
expect(response[1][0]).toMatchObject<Cardano.TxIn>({
69+
index: 1,
70+
txId: Cardano.TransactionId('0f3abbc8fc19c2e61bab6059bf8a466e6e754833a08a62a6c56fe0e78f19d9d5')
71+
});
72+
expect(response[1][1]).toMatchObject<Cardano.TxOut>({
73+
address,
74+
value: {
75+
assets: new Map([
76+
[Cardano.AssetId('b01fb3b8c3dd6b3705a5dc8bcd5a70759f70ad5d97a72005caeac3c652657675746f31333237'), 2n]
77+
]),
78+
coins: 50_928_878n
79+
}
80+
});
81+
});
82+
});
83+
});

packages/cardano-services/src/Program/programs/providerServer.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import {
1818
BlockfrostAssetProvider,
1919
BlockfrostNetworkInfoProvider,
20+
BlockfrostUtxoProvider,
2021
CardanoWsClient,
2122
TxSubmitApiProvider
2223
} from '@cardano-sdk/cardano-services-client';
@@ -45,7 +46,6 @@ import {
4546
} from '../../ChainHistory';
4647
import { BlockfrostRewardsProvider, DbSyncRewardsProvider, RewardsHttpService } from '../../Rewards';
4748
import { BlockfrostTxSubmitProvider, NodeTxSubmitProvider, TxSubmitHttpService } from '../../TxSubmit';
48-
import { BlockfrostUtxoProvider, DbSyncUtxoProvider, UtxoHttpService } from '../../Utxo';
4949
import {
5050
CommonOptionsDescriptions,
5151
ConnectionNames,
@@ -63,6 +63,7 @@ import {
6363
TypeormStakePoolProvider,
6464
createHttpStakePoolMetadataService
6565
} from '../../StakePool';
66+
import { DbSyncUtxoProvider, UtxoHttpService } from '../../Utxo';
6667
import { DnsResolver, createDnsResolver, getCardanoNode, getDbPools, getGenesisData } from '../utils';
6768
import { GenesisData } from '../../types';
6869
import { HandleHttpService, TypeOrmHandleProvider } from '../../Handle';
@@ -298,7 +299,7 @@ const serviceMapFactory = (options: ServiceMapFactoryOptions) => {
298299

299300
const getBlockfrostAssetProvider = () => new BlockfrostAssetProvider(getBlockfrostClient(), logger);
300301

301-
const getBlockfrostUtxoProvider = () => new BlockfrostUtxoProvider({ blockfrost: getBlockfrostApi(), logger });
302+
const getBlockfrostUtxoProvider = () => new BlockfrostUtxoProvider(getBlockfrostClient(), logger);
302303

303304
const getDbSyncUtxoProvider = withDbSyncProvider(
304305
(dbPools, cardanoNode) =>

packages/cardano-services/src/Utxo/BlockfrostUtxoProvider/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
export * from './BlockfrostUtxoProvider';
21
export * from './UtxoHttpService';
32
export * from './DbSyncUtxoProvider';

packages/cardano-services/test/Utxo/BlockfrostUtxoProvider/BlockfrostUtxoProvider.test.ts

Lines changed: 0 additions & 149 deletions
This file was deleted.

0 commit comments

Comments
 (0)