Skip to content

Commit 6209d90

Browse files
authored
Merge pull request #1396 from input-output-hk/blockfrost
Blockfrost
2 parents be0d98d + 8df1252 commit 6209d90

File tree

45 files changed

+3108
-405
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+3108
-405
lines changed

packages/cardano-services/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191
"wait-on": "^6.0.1"
9292
},
9393
"dependencies": {
94-
"@blockfrost/blockfrost-js": "5.5.0-beta.0",
94+
"@blockfrost/blockfrost-js": "^5.5.0",
9595
"@cardano-sdk/cardano-services-client": "workspace:~",
9696
"@cardano-sdk/core": "workspace:~",
9797
"@cardano-sdk/crypto": "workspace:~",
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* eslint-disable unicorn/no-nested-ternary */
2+
import { Asset, AssetProvider, Cardano, GetAssetArgs, GetAssetsArgs } from '@cardano-sdk/core';
3+
import { BlockFrostAPI, Responses } from '@blockfrost/blockfrost-js';
4+
import { BlockfrostProvider } from '../../util/BlockfrostProvider/BlockfrostProvider';
5+
import { blockfrostMetadataToTxMetadata, blockfrostToProviderError, fetchSequentially } from '../../util';
6+
import { replaceNullsWithUndefineds } from '@cardano-sdk/util';
7+
8+
export class BlockfrostAssetProvider extends BlockfrostProvider implements AssetProvider {
9+
protected async getLastMintedTx(assetId: Cardano.AssetId): Promise<Responses['asset_history'][number] | undefined> {
10+
const [lastMintedTx] = await fetchSequentially({
11+
arg: assetId.toString(),
12+
haveEnoughItems: (items: Responses['asset_history']): boolean => items.length > 0,
13+
paginationOptions: { order: 'desc' },
14+
request: this.blockfrost.assetsHistory.bind<BlockFrostAPI['assetsHistory']>(this.blockfrost),
15+
responseTranslator: (response): Responses['asset_history'] => response.filter((tx) => tx.action === 'minted')
16+
});
17+
18+
if (!lastMintedTx) return undefined;
19+
return lastMintedTx;
20+
}
21+
22+
protected async getNftMetadata(
23+
asset: Pick<Asset.AssetInfo, 'name' | 'policyId'>,
24+
lastMintedTxHash: string
25+
): Promise<Asset.NftMetadata | null> {
26+
const metadata = await this.blockfrost.txsMetadata(lastMintedTxHash);
27+
// Not sure if types are correct, missing 'label', but it's present in docs
28+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
29+
const metadatumMap = blockfrostMetadataToTxMetadata(metadata as any);
30+
return Asset.NftMetadata.fromMetadatum(asset, metadatumMap, console) ?? null;
31+
}
32+
33+
protected mapMetadata(
34+
assetId: Cardano.AssetId,
35+
offChain: Responses['asset']['metadata']
36+
): Asset.TokenMetadata | null {
37+
const { logo, ...metadata } = { ...offChain };
38+
39+
if (Object.values(metadata).every((value) => value === undefined || value === null)) return null;
40+
41+
return {
42+
...replaceNullsWithUndefineds(metadata),
43+
assetId,
44+
desc: metadata.description,
45+
// The other type option is any[] - not sure what it means, omitting if no string.
46+
icon: typeof logo === 'string' ? logo : undefined
47+
};
48+
}
49+
50+
async getAsset({ assetId, extraData }: GetAssetArgs) {
51+
try {
52+
const response = await this.blockfrost.assetsById(assetId.toString());
53+
const name = Cardano.AssetId.getAssetName(assetId);
54+
const policyId = Cardano.PolicyId(response.policy_id);
55+
const quantity = BigInt(response.quantity);
56+
57+
const nftMetadata = async () => {
58+
let lastMintedTxHash: string = response.initial_mint_tx_hash;
59+
if (response.mint_or_burn_count > 1) {
60+
const lastMintedTx = await this.getLastMintedTx(assetId);
61+
if (lastMintedTx) lastMintedTxHash = lastMintedTx.tx_hash;
62+
}
63+
return this.getNftMetadata({ name, policyId }, lastMintedTxHash);
64+
};
65+
66+
return {
67+
assetId,
68+
fingerprint: Cardano.AssetFingerprint(response.fingerprint),
69+
// history: extraData?.history ? await history() : undefined,
70+
mintOrBurnCount: response.mint_or_burn_count,
71+
name,
72+
nftMetadata: extraData?.nftMetadata ? await nftMetadata() : undefined,
73+
policyId,
74+
quantity,
75+
supply: quantity,
76+
tokenMetadata: extraData?.tokenMetadata ? this.mapMetadata(assetId, response.metadata) : undefined
77+
};
78+
} catch (error) {
79+
throw blockfrostToProviderError(error);
80+
}
81+
}
82+
async getAssets({ assetIds, extraData }: GetAssetsArgs) {
83+
return Promise.all(assetIds.map((assetId) => this.getAsset({ assetId, extraData })));
84+
}
85+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './BlockfrostAssetProvider';

packages/cardano-services/src/Asset/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './AssetHttpService';
2+
export * from './BlockfrostAssetProvider';
23
export * from './CardanoTokenRegistry';
34
export * from './StubTokenMetadataService';
45
export * from './DbSyncNftMetadataService';

0 commit comments

Comments
 (0)