@koralabs/kora-labs-common 6.10.0 → 6.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chain/config.d.ts +9 -0
- package/chain/config.js +40 -0
- package/chain/datum/imageDatum.d.ts +14 -0
- package/chain/datum/imageDatum.js +87 -0
- package/chain/index.d.ts +5 -0
- package/chain/index.js +7 -3
- package/chain/providerConfig.d.ts +22 -0
- package/chain/providerConfig.js +13 -0
- package/chain/providers/Blockfrost.d.ts +59 -0
- package/chain/providers/Blockfrost.js +142 -0
- package/chain/providers/Koios.d.ts +68 -0
- package/chain/providers/Koios.js +214 -0
- package/package.json +1 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ChainProvider } from './failover/interfaces';
|
|
2
|
+
import { ChainProviderConfig } from './providerConfig';
|
|
3
|
+
export * from './providerConfig';
|
|
4
|
+
/** Read a ChainProviderConfig from the standard environment variables. */
|
|
5
|
+
export declare const chainConfigFromEnv: (env?: NodeJS.ProcessEnv) => ChainProviderConfig;
|
|
6
|
+
/**
|
|
7
|
+
* Factory for the default read-failover provider set: Koios + Blockfrost, mutually redundant.
|
|
8
|
+
*/
|
|
9
|
+
export declare const buildChainProviders: (config: ChainProviderConfig) => ChainProvider[];
|
package/chain/config.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.buildChainProviders = exports.chainConfigFromEnv = void 0;
|
|
18
|
+
const providerConfig_1 = require("./providerConfig");
|
|
19
|
+
const Koios_1 = require("./providers/Koios");
|
|
20
|
+
const Blockfrost_1 = require("./providers/Blockfrost");
|
|
21
|
+
__exportStar(require("./providerConfig"), exports);
|
|
22
|
+
/** Read a ChainProviderConfig from the standard environment variables. */
|
|
23
|
+
const chainConfigFromEnv = (env = process.env) => {
|
|
24
|
+
var _a, _b, _c, _d;
|
|
25
|
+
return ({
|
|
26
|
+
network: (0, providerConfig_1.normalizeNetwork)((_a = env.NETWORK) !== null && _a !== void 0 ? _a : 'mainnet'),
|
|
27
|
+
koiosBearerToken: ((_b = env.KOIOS_API_BEARER_TOKEN) === null || _b === void 0 ? void 0 : _b.trim()) || undefined,
|
|
28
|
+
blockfrostApiKey: ((_c = env.BLOCKFROST_API_KEY) === null || _c === void 0 ? void 0 : _c.trim()) || undefined,
|
|
29
|
+
apiHost: ((_d = env.HANDLE_API_ENDPOINT) === null || _d === void 0 ? void 0 : _d.trim()) || undefined
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
exports.chainConfigFromEnv = chainConfigFromEnv;
|
|
33
|
+
/**
|
|
34
|
+
* Factory for the default read-failover provider set: Koios + Blockfrost, mutually redundant.
|
|
35
|
+
*/
|
|
36
|
+
const buildChainProviders = (config) => [
|
|
37
|
+
new Koios_1.Koios(config),
|
|
38
|
+
new Blockfrost_1.Blockfrost(config)
|
|
39
|
+
];
|
|
40
|
+
exports.buildChainProviders = buildChainProviders;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ICreatorDefaults } from '../../handles/interfaces';
|
|
2
|
+
export declare const decodeDatumViaApi: <T>(apiHost: string, datum: string, schema?: Record<string, unknown>, fetcher?: (url: string, init?: any) => Promise<{
|
|
3
|
+
text: () => Promise<string>;
|
|
4
|
+
}>) => Promise<T>;
|
|
5
|
+
export declare const decode0xHexToUtf8: (v: unknown) => unknown;
|
|
6
|
+
export declare const normalizeCreatorDefaultTextFields: (creatorDefaults: Record<string, unknown>) => void;
|
|
7
|
+
export interface ImageDatumDetails {
|
|
8
|
+
image: string;
|
|
9
|
+
creatorDefaults?: ICreatorDefaults;
|
|
10
|
+
metadata?: Record<string, unknown>;
|
|
11
|
+
}
|
|
12
|
+
export declare const getImageDataFromDatum: (apiHost: string, datum: string, fetcher?: (url: string, init?: any) => Promise<{
|
|
13
|
+
text: () => Promise<string>;
|
|
14
|
+
}>) => Promise<ImageDatumDetails>;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getImageDataFromDatum = exports.normalizeCreatorDefaultTextFields = exports.decode0xHexToUtf8 = exports.decodeDatumViaApi = void 0;
|
|
4
|
+
// Schema-guided datum decoding for background/CIP-68 image details. Ported verbatim (behavior-
|
|
5
|
+
// preserving) from the handle.me BFF: it POSTs the datum CBOR to the Handles API `/datum` decoder
|
|
6
|
+
// with a field schema so specific TEXT fields are UTF-8-decoded. This is handle-property-correctness
|
|
7
|
+
// critical — the schema and the 0x-hex fallback below must not drift.
|
|
8
|
+
const defaultFetch = (url, init) => globalThis.fetch(url, init);
|
|
9
|
+
const decodeDatumViaApi = async (apiHost, datum, schema, fetcher = defaultFetch) => {
|
|
10
|
+
const response = await fetcher(`${apiHost}/datum?from=plutus_data_cbor&to=json`, {
|
|
11
|
+
method: 'POST',
|
|
12
|
+
headers: { 'Content-Type': 'application/json' },
|
|
13
|
+
body: JSON.stringify({ cbor: datum, schema })
|
|
14
|
+
});
|
|
15
|
+
const text = await response.text();
|
|
16
|
+
if (!text.trim()) {
|
|
17
|
+
// Empty response — return empty object instead of crashing.
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
return JSON.parse(text);
|
|
21
|
+
};
|
|
22
|
+
exports.decodeDatumViaApi = decodeDatumViaApi;
|
|
23
|
+
// The api /datum decoder only UTF-8-decodes fields the schema can path to. When a background's
|
|
24
|
+
// CIP-68 `extra` is Constr-wrapped (Constr(0,[map]) at [2]), the schema's `[2]` fields don't match
|
|
25
|
+
// and these TEXT fields come back as `0x<hex>`. Colours/arrays are legitimately hex and left alone;
|
|
26
|
+
// only the known free-text fields are normalized back to UTF-8. A value already decoded (no 0x
|
|
27
|
+
// prefix) passes through unchanged.
|
|
28
|
+
const CREATOR_DEFAULT_TEXT_FIELDS = [
|
|
29
|
+
'font',
|
|
30
|
+
'qr_dot',
|
|
31
|
+
'qr_inner_eye',
|
|
32
|
+
'qr_outer_eye',
|
|
33
|
+
'text_ribbon_gradient',
|
|
34
|
+
'qr_image'
|
|
35
|
+
];
|
|
36
|
+
const decode0xHexToUtf8 = (v) => {
|
|
37
|
+
if (typeof v === 'string' && /^0x[0-9a-fA-F]*$/.test(v) && v.length > 2) {
|
|
38
|
+
try {
|
|
39
|
+
return Buffer.from(v.slice(2), 'hex').toString('utf8');
|
|
40
|
+
}
|
|
41
|
+
catch (_a) {
|
|
42
|
+
return v;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return v;
|
|
46
|
+
};
|
|
47
|
+
exports.decode0xHexToUtf8 = decode0xHexToUtf8;
|
|
48
|
+
const normalizeCreatorDefaultTextFields = (creatorDefaults) => {
|
|
49
|
+
for (const field of CREATOR_DEFAULT_TEXT_FIELDS) {
|
|
50
|
+
if (field in creatorDefaults) {
|
|
51
|
+
creatorDefaults[field] = (0, exports.decode0xHexToUtf8)(creatorDefaults[field]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
exports.normalizeCreatorDefaultTextFields = normalizeCreatorDefaultTextFields;
|
|
56
|
+
const getImageDataFromDatum = async (apiHost, datum, fetcher) => {
|
|
57
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
58
|
+
let decodedDatum;
|
|
59
|
+
try {
|
|
60
|
+
decodedDatum = await (0, exports.decodeDatumViaApi)(apiHost, datum, {
|
|
61
|
+
constructor_0: {
|
|
62
|
+
'[0]': { name: 'string', image: 'string', category: 'string' },
|
|
63
|
+
'[2]': {
|
|
64
|
+
font: 'string',
|
|
65
|
+
text_ribbon_gradient: 'string',
|
|
66
|
+
force_creator_settings: 'bool',
|
|
67
|
+
qr_inner_eye: 'string',
|
|
68
|
+
qr_outer_eye: 'string',
|
|
69
|
+
qr_dot: 'string',
|
|
70
|
+
qr_image: 'string'
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}, fetcher);
|
|
74
|
+
}
|
|
75
|
+
catch (_j) {
|
|
76
|
+
return { image: '' };
|
|
77
|
+
}
|
|
78
|
+
const image = (_b = (_a = decodedDatum === null || decodedDatum === void 0 ? void 0 : decodedDatum.constructor_0) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.image;
|
|
79
|
+
let data = { image };
|
|
80
|
+
const creatorDefaults = (_f = (_e = (_d = (_c = decodedDatum === null || decodedDatum === void 0 ? void 0 : decodedDatum.constructor_0) === null || _c === void 0 ? void 0 : _c[2]) === null || _d === void 0 ? void 0 : _d.constructor_0) === null || _e === void 0 ? void 0 : _e[0]) !== null && _f !== void 0 ? _f : (_g = decodedDatum.constructor_0) === null || _g === void 0 ? void 0 : _g[2];
|
|
81
|
+
if (creatorDefaults) {
|
|
82
|
+
(0, exports.normalizeCreatorDefaultTextFields)(creatorDefaults);
|
|
83
|
+
data = { image, creatorDefaults, metadata: (_h = decodedDatum === null || decodedDatum === void 0 ? void 0 : decodedDatum.constructor_0) === null || _h === void 0 ? void 0 : _h[0] };
|
|
84
|
+
}
|
|
85
|
+
return data;
|
|
86
|
+
};
|
|
87
|
+
exports.getImageDataFromDatum = getImageDataFromDatum;
|
package/chain/index.d.ts
CHANGED
|
@@ -2,3 +2,8 @@ export * from './transport/fetchProviderJson';
|
|
|
2
2
|
export * from './failover/interfaces';
|
|
3
3
|
export * from './failover/ChainProviderFailover';
|
|
4
4
|
export * from './cache/ShortTermCache';
|
|
5
|
+
export * from './providerConfig';
|
|
6
|
+
export * from './config';
|
|
7
|
+
export * from './datum/imageDatum';
|
|
8
|
+
export * from './providers/Koios';
|
|
9
|
+
export * from './providers/Blockfrost';
|
package/chain/index.js
CHANGED
|
@@ -15,10 +15,14 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
// Subpath-only module: `@koralabs/kora-labs-common/chain`.
|
|
18
|
-
// NOT re-exported from the root index — this is a server-side chain-access layer and
|
|
19
|
-
//
|
|
20
|
-
// (same rule the `aws` module follows).
|
|
18
|
+
// NOT re-exported from the root index — this is a server-side chain-access layer and pulls Node-only
|
|
19
|
+
// deps. Keeping it off the root barrel preserves the isomorphic root (same rule the `aws` module follows).
|
|
21
20
|
__exportStar(require("./transport/fetchProviderJson"), exports);
|
|
22
21
|
__exportStar(require("./failover/interfaces"), exports);
|
|
23
22
|
__exportStar(require("./failover/ChainProviderFailover"), exports);
|
|
24
23
|
__exportStar(require("./cache/ShortTermCache"), exports);
|
|
24
|
+
__exportStar(require("./providerConfig"), exports);
|
|
25
|
+
__exportStar(require("./config"), exports);
|
|
26
|
+
__exportStar(require("./datum/imageDatum"), exports);
|
|
27
|
+
__exportStar(require("./providers/Koios"), exports);
|
|
28
|
+
__exportStar(require("./providers/Blockfrost"), exports);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration for the concrete chain providers. Injected explicitly (no reading of app-level
|
|
3
|
+
* constants) so every consumer wires its own env once and the module stays app-agnostic.
|
|
4
|
+
*/
|
|
5
|
+
export interface ChainProviderConfig {
|
|
6
|
+
/** 'mainnet' | 'preview' | 'preprod' — selects Koios/Blockfrost hosts. */
|
|
7
|
+
network: string;
|
|
8
|
+
/** Koios bearer token (optional; anonymous tier works without it). */
|
|
9
|
+
koiosBearerToken?: string;
|
|
10
|
+
/** Blockfrost project id for the target network. */
|
|
11
|
+
blockfrostApiKey?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Base URL of the Handles API used for schema-guided datum decoding (POST /datum). Defaults to
|
|
14
|
+
* the public api.handle.me host for the network. Preserves the exact datum-decode behavior the
|
|
15
|
+
* BFF relied on (schema-pathed UTF-8 field decoding), which is handle-property-correctness
|
|
16
|
+
* critical — do NOT swap it for a local CBOR decode without matching that behavior.
|
|
17
|
+
*/
|
|
18
|
+
apiHost?: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const normalizeNetwork: (network: string) => string;
|
|
21
|
+
/** Public api.handle.me host for a network (mainnet has no subdomain prefix). */
|
|
22
|
+
export declare const defaultApiHost: (network: string) => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Leaf config module (no imports from providers) so the concrete providers and the factory can both
|
|
3
|
+
// depend on it without a cycle.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.defaultApiHost = exports.normalizeNetwork = void 0;
|
|
6
|
+
const normalizeNetwork = (network) => (network || 'mainnet').toLowerCase();
|
|
7
|
+
exports.normalizeNetwork = normalizeNetwork;
|
|
8
|
+
/** Public api.handle.me host for a network (mainnet has no subdomain prefix). */
|
|
9
|
+
const defaultApiHost = (network) => {
|
|
10
|
+
const net = (0, exports.normalizeNetwork)(network);
|
|
11
|
+
return net === 'mainnet' ? 'https://api.handle.me' : `https://${net}.api.handle.me`;
|
|
12
|
+
};
|
|
13
|
+
exports.defaultApiHost = defaultApiHost;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ICreatorDefaults } from '../../handles/interfaces';
|
|
2
|
+
import { AccountAsset, AddressInfo, ChainProvider, ChainProviderAsset, ChainProviderUtxo } from '../failover/interfaces';
|
|
3
|
+
import { ChainProviderConfig } from '../providerConfig';
|
|
4
|
+
export interface DrepMetadataValue {
|
|
5
|
+
'@value': string;
|
|
6
|
+
}
|
|
7
|
+
export interface DrepReference {
|
|
8
|
+
'@type': string;
|
|
9
|
+
label: string | DrepMetadataValue;
|
|
10
|
+
uri: string | DrepMetadataValue;
|
|
11
|
+
}
|
|
12
|
+
interface DrepMetadata {
|
|
13
|
+
drep_id: string;
|
|
14
|
+
json_metadata: {
|
|
15
|
+
body: {
|
|
16
|
+
paymentAddress: string | DrepMetadataValue;
|
|
17
|
+
givenName: string | DrepMetadataValue;
|
|
18
|
+
image: {
|
|
19
|
+
contentUrl: string | DrepMetadataValue;
|
|
20
|
+
};
|
|
21
|
+
objectives: string | DrepMetadataValue;
|
|
22
|
+
motivations: string | DrepMetadataValue;
|
|
23
|
+
qualifications: string | DrepMetadataValue;
|
|
24
|
+
references: DrepReference[];
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export declare class Blockfrost implements ChainProvider {
|
|
29
|
+
private readonly config;
|
|
30
|
+
name: string;
|
|
31
|
+
constructor(config: ChainProviderConfig);
|
|
32
|
+
private fetchBlockfrost;
|
|
33
|
+
getDrepMetadata(drepId: string): Promise<DrepMetadata>;
|
|
34
|
+
getLatestBlock(): Promise<{
|
|
35
|
+
height: number;
|
|
36
|
+
slot: number;
|
|
37
|
+
time: number;
|
|
38
|
+
}>;
|
|
39
|
+
getLatestTransactionForAsset(policyId: string, hex: string): Promise<string | null>;
|
|
40
|
+
getAssets(policyId: string): Promise<{
|
|
41
|
+
policyId: string;
|
|
42
|
+
hex: string;
|
|
43
|
+
}[]>;
|
|
44
|
+
getAssetUtxo(policyId: string, hex: string): Promise<ChainProviderAsset | null>;
|
|
45
|
+
getDatumFromHash(datumHash: string): Promise<string | null>;
|
|
46
|
+
getAssetDatum(policyId: string, hex: string): Promise<string | null>;
|
|
47
|
+
getCip25AssetImage(policyId: string, hex: string): Promise<string | null>;
|
|
48
|
+
getRefScriptCbor(tx: string, policyId: string, hex: string): Promise<string>;
|
|
49
|
+
getTxUtxos(tx: string): Promise<ChainProviderUtxo>;
|
|
50
|
+
getAssetsByStakeKey(stakeKey: string): Promise<AccountAsset[]>;
|
|
51
|
+
getBackgroundImageDetails(policyId: string, hex: string): Promise<{
|
|
52
|
+
image: string;
|
|
53
|
+
creatorDefaults?: ICreatorDefaults;
|
|
54
|
+
metadata?: Record<string, unknown>;
|
|
55
|
+
}>;
|
|
56
|
+
getAddressInfo(bech32Address: string): Promise<AddressInfo>;
|
|
57
|
+
getAddressUTxOs(bech32Address: string): Promise<ChainProviderAsset[]>;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Blockfrost = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const fetchProviderJson_1 = require("../transport/fetchProviderJson");
|
|
6
|
+
const imageDatum_1 = require("../datum/imageDatum");
|
|
7
|
+
const providerConfig_1 = require("../providerConfig");
|
|
8
|
+
class Blockfrost {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.name = 'Blockfrost';
|
|
12
|
+
}
|
|
13
|
+
async fetchBlockfrost(path) {
|
|
14
|
+
var _a;
|
|
15
|
+
const normalizedPath = path.startsWith('/') ? path.slice(1) : path;
|
|
16
|
+
const url = `https://cardano-${this.config.network.toLowerCase()}.blockfrost.io/api/v0/${normalizedPath}`;
|
|
17
|
+
return (0, fetchProviderJson_1.fetchProviderJson)({
|
|
18
|
+
provider: 'Blockfrost',
|
|
19
|
+
url,
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json',
|
|
22
|
+
project_id: (_a = this.config.blockfrostApiKey) !== null && _a !== void 0 ? _a : ''
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
async getDrepMetadata(drepId) {
|
|
27
|
+
return await this.fetchBlockfrost(`/governance/dreps/${drepId}/metadata`);
|
|
28
|
+
}
|
|
29
|
+
async getLatestBlock() {
|
|
30
|
+
return await this.fetchBlockfrost('blocks/latest');
|
|
31
|
+
}
|
|
32
|
+
async getLatestTransactionForAsset(policyId, hex) {
|
|
33
|
+
var _a;
|
|
34
|
+
const res = await this.fetchBlockfrost(`/assets/${policyId}${hex}/transactions?order=desc`);
|
|
35
|
+
const [tx] = res;
|
|
36
|
+
return (_a = tx === null || tx === void 0 ? void 0 : tx.tx_hash) !== null && _a !== void 0 ? _a : null;
|
|
37
|
+
}
|
|
38
|
+
async getAssets(policyId) {
|
|
39
|
+
var _a;
|
|
40
|
+
const res = await this.fetchBlockfrost(`/assets/policy/${policyId}`);
|
|
41
|
+
if (!Array.isArray(res))
|
|
42
|
+
return [];
|
|
43
|
+
return ((_a = res === null || res === void 0 ? void 0 : res.reduce((agg, item) => {
|
|
44
|
+
const { asset, quantity } = item;
|
|
45
|
+
const [, hex] = asset.split(policyId);
|
|
46
|
+
if (hex.includes(types_1.AssetNameLabel.LBL_100) || quantity === '0')
|
|
47
|
+
return agg;
|
|
48
|
+
agg.push({ policyId, hex });
|
|
49
|
+
return agg;
|
|
50
|
+
}, [])) !== null && _a !== void 0 ? _a : []);
|
|
51
|
+
}
|
|
52
|
+
async getAssetUtxo(policyId, hex) {
|
|
53
|
+
var _a;
|
|
54
|
+
// A BURN that only spends the asset is NOT listed by /assets/{asset}/transactions, so
|
|
55
|
+
// getLatestTransactionForAsset returns the pre-burn output tx and the asset is still in its
|
|
56
|
+
// (now-spent) outputs — we'd resurrect a de-indexed handle. /assets DOES reflect the burn
|
|
57
|
+
// (quantity 0), so gate on current supply first: a burned (or absent) asset resolves to null.
|
|
58
|
+
const info = await this.fetchBlockfrost(`/assets/${policyId}${hex}`);
|
|
59
|
+
if (!info || info.status_code === 404 || String(info.quantity) === '0')
|
|
60
|
+
return null;
|
|
61
|
+
const tx = await this.getLatestTransactionForAsset(policyId, hex);
|
|
62
|
+
if (!tx)
|
|
63
|
+
return null;
|
|
64
|
+
const res = await this.fetchBlockfrost(`/txs/${tx}/utxos`);
|
|
65
|
+
const asset = (_a = res === null || res === void 0 ? void 0 : res.outputs) === null || _a === void 0 ? void 0 : _a.find((output) => output.amount.some((a) => a.unit === `${policyId}${hex}`));
|
|
66
|
+
// Defensive: if the latest tx lists the asset only in inputs, return null.
|
|
67
|
+
if (!asset)
|
|
68
|
+
return null;
|
|
69
|
+
return { ...asset, tx_hash: tx };
|
|
70
|
+
}
|
|
71
|
+
async getDatumFromHash(datumHash) {
|
|
72
|
+
const result = await this.fetchBlockfrost(`/scripts/datum/${datumHash}/cbor`);
|
|
73
|
+
if (result.status)
|
|
74
|
+
return null;
|
|
75
|
+
return result.cbor;
|
|
76
|
+
}
|
|
77
|
+
async getAssetDatum(policyId, hex) {
|
|
78
|
+
var _a;
|
|
79
|
+
const asset = await this.getAssetUtxo(policyId, hex);
|
|
80
|
+
return (_a = asset === null || asset === void 0 ? void 0 : asset.inline_datum) !== null && _a !== void 0 ? _a : null;
|
|
81
|
+
}
|
|
82
|
+
async getCip25AssetImage(policyId, hex) {
|
|
83
|
+
var _a, _b;
|
|
84
|
+
const res = await this.fetchBlockfrost(`/assets/${policyId}${hex}`);
|
|
85
|
+
let image = (_b = (_a = res === null || res === void 0 ? void 0 : res.onchain_metadata) === null || _a === void 0 ? void 0 : _a.image) !== null && _b !== void 0 ? _b : null;
|
|
86
|
+
if (Array.isArray(image))
|
|
87
|
+
image = image.join('');
|
|
88
|
+
return image;
|
|
89
|
+
}
|
|
90
|
+
async getRefScriptCbor(tx, policyId, hex) {
|
|
91
|
+
const res = await this.fetchBlockfrost(`/txs/${tx}/utxos`);
|
|
92
|
+
const output = res.outputs.find((o) => o.amount.some((a) => a.unit === `${policyId}${hex}`));
|
|
93
|
+
const scriptHash = output === null || output === void 0 ? void 0 : output.reference_script_hash;
|
|
94
|
+
const { cbor } = await this.fetchBlockfrost(`/scripts/${scriptHash}/cbor`);
|
|
95
|
+
return cbor;
|
|
96
|
+
}
|
|
97
|
+
async getTxUtxos(tx) {
|
|
98
|
+
return await this.fetchBlockfrost(`/txs/${tx}/utxos`);
|
|
99
|
+
}
|
|
100
|
+
async getAssetsByStakeKey(stakeKey) {
|
|
101
|
+
const result = [];
|
|
102
|
+
let hasResults = true;
|
|
103
|
+
let page = 1;
|
|
104
|
+
while (hasResults) {
|
|
105
|
+
const items = await this.fetchBlockfrost(`/accounts/${stakeKey}/addresses/assets?count=100&page=${page}`);
|
|
106
|
+
if (items.length === 0)
|
|
107
|
+
hasResults = false;
|
|
108
|
+
result.push(...items.map((item) => ({ asset: item.unit, amount: item.quantity })));
|
|
109
|
+
page++;
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
async getBackgroundImageDetails(policyId, hex) {
|
|
114
|
+
var _a;
|
|
115
|
+
const data = await this.fetchBlockfrost(`/assets/${policyId}${hex}`);
|
|
116
|
+
const updateHex = hex.startsWith(types_1.AssetNameLabel.LBL_222) || hex.startsWith(types_1.AssetNameLabel.LBL_444)
|
|
117
|
+
? `${types_1.AssetNameLabel.LBL_100}${hex.replace(types_1.AssetNameLabel.LBL_222, '').replace(types_1.AssetNameLabel.LBL_444, '')}`
|
|
118
|
+
: hex;
|
|
119
|
+
const datum = await this.getAssetDatum(policyId, updateHex);
|
|
120
|
+
if (datum) {
|
|
121
|
+
return (0, imageDatum_1.getImageDataFromDatum)((_a = this.config.apiHost) !== null && _a !== void 0 ? _a : (0, providerConfig_1.defaultApiHost)(this.config.network), datum);
|
|
122
|
+
}
|
|
123
|
+
let image = '';
|
|
124
|
+
if ((data === null || data === void 0 ? void 0 : data.onchain_metadata) && (data === null || data === void 0 ? void 0 : data.onchain_metadata.image)) {
|
|
125
|
+
image = data === null || data === void 0 ? void 0 : data.onchain_metadata.image;
|
|
126
|
+
}
|
|
127
|
+
return { image, metadata: data === null || data === void 0 ? void 0 : data.onchain_metadata };
|
|
128
|
+
}
|
|
129
|
+
async getAddressInfo(bech32Address) {
|
|
130
|
+
const result = await this.fetchBlockfrost(`/addresses/${bech32Address}`);
|
|
131
|
+
return {
|
|
132
|
+
address: result.address,
|
|
133
|
+
amount: result.amount,
|
|
134
|
+
stake_address: result.stake_address,
|
|
135
|
+
script: result.script
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async getAddressUTxOs(bech32Address) {
|
|
139
|
+
return await this.fetchBlockfrost(`/addresses/${bech32Address}/utxos`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.Blockfrost = Blockfrost;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ICreatorDefaults } from '../../handles/interfaces';
|
|
2
|
+
import { AccountAsset, AddressInfo, ChainProvider, ChainProviderAsset, ChainProviderUtxo } from '../failover/interfaces';
|
|
3
|
+
import { ChainProviderConfig } from '../providerConfig';
|
|
4
|
+
interface KoiosAsset {
|
|
5
|
+
quantity: string;
|
|
6
|
+
policy_id: string;
|
|
7
|
+
asset_name: string;
|
|
8
|
+
}
|
|
9
|
+
interface KoiosTxOutput {
|
|
10
|
+
value: string;
|
|
11
|
+
tx_hash: string;
|
|
12
|
+
tx_index: number;
|
|
13
|
+
asset_list: KoiosAsset[];
|
|
14
|
+
datum_hash: string | null;
|
|
15
|
+
stake_addr: string;
|
|
16
|
+
inline_datum: {
|
|
17
|
+
bytes: string | null;
|
|
18
|
+
value: string | null;
|
|
19
|
+
} | null;
|
|
20
|
+
payment_addr: {
|
|
21
|
+
bech32: string;
|
|
22
|
+
};
|
|
23
|
+
reference_script: {
|
|
24
|
+
bytes: string | null;
|
|
25
|
+
hash: string | null;
|
|
26
|
+
} | null;
|
|
27
|
+
}
|
|
28
|
+
export declare const buildKoiosHeaders: (bearerToken: string | undefined) => {
|
|
29
|
+
Authorization?: string | undefined;
|
|
30
|
+
'Content-Type': string;
|
|
31
|
+
};
|
|
32
|
+
export declare const buildKoiosAddressUtxoRequestBody: (bech32Address: string) => {
|
|
33
|
+
_addresses: string[];
|
|
34
|
+
_extended: boolean;
|
|
35
|
+
};
|
|
36
|
+
export declare class Koios implements ChainProvider {
|
|
37
|
+
private readonly config;
|
|
38
|
+
name: string;
|
|
39
|
+
constructor(config: ChainProviderConfig);
|
|
40
|
+
private fetchKoios;
|
|
41
|
+
getLatestBlock(): Promise<{
|
|
42
|
+
height: number;
|
|
43
|
+
slot: number;
|
|
44
|
+
time: number;
|
|
45
|
+
}>;
|
|
46
|
+
getLatestTransactionForAsset(policyId: string, hex: string): Promise<string | null>;
|
|
47
|
+
getAssets(policyId: string): Promise<{
|
|
48
|
+
policyId: string;
|
|
49
|
+
hex: string;
|
|
50
|
+
}[]>;
|
|
51
|
+
getAssetUtxo(policyId: string, hex: string): Promise<ChainProviderAsset | null>;
|
|
52
|
+
getDatumFromHash(datumHash: string): Promise<string | null>;
|
|
53
|
+
getAssetDatum(policyId: string, hex: string): Promise<string | null>;
|
|
54
|
+
getRefScriptCbor(tx: string, policyId: string, hex: string): Promise<string>;
|
|
55
|
+
buildChainProviderAsset(output: KoiosTxOutput): Promise<ChainProviderAsset>;
|
|
56
|
+
getTxUtxos(tx: string): Promise<ChainProviderUtxo>;
|
|
57
|
+
getAssetsByStakeKey(stakeKey: string): Promise<AccountAsset[]>;
|
|
58
|
+
getAssetMetadata(policyId: string, hex: string): Promise<Record<string, unknown> | undefined>;
|
|
59
|
+
getCip25AssetImage(policyId: string, hex: string): Promise<string | null>;
|
|
60
|
+
getBackgroundImageDetails(policyId: string, hex: string): Promise<{
|
|
61
|
+
image: string;
|
|
62
|
+
creatorDefaults?: ICreatorDefaults;
|
|
63
|
+
metadata?: Record<string, unknown>;
|
|
64
|
+
}>;
|
|
65
|
+
getAddressInfo(bech32Address: string): Promise<AddressInfo>;
|
|
66
|
+
getAddressUTxOs(bech32Address: string): Promise<ChainProviderAsset[]>;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Koios = exports.buildKoiosAddressUtxoRequestBody = exports.buildKoiosHeaders = void 0;
|
|
4
|
+
const types_1 = require("../../types");
|
|
5
|
+
const fetchProviderJson_1 = require("../transport/fetchProviderJson");
|
|
6
|
+
const imageDatum_1 = require("../datum/imageDatum");
|
|
7
|
+
const providerConfig_1 = require("../providerConfig");
|
|
8
|
+
const buildKoiosHeaders = (bearerToken) => ({
|
|
9
|
+
'Content-Type': 'application/json',
|
|
10
|
+
...(bearerToken ? { Authorization: `Bearer ${bearerToken}` } : {})
|
|
11
|
+
});
|
|
12
|
+
exports.buildKoiosHeaders = buildKoiosHeaders;
|
|
13
|
+
const buildKoiosAddressUtxoRequestBody = (bech32Address) => ({
|
|
14
|
+
_addresses: [bech32Address],
|
|
15
|
+
_extended: true
|
|
16
|
+
});
|
|
17
|
+
exports.buildKoiosAddressUtxoRequestBody = buildKoiosAddressUtxoRequestBody;
|
|
18
|
+
class Koios {
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
this.name = 'Koios';
|
|
22
|
+
}
|
|
23
|
+
async fetchKoios(path, method = 'GET', body) {
|
|
24
|
+
const network = this.config.network.toLowerCase();
|
|
25
|
+
const host = network === 'mainnet' ? 'api' : network;
|
|
26
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
27
|
+
const url = `https://${host}.koios.rest/api/v1${normalizedPath}`;
|
|
28
|
+
return (0, fetchProviderJson_1.fetchProviderJson)({
|
|
29
|
+
provider: 'Koios',
|
|
30
|
+
url,
|
|
31
|
+
method,
|
|
32
|
+
headers: (0, exports.buildKoiosHeaders)(this.config.koiosBearerToken),
|
|
33
|
+
body
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async getLatestBlock() {
|
|
37
|
+
const blocks = await this.fetchKoios('/blocks');
|
|
38
|
+
const latestBlock = blocks[0];
|
|
39
|
+
return { height: latestBlock.block_height, slot: latestBlock.abs_slot, time: latestBlock.block_time };
|
|
40
|
+
}
|
|
41
|
+
async getLatestTransactionForAsset(policyId, hex) {
|
|
42
|
+
var _a;
|
|
43
|
+
const res = await this.fetchKoios(`/asset_txs?_asset_policy=${policyId}&_asset_name=${hex}`);
|
|
44
|
+
const [tx] = res;
|
|
45
|
+
return (_a = tx === null || tx === void 0 ? void 0 : tx.tx_hash) !== null && _a !== void 0 ? _a : null;
|
|
46
|
+
}
|
|
47
|
+
async getAssets(policyId) {
|
|
48
|
+
var _a;
|
|
49
|
+
const res = await this.fetchKoios(`/policy_asset_list?_asset_policy=${policyId}`);
|
|
50
|
+
if (!Array.isArray(res))
|
|
51
|
+
return [];
|
|
52
|
+
return ((_a = res === null || res === void 0 ? void 0 : res.reduce((agg, item) => {
|
|
53
|
+
const { asset_name, total_supply } = item;
|
|
54
|
+
if (asset_name.includes(types_1.AssetNameLabel.LBL_100) || total_supply === '0')
|
|
55
|
+
return agg;
|
|
56
|
+
agg.push({ policyId, hex: asset_name });
|
|
57
|
+
return agg;
|
|
58
|
+
}, [])) !== null && _a !== void 0 ? _a : []);
|
|
59
|
+
}
|
|
60
|
+
async getAssetUtxo(policyId, hex) {
|
|
61
|
+
var _a, _b, _c;
|
|
62
|
+
const tx = await this.getLatestTransactionForAsset(policyId, hex);
|
|
63
|
+
if (!tx)
|
|
64
|
+
return null;
|
|
65
|
+
const payload = { _tx_hashes: [tx], _metadata: true, _assets: true, _scripts: true, _bytecode: true };
|
|
66
|
+
const res = await this.fetchKoios(`/tx_info`, 'POST', JSON.stringify(payload));
|
|
67
|
+
const [firstTransaction] = res;
|
|
68
|
+
const output = (_a = firstTransaction === null || firstTransaction === void 0 ? void 0 : firstTransaction.outputs) === null || _a === void 0 ? void 0 : _a.find((o) => o.asset_list.some((a) => a.policy_id === policyId && a.asset_name === hex));
|
|
69
|
+
if (!output)
|
|
70
|
+
return null;
|
|
71
|
+
const amount = output.asset_list.map((a) => ({
|
|
72
|
+
unit: `${a.policy_id}${a.asset_name}`,
|
|
73
|
+
quantity: a.quantity
|
|
74
|
+
}));
|
|
75
|
+
amount.push({ unit: 'lovelace', quantity: output.value });
|
|
76
|
+
const chainProviderAsset = {
|
|
77
|
+
address: output.payment_addr.bech32,
|
|
78
|
+
amount,
|
|
79
|
+
inline_datum: (_c = (_b = output.inline_datum) === null || _b === void 0 ? void 0 : _b.bytes) !== null && _c !== void 0 ? _c : null,
|
|
80
|
+
output_index: output.tx_index,
|
|
81
|
+
tx_hash: firstTransaction.tx_hash,
|
|
82
|
+
data_hash: output.datum_hash
|
|
83
|
+
};
|
|
84
|
+
return { ...chainProviderAsset, tx_hash: tx };
|
|
85
|
+
}
|
|
86
|
+
async getDatumFromHash(datumHash) {
|
|
87
|
+
const result = await this.fetchKoios(`/datum_info`, 'POST', JSON.stringify({ _datum_hashes: [datumHash] }));
|
|
88
|
+
const [firstResult] = result;
|
|
89
|
+
return firstResult ? firstResult.bytes : null;
|
|
90
|
+
}
|
|
91
|
+
async getAssetDatum(policyId, hex) {
|
|
92
|
+
var _a, _b;
|
|
93
|
+
const assetUtxos = await this.fetchKoios(`/asset_utxos`, 'POST', JSON.stringify({ _asset_list: [[policyId, hex]], _extended: true }));
|
|
94
|
+
const utxo = assetUtxos === null || assetUtxos === void 0 ? void 0 : assetUtxos.find((u) => u.asset_list.some((a) => a.policy_id === policyId && a.asset_name === hex));
|
|
95
|
+
if ((_a = utxo === null || utxo === void 0 ? void 0 : utxo.inline_datum) === null || _a === void 0 ? void 0 : _a.bytes)
|
|
96
|
+
return utxo.inline_datum.bytes;
|
|
97
|
+
if (!((_b = utxo === null || utxo === void 0 ? void 0 : utxo.inline_datum) === null || _b === void 0 ? void 0 : _b.bytes) && (utxo === null || utxo === void 0 ? void 0 : utxo.datum_hash))
|
|
98
|
+
return this.getDatumFromHash(utxo.datum_hash);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
async getRefScriptCbor(tx, policyId, hex) {
|
|
102
|
+
var _a;
|
|
103
|
+
const { outputs } = await this.getTxUtxos(tx);
|
|
104
|
+
const output = outputs.find((o) => o.amount.some((a) => a.unit === `${policyId}${hex}`));
|
|
105
|
+
return (_a = output === null || output === void 0 ? void 0 : output.reference_script_cbor) !== null && _a !== void 0 ? _a : '';
|
|
106
|
+
}
|
|
107
|
+
async buildChainProviderAsset(output) {
|
|
108
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
109
|
+
const amount = output.asset_list.map((a) => ({
|
|
110
|
+
unit: `${a.policy_id}${a.asset_name}`,
|
|
111
|
+
quantity: a.quantity
|
|
112
|
+
}));
|
|
113
|
+
amount.push({ unit: 'lovelace', quantity: output.value });
|
|
114
|
+
const inline_datum = !((_a = output === null || output === void 0 ? void 0 : output.inline_datum) === null || _a === void 0 ? void 0 : _a.bytes) && (output === null || output === void 0 ? void 0 : output.datum_hash)
|
|
115
|
+
? await this.getDatumFromHash(output.datum_hash)
|
|
116
|
+
: (_c = (_b = output.inline_datum) === null || _b === void 0 ? void 0 : _b.bytes) !== null && _c !== void 0 ? _c : null;
|
|
117
|
+
return {
|
|
118
|
+
address: output.payment_addr.bech32,
|
|
119
|
+
amount,
|
|
120
|
+
inline_datum,
|
|
121
|
+
output_index: output.tx_index,
|
|
122
|
+
tx_hash: output.tx_hash,
|
|
123
|
+
data_hash: output.datum_hash,
|
|
124
|
+
reference_script_hash: (_e = (_d = output.reference_script) === null || _d === void 0 ? void 0 : _d.hash) !== null && _e !== void 0 ? _e : null,
|
|
125
|
+
reference_script_cbor: (_g = (_f = output.reference_script) === null || _f === void 0 ? void 0 : _f.bytes) !== null && _g !== void 0 ? _g : null
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
async getTxUtxos(tx) {
|
|
129
|
+
var _a;
|
|
130
|
+
const res = await this.fetchKoios(`/tx_info`, 'POST', JSON.stringify({ _tx_hashes: [tx], _metadata: true, _assets: true }));
|
|
131
|
+
const [firstTransaction] = res;
|
|
132
|
+
const outputs = [];
|
|
133
|
+
for (const output of (_a = firstTransaction === null || firstTransaction === void 0 ? void 0 : firstTransaction.outputs) !== null && _a !== void 0 ? _a : []) {
|
|
134
|
+
outputs.push(await this.buildChainProviderAsset(output));
|
|
135
|
+
}
|
|
136
|
+
return { outputs };
|
|
137
|
+
}
|
|
138
|
+
async getAssetsByStakeKey(stakeKey) {
|
|
139
|
+
const items = await this.fetchKoios(`/account_assets`, 'POST', JSON.stringify({ _stake_addresses: [stakeKey] }));
|
|
140
|
+
return items.reduce((agg, item) => {
|
|
141
|
+
const { policy_id, asset_name, quantity } = item;
|
|
142
|
+
if (quantity === '0')
|
|
143
|
+
return agg;
|
|
144
|
+
agg.push({ asset: `${policy_id}${asset_name}`, amount: quantity });
|
|
145
|
+
return agg;
|
|
146
|
+
}, []);
|
|
147
|
+
}
|
|
148
|
+
async getAssetMetadata(policyId, hex) {
|
|
149
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
150
|
+
const assetInfo = await this.fetchKoios(`/asset_info`, 'POST', JSON.stringify({ _asset_list: [[policyId, hex]] }));
|
|
151
|
+
const [result] = assetInfo;
|
|
152
|
+
let metadata = (_c = (_b = (_a = result === null || result === void 0 ? void 0 : result.minting_tx_metadata) === null || _a === void 0 ? void 0 : _a['721']) === null || _b === void 0 ? void 0 : _b[policyId]) === null || _c === void 0 ? void 0 : _c[hex];
|
|
153
|
+
if (!metadata) {
|
|
154
|
+
const assetName = Buffer.from(hex, 'hex').toString('utf-8');
|
|
155
|
+
metadata = (_f = (_e = (_d = result === null || result === void 0 ? void 0 : result.minting_tx_metadata) === null || _d === void 0 ? void 0 : _d['721']) === null || _e === void 0 ? void 0 : _e[policyId]) === null || _f === void 0 ? void 0 : _f[assetName];
|
|
156
|
+
if (!metadata && (result === null || result === void 0 ? void 0 : result.token_registry_metadata)) {
|
|
157
|
+
metadata = { image: `data:image/png;base64,${(_g = result.token_registry_metadata.logo) !== null && _g !== void 0 ? _g : ''}` };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return metadata;
|
|
161
|
+
}
|
|
162
|
+
async getCip25AssetImage(policyId, hex) {
|
|
163
|
+
var _a;
|
|
164
|
+
const metadata = await this.getAssetMetadata(policyId, hex);
|
|
165
|
+
if (!metadata)
|
|
166
|
+
return null;
|
|
167
|
+
let image = (_a = metadata.image) !== null && _a !== void 0 ? _a : null;
|
|
168
|
+
if (Array.isArray(image))
|
|
169
|
+
image = image.join('');
|
|
170
|
+
return image;
|
|
171
|
+
}
|
|
172
|
+
async getBackgroundImageDetails(policyId, hex) {
|
|
173
|
+
var _a;
|
|
174
|
+
const updateHex = hex.startsWith(types_1.AssetNameLabel.LBL_222) || hex.startsWith(types_1.AssetNameLabel.LBL_444)
|
|
175
|
+
? `${types_1.AssetNameLabel.LBL_100}${hex.replace(types_1.AssetNameLabel.LBL_222, '').replace(types_1.AssetNameLabel.LBL_444, '')}`
|
|
176
|
+
: hex;
|
|
177
|
+
const datum = await this.getAssetDatum(policyId, updateHex);
|
|
178
|
+
const metadata = await this.getAssetMetadata(policyId, hex);
|
|
179
|
+
let image = '';
|
|
180
|
+
if (metadata && metadata.image)
|
|
181
|
+
image = metadata.image;
|
|
182
|
+
if (datum) {
|
|
183
|
+
return (0, imageDatum_1.getImageDataFromDatum)((_a = this.config.apiHost) !== null && _a !== void 0 ? _a : (0, providerConfig_1.defaultApiHost)(this.config.network), datum);
|
|
184
|
+
}
|
|
185
|
+
return { image, metadata };
|
|
186
|
+
}
|
|
187
|
+
async getAddressInfo(bech32Address) {
|
|
188
|
+
const result = (await this.fetchKoios(`/address_info`, 'POST', JSON.stringify({ _addresses: [bech32Address] })))[0];
|
|
189
|
+
const balance = {};
|
|
190
|
+
result.utxo_set.forEach((utxo) => {
|
|
191
|
+
(utxo.asset_list || []).forEach((asset) => {
|
|
192
|
+
const { policy_id, asset_name, quantity } = asset;
|
|
193
|
+
const unit = `${policy_id}${asset_name || ''}`;
|
|
194
|
+
balance[unit] = (balance[unit] || BigInt(0)) + BigInt(quantity);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
const amount = Object.entries(balance).reduce((acc, cur) => [...acc, { unit: cur[0], quantity: cur[1].toString() }], []);
|
|
198
|
+
return {
|
|
199
|
+
address: result.address,
|
|
200
|
+
amount: [{ unit: 'lovelace', quantity: result.balance }].concat(amount.sort((a, b) => (a.unit > b.unit ? 1 : -1))),
|
|
201
|
+
stake_address: result.stake_address,
|
|
202
|
+
script: result.script_address
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
async getAddressUTxOs(bech32Address) {
|
|
206
|
+
const result = await this.fetchKoios(`/address_utxos`, 'POST', JSON.stringify((0, exports.buildKoiosAddressUtxoRequestBody)(bech32Address)));
|
|
207
|
+
const utxos = [];
|
|
208
|
+
for (const output of result) {
|
|
209
|
+
utxos.push(await this.buildChainProviderAsset(output));
|
|
210
|
+
}
|
|
211
|
+
return utxos;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
exports.Koios = Koios;
|