@hashgraphonline/standards-sdk 0.0.111 → 0.0.112-canary.2
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/dist/cjs/hcs-10/base-client.d.ts +46 -1
- package/dist/cjs/hcs-10/base-client.d.ts.map +1 -1
- package/dist/cjs/hcs-10/browser.d.ts +30 -0
- package/dist/cjs/hcs-10/browser.d.ts.map +1 -1
- package/dist/cjs/hcs-10/sdk.d.ts.map +1 -1
- package/dist/cjs/hcs-10/types.d.ts +34 -0
- package/dist/cjs/hcs-10/types.d.ts.map +1 -1
- package/dist/cjs/index-BjSZGzAb.cjs +11 -0
- package/dist/cjs/index-BjSZGzAb.cjs.map +1 -0
- package/dist/cjs/{index-CHar8dVv-B3h_fMlF.cjs → index-CHar8dVv-CRh6n7ac.cjs} +2 -2
- package/dist/cjs/{index-CHar8dVv-B3h_fMlF.cjs.map → index-CHar8dVv-CRh6n7ac.cjs.map} +1 -1
- package/dist/cjs/services/mirror-node.d.ts +249 -2
- package/dist/cjs/services/mirror-node.d.ts.map +1 -1
- package/dist/cjs/services/types.d.ts +328 -0
- package/dist/cjs/services/types.d.ts.map +1 -1
- package/dist/cjs/standards-sdk.cjs +1 -1
- package/dist/es/hcs-10/base-client.d.ts +46 -1
- package/dist/es/hcs-10/base-client.d.ts.map +1 -1
- package/dist/es/hcs-10/browser.d.ts +30 -0
- package/dist/es/hcs-10/browser.d.ts.map +1 -1
- package/dist/es/hcs-10/sdk.d.ts.map +1 -1
- package/dist/es/hcs-10/types.d.ts +34 -0
- package/dist/es/hcs-10/types.d.ts.map +1 -1
- package/dist/es/services/mirror-node.d.ts +249 -2
- package/dist/es/services/mirror-node.d.ts.map +1 -1
- package/dist/es/services/types.d.ts +328 -0
- package/dist/es/services/types.d.ts.map +1 -1
- package/dist/es/standards-sdk.es19.js +6 -6
- package/dist/es/standards-sdk.es20.js +1 -1
- package/dist/es/standards-sdk.es21.js +760 -44
- package/dist/es/standards-sdk.es21.js.map +1 -1
- package/dist/es/standards-sdk.es24.js +7139 -450
- package/dist/es/standards-sdk.es24.js.map +1 -1
- package/dist/es/standards-sdk.es25.js +2 -109
- package/dist/es/standards-sdk.es25.js.map +1 -1
- package/dist/es/standards-sdk.es26.js +469 -34
- package/dist/es/standards-sdk.es26.js.map +1 -1
- package/dist/es/standards-sdk.es27.js +74 -222
- package/dist/es/standards-sdk.es27.js.map +1 -1
- package/dist/es/standards-sdk.es28.js +34 -141
- package/dist/es/standards-sdk.es28.js.map +1 -1
- package/dist/es/standards-sdk.es29.js +251 -5
- package/dist/es/standards-sdk.es29.js.map +1 -1
- package/dist/es/standards-sdk.es30.js +154 -7171
- package/dist/es/standards-sdk.es30.js.map +1 -1
- package/dist/es/standards-sdk.es31.js +11 -2
- package/dist/es/standards-sdk.es31.js.map +1 -1
- package/dist/es/standards-sdk.es32.js +7135 -41
- package/dist/es/standards-sdk.es32.js.map +1 -1
- package/dist/es/standards-sdk.es33.js +41 -7135
- package/dist/es/standards-sdk.es33.js.map +1 -1
- package/dist/es/standards-sdk.es5.js +10 -1
- package/dist/es/standards-sdk.es5.js.map +1 -1
- package/dist/es/standards-sdk.es7.js +3 -2
- package/dist/es/standards-sdk.es7.js.map +1 -1
- package/dist/es/standards-sdk.es8.js +3 -2
- package/dist/es/standards-sdk.es8.js.map +1 -1
- package/dist/es/standards-sdk.es9.js +1 -1
- package/dist/umd/hcs-10/base-client.d.ts +46 -1
- package/dist/umd/hcs-10/base-client.d.ts.map +1 -1
- package/dist/umd/hcs-10/browser.d.ts +30 -0
- package/dist/umd/hcs-10/browser.d.ts.map +1 -1
- package/dist/umd/hcs-10/sdk.d.ts.map +1 -1
- package/dist/umd/hcs-10/types.d.ts +34 -0
- package/dist/umd/hcs-10/types.d.ts.map +1 -1
- package/dist/umd/services/mirror-node.d.ts +249 -2
- package/dist/umd/services/mirror-node.d.ts.map +1 -1
- package/dist/umd/services/types.d.ts +328 -0
- package/dist/umd/services/types.d.ts.map +1 -1
- package/dist/umd/standards-sdk.umd.js +12 -12
- package/dist/umd/standards-sdk.umd.js.map +1 -1
- package/package.json +1 -1
- package/dist/cjs/index-B0xnKxrq.cjs +0 -11
- package/dist/cjs/index-B0xnKxrq.cjs.map +0 -1
|
@@ -4,18 +4,26 @@ import axios from "axios";
|
|
|
4
4
|
import { Logger } from "./standards-sdk.es15.js";
|
|
5
5
|
import { proto } from "@hashgraph/proto";
|
|
6
6
|
class HederaMirrorNode {
|
|
7
|
-
constructor(network, logger) {
|
|
7
|
+
constructor(network, logger, config) {
|
|
8
8
|
this.maxRetries = 3;
|
|
9
9
|
this.initialDelayMs = 1e3;
|
|
10
10
|
this.maxDelayMs = 3e4;
|
|
11
11
|
this.backoffFactor = 2;
|
|
12
12
|
this.network = network;
|
|
13
|
-
this.
|
|
13
|
+
this.apiKey = config?.apiKey;
|
|
14
|
+
this.customHeaders = config?.headers || {};
|
|
15
|
+
this.baseUrl = config?.customUrl || this.getMirrorNodeUrl();
|
|
14
16
|
this.logger = logger || new Logger({
|
|
15
17
|
level: "debug",
|
|
16
18
|
module: "MirrorNode"
|
|
17
19
|
});
|
|
18
20
|
this.isServerEnvironment = typeof window === "undefined";
|
|
21
|
+
if (config?.customUrl) {
|
|
22
|
+
this.logger.info(`Using custom mirror node URL: ${config.customUrl}`);
|
|
23
|
+
}
|
|
24
|
+
if (config?.apiKey) {
|
|
25
|
+
this.logger.info("Using API key for mirror node requests");
|
|
26
|
+
}
|
|
19
27
|
}
|
|
20
28
|
/**
|
|
21
29
|
* Configures the retry mechanism for API requests.
|
|
@@ -30,6 +38,36 @@ class HederaMirrorNode {
|
|
|
30
38
|
`Retry configuration updated: maxRetries=${this.maxRetries}, initialDelayMs=${this.initialDelayMs}, maxDelayMs=${this.maxDelayMs}, backoffFactor=${this.backoffFactor}`
|
|
31
39
|
);
|
|
32
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Updates the mirror node configuration.
|
|
43
|
+
* @param config The new mirror node configuration.
|
|
44
|
+
*/
|
|
45
|
+
configureMirrorNode(config) {
|
|
46
|
+
if (config.customUrl) {
|
|
47
|
+
this.baseUrl = config.customUrl;
|
|
48
|
+
this.logger.info(`Updated mirror node URL: ${config.customUrl}`);
|
|
49
|
+
}
|
|
50
|
+
if (config.apiKey) {
|
|
51
|
+
this.apiKey = config.apiKey;
|
|
52
|
+
this.logger.info("Updated API key for mirror node requests");
|
|
53
|
+
}
|
|
54
|
+
if (config.headers) {
|
|
55
|
+
this.customHeaders = { ...this.customHeaders, ...config.headers };
|
|
56
|
+
this.logger.info("Updated custom headers for mirror node requests");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Constructs a full URL for API requests, handling custom providers with API keys in the path.
|
|
61
|
+
* @param endpoint The API endpoint (e.g., '/api/v1/accounts/0.0.123')
|
|
62
|
+
* @returns The full URL for the request
|
|
63
|
+
*/
|
|
64
|
+
constructUrl(endpoint) {
|
|
65
|
+
if (this.baseUrl.includes("<API-KEY>") && this.apiKey) {
|
|
66
|
+
const baseUrlWithKey = this.baseUrl.replace("<API-KEY>", this.apiKey);
|
|
67
|
+
return endpoint.startsWith("/") ? `${baseUrlWithKey}${endpoint}` : `${baseUrlWithKey}/${endpoint}`;
|
|
68
|
+
}
|
|
69
|
+
return endpoint.startsWith("/") ? `${this.baseUrl}${endpoint}` : `${this.baseUrl}/${endpoint}`;
|
|
70
|
+
}
|
|
33
71
|
getMirrorNodeUrl() {
|
|
34
72
|
return this.network === "mainnet" ? "https://mainnet-public.mirrornode.hedera.com" : "https://testnet.mirrornode.hedera.com";
|
|
35
73
|
}
|
|
@@ -67,10 +105,9 @@ class HederaMirrorNode {
|
|
|
67
105
|
*/
|
|
68
106
|
async getAccountMemo(accountId) {
|
|
69
107
|
this.logger.info(`Getting account memo for account ID: ${accountId}`);
|
|
70
|
-
const accountInfoUrl = `${this.baseUrl}/api/v1/accounts/${accountId}`;
|
|
71
108
|
try {
|
|
72
109
|
const accountInfo = await this._requestWithRetry(
|
|
73
|
-
|
|
110
|
+
`/api/v1/accounts/${accountId}`
|
|
74
111
|
);
|
|
75
112
|
if (accountInfo?.memo) {
|
|
76
113
|
return accountInfo.memo;
|
|
@@ -93,9 +130,10 @@ class HederaMirrorNode {
|
|
|
93
130
|
*/
|
|
94
131
|
async getTopicInfo(topicId) {
|
|
95
132
|
try {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
133
|
+
this.logger.debug(`Fetching topic info for ${topicId}`);
|
|
134
|
+
const data = await this._requestWithRetry(
|
|
135
|
+
`/api/v1/topics/${topicId}`
|
|
136
|
+
);
|
|
99
137
|
return data;
|
|
100
138
|
} catch (e) {
|
|
101
139
|
const error = e;
|
|
@@ -130,9 +168,10 @@ class HederaMirrorNode {
|
|
|
130
168
|
async getHBARPrice(date) {
|
|
131
169
|
try {
|
|
132
170
|
const timestamp = Timestamp.fromDate(date).toString();
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
171
|
+
this.logger.debug(`Fetching HBAR price for timestamp ${timestamp}`);
|
|
172
|
+
const response = await this._requestWithRetry(
|
|
173
|
+
`/api/v1/network/exchangerate?timestamp=${timestamp}`
|
|
174
|
+
);
|
|
136
175
|
const usdPrice = Number(response?.current_rate?.cent_equivalent) / Number(response?.current_rate?.hbar_equivalent) / 100;
|
|
137
176
|
return usdPrice;
|
|
138
177
|
} catch (e) {
|
|
@@ -151,9 +190,8 @@ class HederaMirrorNode {
|
|
|
151
190
|
async getTokenInfo(tokenId) {
|
|
152
191
|
this.logger.debug(`Fetching token info for ${tokenId}`);
|
|
153
192
|
try {
|
|
154
|
-
const tokenInfoUrl = `${this.baseUrl}/api/v1/tokens/${tokenId}`;
|
|
155
193
|
const data = await this._requestWithRetry(
|
|
156
|
-
|
|
194
|
+
`/api/v1/tokens/${tokenId}`
|
|
157
195
|
);
|
|
158
196
|
if (data) {
|
|
159
197
|
this.logger.trace(`Token info found for ${tokenId}:`, data);
|
|
@@ -176,12 +214,12 @@ class HederaMirrorNode {
|
|
|
176
214
|
*/
|
|
177
215
|
async getTopicMessages(topicId) {
|
|
178
216
|
this.logger.trace(`Querying messages for topic ${topicId}`);
|
|
179
|
-
let
|
|
217
|
+
let nextEndpoint = `/api/v1/topics/${topicId}/messages`;
|
|
180
218
|
const messages = [];
|
|
181
|
-
while (
|
|
219
|
+
while (nextEndpoint) {
|
|
182
220
|
try {
|
|
183
221
|
const data = await this._requestWithRetry(
|
|
184
|
-
|
|
222
|
+
nextEndpoint
|
|
185
223
|
);
|
|
186
224
|
if (data.messages && data.messages.length > 0) {
|
|
187
225
|
for (const message of data.messages) {
|
|
@@ -230,10 +268,10 @@ class HederaMirrorNode {
|
|
|
230
268
|
}
|
|
231
269
|
}
|
|
232
270
|
}
|
|
233
|
-
|
|
271
|
+
nextEndpoint = data.links?.next || "";
|
|
234
272
|
} catch (e) {
|
|
235
273
|
const error = e;
|
|
236
|
-
const logMessage = `Error querying topic messages for topic ${topicId} (
|
|
274
|
+
const logMessage = `Error querying topic messages for topic ${topicId} (endpoint: ${nextEndpoint}) after retries: ${error.message}`;
|
|
237
275
|
this.logger.error(logMessage);
|
|
238
276
|
throw new Error(logMessage);
|
|
239
277
|
}
|
|
@@ -248,10 +286,9 @@ class HederaMirrorNode {
|
|
|
248
286
|
*/
|
|
249
287
|
async requestAccount(accountId) {
|
|
250
288
|
try {
|
|
251
|
-
|
|
252
|
-
this.logger.debug(`Requesting account info from ${accountInfoUrl}`);
|
|
289
|
+
this.logger.debug(`Requesting account info for ${accountId}`);
|
|
253
290
|
const data = await this._requestWithRetry(
|
|
254
|
-
|
|
291
|
+
`/api/v1/accounts/${accountId}`
|
|
255
292
|
);
|
|
256
293
|
if (!data) {
|
|
257
294
|
throw new Error(
|
|
@@ -364,8 +401,9 @@ class HederaMirrorNode {
|
|
|
364
401
|
this.logger.info(
|
|
365
402
|
`Getting information for scheduled transaction ${scheduleId}`
|
|
366
403
|
);
|
|
367
|
-
const
|
|
368
|
-
|
|
404
|
+
const data = await this._requestWithRetry(
|
|
405
|
+
`/api/v1/schedules/${scheduleId}`
|
|
406
|
+
);
|
|
369
407
|
if (data) {
|
|
370
408
|
return data;
|
|
371
409
|
}
|
|
@@ -416,10 +454,8 @@ class HederaMirrorNode {
|
|
|
416
454
|
this.logger.info(
|
|
417
455
|
`Getting transaction details for ID/hash: ${transactionIdOrHash}`
|
|
418
456
|
);
|
|
419
|
-
const endpoint = transactionIdOrHash.includes("-") ? `transactions/${transactionIdOrHash}` : `transactions/${transactionIdOrHash}`;
|
|
420
|
-
const transactionDetailsUrl = `${this.baseUrl}/api/v1/${endpoint}`;
|
|
421
457
|
try {
|
|
422
|
-
const response = await this._requestWithRetry(
|
|
458
|
+
const response = await this._requestWithRetry(`/api/v1/transactions/${transactionIdOrHash}`);
|
|
423
459
|
if (response?.transactions?.length > 0) {
|
|
424
460
|
this.logger.trace(
|
|
425
461
|
`Transaction details found for ${transactionIdOrHash}:`,
|
|
@@ -442,12 +478,27 @@ class HederaMirrorNode {
|
|
|
442
478
|
/**
|
|
443
479
|
* Private helper to make GET requests with retry logic using Axios.
|
|
444
480
|
*/
|
|
445
|
-
async _requestWithRetry(
|
|
481
|
+
async _requestWithRetry(endpoint, axiosConfig) {
|
|
446
482
|
let attempt = 0;
|
|
447
483
|
let delay = this.initialDelayMs;
|
|
484
|
+
const url = this.constructUrl(endpoint);
|
|
485
|
+
const config = {
|
|
486
|
+
...axiosConfig,
|
|
487
|
+
headers: {
|
|
488
|
+
...this.customHeaders,
|
|
489
|
+
...axiosConfig?.headers
|
|
490
|
+
}
|
|
491
|
+
};
|
|
492
|
+
if (this.apiKey) {
|
|
493
|
+
config.headers = {
|
|
494
|
+
...config.headers,
|
|
495
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
496
|
+
"X-API-Key": this.apiKey
|
|
497
|
+
};
|
|
498
|
+
}
|
|
448
499
|
while (attempt < this.maxRetries) {
|
|
449
500
|
try {
|
|
450
|
-
const response = await axios.get(url,
|
|
501
|
+
const response = await axios.get(url, config);
|
|
451
502
|
return response.data;
|
|
452
503
|
} catch (error) {
|
|
453
504
|
attempt++;
|
|
@@ -482,9 +533,33 @@ class HederaMirrorNode {
|
|
|
482
533
|
async _fetchWithRetry(url, fetchOptions) {
|
|
483
534
|
let attempt = 0;
|
|
484
535
|
let delay = this.initialDelayMs;
|
|
536
|
+
const headers = {
|
|
537
|
+
...this.customHeaders
|
|
538
|
+
};
|
|
539
|
+
if (fetchOptions?.headers) {
|
|
540
|
+
if (fetchOptions.headers instanceof Headers) {
|
|
541
|
+
fetchOptions.headers.forEach((value, key) => {
|
|
542
|
+
headers[key] = value;
|
|
543
|
+
});
|
|
544
|
+
} else if (Array.isArray(fetchOptions.headers)) {
|
|
545
|
+
fetchOptions.headers.forEach(([key, value]) => {
|
|
546
|
+
headers[key] = value;
|
|
547
|
+
});
|
|
548
|
+
} else {
|
|
549
|
+
Object.assign(headers, fetchOptions.headers);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (this.apiKey) {
|
|
553
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
554
|
+
headers["X-API-Key"] = this.apiKey;
|
|
555
|
+
}
|
|
556
|
+
const options = {
|
|
557
|
+
...fetchOptions,
|
|
558
|
+
headers
|
|
559
|
+
};
|
|
485
560
|
while (attempt < this.maxRetries) {
|
|
486
561
|
try {
|
|
487
|
-
const request = await fetch(url,
|
|
562
|
+
const request = await fetch(url, options);
|
|
488
563
|
if (!request.ok) {
|
|
489
564
|
if (request.status >= 400 && request.status < 500 && request.status !== 429) {
|
|
490
565
|
this.logger.error(
|
|
@@ -558,7 +633,7 @@ class HederaMirrorNode {
|
|
|
558
633
|
options
|
|
559
634
|
)}`
|
|
560
635
|
);
|
|
561
|
-
let nextUrl =
|
|
636
|
+
let nextUrl = `/api/v1/topics/${topicId}/messages`;
|
|
562
637
|
const params = new URLSearchParams();
|
|
563
638
|
if (options?.limit) {
|
|
564
639
|
params.append("limit", options.limit.toString());
|
|
@@ -638,7 +713,7 @@ class HederaMirrorNode {
|
|
|
638
713
|
}
|
|
639
714
|
}
|
|
640
715
|
if (options?.limit && messages.length >= options.limit) break;
|
|
641
|
-
nextUrl = data.links?.next ? `${
|
|
716
|
+
nextUrl = data.links?.next ? `${data.links.next}` : "";
|
|
642
717
|
}
|
|
643
718
|
return messages;
|
|
644
719
|
} catch (e) {
|
|
@@ -658,17 +733,17 @@ class HederaMirrorNode {
|
|
|
658
733
|
async getAccountTokens(accountId, limit = 100) {
|
|
659
734
|
this.logger.info(`Getting tokens for account ${accountId}`);
|
|
660
735
|
let allTokens = [];
|
|
661
|
-
let
|
|
736
|
+
let endpoint = `/api/v1/accounts/${accountId}/tokens?limit=${limit}`;
|
|
662
737
|
try {
|
|
663
|
-
for (let i = 0; i < 10 &&
|
|
738
|
+
for (let i = 0; i < 10 && endpoint; i++) {
|
|
664
739
|
const response = await this._requestWithRetry(
|
|
665
|
-
|
|
740
|
+
endpoint
|
|
666
741
|
);
|
|
667
742
|
if (response && response.tokens) {
|
|
668
743
|
allTokens = allTokens.concat(response.tokens);
|
|
669
744
|
}
|
|
670
|
-
|
|
671
|
-
if (!
|
|
745
|
+
endpoint = response.links?.next || "";
|
|
746
|
+
if (!endpoint || limit && allTokens.length >= limit) {
|
|
672
747
|
if (limit && allTokens.length > limit) {
|
|
673
748
|
allTokens = allTokens.slice(0, limit);
|
|
674
749
|
}
|
|
@@ -690,9 +765,8 @@ class HederaMirrorNode {
|
|
|
690
765
|
*/
|
|
691
766
|
async getTransactionByTimestamp(timestamp) {
|
|
692
767
|
this.logger.info(`Getting transaction by timestamp: ${timestamp}`);
|
|
693
|
-
const url = `${this.baseUrl}/api/v1/transactions?timestamp=${timestamp}&limit=1`;
|
|
694
768
|
try {
|
|
695
|
-
const response = await this._requestWithRetry(
|
|
769
|
+
const response = await this._requestWithRetry(`/api/v1/transactions?timestamp=${timestamp}&limit=1`);
|
|
696
770
|
return response.transactions;
|
|
697
771
|
} catch (error) {
|
|
698
772
|
this.logger.error(
|
|
@@ -713,13 +787,15 @@ class HederaMirrorNode {
|
|
|
713
787
|
`Getting NFTs for account ${accountId}${tokenId ? ` for token ${tokenId}` : ""}`
|
|
714
788
|
);
|
|
715
789
|
let allNfts = [];
|
|
716
|
-
let
|
|
790
|
+
let endpoint = `/api/v1/accounts/${accountId}/nfts?limit=${limit}`;
|
|
717
791
|
if (tokenId) {
|
|
718
|
-
|
|
792
|
+
endpoint += `&token.id=${tokenId}`;
|
|
719
793
|
}
|
|
720
794
|
try {
|
|
721
|
-
for (let i = 0; i < 10 &&
|
|
722
|
-
const response = await this._requestWithRetry(
|
|
795
|
+
for (let i = 0; i < 10 && endpoint; i++) {
|
|
796
|
+
const response = await this._requestWithRetry(
|
|
797
|
+
endpoint
|
|
798
|
+
);
|
|
723
799
|
if (response && response.nfts) {
|
|
724
800
|
const nftsWithUri = response.nfts.map((nft) => {
|
|
725
801
|
let tokenUri = void 0;
|
|
@@ -744,8 +820,8 @@ class HederaMirrorNode {
|
|
|
744
820
|
});
|
|
745
821
|
allNfts = allNfts.concat(nftsWithUri);
|
|
746
822
|
}
|
|
747
|
-
|
|
748
|
-
if (!
|
|
823
|
+
endpoint = response.links?.next || "";
|
|
824
|
+
if (!endpoint) break;
|
|
749
825
|
}
|
|
750
826
|
return allNfts;
|
|
751
827
|
} catch (error) {
|
|
@@ -794,7 +870,6 @@ class HederaMirrorNode {
|
|
|
794
870
|
this.logger.info(
|
|
795
871
|
`Reading smart contract ${contractIdOrAddress} with selector ${functionSelector}`
|
|
796
872
|
);
|
|
797
|
-
const url = `${this.baseUrl}/api/v1/contracts/call`;
|
|
798
873
|
const toAddress = contractIdOrAddress.startsWith("0x") ? contractIdOrAddress : `0x${AccountId.fromString(contractIdOrAddress).toSolidityAddress()}`;
|
|
799
874
|
const fromAddress = payerAccountId.startsWith("0x") ? payerAccountId : `0x${AccountId.fromString(payerAccountId).toSolidityAddress()}`;
|
|
800
875
|
const body = {
|
|
@@ -814,6 +889,7 @@ class HederaMirrorNode {
|
|
|
814
889
|
}
|
|
815
890
|
});
|
|
816
891
|
try {
|
|
892
|
+
const url = this.constructUrl("/api/v1/contracts/call");
|
|
817
893
|
const response = await this._fetchWithRetry(
|
|
818
894
|
url,
|
|
819
895
|
{
|
|
@@ -832,6 +908,646 @@ class HederaMirrorNode {
|
|
|
832
908
|
return null;
|
|
833
909
|
}
|
|
834
910
|
}
|
|
911
|
+
/**
|
|
912
|
+
* Retrieves outstanding token airdrops sent by an account.
|
|
913
|
+
* @param accountId The ID of the account that sent the airdrops.
|
|
914
|
+
* @param options Optional parameters for filtering airdrops.
|
|
915
|
+
* @returns A promise that resolves to an array of TokenAirdrop or null.
|
|
916
|
+
*/
|
|
917
|
+
async getOutstandingTokenAirdrops(accountId, options) {
|
|
918
|
+
this.logger.info(
|
|
919
|
+
`Getting outstanding token airdrops sent by account ${accountId}`
|
|
920
|
+
);
|
|
921
|
+
let endpoint = `/api/v1/accounts/${accountId}/airdrops/outstanding`;
|
|
922
|
+
const params = new URLSearchParams();
|
|
923
|
+
if (options?.limit) {
|
|
924
|
+
params.append("limit", options.limit.toString());
|
|
925
|
+
}
|
|
926
|
+
if (options?.order) {
|
|
927
|
+
params.append("order", options.order);
|
|
928
|
+
}
|
|
929
|
+
if (options?.receiverId) {
|
|
930
|
+
params.append("receiver.id", options.receiverId);
|
|
931
|
+
}
|
|
932
|
+
if (options?.serialNumber) {
|
|
933
|
+
params.append("serialnumber", options.serialNumber);
|
|
934
|
+
}
|
|
935
|
+
if (options?.tokenId) {
|
|
936
|
+
params.append("token.id", options.tokenId);
|
|
937
|
+
}
|
|
938
|
+
const queryString = params.toString();
|
|
939
|
+
if (queryString) {
|
|
940
|
+
endpoint += `?${queryString}`;
|
|
941
|
+
}
|
|
942
|
+
try {
|
|
943
|
+
const response = await this._requestWithRetry(
|
|
944
|
+
endpoint
|
|
945
|
+
);
|
|
946
|
+
return response.airdrops || [];
|
|
947
|
+
} catch (error) {
|
|
948
|
+
this.logger.error(
|
|
949
|
+
`Error fetching outstanding token airdrops for account ${accountId}: ${error.message}`
|
|
950
|
+
);
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
/**
|
|
955
|
+
* Retrieves pending token airdrops received by an account.
|
|
956
|
+
* @param accountId The ID of the account that received the airdrops.
|
|
957
|
+
* @param options Optional parameters for filtering airdrops.
|
|
958
|
+
* @returns A promise that resolves to an array of TokenAirdrop or null.
|
|
959
|
+
*/
|
|
960
|
+
async getPendingTokenAirdrops(accountId, options) {
|
|
961
|
+
this.logger.info(
|
|
962
|
+
`Getting pending token airdrops received by account ${accountId}`
|
|
963
|
+
);
|
|
964
|
+
let endpoint = `/api/v1/accounts/${accountId}/airdrops/pending`;
|
|
965
|
+
const params = new URLSearchParams();
|
|
966
|
+
if (options?.limit) {
|
|
967
|
+
params.append("limit", options.limit.toString());
|
|
968
|
+
}
|
|
969
|
+
if (options?.order) {
|
|
970
|
+
params.append("order", options.order);
|
|
971
|
+
}
|
|
972
|
+
if (options?.senderId) {
|
|
973
|
+
params.append("sender.id", options.senderId);
|
|
974
|
+
}
|
|
975
|
+
if (options?.serialNumber) {
|
|
976
|
+
params.append("serialnumber", options.serialNumber);
|
|
977
|
+
}
|
|
978
|
+
if (options?.tokenId) {
|
|
979
|
+
params.append("token.id", options.tokenId);
|
|
980
|
+
}
|
|
981
|
+
const queryString = params.toString();
|
|
982
|
+
if (queryString) {
|
|
983
|
+
endpoint += `?${queryString}`;
|
|
984
|
+
}
|
|
985
|
+
try {
|
|
986
|
+
const response = await this._requestWithRetry(
|
|
987
|
+
endpoint
|
|
988
|
+
);
|
|
989
|
+
return response.airdrops || [];
|
|
990
|
+
} catch (error) {
|
|
991
|
+
this.logger.error(
|
|
992
|
+
`Error fetching pending token airdrops for account ${accountId}: ${error.message}`
|
|
993
|
+
);
|
|
994
|
+
return null;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* Retrieves blocks from the network.
|
|
999
|
+
* @param options Optional parameters for filtering blocks.
|
|
1000
|
+
* @returns A promise that resolves to an array of Block or null.
|
|
1001
|
+
*/
|
|
1002
|
+
async getBlocks(options) {
|
|
1003
|
+
this.logger.info("Getting blocks from the network");
|
|
1004
|
+
let endpoint = `/api/v1/blocks`;
|
|
1005
|
+
const params = new URLSearchParams();
|
|
1006
|
+
if (options?.limit) {
|
|
1007
|
+
params.append("limit", options.limit.toString());
|
|
1008
|
+
}
|
|
1009
|
+
if (options?.order) {
|
|
1010
|
+
params.append("order", options.order);
|
|
1011
|
+
}
|
|
1012
|
+
if (options?.timestamp) {
|
|
1013
|
+
params.append("timestamp", options.timestamp);
|
|
1014
|
+
}
|
|
1015
|
+
if (options?.blockNumber) {
|
|
1016
|
+
params.append("block.number", options.blockNumber);
|
|
1017
|
+
}
|
|
1018
|
+
const queryString = params.toString();
|
|
1019
|
+
if (queryString) {
|
|
1020
|
+
endpoint += `?${queryString}`;
|
|
1021
|
+
}
|
|
1022
|
+
try {
|
|
1023
|
+
const response = await this._requestWithRetry(endpoint);
|
|
1024
|
+
return response.blocks || [];
|
|
1025
|
+
} catch (error) {
|
|
1026
|
+
this.logger.error(`Error fetching blocks: ${error.message}`);
|
|
1027
|
+
return null;
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Retrieves a specific block by number or hash.
|
|
1032
|
+
* @param blockNumberOrHash The block number or hash.
|
|
1033
|
+
* @returns A promise that resolves to a Block or null.
|
|
1034
|
+
*/
|
|
1035
|
+
async getBlock(blockNumberOrHash) {
|
|
1036
|
+
this.logger.info(`Getting block ${blockNumberOrHash}`);
|
|
1037
|
+
try {
|
|
1038
|
+
const response = await this._requestWithRetry(
|
|
1039
|
+
`/api/v1/blocks/${blockNumberOrHash}`
|
|
1040
|
+
);
|
|
1041
|
+
return response;
|
|
1042
|
+
} catch (error) {
|
|
1043
|
+
this.logger.error(
|
|
1044
|
+
`Error fetching block ${blockNumberOrHash}: ${error.message}`
|
|
1045
|
+
);
|
|
1046
|
+
return null;
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Retrieves contract entities from the network.
|
|
1051
|
+
* @param options Optional parameters for filtering contracts.
|
|
1052
|
+
* @returns A promise that resolves to an array of ContractEntity or null.
|
|
1053
|
+
*/
|
|
1054
|
+
async getContracts(options) {
|
|
1055
|
+
this.logger.info("Getting contracts from the network");
|
|
1056
|
+
let url = `/api/v1/contracts`;
|
|
1057
|
+
const params = new URLSearchParams();
|
|
1058
|
+
if (options?.contractId) {
|
|
1059
|
+
params.append("contract.id", options.contractId);
|
|
1060
|
+
}
|
|
1061
|
+
if (options?.limit) {
|
|
1062
|
+
params.append("limit", options.limit.toString());
|
|
1063
|
+
}
|
|
1064
|
+
if (options?.order) {
|
|
1065
|
+
params.append("order", options.order);
|
|
1066
|
+
}
|
|
1067
|
+
const queryString = params.toString();
|
|
1068
|
+
if (queryString) {
|
|
1069
|
+
url += `?${queryString}`;
|
|
1070
|
+
}
|
|
1071
|
+
try {
|
|
1072
|
+
const response = await this._requestWithRetry(url);
|
|
1073
|
+
return response.contracts || [];
|
|
1074
|
+
} catch (error) {
|
|
1075
|
+
this.logger.error(`Error fetching contracts: ${error.message}`);
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Retrieves a specific contract by ID or address.
|
|
1081
|
+
* @param contractIdOrAddress The contract ID or EVM address.
|
|
1082
|
+
* @param timestamp Optional timestamp for historical data.
|
|
1083
|
+
* @returns A promise that resolves to a ContractEntity or null.
|
|
1084
|
+
*/
|
|
1085
|
+
async getContract(contractIdOrAddress, timestamp) {
|
|
1086
|
+
this.logger.info(`Getting contract ${contractIdOrAddress}`);
|
|
1087
|
+
let url = `/api/v1/contracts/${contractIdOrAddress}`;
|
|
1088
|
+
if (timestamp) {
|
|
1089
|
+
url += `?timestamp=${timestamp}`;
|
|
1090
|
+
}
|
|
1091
|
+
try {
|
|
1092
|
+
const response = await this._requestWithRetry(url);
|
|
1093
|
+
return response;
|
|
1094
|
+
} catch (error) {
|
|
1095
|
+
this.logger.error(
|
|
1096
|
+
`Error fetching contract ${contractIdOrAddress}: ${error.message}`
|
|
1097
|
+
);
|
|
1098
|
+
return null;
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Retrieves contract results from the network.
|
|
1103
|
+
* @param options Optional parameters for filtering contract results.
|
|
1104
|
+
* @returns A promise that resolves to an array of ContractResult or null.
|
|
1105
|
+
*/
|
|
1106
|
+
async getContractResults(options) {
|
|
1107
|
+
this.logger.info("Getting contract results from the network");
|
|
1108
|
+
let url = `/api/v1/contracts/results`;
|
|
1109
|
+
const params = new URLSearchParams();
|
|
1110
|
+
if (options?.from) {
|
|
1111
|
+
params.append("from", options.from);
|
|
1112
|
+
}
|
|
1113
|
+
if (options?.blockHash) {
|
|
1114
|
+
params.append("block.hash", options.blockHash);
|
|
1115
|
+
}
|
|
1116
|
+
if (options?.blockNumber) {
|
|
1117
|
+
params.append("block.number", options.blockNumber);
|
|
1118
|
+
}
|
|
1119
|
+
if (options?.internal !== void 0) {
|
|
1120
|
+
params.append("internal", options.internal.toString());
|
|
1121
|
+
}
|
|
1122
|
+
if (options?.limit) {
|
|
1123
|
+
params.append("limit", options.limit.toString());
|
|
1124
|
+
}
|
|
1125
|
+
if (options?.order) {
|
|
1126
|
+
params.append("order", options.order);
|
|
1127
|
+
}
|
|
1128
|
+
if (options?.timestamp) {
|
|
1129
|
+
params.append("timestamp", options.timestamp);
|
|
1130
|
+
}
|
|
1131
|
+
if (options?.transactionIndex) {
|
|
1132
|
+
params.append("transaction.index", options.transactionIndex.toString());
|
|
1133
|
+
}
|
|
1134
|
+
const queryString = params.toString();
|
|
1135
|
+
if (queryString) {
|
|
1136
|
+
url += `?${queryString}`;
|
|
1137
|
+
}
|
|
1138
|
+
try {
|
|
1139
|
+
const response = await this._requestWithRetry(
|
|
1140
|
+
url
|
|
1141
|
+
);
|
|
1142
|
+
return response.results || [];
|
|
1143
|
+
} catch (error) {
|
|
1144
|
+
this.logger.error(`Error fetching contract results: ${error.message}`);
|
|
1145
|
+
return null;
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
/**
|
|
1149
|
+
* Retrieves a specific contract result by transaction ID or hash.
|
|
1150
|
+
* @param transactionIdOrHash The transaction ID or hash.
|
|
1151
|
+
* @param nonce Optional nonce filter.
|
|
1152
|
+
* @returns A promise that resolves to a ContractResult or null.
|
|
1153
|
+
*/
|
|
1154
|
+
async getContractResult(transactionIdOrHash, nonce) {
|
|
1155
|
+
this.logger.info(`Getting contract result for ${transactionIdOrHash}`);
|
|
1156
|
+
let url = `/api/v1/contracts/results/${transactionIdOrHash}`;
|
|
1157
|
+
if (nonce !== void 0) {
|
|
1158
|
+
url += `?nonce=${nonce}`;
|
|
1159
|
+
}
|
|
1160
|
+
try {
|
|
1161
|
+
const response = await this._requestWithRetry(url);
|
|
1162
|
+
return response;
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
this.logger.error(
|
|
1165
|
+
`Error fetching contract result for ${transactionIdOrHash}: ${error.message}`
|
|
1166
|
+
);
|
|
1167
|
+
return null;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
/**
|
|
1171
|
+
* Retrieves contract results for a specific contract.
|
|
1172
|
+
* @param contractIdOrAddress The contract ID or EVM address.
|
|
1173
|
+
* @param options Optional parameters for filtering.
|
|
1174
|
+
* @returns A promise that resolves to an array of ContractResult or null.
|
|
1175
|
+
*/
|
|
1176
|
+
async getContractResultsByContract(contractIdOrAddress, options) {
|
|
1177
|
+
this.logger.info(
|
|
1178
|
+
`Getting contract results for contract ${contractIdOrAddress}`
|
|
1179
|
+
);
|
|
1180
|
+
let url = `/api/v1/contracts/${contractIdOrAddress}/results`;
|
|
1181
|
+
const params = new URLSearchParams();
|
|
1182
|
+
if (options?.blockHash) {
|
|
1183
|
+
params.append("block.hash", options.blockHash);
|
|
1184
|
+
}
|
|
1185
|
+
if (options?.blockNumber) {
|
|
1186
|
+
params.append("block.number", options.blockNumber);
|
|
1187
|
+
}
|
|
1188
|
+
if (options?.from) {
|
|
1189
|
+
params.append("from", options.from);
|
|
1190
|
+
}
|
|
1191
|
+
if (options?.internal !== void 0) {
|
|
1192
|
+
params.append("internal", options.internal.toString());
|
|
1193
|
+
}
|
|
1194
|
+
if (options?.limit) {
|
|
1195
|
+
params.append("limit", options.limit.toString());
|
|
1196
|
+
}
|
|
1197
|
+
if (options?.order) {
|
|
1198
|
+
params.append("order", options.order);
|
|
1199
|
+
}
|
|
1200
|
+
if (options?.timestamp) {
|
|
1201
|
+
params.append("timestamp", options.timestamp);
|
|
1202
|
+
}
|
|
1203
|
+
if (options?.transactionIndex) {
|
|
1204
|
+
params.append("transaction.index", options.transactionIndex.toString());
|
|
1205
|
+
}
|
|
1206
|
+
const queryString = params.toString();
|
|
1207
|
+
if (queryString) {
|
|
1208
|
+
url += `?${queryString}`;
|
|
1209
|
+
}
|
|
1210
|
+
try {
|
|
1211
|
+
const response = await this._requestWithRetry(
|
|
1212
|
+
url
|
|
1213
|
+
);
|
|
1214
|
+
return response.results || [];
|
|
1215
|
+
} catch (error) {
|
|
1216
|
+
this.logger.error(
|
|
1217
|
+
`Error fetching contract results for ${contractIdOrAddress}: ${error.message}`
|
|
1218
|
+
);
|
|
1219
|
+
return null;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
/**
|
|
1223
|
+
* Retrieves contract state for a specific contract.
|
|
1224
|
+
* @param contractIdOrAddress The contract ID or EVM address.
|
|
1225
|
+
* @param options Optional parameters for filtering.
|
|
1226
|
+
* @returns A promise that resolves to an array of ContractState or null.
|
|
1227
|
+
*/
|
|
1228
|
+
async getContractState(contractIdOrAddress, options) {
|
|
1229
|
+
this.logger.info(`Getting contract state for ${contractIdOrAddress}`);
|
|
1230
|
+
let url = `/api/v1/contracts/${contractIdOrAddress}/state`;
|
|
1231
|
+
const params = new URLSearchParams();
|
|
1232
|
+
if (options?.limit) {
|
|
1233
|
+
params.append("limit", options.limit.toString());
|
|
1234
|
+
}
|
|
1235
|
+
if (options?.order) {
|
|
1236
|
+
params.append("order", options.order);
|
|
1237
|
+
}
|
|
1238
|
+
if (options?.slot) {
|
|
1239
|
+
params.append("slot", options.slot);
|
|
1240
|
+
}
|
|
1241
|
+
if (options?.timestamp) {
|
|
1242
|
+
params.append("timestamp", options.timestamp);
|
|
1243
|
+
}
|
|
1244
|
+
const queryString = params.toString();
|
|
1245
|
+
if (queryString) {
|
|
1246
|
+
url += `?${queryString}`;
|
|
1247
|
+
}
|
|
1248
|
+
try {
|
|
1249
|
+
const response = await this._requestWithRetry(url);
|
|
1250
|
+
return response.state || [];
|
|
1251
|
+
} catch (error) {
|
|
1252
|
+
this.logger.error(
|
|
1253
|
+
`Error fetching contract state for ${contractIdOrAddress}: ${error.message}`
|
|
1254
|
+
);
|
|
1255
|
+
return null;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Retrieves contract actions for a specific transaction.
|
|
1260
|
+
* @param transactionIdOrHash The transaction ID or hash.
|
|
1261
|
+
* @param options Optional parameters for filtering.
|
|
1262
|
+
* @returns A promise that resolves to an array of ContractAction or null.
|
|
1263
|
+
*/
|
|
1264
|
+
async getContractActions(transactionIdOrHash, options) {
|
|
1265
|
+
this.logger.info(`Getting contract actions for ${transactionIdOrHash}`);
|
|
1266
|
+
let url = `/api/v1/contracts/results/${transactionIdOrHash}/actions`;
|
|
1267
|
+
const params = new URLSearchParams();
|
|
1268
|
+
if (options?.index) {
|
|
1269
|
+
params.append("index", options.index);
|
|
1270
|
+
}
|
|
1271
|
+
if (options?.limit) {
|
|
1272
|
+
params.append("limit", options.limit.toString());
|
|
1273
|
+
}
|
|
1274
|
+
if (options?.order) {
|
|
1275
|
+
params.append("order", options.order);
|
|
1276
|
+
}
|
|
1277
|
+
const queryString = params.toString();
|
|
1278
|
+
if (queryString) {
|
|
1279
|
+
url += `?${queryString}`;
|
|
1280
|
+
}
|
|
1281
|
+
try {
|
|
1282
|
+
const response = await this._requestWithRetry(
|
|
1283
|
+
url
|
|
1284
|
+
);
|
|
1285
|
+
return response.actions || [];
|
|
1286
|
+
} catch (error) {
|
|
1287
|
+
this.logger.error(
|
|
1288
|
+
`Error fetching contract actions for ${transactionIdOrHash}: ${error.message}`
|
|
1289
|
+
);
|
|
1290
|
+
return null;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Retrieves contract logs from the network.
|
|
1295
|
+
* @param options Optional parameters for filtering logs.
|
|
1296
|
+
* @returns A promise that resolves to an array of ContractLog or null.
|
|
1297
|
+
*/
|
|
1298
|
+
async getContractLogs(options) {
|
|
1299
|
+
this.logger.info("Getting contract logs from the network");
|
|
1300
|
+
let url = `/api/v1/contracts/results/logs`;
|
|
1301
|
+
const params = new URLSearchParams();
|
|
1302
|
+
if (options?.index) {
|
|
1303
|
+
params.append("index", options.index);
|
|
1304
|
+
}
|
|
1305
|
+
if (options?.limit) {
|
|
1306
|
+
params.append("limit", options.limit.toString());
|
|
1307
|
+
}
|
|
1308
|
+
if (options?.order) {
|
|
1309
|
+
params.append("order", options.order);
|
|
1310
|
+
}
|
|
1311
|
+
if (options?.timestamp) {
|
|
1312
|
+
params.append("timestamp", options.timestamp);
|
|
1313
|
+
}
|
|
1314
|
+
if (options?.topic0) {
|
|
1315
|
+
params.append("topic0", options.topic0);
|
|
1316
|
+
}
|
|
1317
|
+
if (options?.topic1) {
|
|
1318
|
+
params.append("topic1", options.topic1);
|
|
1319
|
+
}
|
|
1320
|
+
if (options?.topic2) {
|
|
1321
|
+
params.append("topic2", options.topic2);
|
|
1322
|
+
}
|
|
1323
|
+
if (options?.topic3) {
|
|
1324
|
+
params.append("topic3", options.topic3);
|
|
1325
|
+
}
|
|
1326
|
+
if (options?.transactionHash) {
|
|
1327
|
+
params.append("transaction.hash", options.transactionHash);
|
|
1328
|
+
}
|
|
1329
|
+
const queryString = params.toString();
|
|
1330
|
+
if (queryString) {
|
|
1331
|
+
url += `?${queryString}`;
|
|
1332
|
+
}
|
|
1333
|
+
try {
|
|
1334
|
+
const response = await this._requestWithRetry(url);
|
|
1335
|
+
return response.logs || [];
|
|
1336
|
+
} catch (error) {
|
|
1337
|
+
this.logger.error(`Error fetching contract logs: ${error.message}`);
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
/**
|
|
1342
|
+
* Retrieves contract logs for a specific contract.
|
|
1343
|
+
* @param contractIdOrAddress The contract ID or EVM address.
|
|
1344
|
+
* @param options Optional parameters for filtering logs.
|
|
1345
|
+
* @returns A promise that resolves to an array of ContractLog or null.
|
|
1346
|
+
*/
|
|
1347
|
+
async getContractLogsByContract(contractIdOrAddress, options) {
|
|
1348
|
+
this.logger.info(
|
|
1349
|
+
`Getting contract logs for contract ${contractIdOrAddress}`
|
|
1350
|
+
);
|
|
1351
|
+
let url = `/api/v1/contracts/${contractIdOrAddress}/results/logs`;
|
|
1352
|
+
const params = new URLSearchParams();
|
|
1353
|
+
if (options?.index) {
|
|
1354
|
+
params.append("index", options.index);
|
|
1355
|
+
}
|
|
1356
|
+
if (options?.limit) {
|
|
1357
|
+
params.append("limit", options.limit.toString());
|
|
1358
|
+
}
|
|
1359
|
+
if (options?.order) {
|
|
1360
|
+
params.append("order", options.order);
|
|
1361
|
+
}
|
|
1362
|
+
if (options?.timestamp) {
|
|
1363
|
+
params.append("timestamp", options.timestamp);
|
|
1364
|
+
}
|
|
1365
|
+
if (options?.topic0) {
|
|
1366
|
+
params.append("topic0", options.topic0);
|
|
1367
|
+
}
|
|
1368
|
+
if (options?.topic1) {
|
|
1369
|
+
params.append("topic1", options.topic1);
|
|
1370
|
+
}
|
|
1371
|
+
if (options?.topic2) {
|
|
1372
|
+
params.append("topic2", options.topic2);
|
|
1373
|
+
}
|
|
1374
|
+
if (options?.topic3) {
|
|
1375
|
+
params.append("topic3", options.topic3);
|
|
1376
|
+
}
|
|
1377
|
+
const queryString = params.toString();
|
|
1378
|
+
if (queryString) {
|
|
1379
|
+
url += `?${queryString}`;
|
|
1380
|
+
}
|
|
1381
|
+
try {
|
|
1382
|
+
const response = await this._requestWithRetry(url);
|
|
1383
|
+
return response.logs || [];
|
|
1384
|
+
} catch (error) {
|
|
1385
|
+
this.logger.error(
|
|
1386
|
+
`Error fetching contract logs for ${contractIdOrAddress}: ${error.message}`
|
|
1387
|
+
);
|
|
1388
|
+
return null;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Retrieves NFT information by token ID and serial number.
|
|
1393
|
+
* @param tokenId The token ID.
|
|
1394
|
+
* @param serialNumber The serial number of the NFT.
|
|
1395
|
+
* @returns A promise that resolves to an NftInfo or null.
|
|
1396
|
+
*/
|
|
1397
|
+
async getNftInfo(tokenId, serialNumber) {
|
|
1398
|
+
this.logger.info(`Getting NFT info for ${tokenId}/${serialNumber}`);
|
|
1399
|
+
const url = `/api/v1/tokens/${tokenId}/nfts/${serialNumber}`;
|
|
1400
|
+
try {
|
|
1401
|
+
const response = await this._requestWithRetry(url);
|
|
1402
|
+
return response;
|
|
1403
|
+
} catch (error) {
|
|
1404
|
+
this.logger.error(
|
|
1405
|
+
`Error fetching NFT info for ${tokenId}/${serialNumber}: ${error.message}`
|
|
1406
|
+
);
|
|
1407
|
+
return null;
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
/**
|
|
1411
|
+
* Retrieves NFTs for a specific token.
|
|
1412
|
+
* @param tokenId The token ID.
|
|
1413
|
+
* @param options Optional parameters for filtering NFTs.
|
|
1414
|
+
* @returns A promise that resolves to an array of NftInfo or null.
|
|
1415
|
+
*/
|
|
1416
|
+
async getNftsByToken(tokenId, options) {
|
|
1417
|
+
this.logger.info(`Getting NFTs for token ${tokenId}`);
|
|
1418
|
+
let url = `/api/v1/tokens/${tokenId}/nfts`;
|
|
1419
|
+
const params = new URLSearchParams();
|
|
1420
|
+
if (options?.accountId) {
|
|
1421
|
+
params.append("account.id", options.accountId);
|
|
1422
|
+
}
|
|
1423
|
+
if (options?.limit) {
|
|
1424
|
+
params.append("limit", options.limit.toString());
|
|
1425
|
+
}
|
|
1426
|
+
if (options?.order) {
|
|
1427
|
+
params.append("order", options.order);
|
|
1428
|
+
}
|
|
1429
|
+
if (options?.serialNumber) {
|
|
1430
|
+
params.append("serialnumber", options.serialNumber);
|
|
1431
|
+
}
|
|
1432
|
+
const queryString = params.toString();
|
|
1433
|
+
if (queryString) {
|
|
1434
|
+
url += `?${queryString}`;
|
|
1435
|
+
}
|
|
1436
|
+
try {
|
|
1437
|
+
const response = await this._requestWithRetry(url);
|
|
1438
|
+
return response.nfts || [];
|
|
1439
|
+
} catch (error) {
|
|
1440
|
+
this.logger.error(
|
|
1441
|
+
`Error fetching NFTs for token ${tokenId}: ${error.message}`
|
|
1442
|
+
);
|
|
1443
|
+
return null;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
/**
|
|
1447
|
+
* Retrieves network information.
|
|
1448
|
+
* @returns A promise that resolves to NetworkInfo or null.
|
|
1449
|
+
*/
|
|
1450
|
+
async getNetworkInfo() {
|
|
1451
|
+
this.logger.info("Getting network information");
|
|
1452
|
+
const url = `/api/v1/network/nodes`;
|
|
1453
|
+
try {
|
|
1454
|
+
const response = await this._requestWithRetry(url);
|
|
1455
|
+
return response;
|
|
1456
|
+
} catch (error) {
|
|
1457
|
+
this.logger.error(`Error fetching network info: ${error.message}`);
|
|
1458
|
+
return null;
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
/**
|
|
1462
|
+
* Retrieves network fees.
|
|
1463
|
+
* @param timestamp Optional timestamp for historical fees.
|
|
1464
|
+
* @returns A promise that resolves to NetworkFees or null.
|
|
1465
|
+
*/
|
|
1466
|
+
async getNetworkFees(timestamp) {
|
|
1467
|
+
this.logger.info("Getting network fees");
|
|
1468
|
+
let url = `/api/v1/network/fees`;
|
|
1469
|
+
if (timestamp) {
|
|
1470
|
+
url += `?timestamp=${timestamp}`;
|
|
1471
|
+
}
|
|
1472
|
+
try {
|
|
1473
|
+
const response = await this._requestWithRetry(url);
|
|
1474
|
+
return response;
|
|
1475
|
+
} catch (error) {
|
|
1476
|
+
this.logger.error(`Error fetching network fees: ${error.message}`);
|
|
1477
|
+
return null;
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Retrieves network supply information.
|
|
1482
|
+
* @param timestamp Optional timestamp for historical supply data.
|
|
1483
|
+
* @returns A promise that resolves to NetworkSupply or null.
|
|
1484
|
+
*/
|
|
1485
|
+
async getNetworkSupply(timestamp) {
|
|
1486
|
+
this.logger.info("Getting network supply");
|
|
1487
|
+
let url = `/api/v1/network/supply`;
|
|
1488
|
+
if (timestamp) {
|
|
1489
|
+
url += `?timestamp=${timestamp}`;
|
|
1490
|
+
}
|
|
1491
|
+
try {
|
|
1492
|
+
const response = await this._requestWithRetry(url);
|
|
1493
|
+
return response;
|
|
1494
|
+
} catch (error) {
|
|
1495
|
+
this.logger.error(`Error fetching network supply: ${error.message}`);
|
|
1496
|
+
return null;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Retrieves network stake information.
|
|
1501
|
+
* @param timestamp Optional timestamp for historical stake data.
|
|
1502
|
+
* @returns A promise that resolves to NetworkStake or null.
|
|
1503
|
+
*/
|
|
1504
|
+
async getNetworkStake(timestamp) {
|
|
1505
|
+
this.logger.info("Getting network stake");
|
|
1506
|
+
let url = `/api/v1/network/stake`;
|
|
1507
|
+
if (timestamp) {
|
|
1508
|
+
url += `?timestamp=${timestamp}`;
|
|
1509
|
+
}
|
|
1510
|
+
try {
|
|
1511
|
+
const response = await this._requestWithRetry(url);
|
|
1512
|
+
return response;
|
|
1513
|
+
} catch (error) {
|
|
1514
|
+
this.logger.error(`Error fetching network stake: ${error.message}`);
|
|
1515
|
+
return null;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Retrieves opcode traces for a specific transaction.
|
|
1520
|
+
* @param transactionIdOrHash The transaction ID or hash.
|
|
1521
|
+
* @param options Optional parameters for trace details.
|
|
1522
|
+
* @returns A promise that resolves to an OpcodesResponse or null.
|
|
1523
|
+
*/
|
|
1524
|
+
async getOpcodeTraces(transactionIdOrHash, options) {
|
|
1525
|
+
this.logger.info(`Getting opcode traces for ${transactionIdOrHash}`);
|
|
1526
|
+
let url = `/api/v1/contracts/results/${transactionIdOrHash}/opcodes`;
|
|
1527
|
+
const params = new URLSearchParams();
|
|
1528
|
+
if (options?.stack !== void 0) {
|
|
1529
|
+
params.append("stack", options.stack.toString());
|
|
1530
|
+
}
|
|
1531
|
+
if (options?.memory !== void 0) {
|
|
1532
|
+
params.append("memory", options.memory.toString());
|
|
1533
|
+
}
|
|
1534
|
+
if (options?.storage !== void 0) {
|
|
1535
|
+
params.append("storage", options.storage.toString());
|
|
1536
|
+
}
|
|
1537
|
+
const queryString = params.toString();
|
|
1538
|
+
if (queryString) {
|
|
1539
|
+
url += `?${queryString}`;
|
|
1540
|
+
}
|
|
1541
|
+
try {
|
|
1542
|
+
const response = await this._requestWithRetry(url);
|
|
1543
|
+
return response;
|
|
1544
|
+
} catch (error) {
|
|
1545
|
+
this.logger.error(
|
|
1546
|
+
`Error fetching opcode traces for ${transactionIdOrHash}: ${error.message}`
|
|
1547
|
+
);
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
835
1551
|
}
|
|
836
1552
|
export {
|
|
837
1553
|
HederaMirrorNode
|