@covalenthq/client-sdk 0.2.9 → 0.4.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/README.md +64 -14
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.js +4619 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/services/BalanceService.d.ts +443 -0
- package/dist/cjs/services/BaseService.d.ts +357 -0
- package/dist/cjs/services/CovalentClient.d.ts +65 -0
- package/dist/cjs/services/NftService.d.ts +484 -0
- package/dist/cjs/services/PricingService.d.ts +88 -0
- package/dist/cjs/services/SecurityService.d.ts +96 -0
- package/dist/cjs/services/TransactionService.d.ts +440 -0
- package/dist/cjs/services/XykService.d.ts +682 -0
- package/dist/cjs/util/ApiHelpers.d.ts +5 -0
- package/dist/cjs/util/backoff.d.ts +11 -0
- package/dist/cjs/util/types/BalanceServiceTypes.d.ts +284 -0
- package/dist/cjs/util/types/BaseServiceTypes.d.ts +180 -0
- package/dist/cjs/util/types/GenericTypes.d.ts +96 -0
- package/dist/cjs/util/types/NftServiceTypes.d.ts +221 -0
- package/dist/cjs/util/types/PricingServiceTypes.d.ts +31 -0
- package/dist/cjs/util/types/SecurityServiceTypes.d.ts +71 -0
- package/dist/cjs/util/types/TransactionServiceTypes.d.ts +312 -0
- package/dist/cjs/util/types/XykServiceTypes.d.ts +479 -0
- package/dist/es/index.d.ts +9 -0
- package/dist/es/index.js +4616 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/services/BalanceService.d.ts +443 -0
- package/dist/es/services/BaseService.d.ts +357 -0
- package/dist/es/services/CovalentClient.d.ts +65 -0
- package/dist/es/services/NftService.d.ts +484 -0
- package/dist/es/services/PricingService.d.ts +88 -0
- package/dist/es/services/SecurityService.d.ts +96 -0
- package/dist/es/services/TransactionService.d.ts +440 -0
- package/dist/es/services/XykService.d.ts +682 -0
- package/dist/es/util/ApiHelpers.d.ts +5 -0
- package/dist/es/util/backoff.d.ts +11 -0
- package/dist/es/util/types/BalanceServiceTypes.d.ts +284 -0
- package/dist/es/util/types/BaseServiceTypes.d.ts +180 -0
- package/dist/es/util/types/GenericTypes.d.ts +96 -0
- package/dist/es/util/types/NftServiceTypes.d.ts +221 -0
- package/dist/es/util/types/PricingServiceTypes.d.ts +31 -0
- package/dist/es/util/types/SecurityServiceTypes.d.ts +71 -0
- package/dist/es/util/types/TransactionServiceTypes.d.ts +312 -0
- package/dist/es/util/types/XykServiceTypes.d.ts +479 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +4616 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/services/BalanceService.d.ts +443 -0
- package/dist/esm/services/BaseService.d.ts +357 -0
- package/dist/esm/services/CovalentClient.d.ts +65 -0
- package/dist/esm/services/NftService.d.ts +484 -0
- package/dist/esm/services/PricingService.d.ts +88 -0
- package/dist/esm/services/SecurityService.d.ts +96 -0
- package/dist/esm/services/TransactionService.d.ts +440 -0
- package/dist/esm/services/XykService.d.ts +682 -0
- package/dist/esm/util/ApiHelpers.d.ts +5 -0
- package/dist/esm/util/backoff.d.ts +11 -0
- package/dist/esm/util/types/BalanceServiceTypes.d.ts +284 -0
- package/dist/esm/util/types/BaseServiceTypes.d.ts +180 -0
- package/dist/esm/util/types/GenericTypes.d.ts +96 -0
- package/dist/esm/util/types/NftServiceTypes.d.ts +221 -0
- package/dist/esm/util/types/PricingServiceTypes.d.ts +31 -0
- package/dist/esm/util/types/SecurityServiceTypes.d.ts +71 -0
- package/dist/esm/util/types/TransactionServiceTypes.d.ts +312 -0
- package/dist/esm/util/types/XykServiceTypes.d.ts +479 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +9 -27
- package/dist/index.js.map +1 -1
- package/dist/services/BalanceService.d.ts +49 -11
- package/dist/services/BalanceService.js +110 -81
- package/dist/services/BalanceService.js.map +1 -1
- package/dist/services/BaseService.d.ts +46 -10
- package/dist/services/BaseService.js +193 -145
- package/dist/services/BaseService.js.map +1 -1
- package/dist/services/CovalentClient.d.ts +65 -0
- package/dist/services/CovalentClient.js +44 -0
- package/dist/services/CovalentClient.js.map +1 -0
- package/dist/services/NftService.d.ts +52 -22
- package/dist/services/NftService.js +236 -235
- package/dist/services/NftService.js.map +1 -1
- package/dist/services/PricingService.d.ts +8 -3
- package/dist/services/PricingService.js +43 -37
- package/dist/services/PricingService.js.map +1 -1
- package/dist/services/SecurityService.d.ts +9 -3
- package/dist/services/SecurityService.js +38 -31
- package/dist/services/SecurityService.js.map +1 -1
- package/dist/services/TransactionService.d.ts +41 -9
- package/dist/services/TransactionService.js +133 -100
- package/dist/services/TransactionService.js.map +1 -1
- package/dist/services/XykService.d.ts +81 -19
- package/dist/services/XykService.js +451 -278
- package/dist/services/XykService.js.map +1 -1
- package/dist/util/ApiHelpers.d.ts +2 -1
- package/dist/util/ApiHelpers.js +57 -36
- package/dist/util/ApiHelpers.js.map +1 -1
- package/dist/util/backoff.d.ts +5 -3
- package/dist/util/backoff.js +35 -13
- package/dist/util/backoff.js.map +1 -1
- package/dist/util/types/BalanceServiceTypes.d.ts +25 -0
- package/dist/util/types/BalanceServiceTypes.js +1 -2
- package/dist/util/types/BaseServiceTypes.d.ts +8 -0
- package/dist/util/types/BaseServiceTypes.js +1 -2
- package/dist/util/types/GenericTypes.d.ts +7 -0
- package/dist/util/types/GenericTypes.js +1 -2
- package/dist/util/types/NftServiceTypes.d.ts +10 -2
- package/dist/util/types/NftServiceTypes.js +1 -2
- package/dist/util/types/PricingServiceTypes.js +1 -2
- package/dist/util/types/SecurityServiceTypes.d.ts +1 -0
- package/dist/util/types/SecurityServiceTypes.js +1 -2
- package/dist/util/types/TransactionServiceTypes.d.ts +14 -2
- package/dist/util/types/TransactionServiceTypes.js +1 -2
- package/dist/util/types/XykServiceTypes.d.ts +20 -6
- package/dist/util/types/XykServiceTypes.js +1 -2
- package/package.json +19 -4
- package/dist/services/Client.d.ts +0 -29
- package/dist/services/Client.js +0 -30
- package/dist/services/Client.js.map +0 -1
|
@@ -0,0 +1,4619 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chalk = require('chalk');
|
|
4
|
+
var dateFns = require('date-fns');
|
|
5
|
+
|
|
6
|
+
const DEFAULT_BACKOFF_MAX_RETRIES = 5;
|
|
7
|
+
const BASE_DELAY_MS = 1000; // Base delay in milliseconds
|
|
8
|
+
class ExponentialBackoff {
|
|
9
|
+
constructor(apiKey, debug, maxRetries = DEFAULT_BACKOFF_MAX_RETRIES) {
|
|
10
|
+
this.maxRetries = maxRetries;
|
|
11
|
+
this.retryCount = 1;
|
|
12
|
+
this._apiKey = apiKey;
|
|
13
|
+
this._debug = debug;
|
|
14
|
+
}
|
|
15
|
+
async backOff(url) {
|
|
16
|
+
try {
|
|
17
|
+
let startTime;
|
|
18
|
+
if (this._debug) {
|
|
19
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
20
|
+
}
|
|
21
|
+
const response = await fetch(url, {
|
|
22
|
+
headers: {
|
|
23
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
24
|
+
"X-Requested-With": userAgent
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
debugOutput(response.url, response.status, startTime);
|
|
28
|
+
if (response.status === 429) {
|
|
29
|
+
throw new Error(`Received status code: ${response.status}`);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
return response.json();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (error.message.includes(`Received status code: 429`) && this.retryCount < this.maxRetries) {
|
|
37
|
+
this.retryCount++;
|
|
38
|
+
const delayMs = Math.pow(2, this.retryCount) * BASE_DELAY_MS;
|
|
39
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
40
|
+
return this.backOff(url);
|
|
41
|
+
}
|
|
42
|
+
return Promise.reject(new Error(`Max retries exceeded: ${this.maxRetries}`));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// to reset the numAttempts for another request
|
|
46
|
+
setNumAttempts(retryCount) {
|
|
47
|
+
this.retryCount = retryCount;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getDefaultExportFromCjs (x) {
|
|
52
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class Node {
|
|
56
|
+
/// value;
|
|
57
|
+
/// next;
|
|
58
|
+
|
|
59
|
+
constructor(value) {
|
|
60
|
+
this.value = value;
|
|
61
|
+
|
|
62
|
+
// TODO: Remove this when targeting Node.js 12.
|
|
63
|
+
this.next = undefined;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let Queue$1 = class Queue {
|
|
68
|
+
// TODO: Use private class fields when targeting Node.js 12.
|
|
69
|
+
// #_head;
|
|
70
|
+
// #_tail;
|
|
71
|
+
// #_size;
|
|
72
|
+
|
|
73
|
+
constructor() {
|
|
74
|
+
this.clear();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
enqueue(value) {
|
|
78
|
+
const node = new Node(value);
|
|
79
|
+
|
|
80
|
+
if (this._head) {
|
|
81
|
+
this._tail.next = node;
|
|
82
|
+
this._tail = node;
|
|
83
|
+
} else {
|
|
84
|
+
this._head = node;
|
|
85
|
+
this._tail = node;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
this._size++;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
dequeue() {
|
|
92
|
+
const current = this._head;
|
|
93
|
+
if (!current) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
this._head = this._head.next;
|
|
98
|
+
this._size--;
|
|
99
|
+
return current.value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
clear() {
|
|
103
|
+
this._head = undefined;
|
|
104
|
+
this._tail = undefined;
|
|
105
|
+
this._size = 0;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get size() {
|
|
109
|
+
return this._size;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
* [Symbol.iterator]() {
|
|
113
|
+
let current = this._head;
|
|
114
|
+
|
|
115
|
+
while (current) {
|
|
116
|
+
yield current.value;
|
|
117
|
+
current = current.next;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
var yoctoQueue = Queue$1;
|
|
123
|
+
|
|
124
|
+
const Queue = yoctoQueue;
|
|
125
|
+
|
|
126
|
+
const pLimit = concurrency => {
|
|
127
|
+
if (!((Number.isInteger(concurrency) || concurrency === Infinity) && concurrency > 0)) {
|
|
128
|
+
throw new TypeError('Expected `concurrency` to be a number from 1 and up');
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const queue = new Queue();
|
|
132
|
+
let activeCount = 0;
|
|
133
|
+
|
|
134
|
+
const next = () => {
|
|
135
|
+
activeCount--;
|
|
136
|
+
|
|
137
|
+
if (queue.size > 0) {
|
|
138
|
+
queue.dequeue()();
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const run = async (fn, resolve, ...args) => {
|
|
143
|
+
activeCount++;
|
|
144
|
+
|
|
145
|
+
const result = (async () => fn(...args))();
|
|
146
|
+
|
|
147
|
+
resolve(result);
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
await result;
|
|
151
|
+
} catch {}
|
|
152
|
+
|
|
153
|
+
next();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
const enqueue = (fn, resolve, ...args) => {
|
|
157
|
+
queue.enqueue(run.bind(null, fn, resolve, ...args));
|
|
158
|
+
|
|
159
|
+
(async () => {
|
|
160
|
+
// This function needs to wait until the next microtask before comparing
|
|
161
|
+
// `activeCount` to `concurrency`, because `activeCount` is updated asynchronously
|
|
162
|
+
// when the run function is dequeued and called. The comparison in the if-statement
|
|
163
|
+
// needs to happen asynchronously as well to get an up-to-date value for `activeCount`.
|
|
164
|
+
await Promise.resolve();
|
|
165
|
+
|
|
166
|
+
if (activeCount < concurrency && queue.size > 0) {
|
|
167
|
+
queue.dequeue()();
|
|
168
|
+
}
|
|
169
|
+
})();
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const generator = (fn, ...args) => new Promise(resolve => {
|
|
173
|
+
enqueue(fn, resolve, ...args);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
Object.defineProperties(generator, {
|
|
177
|
+
activeCount: {
|
|
178
|
+
get: () => activeCount
|
|
179
|
+
},
|
|
180
|
+
pendingCount: {
|
|
181
|
+
get: () => queue.size
|
|
182
|
+
},
|
|
183
|
+
clearQueue: {
|
|
184
|
+
value: () => {
|
|
185
|
+
queue.clear();
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
return generator;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
var pLimit_1 = pLimit;
|
|
194
|
+
|
|
195
|
+
var pLimit$1 = /*@__PURE__*/getDefaultExportFromCjs(pLimit_1);
|
|
196
|
+
|
|
197
|
+
function checkAndModifyResponse(jsonObj) {
|
|
198
|
+
for (const key in jsonObj) {
|
|
199
|
+
if (key === 'next_update_at') {
|
|
200
|
+
delete jsonObj[key];
|
|
201
|
+
}
|
|
202
|
+
else if (typeof jsonObj[key] === 'object') {
|
|
203
|
+
checkAndModifyResponse(jsonObj[key]);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
async function debugOutput(url, responseStatus, startTime) {
|
|
208
|
+
let endTime;
|
|
209
|
+
let elapsedTime;
|
|
210
|
+
if (startTime === undefined) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (typeof startTime !== 'number') {
|
|
214
|
+
endTime = process.hrtime(startTime);
|
|
215
|
+
elapsedTime = (endTime[0] * 1000 + endTime[1] / 1e6);
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
endTime = performance.now();
|
|
219
|
+
elapsedTime = endTime - startTime;
|
|
220
|
+
}
|
|
221
|
+
console.log(`${chalk.red("[DEBUG]")}` + " |" + ` Request URL: ${chalk.yellow(url)}` + " |" + ` Response code: ${responseStatus !== 200 ? chalk.red(responseStatus) : chalk.green(responseStatus)}` + " |" + ` Response time: ${chalk.cyan(elapsedTime.toFixed(2) + "ms")}`);
|
|
222
|
+
}
|
|
223
|
+
async function* paginateEndpoint$1(url, apiKey, urlsParams, dataClassConstructor, debug, threadCount) {
|
|
224
|
+
let hasNext = true;
|
|
225
|
+
let response;
|
|
226
|
+
let data;
|
|
227
|
+
const backoff = new ExponentialBackoff(apiKey, debug);
|
|
228
|
+
let page_number = 0;
|
|
229
|
+
const LIMIT = pLimit$1(threadCount);
|
|
230
|
+
while (hasNext) {
|
|
231
|
+
try {
|
|
232
|
+
let startTime;
|
|
233
|
+
if (debug) {
|
|
234
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
235
|
+
}
|
|
236
|
+
response = await LIMIT(() => fetch(urlsParams.get("page-number") ? `${url}?${urlsParams}` : `${url}?${urlsParams}&page-number=${page_number}`, {
|
|
237
|
+
headers: {
|
|
238
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
239
|
+
"X-Requested-With": userAgent
|
|
240
|
+
}
|
|
241
|
+
}));
|
|
242
|
+
debugOutput(response.url, response.status, startTime);
|
|
243
|
+
if (response.status === 429) {
|
|
244
|
+
try {
|
|
245
|
+
data = await LIMIT(() => backoff.backOff(response.url));
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
hasNext = false;
|
|
249
|
+
throw new Error(`An error occurred ${response.status}: ${error.message}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
data = await response.json();
|
|
254
|
+
}
|
|
255
|
+
for (const tx of data.data.items) {
|
|
256
|
+
const dataClass = new dataClassConstructor(tx);
|
|
257
|
+
checkAndModifyResponse(dataClass);
|
|
258
|
+
yield dataClass;
|
|
259
|
+
}
|
|
260
|
+
backoff.setNumAttempts(1);
|
|
261
|
+
if (!data.error) {
|
|
262
|
+
if ((data.data !== null) && data.data.pagination !== null && data.data.pagination.has_more === false) {
|
|
263
|
+
hasNext = false;
|
|
264
|
+
}
|
|
265
|
+
if (urlsParams.get("page-number")) {
|
|
266
|
+
const next_page = parseInt(urlsParams.get("page-number")) + 1;
|
|
267
|
+
urlsParams.set("page-number", next_page.toString());
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
page_number = page_number + 1;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
else {
|
|
274
|
+
hasNext = false;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
hasNext = false;
|
|
279
|
+
if (error.message.includes("An error occurred 429")) {
|
|
280
|
+
throw new Error(error.message);
|
|
281
|
+
}
|
|
282
|
+
throw new Error(`An error occurred ${data ? data.error_code : response.status}: ${data ? data.error_message : "401 Authorization Required"}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
class ApprovalsResponse {
|
|
288
|
+
constructor(data) {
|
|
289
|
+
this.address = data.address;
|
|
290
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
291
|
+
this.quote_currency = data.quote_currency;
|
|
292
|
+
this.chain_id = data.chain_id;
|
|
293
|
+
this.chain_name = data.chain_name;
|
|
294
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new TokensApprovalItem(itemData)) : null;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
class TokensApprovalItem {
|
|
298
|
+
constructor(data) {
|
|
299
|
+
this.token_address = data.token_address;
|
|
300
|
+
this.token_address_label = data.token_address_label;
|
|
301
|
+
this.ticker_symbol = data.ticker_symbol;
|
|
302
|
+
this.contract_decimals = data.contract_decimals;
|
|
303
|
+
this.logo_url = data.logo_url;
|
|
304
|
+
this.quote_rate = data.quote_rate;
|
|
305
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
306
|
+
this.balance_quote = data.balance_quote;
|
|
307
|
+
this.pretty_balance_quote = data.pretty_balance_quote;
|
|
308
|
+
this.value_at_risk = data.value_at_risk;
|
|
309
|
+
this.value_at_risk_quote = data.value_at_risk_quote;
|
|
310
|
+
this.pretty_value_at_risk_quote = data.pretty_value_at_risk_quote;
|
|
311
|
+
this.spenders = data.spenders && data.spenders !== null ? data.spenders.map((itemData) => new TokenSpenderItem(itemData)) : null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
class TokenSpenderItem {
|
|
315
|
+
constructor(data) {
|
|
316
|
+
this.block_height = data.block_height;
|
|
317
|
+
this.tx_offset = data.tx_offset;
|
|
318
|
+
this.log_offset = data.log_offset;
|
|
319
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
320
|
+
this.tx_hash = data.tx_hash;
|
|
321
|
+
this.spender_address = data.spender_address;
|
|
322
|
+
this.spender_address_label = data.spender_address_label;
|
|
323
|
+
this.allowance = data.allowance;
|
|
324
|
+
this.allowance_quote = data.allowance_quote;
|
|
325
|
+
this.pretty_allowance_quote = data.pretty_allowance_quote;
|
|
326
|
+
this.value_at_risk = data.value_at_risk;
|
|
327
|
+
this.value_at_risk_quote = data.value_at_risk_quote;
|
|
328
|
+
this.pretty_value_at_risk_quote = data.pretty_value_at_risk_quote;
|
|
329
|
+
this.risk_factor = data.risk_factor;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Approvals API
|
|
334
|
+
*
|
|
335
|
+
*/
|
|
336
|
+
class SecurityService {
|
|
337
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
338
|
+
this.apiKey = apiKey;
|
|
339
|
+
this.debug = debug;
|
|
340
|
+
this.threadCount = threadCount;
|
|
341
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
*
|
|
345
|
+
* Commonly used to get a list of approvals across all token contracts categorized by spenders for a wallet’s assets.
|
|
346
|
+
*
|
|
347
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
348
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
349
|
+
*
|
|
350
|
+
*/
|
|
351
|
+
async getApprovals(chainName, walletAddress) {
|
|
352
|
+
let success = false;
|
|
353
|
+
let data;
|
|
354
|
+
let response;
|
|
355
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
356
|
+
while (!success) {
|
|
357
|
+
try {
|
|
358
|
+
const urlParams = new URLSearchParams();
|
|
359
|
+
let startTime;
|
|
360
|
+
if (this.debug) {
|
|
361
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
362
|
+
}
|
|
363
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/approvals/${walletAddress}/?${urlParams}`, {
|
|
364
|
+
headers: {
|
|
365
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
366
|
+
"X-Requested-With": userAgent
|
|
367
|
+
}
|
|
368
|
+
}));
|
|
369
|
+
debugOutput(response.url, response.status, startTime);
|
|
370
|
+
if (response.status === 429) {
|
|
371
|
+
try {
|
|
372
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
success = true;
|
|
376
|
+
return {
|
|
377
|
+
data: null,
|
|
378
|
+
error: true,
|
|
379
|
+
error_code: response.status,
|
|
380
|
+
error_message: error.message
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
data = await response.json();
|
|
386
|
+
}
|
|
387
|
+
const dataClass = new ApprovalsResponse(data.data);
|
|
388
|
+
checkAndModifyResponse(dataClass);
|
|
389
|
+
success = true;
|
|
390
|
+
return {
|
|
391
|
+
data: dataClass,
|
|
392
|
+
error: data.error,
|
|
393
|
+
error_code: data ? data.error_code : response.status,
|
|
394
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
success = true;
|
|
399
|
+
return {
|
|
400
|
+
data: null,
|
|
401
|
+
error: true,
|
|
402
|
+
error_code: data ? data.error_code : response.status,
|
|
403
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
class BalancesResponse {
|
|
411
|
+
constructor(data) {
|
|
412
|
+
this.address = data.address;
|
|
413
|
+
this.chain_id = data.chain_id;
|
|
414
|
+
this.chain_name = data.chain_name;
|
|
415
|
+
this.quote_currency = data.quote_currency;
|
|
416
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
417
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new BalanceItem(itemData)) : null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
class BalanceItem {
|
|
421
|
+
constructor(data) {
|
|
422
|
+
this.contract_decimals = data.contract_decimals;
|
|
423
|
+
this.contract_name = data.contract_name;
|
|
424
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
425
|
+
this.contract_address = data.contract_address;
|
|
426
|
+
this.supports_erc = data.supports_erc;
|
|
427
|
+
this.logo_url = data.logo_url;
|
|
428
|
+
this.last_transferred_at = data.last_transferred_at && data.last_transferred_at !== null ? dateFns.parseISO(data.last_transferred_at.toString()) : null;
|
|
429
|
+
this.native_token = data.native_token;
|
|
430
|
+
this.type = data.type;
|
|
431
|
+
this.is_spam = data.is_spam;
|
|
432
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
433
|
+
this.balance_24h = data.balance_24h && data.balance_24h !== null ? BigInt(data.balance_24h) : null;
|
|
434
|
+
this.quote_rate = data.quote_rate;
|
|
435
|
+
this.quote_rate_24h = data.quote_rate_24h;
|
|
436
|
+
this.quote = data.quote;
|
|
437
|
+
this.quote_24h = data.quote_24h;
|
|
438
|
+
this.pretty_quote = data.pretty_quote;
|
|
439
|
+
this.pretty_quote_24h = data.pretty_quote_24h;
|
|
440
|
+
this.nft_data = data.nft_data && data.nft_data !== null ? data.nft_data.map((itemData) => new NftData$1(itemData)) : null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
let NftData$1 = class NftData {
|
|
444
|
+
constructor(data) {
|
|
445
|
+
this.token_id = data.token_id && data.token_id !== null ? BigInt(data.token_id) : null;
|
|
446
|
+
this.token_url = data.token_url;
|
|
447
|
+
this.original_owner = data.original_owner;
|
|
448
|
+
this.asset_cached = data.asset_cached;
|
|
449
|
+
this.image_cached = data.image_cached;
|
|
450
|
+
this.external_data = data.external_data && data.external_data !== null ? new NftExternalData$1(data.external_data) : null;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
let NftExternalData$1 = class NftExternalData {
|
|
454
|
+
constructor(data) {
|
|
455
|
+
this.name = data.name;
|
|
456
|
+
this.description = data.description;
|
|
457
|
+
this.asset_url = data.asset_url;
|
|
458
|
+
this.asset_file_extension = data.asset_file_extension;
|
|
459
|
+
this.asset_mime_type = data.asset_mime_type;
|
|
460
|
+
this.asset_size_bytes = data.asset_size_bytes;
|
|
461
|
+
this.image = data.image;
|
|
462
|
+
this.image_256 = data.image_256;
|
|
463
|
+
this.image_512 = data.image_512;
|
|
464
|
+
this.image_1024 = data.image_1024;
|
|
465
|
+
this.animation_url = data.animation_url;
|
|
466
|
+
this.external_url = data.external_url;
|
|
467
|
+
this.attributes = data.attributes && data.attributes !== null ? data.attributes.map((itemData) => new NftCollectionAttribute$1(itemData)) : null;
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
let NftCollectionAttribute$1 = class NftCollectionAttribute {
|
|
471
|
+
constructor(data) {
|
|
472
|
+
this.trait_type = data.trait_type;
|
|
473
|
+
this.value = data.value;
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
class PortfolioResponse {
|
|
477
|
+
constructor(data) {
|
|
478
|
+
this.address = data.address;
|
|
479
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
480
|
+
this.quote_currency = data.quote_currency;
|
|
481
|
+
this.chain_id = data.chain_id;
|
|
482
|
+
this.chain_name = data.chain_name;
|
|
483
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new PortfolioItem(itemData)) : null;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
class PortfolioItem {
|
|
487
|
+
constructor(data) {
|
|
488
|
+
this.contract_address = data.contract_address;
|
|
489
|
+
this.contract_decimals = data.contract_decimals;
|
|
490
|
+
this.contract_name = data.contract_name;
|
|
491
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
492
|
+
this.logo_url = data.logo_url;
|
|
493
|
+
this.holdings = data.holdings && data.holdings !== null ? data.holdings.map((itemData) => new HoldingItem(itemData)) : null;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
class HoldingItem {
|
|
497
|
+
constructor(data) {
|
|
498
|
+
this.quote_rate = data.quote_rate;
|
|
499
|
+
this.timestamp = data.timestamp && data.timestamp !== null ? dateFns.parseISO(data.timestamp.toString()) : null;
|
|
500
|
+
this.close = data.close && data.close !== null ? new OhlcItem(data.close) : null;
|
|
501
|
+
this.high = data.high && data.high !== null ? new OhlcItem(data.high) : null;
|
|
502
|
+
this.low = data.low && data.low !== null ? new OhlcItem(data.low) : null;
|
|
503
|
+
this.open = data.open && data.open !== null ? new OhlcItem(data.open) : null;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
class OhlcItem {
|
|
507
|
+
constructor(data) {
|
|
508
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
509
|
+
this.quote = data.quote;
|
|
510
|
+
this.pretty_quote = data.pretty_quote;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
class BlockTransactionWithContractTransfers {
|
|
514
|
+
constructor(data) {
|
|
515
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
516
|
+
this.block_height = data.block_height;
|
|
517
|
+
this.tx_hash = data.tx_hash;
|
|
518
|
+
this.tx_offset = data.tx_offset;
|
|
519
|
+
this.successful = data.successful;
|
|
520
|
+
this.from_address = data.from_address;
|
|
521
|
+
this.from_address_label = data.from_address_label;
|
|
522
|
+
this.to_address = data.to_address;
|
|
523
|
+
this.to_address_label = data.to_address_label;
|
|
524
|
+
this.value = data.value && data.value !== null ? BigInt(data.value) : null;
|
|
525
|
+
this.value_quote = data.value_quote;
|
|
526
|
+
this.pretty_value_quote = data.pretty_value_quote;
|
|
527
|
+
this.gas_offered = data.gas_offered;
|
|
528
|
+
this.gas_spent = data.gas_spent;
|
|
529
|
+
this.gas_price = data.gas_price;
|
|
530
|
+
this.fees_paid = data.fees_paid && data.fees_paid !== null ? BigInt(data.fees_paid) : null;
|
|
531
|
+
this.gas_quote = data.gas_quote;
|
|
532
|
+
this.pretty_gas_quote = data.pretty_gas_quote;
|
|
533
|
+
this.gas_quote_rate = data.gas_quote_rate;
|
|
534
|
+
this.transfers = data.transfers && data.transfers !== null ? data.transfers.map((itemData) => new TokenTransferItem(itemData)) : null;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
class TokenTransferItem {
|
|
538
|
+
constructor(data) {
|
|
539
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
540
|
+
this.tx_hash = data.tx_hash;
|
|
541
|
+
this.from_address = data.from_address;
|
|
542
|
+
this.from_address_label = data.from_address_label;
|
|
543
|
+
this.to_address = data.to_address;
|
|
544
|
+
this.to_address_label = data.to_address_label;
|
|
545
|
+
this.contract_decimals = data.contract_decimals;
|
|
546
|
+
this.contract_name = data.contract_name;
|
|
547
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
548
|
+
this.contract_address = data.contract_address;
|
|
549
|
+
this.logo_url = data.logo_url;
|
|
550
|
+
this.transfer_type = data.transfer_type;
|
|
551
|
+
this.delta = data.delta && data.delta !== null ? BigInt(data.delta) : null;
|
|
552
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
553
|
+
this.quote_rate = data.quote_rate;
|
|
554
|
+
this.delta_quote = data.delta_quote;
|
|
555
|
+
this.pretty_delta_quote = data.pretty_delta_quote;
|
|
556
|
+
this.balance_quote = data.balance_quote;
|
|
557
|
+
this.method_calls = data.method_calls && data.method_calls !== null ? data.method_calls.map((itemData) => new MethodCallsForTransfers(itemData)) : null;
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
class MethodCallsForTransfers {
|
|
561
|
+
constructor(data) {
|
|
562
|
+
this.sender_address = data.sender_address;
|
|
563
|
+
this.method = data.method;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
class TokenHolder {
|
|
567
|
+
constructor(data) {
|
|
568
|
+
this.contract_decimals = data.contract_decimals;
|
|
569
|
+
this.contract_name = data.contract_name;
|
|
570
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
571
|
+
this.contract_address = data.contract_address;
|
|
572
|
+
this.supports_erc = data.supports_erc;
|
|
573
|
+
this.logo_url = data.logo_url;
|
|
574
|
+
this.address = data.address;
|
|
575
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
576
|
+
this.total_supply = data.total_supply && data.total_supply !== null ? BigInt(data.total_supply) : null;
|
|
577
|
+
this.block_height = data.block_height;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
class HistoricalBalancesResponse {
|
|
581
|
+
constructor(data) {
|
|
582
|
+
this.address = data.address;
|
|
583
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
584
|
+
this.quote_currency = data.quote_currency;
|
|
585
|
+
this.chain_id = data.chain_id;
|
|
586
|
+
this.chain_name = data.chain_name;
|
|
587
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new HistoricalBalanceItem(itemData)) : null;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
class HistoricalBalanceItem {
|
|
591
|
+
constructor(data) {
|
|
592
|
+
this.contract_decimals = data.contract_decimals;
|
|
593
|
+
this.contract_name = data.contract_name;
|
|
594
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
595
|
+
this.contract_address = data.contract_address;
|
|
596
|
+
this.supports_erc = data.supports_erc;
|
|
597
|
+
this.logo_url = data.logo_url;
|
|
598
|
+
this.block_height = data.block_height;
|
|
599
|
+
this.last_transferred_block_height = data.last_transferred_block_height;
|
|
600
|
+
this.last_transferred_at = data.last_transferred_at && data.last_transferred_at !== null ? dateFns.parseISO(data.last_transferred_at.toString()) : null;
|
|
601
|
+
this.native_token = data.native_token;
|
|
602
|
+
this.type = data.type;
|
|
603
|
+
this.is_spam = data.is_spam;
|
|
604
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
605
|
+
this.quote_rate = data.quote_rate;
|
|
606
|
+
this.quote = data.quote;
|
|
607
|
+
this.pretty_quote = data.pretty_quote;
|
|
608
|
+
this.nft_data = data.nft_data && data.nft_data !== null ? data.nft_data.map((itemData) => new NftData$1(itemData)) : null;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Balances APIs
|
|
613
|
+
*
|
|
614
|
+
*/
|
|
615
|
+
class BalanceService {
|
|
616
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
617
|
+
this.apiKey = apiKey;
|
|
618
|
+
this.debug = debug;
|
|
619
|
+
this.threadCount = threadCount;
|
|
620
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
*
|
|
624
|
+
* Commonly used to fetch the native, fungible (ERC20), and non-fungible (ERC721 & ERC1155) tokens held by an address. Response includes spot prices and other metadata.
|
|
625
|
+
*
|
|
626
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
627
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
628
|
+
* @param {GetTokenBalancesForWalletAddressQueryParamOpts} queryParamOpts
|
|
629
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
630
|
+
* - `nft`: If `true`, NFTs will be included in the response.
|
|
631
|
+
* - `noNftFetch`: If `true`, only NFTs that have been cached will be included in the response. Helpful for faster response times.
|
|
632
|
+
* - `noSpam`: If `true`, the suspected spam tokens are removed. Supports `eth-mainnet` and `matic-mainnet`.
|
|
633
|
+
* - `noNftAssetMetadata`: If `true`, the response shape is limited to a list of collections and token ids, omitting metadata and asset information. Helpful for faster response times and wallets holding a large number of NFTs.
|
|
634
|
+
*
|
|
635
|
+
*/
|
|
636
|
+
async getTokenBalancesForWalletAddress(chainName, walletAddress, queryParamOpts) {
|
|
637
|
+
let success = false;
|
|
638
|
+
let data;
|
|
639
|
+
let response;
|
|
640
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
641
|
+
while (!success) {
|
|
642
|
+
try {
|
|
643
|
+
const urlParams = new URLSearchParams();
|
|
644
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
645
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
646
|
+
}
|
|
647
|
+
if (queryParamOpts?.nft !== undefined) {
|
|
648
|
+
urlParams.append("nft", queryParamOpts?.nft.toString());
|
|
649
|
+
}
|
|
650
|
+
if (queryParamOpts?.noNftFetch !== undefined) {
|
|
651
|
+
urlParams.append("no-nft-fetch", queryParamOpts?.noNftFetch.toString());
|
|
652
|
+
}
|
|
653
|
+
if (queryParamOpts?.noSpam !== undefined) {
|
|
654
|
+
urlParams.append("no-spam", queryParamOpts?.noSpam.toString());
|
|
655
|
+
}
|
|
656
|
+
if (queryParamOpts?.noNftAssetMetadata !== undefined) {
|
|
657
|
+
urlParams.append("no-nft-asset-metadata", queryParamOpts?.noNftAssetMetadata.toString());
|
|
658
|
+
}
|
|
659
|
+
let startTime;
|
|
660
|
+
if (this.debug) {
|
|
661
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
662
|
+
}
|
|
663
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/balances_v2/?${urlParams}`, {
|
|
664
|
+
headers: {
|
|
665
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
666
|
+
"X-Requested-With": userAgent
|
|
667
|
+
}
|
|
668
|
+
}));
|
|
669
|
+
debugOutput(response.url, response.status, startTime);
|
|
670
|
+
if (response.status === 429) {
|
|
671
|
+
try {
|
|
672
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
673
|
+
}
|
|
674
|
+
catch (error) {
|
|
675
|
+
success = true;
|
|
676
|
+
return {
|
|
677
|
+
data: null,
|
|
678
|
+
error: true,
|
|
679
|
+
error_code: response.status,
|
|
680
|
+
error_message: error.message
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
data = await response.json();
|
|
686
|
+
}
|
|
687
|
+
const dataClass = new BalancesResponse(data.data);
|
|
688
|
+
checkAndModifyResponse(dataClass);
|
|
689
|
+
success = true;
|
|
690
|
+
return {
|
|
691
|
+
data: dataClass,
|
|
692
|
+
error: data.error,
|
|
693
|
+
error_code: data ? data.error_code : response.status,
|
|
694
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
catch (error) {
|
|
698
|
+
success = true;
|
|
699
|
+
return {
|
|
700
|
+
data: null,
|
|
701
|
+
error: true,
|
|
702
|
+
error_code: data ? data.error_code : response.status,
|
|
703
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
*
|
|
710
|
+
* Commonly used to render a daily portfolio balance for an address broken down by the token. The timeframe is user-configurable, defaults to 30 days.
|
|
711
|
+
*
|
|
712
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
713
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
714
|
+
* @param {GetHistoricalPortfolioForWalletAddressQueryParamOpts} queryParamOpts
|
|
715
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
716
|
+
* - `days`: The number of days to return data for. Defaults to 30 days.
|
|
717
|
+
*
|
|
718
|
+
*/
|
|
719
|
+
async getHistoricalPortfolioForWalletAddress(chainName, walletAddress, queryParamOpts) {
|
|
720
|
+
let success = false;
|
|
721
|
+
let data;
|
|
722
|
+
let response;
|
|
723
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
724
|
+
while (!success) {
|
|
725
|
+
try {
|
|
726
|
+
const urlParams = new URLSearchParams();
|
|
727
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
728
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
729
|
+
}
|
|
730
|
+
if (queryParamOpts?.days !== undefined) {
|
|
731
|
+
urlParams.append("days", queryParamOpts?.days.toString());
|
|
732
|
+
}
|
|
733
|
+
let startTime;
|
|
734
|
+
if (this.debug) {
|
|
735
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
736
|
+
}
|
|
737
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/portfolio_v2/?${urlParams}`, {
|
|
738
|
+
headers: {
|
|
739
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
740
|
+
"X-Requested-With": userAgent
|
|
741
|
+
}
|
|
742
|
+
}));
|
|
743
|
+
debugOutput(response.url, response.status, startTime);
|
|
744
|
+
if (response.status === 429) {
|
|
745
|
+
try {
|
|
746
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
747
|
+
}
|
|
748
|
+
catch (error) {
|
|
749
|
+
success = true;
|
|
750
|
+
return {
|
|
751
|
+
data: null,
|
|
752
|
+
error: true,
|
|
753
|
+
error_code: response.status,
|
|
754
|
+
error_message: error.message
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
data = await response.json();
|
|
760
|
+
}
|
|
761
|
+
const dataClass = new PortfolioResponse(data.data);
|
|
762
|
+
checkAndModifyResponse(dataClass);
|
|
763
|
+
success = true;
|
|
764
|
+
return {
|
|
765
|
+
data: dataClass,
|
|
766
|
+
error: data.error,
|
|
767
|
+
error_code: data ? data.error_code : response.status,
|
|
768
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
catch (error) {
|
|
772
|
+
success = true;
|
|
773
|
+
return {
|
|
774
|
+
data: null,
|
|
775
|
+
error: true,
|
|
776
|
+
error_code: data ? data.error_code : response.status,
|
|
777
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
*
|
|
784
|
+
* Commonly used to render the transfer-in and transfer-out of a token along with historical prices from an address.
|
|
785
|
+
*
|
|
786
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
787
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
788
|
+
* @param {GetErc20TransfersForWalletAddressQueryParamOpts} queryParamOpts
|
|
789
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
790
|
+
* - `contractAddress`: The requested contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
791
|
+
* - `startingBlock`: The block height to start from, defaults to `0`.
|
|
792
|
+
* - `endingBlock`: The block height to end at, defaults to current block height.
|
|
793
|
+
* - `pageSize`: Number of items per page. Omitting this parameter defaults to 100.
|
|
794
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
795
|
+
*
|
|
796
|
+
*/
|
|
797
|
+
async *getErc20TransfersForWalletAddress(chainName, walletAddress, queryParamOpts) {
|
|
798
|
+
let success = false;
|
|
799
|
+
let res;
|
|
800
|
+
while (!success) {
|
|
801
|
+
try {
|
|
802
|
+
const urlParams = new URLSearchParams();
|
|
803
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
804
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
805
|
+
}
|
|
806
|
+
if (queryParamOpts?.contractAddress !== undefined) {
|
|
807
|
+
urlParams.append("contract-address", queryParamOpts?.contractAddress.toString());
|
|
808
|
+
}
|
|
809
|
+
if (queryParamOpts?.startingBlock !== undefined) {
|
|
810
|
+
urlParams.append("starting-block", queryParamOpts?.startingBlock.toString());
|
|
811
|
+
}
|
|
812
|
+
if (queryParamOpts?.endingBlock !== undefined) {
|
|
813
|
+
urlParams.append("ending-block", queryParamOpts?.endingBlock.toString());
|
|
814
|
+
}
|
|
815
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
816
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
817
|
+
}
|
|
818
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
819
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
820
|
+
}
|
|
821
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/transfers_v2/`, this.apiKey, urlParams, BlockTransactionWithContractTransfers, this.debug, this.threadCount)) {
|
|
822
|
+
yield res;
|
|
823
|
+
}
|
|
824
|
+
success = true;
|
|
825
|
+
}
|
|
826
|
+
catch (error) {
|
|
827
|
+
success = true;
|
|
828
|
+
throw new Error(error.message);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
*
|
|
834
|
+
* Commonly used to get a list of all the token holders for a specified ERC20 or ERC721 token. Returns historic token holders when block-height is set (defaults to `latest`). Useful for building pie charts of token holders.
|
|
835
|
+
*
|
|
836
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
837
|
+
* @param {string} tokenAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
838
|
+
* @param {GetTokenHoldersV2ForTokenAddressQueryParamOpts} queryParamOpts
|
|
839
|
+
* - `blockHeight`: Ending block to define a block range. Omitting this parameter defaults to the latest block height.
|
|
840
|
+
* - `pageSize`: Number of items per page. Note: Currently, only values of `100` and `1000` are supported. Omitting this parameter defaults to 100.
|
|
841
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
842
|
+
*
|
|
843
|
+
*/
|
|
844
|
+
async *getTokenHoldersV2ForTokenAddress(chainName, tokenAddress, queryParamOpts) {
|
|
845
|
+
let success = false;
|
|
846
|
+
let res;
|
|
847
|
+
while (!success) {
|
|
848
|
+
try {
|
|
849
|
+
const urlParams = new URLSearchParams();
|
|
850
|
+
if (queryParamOpts?.blockHeight !== undefined) {
|
|
851
|
+
urlParams.append("block-height", queryParamOpts?.blockHeight.toString());
|
|
852
|
+
}
|
|
853
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
854
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
855
|
+
}
|
|
856
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
857
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
858
|
+
}
|
|
859
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/tokens/${tokenAddress}/token_holders_v2/`, this.apiKey, urlParams, TokenHolder, this.debug, this.threadCount)) {
|
|
860
|
+
yield res;
|
|
861
|
+
}
|
|
862
|
+
success = true;
|
|
863
|
+
}
|
|
864
|
+
catch (error) {
|
|
865
|
+
success = true;
|
|
866
|
+
throw new Error(error.message);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
870
|
+
/**
|
|
871
|
+
*
|
|
872
|
+
* Commonly used to fetch the historical native, fungible (ERC20), and non-fungible (ERC721 & ERC1155) tokens held by an address at a given block height or date. Response includes daily prices and other metadata.
|
|
873
|
+
*
|
|
874
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
875
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
876
|
+
* @param {GetHistoricalTokenBalancesForWalletAddressQueryParamOpts} queryParamOpts
|
|
877
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
878
|
+
* - `nft`: If `true`, NFTs will be included in the response.
|
|
879
|
+
* - `noNftFetch`: If `true`, only NFTs that have been cached will be included in the response. Helpful for faster response times.
|
|
880
|
+
* - `noSpam`: If `true`, the suspected spam tokens are removed. Supports `eth-mainnet` and `matic-mainnet`.
|
|
881
|
+
* - `noNftAssetMetadata`: If `true`, the response shape is limited to a list of collections and token ids, omitting metadata and asset information. Helpful for faster response times and wallets holding a large number of NFTs.
|
|
882
|
+
* - `blockHeight`: Ending block to define a block range. Omitting this parameter defaults to the latest block height.
|
|
883
|
+
* - `date`: Ending date to define a block range (YYYY-MM-DD). Omitting this parameter defaults to the current date.
|
|
884
|
+
*
|
|
885
|
+
*/
|
|
886
|
+
async getHistoricalTokenBalancesForWalletAddress(chainName, walletAddress, queryParamOpts) {
|
|
887
|
+
let success = false;
|
|
888
|
+
let data;
|
|
889
|
+
let response;
|
|
890
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
891
|
+
while (!success) {
|
|
892
|
+
try {
|
|
893
|
+
const urlParams = new URLSearchParams();
|
|
894
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
895
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
896
|
+
}
|
|
897
|
+
if (queryParamOpts?.nft !== undefined) {
|
|
898
|
+
urlParams.append("nft", queryParamOpts?.nft.toString());
|
|
899
|
+
}
|
|
900
|
+
if (queryParamOpts?.noNftFetch !== undefined) {
|
|
901
|
+
urlParams.append("no-nft-fetch", queryParamOpts?.noNftFetch.toString());
|
|
902
|
+
}
|
|
903
|
+
if (queryParamOpts?.noSpam !== undefined) {
|
|
904
|
+
urlParams.append("no-spam", queryParamOpts?.noSpam.toString());
|
|
905
|
+
}
|
|
906
|
+
if (queryParamOpts?.noNftAssetMetadata !== undefined) {
|
|
907
|
+
urlParams.append("no-nft-asset-metadata", queryParamOpts?.noNftAssetMetadata.toString());
|
|
908
|
+
}
|
|
909
|
+
if (queryParamOpts?.blockHeight !== undefined) {
|
|
910
|
+
urlParams.append("block-height", queryParamOpts?.blockHeight.toString());
|
|
911
|
+
}
|
|
912
|
+
if (queryParamOpts?.date !== undefined) {
|
|
913
|
+
urlParams.append("date", queryParamOpts?.date.toString());
|
|
914
|
+
}
|
|
915
|
+
let startTime;
|
|
916
|
+
if (this.debug) {
|
|
917
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
918
|
+
}
|
|
919
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/historical_balances/?${urlParams}`, {
|
|
920
|
+
headers: {
|
|
921
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
922
|
+
"X-Requested-With": userAgent
|
|
923
|
+
}
|
|
924
|
+
}));
|
|
925
|
+
debugOutput(response.url, response.status, startTime);
|
|
926
|
+
if (response.status === 429) {
|
|
927
|
+
try {
|
|
928
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
929
|
+
}
|
|
930
|
+
catch (error) {
|
|
931
|
+
success = true;
|
|
932
|
+
return {
|
|
933
|
+
data: null,
|
|
934
|
+
error: true,
|
|
935
|
+
error_code: response.status,
|
|
936
|
+
error_message: error.message
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
else {
|
|
941
|
+
data = await response.json();
|
|
942
|
+
}
|
|
943
|
+
const dataClass = new HistoricalBalancesResponse(data.data);
|
|
944
|
+
checkAndModifyResponse(dataClass);
|
|
945
|
+
success = true;
|
|
946
|
+
return {
|
|
947
|
+
data: dataClass,
|
|
948
|
+
error: data.error,
|
|
949
|
+
error_code: data ? data.error_code : response.status,
|
|
950
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
catch (error) {
|
|
954
|
+
success = true;
|
|
955
|
+
return {
|
|
956
|
+
data: null,
|
|
957
|
+
error: true,
|
|
958
|
+
error_code: data ? data.error_code : response.status,
|
|
959
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
class BlockResponse {
|
|
967
|
+
constructor(data) {
|
|
968
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
969
|
+
this.chain_id = data.chain_id;
|
|
970
|
+
this.chain_name = data.chain_name;
|
|
971
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new Block(itemData)) : null;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
class Block {
|
|
975
|
+
constructor(data) {
|
|
976
|
+
this.signed_at = data.signed_at && data.signed_at !== null ? dateFns.parseISO(data.signed_at.toString()) : null;
|
|
977
|
+
this.height = data.height;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
class ResolvedAddress {
|
|
981
|
+
constructor(data) {
|
|
982
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
983
|
+
this.chain_id = data.chain_id;
|
|
984
|
+
this.chain_name = data.chain_name;
|
|
985
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ResolvedAddressItem(itemData)) : null;
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
class ResolvedAddressItem {
|
|
989
|
+
constructor(data) {
|
|
990
|
+
this.address = data.address;
|
|
991
|
+
this.name = data.name;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
class GetLogsResponse {
|
|
995
|
+
constructor(data) {
|
|
996
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
997
|
+
this.chain_id = data.chain_id;
|
|
998
|
+
this.chain_name = data.chain_name;
|
|
999
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new GetLogsEvent(itemData)) : null;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
class GetLogsEvent {
|
|
1003
|
+
constructor(data) {
|
|
1004
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
1005
|
+
this.block_height = data.block_height;
|
|
1006
|
+
this.block_hash = data.block_hash;
|
|
1007
|
+
this.tx_offset = data.tx_offset;
|
|
1008
|
+
this.log_offset = data.log_offset;
|
|
1009
|
+
this.tx_hash = data.tx_hash;
|
|
1010
|
+
this.raw_log_topics = data.raw_log_topics;
|
|
1011
|
+
this.sender_contract_decimals = data.sender_contract_decimals;
|
|
1012
|
+
this.sender_name = data.sender_name;
|
|
1013
|
+
this.sender_contract_ticker_symbol = data.sender_contract_ticker_symbol;
|
|
1014
|
+
this.sender_address = data.sender_address;
|
|
1015
|
+
this.sender_address_label = data.sender_address_label;
|
|
1016
|
+
this.sender_logo_url = data.sender_logo_url;
|
|
1017
|
+
this.raw_log_data = data.raw_log_data;
|
|
1018
|
+
this.decoded = data.decoded && data.decoded !== null ? new DecodedItem$2(data.decoded) : null;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
let DecodedItem$2 = class DecodedItem {
|
|
1022
|
+
constructor(data) {
|
|
1023
|
+
this.name = data.name;
|
|
1024
|
+
this.signature = data.signature;
|
|
1025
|
+
this.params = data.params && data.params !== null ? data.params.map((itemData) => new Param$2(itemData)) : null;
|
|
1026
|
+
}
|
|
1027
|
+
};
|
|
1028
|
+
let Param$2 = class Param {
|
|
1029
|
+
constructor(data) {
|
|
1030
|
+
this.name = data.name;
|
|
1031
|
+
this.type = data.type;
|
|
1032
|
+
this.indexed = data.indexed;
|
|
1033
|
+
this.decoded = data.decoded;
|
|
1034
|
+
this.value = data.value;
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
let LogEvent$2 = class LogEvent {
|
|
1038
|
+
constructor(data) {
|
|
1039
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
1040
|
+
this.block_height = data.block_height;
|
|
1041
|
+
this.tx_offset = data.tx_offset;
|
|
1042
|
+
this.log_offset = data.log_offset;
|
|
1043
|
+
this.tx_hash = data.tx_hash;
|
|
1044
|
+
this.raw_log_topics = data.raw_log_topics;
|
|
1045
|
+
this.sender_contract_decimals = data.sender_contract_decimals;
|
|
1046
|
+
this.sender_name = data.sender_name;
|
|
1047
|
+
this.sender_contract_ticker_symbol = data.sender_contract_ticker_symbol;
|
|
1048
|
+
this.sender_address = data.sender_address;
|
|
1049
|
+
this.sender_address_label = data.sender_address_label;
|
|
1050
|
+
this.sender_logo_url = data.sender_logo_url;
|
|
1051
|
+
this.raw_log_data = data.raw_log_data;
|
|
1052
|
+
this.decoded = data.decoded && data.decoded !== null ? new DecodedItem$2(data.decoded) : null;
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
class AllChainsResponse {
|
|
1056
|
+
constructor(data) {
|
|
1057
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1058
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ChainItem(itemData)) : null;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
class ChainItem {
|
|
1062
|
+
constructor(data) {
|
|
1063
|
+
this.name = data.name;
|
|
1064
|
+
this.chain_id = data.chain_id;
|
|
1065
|
+
this.is_testnet = data.is_testnet;
|
|
1066
|
+
this.db_schema_name = data.db_schema_name;
|
|
1067
|
+
this.label = data.label;
|
|
1068
|
+
this.category_label = data.category_label;
|
|
1069
|
+
this.logo_url = data.logo_url;
|
|
1070
|
+
this.black_logo_url = data.black_logo_url;
|
|
1071
|
+
this.white_logo_url = data.white_logo_url;
|
|
1072
|
+
this.is_appchain = data.is_appchain;
|
|
1073
|
+
this.appchain_of = data.appchain_of && data.appchain_of !== null ? new ChainItem(data.appchain_of) : null;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
class AllChainsStatusResponse {
|
|
1077
|
+
constructor(data) {
|
|
1078
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1079
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ChainStatusItem(itemData)) : null;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
class ChainStatusItem {
|
|
1083
|
+
constructor(data) {
|
|
1084
|
+
this.name = data.name;
|
|
1085
|
+
this.chain_id = data.chain_id;
|
|
1086
|
+
this.is_testnet = data.is_testnet;
|
|
1087
|
+
this.logo_url = data.logo_url;
|
|
1088
|
+
this.black_logo_url = data.black_logo_url;
|
|
1089
|
+
this.white_logo_url = data.white_logo_url;
|
|
1090
|
+
this.is_appchain = data.is_appchain;
|
|
1091
|
+
this.synced_block_height = data.synced_block_height;
|
|
1092
|
+
this.synced_blocked_signed_at = data.synced_blocked_signed_at && data.synced_blocked_signed_at !== null ? dateFns.parseISO(data.synced_blocked_signed_at.toString()) : null;
|
|
1093
|
+
this.has_data = data.has_data;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
class ChainActivityResponse {
|
|
1097
|
+
constructor(data) {
|
|
1098
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1099
|
+
this.address = data.address;
|
|
1100
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ChainActivityEvent(itemData)) : null;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
class ChainActivityEvent extends ChainItem {
|
|
1104
|
+
constructor(data) {
|
|
1105
|
+
super(data);
|
|
1106
|
+
this.last_seen_at = data.last_seen_at && data.last_seen_at !== null ? dateFns.parseISO(data.last_seen_at.toString()) : null;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Class A - Base
|
|
1111
|
+
*
|
|
1112
|
+
*/
|
|
1113
|
+
class BaseService {
|
|
1114
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
1115
|
+
this.apiKey = apiKey;
|
|
1116
|
+
this.debug = debug;
|
|
1117
|
+
this.threadCount = threadCount;
|
|
1118
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
*
|
|
1122
|
+
* Commonly used to fetch and render a single block for a block explorer.
|
|
1123
|
+
*
|
|
1124
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1125
|
+
* @param {string} blockHeight - The block height or `latest` for the latest block available.
|
|
1126
|
+
*
|
|
1127
|
+
*/
|
|
1128
|
+
async getBlock(chainName, blockHeight) {
|
|
1129
|
+
let success = false;
|
|
1130
|
+
let data;
|
|
1131
|
+
let response;
|
|
1132
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1133
|
+
while (!success) {
|
|
1134
|
+
try {
|
|
1135
|
+
const urlParams = new URLSearchParams();
|
|
1136
|
+
let startTime;
|
|
1137
|
+
if (this.debug) {
|
|
1138
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1139
|
+
}
|
|
1140
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/block_v2/${blockHeight}/?${urlParams}`, {
|
|
1141
|
+
headers: {
|
|
1142
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1143
|
+
"X-Requested-With": userAgent
|
|
1144
|
+
}
|
|
1145
|
+
}));
|
|
1146
|
+
debugOutput(response.url, response.status, startTime);
|
|
1147
|
+
if (response.status === 429) {
|
|
1148
|
+
try {
|
|
1149
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1150
|
+
}
|
|
1151
|
+
catch (error) {
|
|
1152
|
+
success = true;
|
|
1153
|
+
return {
|
|
1154
|
+
data: null,
|
|
1155
|
+
error: true,
|
|
1156
|
+
error_code: response.status,
|
|
1157
|
+
error_message: error.message
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
else {
|
|
1162
|
+
data = await response.json();
|
|
1163
|
+
}
|
|
1164
|
+
const dataClass = new BlockResponse(data.data);
|
|
1165
|
+
checkAndModifyResponse(dataClass);
|
|
1166
|
+
success = true;
|
|
1167
|
+
return {
|
|
1168
|
+
data: dataClass,
|
|
1169
|
+
error: data.error,
|
|
1170
|
+
error_code: data ? data.error_code : response.status,
|
|
1171
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
catch (error) {
|
|
1175
|
+
success = true;
|
|
1176
|
+
return {
|
|
1177
|
+
data: null,
|
|
1178
|
+
error: true,
|
|
1179
|
+
error_code: data ? data.error_code : response.status,
|
|
1180
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1181
|
+
};
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
*
|
|
1187
|
+
* Commonly used to resolve ENS, RNS and Unstoppable Domains addresses.
|
|
1188
|
+
*
|
|
1189
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1190
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
1191
|
+
*
|
|
1192
|
+
*/
|
|
1193
|
+
async getResolvedAddress(chainName, walletAddress) {
|
|
1194
|
+
let success = false;
|
|
1195
|
+
let data;
|
|
1196
|
+
let response;
|
|
1197
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1198
|
+
while (!success) {
|
|
1199
|
+
try {
|
|
1200
|
+
const urlParams = new URLSearchParams();
|
|
1201
|
+
let startTime;
|
|
1202
|
+
if (this.debug) {
|
|
1203
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1204
|
+
}
|
|
1205
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/resolve_address/?${urlParams}`, {
|
|
1206
|
+
headers: {
|
|
1207
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1208
|
+
"X-Requested-With": userAgent
|
|
1209
|
+
}
|
|
1210
|
+
}));
|
|
1211
|
+
debugOutput(response.url, response.status, startTime);
|
|
1212
|
+
if (response.status === 429) {
|
|
1213
|
+
try {
|
|
1214
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1215
|
+
}
|
|
1216
|
+
catch (error) {
|
|
1217
|
+
success = true;
|
|
1218
|
+
return {
|
|
1219
|
+
data: null,
|
|
1220
|
+
error: true,
|
|
1221
|
+
error_code: response.status,
|
|
1222
|
+
error_message: error.message
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
else {
|
|
1227
|
+
data = await response.json();
|
|
1228
|
+
}
|
|
1229
|
+
const dataClass = new ResolvedAddress(data.data);
|
|
1230
|
+
checkAndModifyResponse(dataClass);
|
|
1231
|
+
success = true;
|
|
1232
|
+
return {
|
|
1233
|
+
data: dataClass,
|
|
1234
|
+
error: data.error,
|
|
1235
|
+
error_code: data ? data.error_code : response.status,
|
|
1236
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1237
|
+
};
|
|
1238
|
+
}
|
|
1239
|
+
catch (error) {
|
|
1240
|
+
success = true;
|
|
1241
|
+
return {
|
|
1242
|
+
data: null,
|
|
1243
|
+
error: true,
|
|
1244
|
+
error_code: data ? data.error_code : response.status,
|
|
1245
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1246
|
+
};
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
*
|
|
1252
|
+
* Commonly used to get all the block heights within a particular date range. Useful for rendering a display where you sort blocks by day.
|
|
1253
|
+
*
|
|
1254
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1255
|
+
* @param {string} startDate - The start date in YYYY-MM-DD format.
|
|
1256
|
+
* @param {string} endDate - The end date in YYYY-MM-DD format.
|
|
1257
|
+
* @param {GetBlockHeightsQueryParamOpts} queryParamOpts
|
|
1258
|
+
* - `pageSize`: Number of items per page. Omitting this parameter defaults to 100.
|
|
1259
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
1260
|
+
*
|
|
1261
|
+
*/
|
|
1262
|
+
async *getBlockHeights(chainName, startDate, endDate, queryParamOpts) {
|
|
1263
|
+
let success = false;
|
|
1264
|
+
let res;
|
|
1265
|
+
while (!success) {
|
|
1266
|
+
try {
|
|
1267
|
+
const urlParams = new URLSearchParams();
|
|
1268
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
1269
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
1270
|
+
}
|
|
1271
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
1272
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
1273
|
+
}
|
|
1274
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/block_v2/${startDate}/${endDate}/`, this.apiKey, urlParams, Block, this.debug, this.threadCount)) {
|
|
1275
|
+
yield res;
|
|
1276
|
+
}
|
|
1277
|
+
success = true;
|
|
1278
|
+
}
|
|
1279
|
+
catch (error) {
|
|
1280
|
+
success = true;
|
|
1281
|
+
throw new Error(error.message);
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
/**
|
|
1286
|
+
*
|
|
1287
|
+
* Commonly used to get all the event logs of the latest block, or for a range of blocks. Includes sender contract metadata as well as decoded logs.
|
|
1288
|
+
*
|
|
1289
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1290
|
+
* @param {GetLogsQueryParamOpts} queryParamOpts
|
|
1291
|
+
* - `startingBlock`: The first block to retrieve log events with. Accepts decimals, hexadecimals, or the strings `earliest` and `latest`.
|
|
1292
|
+
* - `endingBlock`: The last block to retrieve log events with. Accepts decimals, hexadecimals, or the strings `earliest` and `latest`.
|
|
1293
|
+
* - `address`: The address of the log events sender contract.
|
|
1294
|
+
* - `topics`: The topic hash(es) to retrieve logs with.
|
|
1295
|
+
* - `blockHash`: The block hash to retrieve logs for.
|
|
1296
|
+
* - `skipDecode`: Omit decoded log events.
|
|
1297
|
+
*
|
|
1298
|
+
*/
|
|
1299
|
+
async getLogs(chainName, queryParamOpts) {
|
|
1300
|
+
let success = false;
|
|
1301
|
+
let data;
|
|
1302
|
+
let response;
|
|
1303
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1304
|
+
while (!success) {
|
|
1305
|
+
try {
|
|
1306
|
+
const urlParams = new URLSearchParams();
|
|
1307
|
+
if (queryParamOpts?.startingBlock !== undefined) {
|
|
1308
|
+
urlParams.append("starting-block", queryParamOpts?.startingBlock.toString());
|
|
1309
|
+
}
|
|
1310
|
+
if (queryParamOpts?.endingBlock !== undefined) {
|
|
1311
|
+
urlParams.append("ending-block", queryParamOpts?.endingBlock.toString());
|
|
1312
|
+
}
|
|
1313
|
+
if (queryParamOpts?.address !== undefined) {
|
|
1314
|
+
urlParams.append("address", queryParamOpts?.address.toString());
|
|
1315
|
+
}
|
|
1316
|
+
if (queryParamOpts?.topics !== undefined) {
|
|
1317
|
+
urlParams.append("topics", queryParamOpts?.topics.toString());
|
|
1318
|
+
}
|
|
1319
|
+
if (queryParamOpts?.blockHash !== undefined) {
|
|
1320
|
+
urlParams.append("block-hash", queryParamOpts?.blockHash.toString());
|
|
1321
|
+
}
|
|
1322
|
+
if (queryParamOpts?.skipDecode !== undefined) {
|
|
1323
|
+
urlParams.append("skip-decode", queryParamOpts?.skipDecode.toString());
|
|
1324
|
+
}
|
|
1325
|
+
let startTime;
|
|
1326
|
+
if (this.debug) {
|
|
1327
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1328
|
+
}
|
|
1329
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/events/?${urlParams}`, {
|
|
1330
|
+
headers: {
|
|
1331
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1332
|
+
"X-Requested-With": userAgent
|
|
1333
|
+
}
|
|
1334
|
+
}));
|
|
1335
|
+
debugOutput(response.url, response.status, startTime);
|
|
1336
|
+
if (response.status === 429) {
|
|
1337
|
+
try {
|
|
1338
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1339
|
+
}
|
|
1340
|
+
catch (error) {
|
|
1341
|
+
success = true;
|
|
1342
|
+
return {
|
|
1343
|
+
data: null,
|
|
1344
|
+
error: true,
|
|
1345
|
+
error_code: response.status,
|
|
1346
|
+
error_message: error.message
|
|
1347
|
+
};
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
else {
|
|
1351
|
+
data = await response.json();
|
|
1352
|
+
}
|
|
1353
|
+
const dataClass = new GetLogsResponse(data.data);
|
|
1354
|
+
checkAndModifyResponse(dataClass);
|
|
1355
|
+
success = true;
|
|
1356
|
+
return {
|
|
1357
|
+
data: dataClass,
|
|
1358
|
+
error: data.error,
|
|
1359
|
+
error_code: data ? data.error_code : response.status,
|
|
1360
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1363
|
+
catch (error) {
|
|
1364
|
+
success = true;
|
|
1365
|
+
return {
|
|
1366
|
+
data: null,
|
|
1367
|
+
error: true,
|
|
1368
|
+
error_code: data ? data.error_code : response.status,
|
|
1369
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1370
|
+
};
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1375
|
+
*
|
|
1376
|
+
* Commonly used to get all the event logs emitted from a particular contract address. Useful for building dashboards that examine on-chain interactions.
|
|
1377
|
+
*
|
|
1378
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1379
|
+
* @param {string} contractAddress - The requested contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
1380
|
+
* @param {GetLogEventsByAddressQueryParamOpts} queryParamOpts
|
|
1381
|
+
* - `startingBlock`: The first block to retrieve log events with. Accepts decimals, hexadecimals, or the strings `earliest` and `latest`.
|
|
1382
|
+
* - `endingBlock`: The last block to retrieve log events with. Accepts decimals, hexadecimals, or the strings `earliest` and `latest`.
|
|
1383
|
+
* - `pageSize`: Number of items per page. Omitting this parameter defaults to 100.
|
|
1384
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
1385
|
+
*
|
|
1386
|
+
*/
|
|
1387
|
+
async *getLogEventsByAddress(chainName, contractAddress, queryParamOpts) {
|
|
1388
|
+
let success = false;
|
|
1389
|
+
let res;
|
|
1390
|
+
while (!success) {
|
|
1391
|
+
try {
|
|
1392
|
+
const urlParams = new URLSearchParams();
|
|
1393
|
+
if (queryParamOpts?.startingBlock !== undefined) {
|
|
1394
|
+
urlParams.append("starting-block", queryParamOpts?.startingBlock.toString());
|
|
1395
|
+
}
|
|
1396
|
+
if (queryParamOpts?.endingBlock !== undefined) {
|
|
1397
|
+
urlParams.append("ending-block", queryParamOpts?.endingBlock.toString());
|
|
1398
|
+
}
|
|
1399
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
1400
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
1401
|
+
}
|
|
1402
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
1403
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
1404
|
+
}
|
|
1405
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/events/address/${contractAddress}/`, this.apiKey, urlParams, LogEvent$2, this.debug, this.threadCount)) {
|
|
1406
|
+
yield res;
|
|
1407
|
+
}
|
|
1408
|
+
success = true;
|
|
1409
|
+
}
|
|
1410
|
+
catch (error) {
|
|
1411
|
+
success = true;
|
|
1412
|
+
throw new Error(error.message);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
/**
|
|
1417
|
+
*
|
|
1418
|
+
* Commonly used to get all event logs of the same topic hash across all contracts within a particular chain. Useful for cross-sectional analysis of event logs that are emitted on-chain.
|
|
1419
|
+
*
|
|
1420
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1421
|
+
* @param {string} topicHash - The endpoint will return event logs that contain this topic hash.
|
|
1422
|
+
* @param {GetLogEventsByTopicHashQueryParamOpts} queryParamOpts
|
|
1423
|
+
* - `startingBlock`: The first block to retrieve log events with. Accepts decimals, hexadecimals, or the strings `earliest` and `latest`.
|
|
1424
|
+
* - `endingBlock`: The last block to retrieve log events with. Accepts decimals, hexadecimals, or the strings `earliest` and `latest`.
|
|
1425
|
+
* - `secondaryTopics`: Additional topic hash(es) to filter on - padded & unpadded address fields are supported. Separate multiple topics with a comma.
|
|
1426
|
+
* - `pageSize`: Number of items per page. Omitting this parameter defaults to 100.
|
|
1427
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
1428
|
+
*
|
|
1429
|
+
*/
|
|
1430
|
+
async *getLogEventsByTopicHash(chainName, topicHash, queryParamOpts) {
|
|
1431
|
+
let success = false;
|
|
1432
|
+
let res;
|
|
1433
|
+
while (!success) {
|
|
1434
|
+
try {
|
|
1435
|
+
const urlParams = new URLSearchParams();
|
|
1436
|
+
if (queryParamOpts?.startingBlock !== undefined) {
|
|
1437
|
+
urlParams.append("starting-block", queryParamOpts?.startingBlock.toString());
|
|
1438
|
+
}
|
|
1439
|
+
if (queryParamOpts?.endingBlock !== undefined) {
|
|
1440
|
+
urlParams.append("ending-block", queryParamOpts?.endingBlock.toString());
|
|
1441
|
+
}
|
|
1442
|
+
if (queryParamOpts?.secondaryTopics !== undefined) {
|
|
1443
|
+
urlParams.append("secondary-topics", queryParamOpts?.secondaryTopics.toString());
|
|
1444
|
+
}
|
|
1445
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
1446
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
1447
|
+
}
|
|
1448
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
1449
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
1450
|
+
}
|
|
1451
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/events/topics/${topicHash}/`, this.apiKey, urlParams, LogEvent$2, this.debug, this.threadCount)) {
|
|
1452
|
+
yield res;
|
|
1453
|
+
}
|
|
1454
|
+
success = true;
|
|
1455
|
+
}
|
|
1456
|
+
catch (error) {
|
|
1457
|
+
success = true;
|
|
1458
|
+
throw new Error(error.message);
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
*
|
|
1464
|
+
* Commonly used to build internal dashboards for all supported chains on Covalent.
|
|
1465
|
+
*
|
|
1466
|
+
*
|
|
1467
|
+
*/
|
|
1468
|
+
async getAllChains() {
|
|
1469
|
+
let success = false;
|
|
1470
|
+
let data;
|
|
1471
|
+
let response;
|
|
1472
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1473
|
+
while (!success) {
|
|
1474
|
+
try {
|
|
1475
|
+
const urlParams = new URLSearchParams();
|
|
1476
|
+
let startTime;
|
|
1477
|
+
if (this.debug) {
|
|
1478
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1479
|
+
}
|
|
1480
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/chains/?${urlParams}`, {
|
|
1481
|
+
headers: {
|
|
1482
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1483
|
+
"X-Requested-With": userAgent
|
|
1484
|
+
}
|
|
1485
|
+
}));
|
|
1486
|
+
debugOutput(response.url, response.status, startTime);
|
|
1487
|
+
if (response.status === 429) {
|
|
1488
|
+
try {
|
|
1489
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1490
|
+
}
|
|
1491
|
+
catch (error) {
|
|
1492
|
+
success = true;
|
|
1493
|
+
return {
|
|
1494
|
+
data: null,
|
|
1495
|
+
error: true,
|
|
1496
|
+
error_code: response.status,
|
|
1497
|
+
error_message: error.message
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
else {
|
|
1502
|
+
data = await response.json();
|
|
1503
|
+
}
|
|
1504
|
+
const dataClass = new AllChainsResponse(data.data);
|
|
1505
|
+
checkAndModifyResponse(dataClass);
|
|
1506
|
+
success = true;
|
|
1507
|
+
return {
|
|
1508
|
+
data: dataClass,
|
|
1509
|
+
error: data.error,
|
|
1510
|
+
error_code: data ? data.error_code : response.status,
|
|
1511
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
catch (error) {
|
|
1515
|
+
success = true;
|
|
1516
|
+
return {
|
|
1517
|
+
data: null,
|
|
1518
|
+
error: true,
|
|
1519
|
+
error_code: data ? data.error_code : response.status,
|
|
1520
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
*
|
|
1527
|
+
* Commonly used to build internal status dashboards of all supported chains.
|
|
1528
|
+
*
|
|
1529
|
+
*
|
|
1530
|
+
*/
|
|
1531
|
+
async getAllChainStatus() {
|
|
1532
|
+
let success = false;
|
|
1533
|
+
let data;
|
|
1534
|
+
let response;
|
|
1535
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1536
|
+
while (!success) {
|
|
1537
|
+
try {
|
|
1538
|
+
const urlParams = new URLSearchParams();
|
|
1539
|
+
let startTime;
|
|
1540
|
+
if (this.debug) {
|
|
1541
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1542
|
+
}
|
|
1543
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/chains/status/?${urlParams}`, {
|
|
1544
|
+
headers: {
|
|
1545
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1546
|
+
"X-Requested-With": userAgent
|
|
1547
|
+
}
|
|
1548
|
+
}));
|
|
1549
|
+
debugOutput(response.url, response.status, startTime);
|
|
1550
|
+
if (response.status === 429) {
|
|
1551
|
+
try {
|
|
1552
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1553
|
+
}
|
|
1554
|
+
catch (error) {
|
|
1555
|
+
success = true;
|
|
1556
|
+
return {
|
|
1557
|
+
data: null,
|
|
1558
|
+
error: true,
|
|
1559
|
+
error_code: response.status,
|
|
1560
|
+
error_message: error.message
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
else {
|
|
1565
|
+
data = await response.json();
|
|
1566
|
+
}
|
|
1567
|
+
const dataClass = new AllChainsStatusResponse(data.data);
|
|
1568
|
+
checkAndModifyResponse(dataClass);
|
|
1569
|
+
success = true;
|
|
1570
|
+
return {
|
|
1571
|
+
data: dataClass,
|
|
1572
|
+
error: data.error,
|
|
1573
|
+
error_code: data ? data.error_code : response.status,
|
|
1574
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1577
|
+
catch (error) {
|
|
1578
|
+
success = true;
|
|
1579
|
+
return {
|
|
1580
|
+
data: null,
|
|
1581
|
+
error: true,
|
|
1582
|
+
error_code: data ? data.error_code : response.status,
|
|
1583
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
/**
|
|
1589
|
+
*
|
|
1590
|
+
* Commonly used to locate chains which an address is active on with a single API call.
|
|
1591
|
+
*
|
|
1592
|
+
* @param {string} walletAddress - The requested wallet address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
1593
|
+
* @param {GetAddressActivityQueryParamOpts} queryParamOpts
|
|
1594
|
+
* - `testnets`: Set to true to include testnets with activity in the response. By default, it's set to `false` and only returns mainnet activity.
|
|
1595
|
+
*
|
|
1596
|
+
*/
|
|
1597
|
+
async getAddressActivity(walletAddress, queryParamOpts) {
|
|
1598
|
+
let success = false;
|
|
1599
|
+
let data;
|
|
1600
|
+
let response;
|
|
1601
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1602
|
+
while (!success) {
|
|
1603
|
+
try {
|
|
1604
|
+
const urlParams = new URLSearchParams();
|
|
1605
|
+
if (queryParamOpts?.testnets !== undefined) {
|
|
1606
|
+
urlParams.append("testnets", queryParamOpts?.testnets.toString());
|
|
1607
|
+
}
|
|
1608
|
+
let startTime;
|
|
1609
|
+
if (this.debug) {
|
|
1610
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1611
|
+
}
|
|
1612
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/address/${walletAddress}/activity/?${urlParams}`, {
|
|
1613
|
+
headers: {
|
|
1614
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1615
|
+
"X-Requested-With": userAgent
|
|
1616
|
+
}
|
|
1617
|
+
}));
|
|
1618
|
+
debugOutput(response.url, response.status, startTime);
|
|
1619
|
+
if (response.status === 429) {
|
|
1620
|
+
try {
|
|
1621
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1622
|
+
}
|
|
1623
|
+
catch (error) {
|
|
1624
|
+
success = true;
|
|
1625
|
+
return {
|
|
1626
|
+
data: null,
|
|
1627
|
+
error: true,
|
|
1628
|
+
error_code: response.status,
|
|
1629
|
+
error_message: error.message
|
|
1630
|
+
};
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
else {
|
|
1634
|
+
data = await response.json();
|
|
1635
|
+
}
|
|
1636
|
+
const dataClass = new ChainActivityResponse(data.data);
|
|
1637
|
+
checkAndModifyResponse(dataClass);
|
|
1638
|
+
success = true;
|
|
1639
|
+
return {
|
|
1640
|
+
data: dataClass,
|
|
1641
|
+
error: data.error,
|
|
1642
|
+
error_code: data ? data.error_code : response.status,
|
|
1643
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
catch (error) {
|
|
1647
|
+
success = true;
|
|
1648
|
+
return {
|
|
1649
|
+
data: null,
|
|
1650
|
+
error: true,
|
|
1651
|
+
error_code: data ? data.error_code : response.status,
|
|
1652
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
1653
|
+
};
|
|
1654
|
+
}
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
class ChainCollectionItem {
|
|
1660
|
+
constructor(data) {
|
|
1661
|
+
this.contract_address = data.contract_address;
|
|
1662
|
+
this.contract_name = data.contract_name;
|
|
1663
|
+
this.is_spam = data.is_spam;
|
|
1664
|
+
this.token_total_supply = data.token_total_supply;
|
|
1665
|
+
this.cached_metadata_count = data.cached_metadata_count;
|
|
1666
|
+
this.cached_asset_count = data.cached_asset_count;
|
|
1667
|
+
this.last_scraped_at = data.last_scraped_at && data.last_scraped_at !== null ? dateFns.parseISO(data.last_scraped_at.toString()) : null;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
let Pagination$1 = class Pagination {
|
|
1671
|
+
constructor(data) {
|
|
1672
|
+
this.has_more = data.has_more;
|
|
1673
|
+
this.page_number = data.page_number;
|
|
1674
|
+
this.page_size = data.page_size;
|
|
1675
|
+
this.total_count = data.total_count;
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
class NftAddressBalanceNftResponse {
|
|
1679
|
+
constructor(data) {
|
|
1680
|
+
this.address = data.address;
|
|
1681
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1682
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftTokenContractBalanceItem(itemData)) : null;
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
class NftTokenContractBalanceItem {
|
|
1686
|
+
constructor(data) {
|
|
1687
|
+
this.contract_name = data.contract_name;
|
|
1688
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
1689
|
+
this.contract_address = data.contract_address;
|
|
1690
|
+
this.supports_erc = data.supports_erc;
|
|
1691
|
+
this.is_spam = data.is_spam;
|
|
1692
|
+
this.last_transfered_at = data.last_transfered_at && data.last_transfered_at !== null ? dateFns.parseISO(data.last_transfered_at.toString()) : null;
|
|
1693
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
1694
|
+
this.balance_24h = data.balance_24h;
|
|
1695
|
+
this.type = data.type;
|
|
1696
|
+
this.nft_data = data.nft_data && data.nft_data !== null ? data.nft_data.map((itemData) => new NftData(itemData)) : null;
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
class NftData {
|
|
1700
|
+
constructor(data) {
|
|
1701
|
+
this.token_id = data.token_id && data.token_id !== null ? BigInt(data.token_id) : null;
|
|
1702
|
+
this.token_url = data.token_url;
|
|
1703
|
+
this.original_owner = data.original_owner;
|
|
1704
|
+
this.asset_cached = data.asset_cached;
|
|
1705
|
+
this.image_cached = data.image_cached;
|
|
1706
|
+
this.external_data = data.external_data && data.external_data !== null ? new NftExternalData(data.external_data) : null;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
class NftExternalData {
|
|
1710
|
+
constructor(data) {
|
|
1711
|
+
this.name = data.name;
|
|
1712
|
+
this.description = data.description;
|
|
1713
|
+
this.asset_url = data.asset_url;
|
|
1714
|
+
this.asset_file_extension = data.asset_file_extension;
|
|
1715
|
+
this.asset_mime_type = data.asset_mime_type;
|
|
1716
|
+
this.asset_size_bytes = data.asset_size_bytes;
|
|
1717
|
+
this.image = data.image;
|
|
1718
|
+
this.image_256 = data.image_256;
|
|
1719
|
+
this.image_512 = data.image_512;
|
|
1720
|
+
this.image_1024 = data.image_1024;
|
|
1721
|
+
this.animation_url = data.animation_url;
|
|
1722
|
+
this.external_url = data.external_url;
|
|
1723
|
+
this.attributes = data.attributes && data.attributes !== null ? data.attributes.map((itemData) => new NftCollectionAttribute(itemData)) : null;
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
class NftCollectionAttribute {
|
|
1727
|
+
constructor(data) {
|
|
1728
|
+
this.trait_type = data.trait_type;
|
|
1729
|
+
this.value = data.value;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
class NftMetadataResponse {
|
|
1733
|
+
constructor(data) {
|
|
1734
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1735
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftTokenContract(itemData)) : null;
|
|
1736
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination$1(data.pagination) : null;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
class NftTokenContract {
|
|
1740
|
+
constructor(data) {
|
|
1741
|
+
this.contract_name = data.contract_name;
|
|
1742
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
1743
|
+
this.contract_address = data.contract_address;
|
|
1744
|
+
this.is_spam = data.is_spam;
|
|
1745
|
+
this.type = data.type;
|
|
1746
|
+
this.nft_data = data.nft_data && data.nft_data !== null ? new NftData(data.nft_data) : null;
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
class NftTransactionsResponse {
|
|
1750
|
+
constructor(data) {
|
|
1751
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1752
|
+
this.chain_id = data.chain_id;
|
|
1753
|
+
this.chain_name = data.chain_name;
|
|
1754
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftTransaction(itemData)) : null;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
class NftTransaction {
|
|
1758
|
+
constructor(data) {
|
|
1759
|
+
this.contract_decimals = data.contract_decimals;
|
|
1760
|
+
this.contract_name = data.contract_name;
|
|
1761
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
1762
|
+
this.logo_url = data.logo_url;
|
|
1763
|
+
this.contract_address = data.contract_address;
|
|
1764
|
+
this.supports_erc = data.supports_erc;
|
|
1765
|
+
this.is_spam = data.is_spam;
|
|
1766
|
+
this.nft_transactions = data.nft_transactions && data.nft_transactions !== null ? data.nft_transactions.map((itemData) => new NftTransactionItem(itemData)) : null;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
class NftTransactionItem {
|
|
1770
|
+
constructor(data) {
|
|
1771
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
1772
|
+
this.block_height = data.block_height;
|
|
1773
|
+
this.tx_hash = data.tx_hash;
|
|
1774
|
+
this.tx_offset = data.tx_offset;
|
|
1775
|
+
this.successful = data.successful;
|
|
1776
|
+
this.from_address = data.from_address;
|
|
1777
|
+
this.from_address_label = data.from_address_label;
|
|
1778
|
+
this.to_address = data.to_address;
|
|
1779
|
+
this.to_address_label = data.to_address_label;
|
|
1780
|
+
this.value = data.value && data.value !== null ? BigInt(data.value) : null;
|
|
1781
|
+
this.value_quote = data.value_quote;
|
|
1782
|
+
this.pretty_value_quote = data.pretty_value_quote;
|
|
1783
|
+
this.gas_offered = data.gas_offered;
|
|
1784
|
+
this.gas_spent = data.gas_spent;
|
|
1785
|
+
this.gas_price = data.gas_price;
|
|
1786
|
+
this.fees_paid = data.fees_paid && data.fees_paid !== null ? BigInt(data.fees_paid) : null;
|
|
1787
|
+
this.gas_quote = data.gas_quote;
|
|
1788
|
+
this.pretty_gas_quote = data.pretty_gas_quote;
|
|
1789
|
+
this.gas_quote_rate = data.gas_quote_rate;
|
|
1790
|
+
this.log_events = data.log_events && data.log_events !== null ? data.log_events.map((itemData) => new LogEvent$1(itemData)) : null;
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
let LogEvent$1 = class LogEvent {
|
|
1794
|
+
constructor(data) {
|
|
1795
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
1796
|
+
this.block_height = data.block_height;
|
|
1797
|
+
this.tx_offset = data.tx_offset;
|
|
1798
|
+
this.log_offset = data.log_offset;
|
|
1799
|
+
this.tx_hash = data.tx_hash;
|
|
1800
|
+
this.raw_log_topics = data.raw_log_topics;
|
|
1801
|
+
this.sender_contract_decimals = data.sender_contract_decimals;
|
|
1802
|
+
this.sender_name = data.sender_name;
|
|
1803
|
+
this.sender_contract_ticker_symbol = data.sender_contract_ticker_symbol;
|
|
1804
|
+
this.sender_address = data.sender_address;
|
|
1805
|
+
this.sender_address_label = data.sender_address_label;
|
|
1806
|
+
this.sender_logo_url = data.sender_logo_url;
|
|
1807
|
+
this.raw_log_data = data.raw_log_data;
|
|
1808
|
+
this.decoded = data.decoded && data.decoded !== null ? new DecodedItem$1(data.decoded) : null;
|
|
1809
|
+
}
|
|
1810
|
+
};
|
|
1811
|
+
let DecodedItem$1 = class DecodedItem {
|
|
1812
|
+
constructor(data) {
|
|
1813
|
+
this.name = data.name;
|
|
1814
|
+
this.signature = data.signature;
|
|
1815
|
+
this.params = data.params && data.params !== null ? data.params.map((itemData) => new Param$1(itemData)) : null;
|
|
1816
|
+
}
|
|
1817
|
+
};
|
|
1818
|
+
let Param$1 = class Param {
|
|
1819
|
+
constructor(data) {
|
|
1820
|
+
this.name = data.name;
|
|
1821
|
+
this.type = data.type;
|
|
1822
|
+
this.indexed = data.indexed;
|
|
1823
|
+
this.decoded = data.decoded;
|
|
1824
|
+
this.value = data.value;
|
|
1825
|
+
}
|
|
1826
|
+
};
|
|
1827
|
+
class NftCollectionTraitsResponse {
|
|
1828
|
+
constructor(data) {
|
|
1829
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1830
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftTrait(itemData)) : null;
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
class NftTrait {
|
|
1834
|
+
constructor(data) {
|
|
1835
|
+
this.name = data.name;
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
class NftCollectionAttributesForTraitResponse {
|
|
1839
|
+
constructor(data) {
|
|
1840
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1841
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftSummaryAttribute(itemData)) : null;
|
|
1842
|
+
}
|
|
1843
|
+
}
|
|
1844
|
+
class NftSummaryAttribute {
|
|
1845
|
+
constructor(data) {
|
|
1846
|
+
this.trait_type = data.trait_type;
|
|
1847
|
+
this.unique_values = data.unique_values;
|
|
1848
|
+
this.values = data.values && data.values !== null ? data.values.map((itemData) => new NftAttribute(itemData)) : null;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
class NftAttribute {
|
|
1852
|
+
constructor(data) {
|
|
1853
|
+
this.value = data.value;
|
|
1854
|
+
this.count = data.count;
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
class NftCollectionTraitSummaryResponse {
|
|
1858
|
+
constructor(data) {
|
|
1859
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1860
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftTraitSummary(itemData)) : null;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
class NftTraitSummary {
|
|
1864
|
+
constructor(data) {
|
|
1865
|
+
this.name = data.name;
|
|
1866
|
+
this.value_type = data.value_type;
|
|
1867
|
+
this.value_numeric = data.value_numeric && data.value_numeric !== null ? new NftTraitNumeric(data.value_numeric) : null;
|
|
1868
|
+
this.value_string = data.value_string && data.value_string !== null ? new NftTraitString(data.value_string) : null;
|
|
1869
|
+
this.attributes = data.attributes && data.attributes !== null ? data.attributes.map((itemData) => new NftSummaryAttribute(itemData)) : null;
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
class NftTraitNumeric {
|
|
1873
|
+
constructor(data) {
|
|
1874
|
+
this.min = data.min;
|
|
1875
|
+
this.max = data.max;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
class NftTraitString {
|
|
1879
|
+
constructor(data) {
|
|
1880
|
+
this.value = data.value;
|
|
1881
|
+
this.token_count = data.token_count;
|
|
1882
|
+
this.trait_percentage = data.trait_percentage;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
class NftOwnershipForCollectionResponse {
|
|
1886
|
+
constructor(data) {
|
|
1887
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
1888
|
+
this.address = data.address;
|
|
1889
|
+
this.collection = data.collection;
|
|
1890
|
+
this.is_spam = data.is_spam;
|
|
1891
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new NftOwnershipForCollectionItem(itemData)) : null;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
class NftOwnershipForCollectionItem {
|
|
1895
|
+
constructor(data) {
|
|
1896
|
+
this.contract_name = data.contract_name;
|
|
1897
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
1898
|
+
this.contract_address = data.contract_address;
|
|
1899
|
+
this.token_id = data.token_id && data.token_id !== null ? BigInt(data.token_id) : null;
|
|
1900
|
+
this.supports_erc = data.supports_erc;
|
|
1901
|
+
this.last_transfered_at = data.last_transfered_at && data.last_transfered_at !== null ? dateFns.parseISO(data.last_transfered_at.toString()) : null;
|
|
1902
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
1903
|
+
this.balance_24h = data.balance_24h;
|
|
1904
|
+
this.type = data.type;
|
|
1905
|
+
this.nft_data = data.nft_data && data.nft_data !== null ? new NftData(data.nft_data) : null;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
/**
|
|
1909
|
+
* NFT APIs
|
|
1910
|
+
*
|
|
1911
|
+
*/
|
|
1912
|
+
class NftService {
|
|
1913
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
1914
|
+
this.apiKey = apiKey;
|
|
1915
|
+
this.debug = debug;
|
|
1916
|
+
this.threadCount = threadCount;
|
|
1917
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
*
|
|
1921
|
+
* Commonly used to fetch the list of NFT collections with downloaded and cached off chain data like token metadata and asset files.
|
|
1922
|
+
*
|
|
1923
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1924
|
+
* @param {GetChainCollectionsQueryParamOpts} queryParamOpts
|
|
1925
|
+
* - `pageSize`: Number of items per page. Omitting this parameter defaults to 100.
|
|
1926
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
1927
|
+
* - `noSpam`: If `true`, the suspected spam tokens are removed. Supports `eth-mainnet` and `matic-mainnet`.
|
|
1928
|
+
*
|
|
1929
|
+
*/
|
|
1930
|
+
async *getChainCollections(chainName, queryParamOpts) {
|
|
1931
|
+
let success = false;
|
|
1932
|
+
let res;
|
|
1933
|
+
while (!success) {
|
|
1934
|
+
try {
|
|
1935
|
+
const urlParams = new URLSearchParams();
|
|
1936
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
1937
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
1938
|
+
}
|
|
1939
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
1940
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
1941
|
+
}
|
|
1942
|
+
if (queryParamOpts?.noSpam !== undefined) {
|
|
1943
|
+
urlParams.append("no-spam", queryParamOpts?.noSpam.toString());
|
|
1944
|
+
}
|
|
1945
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/nft/collections/`, this.apiKey, urlParams, ChainCollectionItem, this.debug, this.threadCount)) {
|
|
1946
|
+
yield res;
|
|
1947
|
+
}
|
|
1948
|
+
success = true;
|
|
1949
|
+
}
|
|
1950
|
+
catch (error) {
|
|
1951
|
+
success = true;
|
|
1952
|
+
throw new Error(error.message);
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
}
|
|
1956
|
+
/**
|
|
1957
|
+
*
|
|
1958
|
+
* Commonly used to render the NFTs (including ERC721 and ERC1155) held by an address.
|
|
1959
|
+
*
|
|
1960
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
1961
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
1962
|
+
* @param {GetNftsForAddressQueryParamOpts} queryParamOpts
|
|
1963
|
+
* - `noSpam`: If `true`, the suspected spam tokens are removed. Supports `eth-mainnet` and `matic-mainnet`.
|
|
1964
|
+
* - `noNftAssetMetadata`: If `true`, the response shape is limited to a list of collections and token ids, omitting metadata and asset information. Helpful for faster response times and wallets holding a large number of NFTs.
|
|
1965
|
+
* - `withUncached`: By default, this endpoint only works on chains where we've cached the assets and the metadata. When set to `true`, the API will fetch metadata from upstream servers even if it's not cached - the downside being that the upstream server can block or rate limit the call and therefore resulting in time outs or slow response times on the Covalent side.
|
|
1966
|
+
*
|
|
1967
|
+
*/
|
|
1968
|
+
async getNftsForAddress(chainName, walletAddress, queryParamOpts) {
|
|
1969
|
+
let success = false;
|
|
1970
|
+
let data;
|
|
1971
|
+
let response;
|
|
1972
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
1973
|
+
while (!success) {
|
|
1974
|
+
try {
|
|
1975
|
+
const urlParams = new URLSearchParams();
|
|
1976
|
+
if (queryParamOpts?.noSpam !== undefined) {
|
|
1977
|
+
urlParams.append("no-spam", queryParamOpts?.noSpam.toString());
|
|
1978
|
+
}
|
|
1979
|
+
if (queryParamOpts?.noNftAssetMetadata !== undefined) {
|
|
1980
|
+
urlParams.append("no-nft-asset-metadata", queryParamOpts?.noNftAssetMetadata.toString());
|
|
1981
|
+
}
|
|
1982
|
+
if (queryParamOpts?.withUncached !== undefined) {
|
|
1983
|
+
urlParams.append("with-uncached", queryParamOpts?.withUncached.toString());
|
|
1984
|
+
}
|
|
1985
|
+
let startTime;
|
|
1986
|
+
if (this.debug) {
|
|
1987
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
1988
|
+
}
|
|
1989
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/balances_nft/?${urlParams}`, {
|
|
1990
|
+
headers: {
|
|
1991
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
1992
|
+
"X-Requested-With": userAgent
|
|
1993
|
+
}
|
|
1994
|
+
}));
|
|
1995
|
+
debugOutput(response.url, response.status, startTime);
|
|
1996
|
+
if (response.status === 429) {
|
|
1997
|
+
try {
|
|
1998
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
1999
|
+
}
|
|
2000
|
+
catch (error) {
|
|
2001
|
+
success = true;
|
|
2002
|
+
return {
|
|
2003
|
+
data: null,
|
|
2004
|
+
error: true,
|
|
2005
|
+
error_code: response.status,
|
|
2006
|
+
error_message: error.message
|
|
2007
|
+
};
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
else {
|
|
2011
|
+
data = await response.json();
|
|
2012
|
+
}
|
|
2013
|
+
const dataClass = new NftAddressBalanceNftResponse(data.data);
|
|
2014
|
+
checkAndModifyResponse(dataClass);
|
|
2015
|
+
success = true;
|
|
2016
|
+
return {
|
|
2017
|
+
data: dataClass,
|
|
2018
|
+
error: data.error,
|
|
2019
|
+
error_code: data ? data.error_code : response.status,
|
|
2020
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
catch (error) {
|
|
2024
|
+
success = true;
|
|
2025
|
+
return {
|
|
2026
|
+
data: null,
|
|
2027
|
+
error: true,
|
|
2028
|
+
error_code: data ? data.error_code : response.status,
|
|
2029
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
/**
|
|
2035
|
+
*
|
|
2036
|
+
* Commonly used to get NFT token IDs with metadata from a collection. Useful for building NFT card displays.
|
|
2037
|
+
*
|
|
2038
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2039
|
+
* @param {string} contractAddress - The requested contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2040
|
+
* @param {GetTokenIdsForContractWithMetadataQueryParamOpts} queryParamOpts
|
|
2041
|
+
* - `noMetadata`: Omit metadata.
|
|
2042
|
+
* - `pageSize`: Number of items per page. Omitting this parameter defaults to 100.
|
|
2043
|
+
* - `pageNumber`: 0-indexed page number to begin pagination.
|
|
2044
|
+
* - `traitsFilter`: Filters NFTs based on a specific trait. If this filter is used, the API will return all NFTs with the specified trait. Accepts comma-separated values, is case-sensitive, and requires proper URL encoding.
|
|
2045
|
+
* - `valuesFilter`: Filters NFTs based on a specific trait value. If this filter is used, the API will return all NFTs with the specified trait value. If used with "traits-filter", only NFTs matching both filters will be returned. Accepts comma-separated values, is case-sensitive, and requires proper URL encoding.
|
|
2046
|
+
* - `withUncached`: By default, this endpoint only works on chains where we've cached the assets and the metadata. When set to `true`, the API will fetch metadata from upstream servers even if it's not cached - the downside being that the upstream server can block or rate limit the call and therefore resulting in time outs or slow response times on the Covalent side.
|
|
2047
|
+
*
|
|
2048
|
+
*/
|
|
2049
|
+
async *getTokenIdsForContractWithMetadata(chainName, contractAddress, queryParamOpts) {
|
|
2050
|
+
let success = false;
|
|
2051
|
+
let res;
|
|
2052
|
+
while (!success) {
|
|
2053
|
+
try {
|
|
2054
|
+
const urlParams = new URLSearchParams();
|
|
2055
|
+
if (queryParamOpts?.noMetadata !== undefined) {
|
|
2056
|
+
urlParams.append("no-metadata", queryParamOpts?.noMetadata.toString());
|
|
2057
|
+
}
|
|
2058
|
+
if (queryParamOpts?.pageSize !== undefined) {
|
|
2059
|
+
urlParams.append("page-size", queryParamOpts?.pageSize.toString());
|
|
2060
|
+
}
|
|
2061
|
+
if (queryParamOpts?.pageNumber !== undefined) {
|
|
2062
|
+
urlParams.append("page-number", queryParamOpts?.pageNumber.toString());
|
|
2063
|
+
}
|
|
2064
|
+
if (queryParamOpts?.traitsFilter !== undefined) {
|
|
2065
|
+
urlParams.append("traits-filter", queryParamOpts?.traitsFilter.toString());
|
|
2066
|
+
}
|
|
2067
|
+
if (queryParamOpts?.valuesFilter !== undefined) {
|
|
2068
|
+
urlParams.append("values-filter", queryParamOpts?.valuesFilter.toString());
|
|
2069
|
+
}
|
|
2070
|
+
if (queryParamOpts?.withUncached !== undefined) {
|
|
2071
|
+
urlParams.append("with-uncached", queryParamOpts?.withUncached.toString());
|
|
2072
|
+
}
|
|
2073
|
+
for await (res of paginateEndpoint$1(`https://api.covalenthq.com/v1/${chainName}/nft/${contractAddress}/metadata/`, this.apiKey, urlParams, NftTokenContract, this.debug, this.threadCount)) {
|
|
2074
|
+
yield res;
|
|
2075
|
+
}
|
|
2076
|
+
success = true;
|
|
2077
|
+
}
|
|
2078
|
+
catch (error) {
|
|
2079
|
+
success = true;
|
|
2080
|
+
throw new Error(error.message);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
/**
|
|
2085
|
+
*
|
|
2086
|
+
* Commonly used to get a single NFT metadata by token ID from a collection. Useful for building NFT card displays.
|
|
2087
|
+
*
|
|
2088
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2089
|
+
* @param {string} contractAddress - The requested contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2090
|
+
* @param {string} tokenId - The requested token ID.
|
|
2091
|
+
* @param {GetNftMetadataForGivenTokenIdForContractQueryParamOpts} queryParamOpts
|
|
2092
|
+
* - `noMetadata`: Omit metadata.
|
|
2093
|
+
* - `withUncached`: By default, this endpoint only works on chains where we've cached the assets and the metadata. When set to `true`, the API will fetch metadata from upstream servers even if it's not cached - the downside being that the upstream server can block or rate limit the call and therefore resulting in time outs or slow response times on the Covalent side.
|
|
2094
|
+
*
|
|
2095
|
+
*/
|
|
2096
|
+
async getNftMetadataForGivenTokenIdForContract(chainName, contractAddress, tokenId, queryParamOpts) {
|
|
2097
|
+
let success = false;
|
|
2098
|
+
let data;
|
|
2099
|
+
let response;
|
|
2100
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2101
|
+
while (!success) {
|
|
2102
|
+
try {
|
|
2103
|
+
const urlParams = new URLSearchParams();
|
|
2104
|
+
if (queryParamOpts?.noMetadata !== undefined) {
|
|
2105
|
+
urlParams.append("no-metadata", queryParamOpts?.noMetadata.toString());
|
|
2106
|
+
}
|
|
2107
|
+
if (queryParamOpts?.withUncached !== undefined) {
|
|
2108
|
+
urlParams.append("with-uncached", queryParamOpts?.withUncached.toString());
|
|
2109
|
+
}
|
|
2110
|
+
let startTime;
|
|
2111
|
+
if (this.debug) {
|
|
2112
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2113
|
+
}
|
|
2114
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/nft/${contractAddress}/metadata/${tokenId}/?${urlParams}`, {
|
|
2115
|
+
headers: {
|
|
2116
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2117
|
+
"X-Requested-With": userAgent
|
|
2118
|
+
}
|
|
2119
|
+
}));
|
|
2120
|
+
debugOutput(response.url, response.status, startTime);
|
|
2121
|
+
if (response.status === 429) {
|
|
2122
|
+
try {
|
|
2123
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2124
|
+
}
|
|
2125
|
+
catch (error) {
|
|
2126
|
+
success = true;
|
|
2127
|
+
return {
|
|
2128
|
+
data: null,
|
|
2129
|
+
error: true,
|
|
2130
|
+
error_code: response.status,
|
|
2131
|
+
error_message: error.message
|
|
2132
|
+
};
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
else {
|
|
2136
|
+
data = await response.json();
|
|
2137
|
+
}
|
|
2138
|
+
const dataClass = new NftMetadataResponse(data.data);
|
|
2139
|
+
checkAndModifyResponse(dataClass);
|
|
2140
|
+
success = true;
|
|
2141
|
+
return {
|
|
2142
|
+
data: dataClass,
|
|
2143
|
+
error: data.error,
|
|
2144
|
+
error_code: data ? data.error_code : response.status,
|
|
2145
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
catch (error) {
|
|
2149
|
+
success = true;
|
|
2150
|
+
return {
|
|
2151
|
+
data: null,
|
|
2152
|
+
error: true,
|
|
2153
|
+
error_code: data ? data.error_code : response.status,
|
|
2154
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2155
|
+
};
|
|
2156
|
+
}
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
*
|
|
2161
|
+
* Commonly used to get all transactions of an NFT token. Useful for building a transaction history table or price chart.
|
|
2162
|
+
*
|
|
2163
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2164
|
+
* @param {string} contractAddress - The requested contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2165
|
+
* @param {string} tokenId - The requested token ID.
|
|
2166
|
+
* @param {GetNftTransactionsForContractTokenIdQueryParamOpts} queryParamOpts
|
|
2167
|
+
* - `noSpam`: If `true`, the suspected spam tokens are removed. Supports `eth-mainnet` and `matic-mainnet`.
|
|
2168
|
+
*
|
|
2169
|
+
*/
|
|
2170
|
+
async getNftTransactionsForContractTokenId(chainName, contractAddress, tokenId, queryParamOpts) {
|
|
2171
|
+
let success = false;
|
|
2172
|
+
let data;
|
|
2173
|
+
let response;
|
|
2174
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2175
|
+
while (!success) {
|
|
2176
|
+
try {
|
|
2177
|
+
const urlParams = new URLSearchParams();
|
|
2178
|
+
if (queryParamOpts?.noSpam !== undefined) {
|
|
2179
|
+
urlParams.append("no-spam", queryParamOpts?.noSpam.toString());
|
|
2180
|
+
}
|
|
2181
|
+
let startTime;
|
|
2182
|
+
if (this.debug) {
|
|
2183
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2184
|
+
}
|
|
2185
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/tokens/${contractAddress}/nft_transactions/${tokenId}/?${urlParams}`, {
|
|
2186
|
+
headers: {
|
|
2187
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2188
|
+
"X-Requested-With": userAgent
|
|
2189
|
+
}
|
|
2190
|
+
}));
|
|
2191
|
+
debugOutput(response.url, response.status, startTime);
|
|
2192
|
+
if (response.status === 429) {
|
|
2193
|
+
try {
|
|
2194
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2195
|
+
}
|
|
2196
|
+
catch (error) {
|
|
2197
|
+
success = true;
|
|
2198
|
+
return {
|
|
2199
|
+
data: null,
|
|
2200
|
+
error: true,
|
|
2201
|
+
error_code: response.status,
|
|
2202
|
+
error_message: error.message
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
else {
|
|
2207
|
+
data = await response.json();
|
|
2208
|
+
}
|
|
2209
|
+
const dataClass = new NftTransactionsResponse(data.data);
|
|
2210
|
+
checkAndModifyResponse(dataClass);
|
|
2211
|
+
success = true;
|
|
2212
|
+
return {
|
|
2213
|
+
data: dataClass,
|
|
2214
|
+
error: data.error,
|
|
2215
|
+
error_code: data ? data.error_code : response.status,
|
|
2216
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2217
|
+
};
|
|
2218
|
+
}
|
|
2219
|
+
catch (error) {
|
|
2220
|
+
success = true;
|
|
2221
|
+
return {
|
|
2222
|
+
data: null,
|
|
2223
|
+
error: true,
|
|
2224
|
+
error_code: data ? data.error_code : response.status,
|
|
2225
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2226
|
+
};
|
|
2227
|
+
}
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2230
|
+
/**
|
|
2231
|
+
*
|
|
2232
|
+
* Commonly used to fetch and render the traits of a collection as seen in rarity calculators.
|
|
2233
|
+
*
|
|
2234
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2235
|
+
* @param {string} collectionContract - The requested collection address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2236
|
+
*
|
|
2237
|
+
*/
|
|
2238
|
+
async getTraitsForCollection(chainName, collectionContract) {
|
|
2239
|
+
let success = false;
|
|
2240
|
+
let data;
|
|
2241
|
+
let response;
|
|
2242
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2243
|
+
while (!success) {
|
|
2244
|
+
try {
|
|
2245
|
+
const urlParams = new URLSearchParams();
|
|
2246
|
+
let startTime;
|
|
2247
|
+
if (this.debug) {
|
|
2248
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2249
|
+
}
|
|
2250
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/nft/${collectionContract}/traits/?${urlParams}`, {
|
|
2251
|
+
headers: {
|
|
2252
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2253
|
+
"X-Requested-With": userAgent
|
|
2254
|
+
}
|
|
2255
|
+
}));
|
|
2256
|
+
debugOutput(response.url, response.status, startTime);
|
|
2257
|
+
if (response.status === 429) {
|
|
2258
|
+
try {
|
|
2259
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2260
|
+
}
|
|
2261
|
+
catch (error) {
|
|
2262
|
+
success = true;
|
|
2263
|
+
return {
|
|
2264
|
+
data: null,
|
|
2265
|
+
error: true,
|
|
2266
|
+
error_code: response.status,
|
|
2267
|
+
error_message: error.message
|
|
2268
|
+
};
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
else {
|
|
2272
|
+
data = await response.json();
|
|
2273
|
+
}
|
|
2274
|
+
const dataClass = new NftCollectionTraitsResponse(data.data);
|
|
2275
|
+
checkAndModifyResponse(dataClass);
|
|
2276
|
+
success = true;
|
|
2277
|
+
return {
|
|
2278
|
+
data: dataClass,
|
|
2279
|
+
error: data.error,
|
|
2280
|
+
error_code: data ? data.error_code : response.status,
|
|
2281
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2282
|
+
};
|
|
2283
|
+
}
|
|
2284
|
+
catch (error) {
|
|
2285
|
+
success = true;
|
|
2286
|
+
return {
|
|
2287
|
+
data: null,
|
|
2288
|
+
error: true,
|
|
2289
|
+
error_code: data ? data.error_code : response.status,
|
|
2290
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2291
|
+
};
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
/**
|
|
2296
|
+
*
|
|
2297
|
+
* Commonly used to get the count of unique values for traits within an NFT collection.
|
|
2298
|
+
*
|
|
2299
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2300
|
+
* @param {string} collectionContract - The requested collection address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2301
|
+
* @param {string} trait - The requested trait.
|
|
2302
|
+
*
|
|
2303
|
+
*/
|
|
2304
|
+
async getAttributesForTraitInCollection(chainName, collectionContract, trait) {
|
|
2305
|
+
let success = false;
|
|
2306
|
+
let data;
|
|
2307
|
+
let response;
|
|
2308
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2309
|
+
while (!success) {
|
|
2310
|
+
try {
|
|
2311
|
+
const urlParams = new URLSearchParams();
|
|
2312
|
+
let startTime;
|
|
2313
|
+
if (this.debug) {
|
|
2314
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2315
|
+
}
|
|
2316
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/nft/${collectionContract}/traits/${trait}/attributes/?${urlParams}`, {
|
|
2317
|
+
headers: {
|
|
2318
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2319
|
+
"X-Requested-With": userAgent
|
|
2320
|
+
}
|
|
2321
|
+
}));
|
|
2322
|
+
debugOutput(response.url, response.status, startTime);
|
|
2323
|
+
if (response.status === 429) {
|
|
2324
|
+
try {
|
|
2325
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2326
|
+
}
|
|
2327
|
+
catch (error) {
|
|
2328
|
+
success = true;
|
|
2329
|
+
return {
|
|
2330
|
+
data: null,
|
|
2331
|
+
error: true,
|
|
2332
|
+
error_code: response.status,
|
|
2333
|
+
error_message: error.message
|
|
2334
|
+
};
|
|
2335
|
+
}
|
|
2336
|
+
}
|
|
2337
|
+
else {
|
|
2338
|
+
data = await response.json();
|
|
2339
|
+
}
|
|
2340
|
+
const dataClass = new NftCollectionAttributesForTraitResponse(data.data);
|
|
2341
|
+
checkAndModifyResponse(dataClass);
|
|
2342
|
+
success = true;
|
|
2343
|
+
return {
|
|
2344
|
+
data: dataClass,
|
|
2345
|
+
error: data.error,
|
|
2346
|
+
error_code: data ? data.error_code : response.status,
|
|
2347
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
catch (error) {
|
|
2351
|
+
success = true;
|
|
2352
|
+
return {
|
|
2353
|
+
data: null,
|
|
2354
|
+
error: true,
|
|
2355
|
+
error_code: data ? data.error_code : response.status,
|
|
2356
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2357
|
+
};
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
}
|
|
2361
|
+
/**
|
|
2362
|
+
*
|
|
2363
|
+
* Commonly used to calculate rarity scores for a collection based on its traits.
|
|
2364
|
+
*
|
|
2365
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2366
|
+
* @param {string} collectionContract - The requested collection address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2367
|
+
*
|
|
2368
|
+
*/
|
|
2369
|
+
async getCollectionTraitsSummary(chainName, collectionContract) {
|
|
2370
|
+
let success = false;
|
|
2371
|
+
let data;
|
|
2372
|
+
let response;
|
|
2373
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2374
|
+
while (!success) {
|
|
2375
|
+
try {
|
|
2376
|
+
const urlParams = new URLSearchParams();
|
|
2377
|
+
let startTime;
|
|
2378
|
+
if (this.debug) {
|
|
2379
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2380
|
+
}
|
|
2381
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/nft/${collectionContract}/traits_summary/?${urlParams}`, {
|
|
2382
|
+
headers: {
|
|
2383
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2384
|
+
"X-Requested-With": userAgent
|
|
2385
|
+
}
|
|
2386
|
+
}));
|
|
2387
|
+
debugOutput(response.url, response.status, startTime);
|
|
2388
|
+
if (response.status === 429) {
|
|
2389
|
+
try {
|
|
2390
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2391
|
+
}
|
|
2392
|
+
catch (error) {
|
|
2393
|
+
success = true;
|
|
2394
|
+
return {
|
|
2395
|
+
data: null,
|
|
2396
|
+
error: true,
|
|
2397
|
+
error_code: response.status,
|
|
2398
|
+
error_message: error.message
|
|
2399
|
+
};
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
else {
|
|
2403
|
+
data = await response.json();
|
|
2404
|
+
}
|
|
2405
|
+
const dataClass = new NftCollectionTraitSummaryResponse(data.data);
|
|
2406
|
+
checkAndModifyResponse(dataClass);
|
|
2407
|
+
success = true;
|
|
2408
|
+
return {
|
|
2409
|
+
data: dataClass,
|
|
2410
|
+
error: data.error,
|
|
2411
|
+
error_code: data ? data.error_code : response.status,
|
|
2412
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
catch (error) {
|
|
2416
|
+
success = true;
|
|
2417
|
+
return {
|
|
2418
|
+
data: null,
|
|
2419
|
+
error: true,
|
|
2420
|
+
error_code: data ? data.error_code : response.status,
|
|
2421
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
}
|
|
2426
|
+
/**
|
|
2427
|
+
*
|
|
2428
|
+
* Commonly used to verify ownership of NFTs (including ERC-721 and ERC-1155) within a collection.
|
|
2429
|
+
*
|
|
2430
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2431
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2432
|
+
* @param {string} collectionContract - The requested collection address.
|
|
2433
|
+
*
|
|
2434
|
+
*/
|
|
2435
|
+
async checkOwnershipInNft(chainName, walletAddress, collectionContract) {
|
|
2436
|
+
let success = false;
|
|
2437
|
+
let data;
|
|
2438
|
+
let response;
|
|
2439
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2440
|
+
while (!success) {
|
|
2441
|
+
try {
|
|
2442
|
+
const urlParams = new URLSearchParams();
|
|
2443
|
+
let startTime;
|
|
2444
|
+
if (this.debug) {
|
|
2445
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2446
|
+
}
|
|
2447
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/collection/${collectionContract}/?${urlParams}`, {
|
|
2448
|
+
headers: {
|
|
2449
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2450
|
+
"X-Requested-With": userAgent
|
|
2451
|
+
}
|
|
2452
|
+
}));
|
|
2453
|
+
debugOutput(response.url, response.status, startTime);
|
|
2454
|
+
if (response.status === 429) {
|
|
2455
|
+
try {
|
|
2456
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2457
|
+
}
|
|
2458
|
+
catch (error) {
|
|
2459
|
+
success = true;
|
|
2460
|
+
return {
|
|
2461
|
+
data: null,
|
|
2462
|
+
error: true,
|
|
2463
|
+
error_code: response.status,
|
|
2464
|
+
error_message: error.message
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
else {
|
|
2469
|
+
data = await response.json();
|
|
2470
|
+
}
|
|
2471
|
+
const dataClass = new NftOwnershipForCollectionResponse(data.data);
|
|
2472
|
+
checkAndModifyResponse(dataClass);
|
|
2473
|
+
success = true;
|
|
2474
|
+
return {
|
|
2475
|
+
data: dataClass,
|
|
2476
|
+
error: data.error,
|
|
2477
|
+
error_code: data ? data.error_code : response.status,
|
|
2478
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2479
|
+
};
|
|
2480
|
+
}
|
|
2481
|
+
catch (error) {
|
|
2482
|
+
success = true;
|
|
2483
|
+
return {
|
|
2484
|
+
data: null,
|
|
2485
|
+
error: true,
|
|
2486
|
+
error_code: data ? data.error_code : response.status,
|
|
2487
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2488
|
+
};
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
/**
|
|
2493
|
+
*
|
|
2494
|
+
* Commonly used to verify ownership of a specific token (ERC-721 or ERC-1155) within a collection.
|
|
2495
|
+
*
|
|
2496
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2497
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2498
|
+
* @param {string} collectionContract - The requested collection address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
2499
|
+
* @param {string} tokenId - The requested token ID.
|
|
2500
|
+
*
|
|
2501
|
+
*/
|
|
2502
|
+
async checkOwnershipInNftForSpecificTokenId(chainName, walletAddress, collectionContract, tokenId) {
|
|
2503
|
+
let success = false;
|
|
2504
|
+
let data;
|
|
2505
|
+
let response;
|
|
2506
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2507
|
+
while (!success) {
|
|
2508
|
+
try {
|
|
2509
|
+
const urlParams = new URLSearchParams();
|
|
2510
|
+
let startTime;
|
|
2511
|
+
if (this.debug) {
|
|
2512
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2513
|
+
}
|
|
2514
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/collection/${collectionContract}/token/${tokenId}/?${urlParams}`, {
|
|
2515
|
+
headers: {
|
|
2516
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2517
|
+
"X-Requested-With": userAgent
|
|
2518
|
+
}
|
|
2519
|
+
}));
|
|
2520
|
+
debugOutput(response.url, response.status, startTime);
|
|
2521
|
+
if (response.status === 429) {
|
|
2522
|
+
try {
|
|
2523
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2524
|
+
}
|
|
2525
|
+
catch (error) {
|
|
2526
|
+
success = true;
|
|
2527
|
+
return {
|
|
2528
|
+
data: null,
|
|
2529
|
+
error: true,
|
|
2530
|
+
error_code: response.status,
|
|
2531
|
+
error_message: error.message
|
|
2532
|
+
};
|
|
2533
|
+
}
|
|
2534
|
+
}
|
|
2535
|
+
else {
|
|
2536
|
+
data = await response.json();
|
|
2537
|
+
}
|
|
2538
|
+
const dataClass = new NftOwnershipForCollectionResponse(data.data);
|
|
2539
|
+
checkAndModifyResponse(dataClass);
|
|
2540
|
+
success = true;
|
|
2541
|
+
return {
|
|
2542
|
+
data: dataClass,
|
|
2543
|
+
error: data.error,
|
|
2544
|
+
error_code: data ? data.error_code : response.status,
|
|
2545
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2548
|
+
catch (error) {
|
|
2549
|
+
success = true;
|
|
2550
|
+
return {
|
|
2551
|
+
data: null,
|
|
2552
|
+
error: true,
|
|
2553
|
+
error_code: data ? data.error_code : response.status,
|
|
2554
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2555
|
+
};
|
|
2556
|
+
}
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
class TokenPricesResponse {
|
|
2562
|
+
constructor(data) {
|
|
2563
|
+
this.contract_decimals = data.contract_decimals;
|
|
2564
|
+
this.contract_name = data.contract_name;
|
|
2565
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
2566
|
+
this.contract_address = data.contract_address;
|
|
2567
|
+
this.supports_erc = data.supports_erc;
|
|
2568
|
+
this.logo_url = data.logo_url;
|
|
2569
|
+
this.update_at = data.update_at && data.update_at !== null ? dateFns.parseISO(data.update_at.toString()) : null;
|
|
2570
|
+
this.quote_currency = data.quote_currency;
|
|
2571
|
+
this.prices = data.prices && data.prices !== null ? data.prices.map((itemData) => new Price(itemData)) : null;
|
|
2572
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new Price(itemData)) : null;
|
|
2573
|
+
}
|
|
2574
|
+
}
|
|
2575
|
+
class Price {
|
|
2576
|
+
constructor(data) {
|
|
2577
|
+
this.date = data.date && data.date !== null ? dateFns.parseISO(data.date.toString()) : null;
|
|
2578
|
+
this.price = data.price;
|
|
2579
|
+
this.pretty_price = data.pretty_price;
|
|
2580
|
+
this.contract_metadata = data.contract_metadata && data.contract_metadata !== null ? new ContractMetadata$1(data.contract_metadata) : null;
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
let ContractMetadata$1 = class ContractMetadata {
|
|
2584
|
+
constructor(data) {
|
|
2585
|
+
this.contract_decimals = data.contract_decimals;
|
|
2586
|
+
this.contract_name = data.contract_name;
|
|
2587
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
2588
|
+
this.contract_address = data.contract_address;
|
|
2589
|
+
this.supports_erc = data.supports_erc;
|
|
2590
|
+
this.logo_url = data.logo_url;
|
|
2591
|
+
}
|
|
2592
|
+
};
|
|
2593
|
+
class PricingService {
|
|
2594
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
2595
|
+
this.apiKey = apiKey;
|
|
2596
|
+
this.debug = debug;
|
|
2597
|
+
this.threadCount = threadCount;
|
|
2598
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
2599
|
+
}
|
|
2600
|
+
/**
|
|
2601
|
+
*
|
|
2602
|
+
* Commonly used to get historic prices of a token between date ranges. Supports native tokens.
|
|
2603
|
+
*
|
|
2604
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2605
|
+
* @param {string} quoteCurrency - The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
2606
|
+
* @param {string} contractAddress - Contract address for the token. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically. Supports multiple contract addresses separated by commas.
|
|
2607
|
+
* @param {GetTokenPricesQueryParamOpts} queryParamOpts
|
|
2608
|
+
* - `from`: The start day of the historical price range (YYYY-MM-DD).
|
|
2609
|
+
* - `to`: The end day of the historical price range (YYYY-MM-DD).
|
|
2610
|
+
* - `pricesAtAsc`: Sort the prices in chronological ascending order. By default, it's set to `false` and returns prices in chronological descending order.
|
|
2611
|
+
*
|
|
2612
|
+
*/
|
|
2613
|
+
async getTokenPrices(chainName, quoteCurrency, contractAddress, queryParamOpts) {
|
|
2614
|
+
let success = false;
|
|
2615
|
+
let data;
|
|
2616
|
+
let response;
|
|
2617
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
2618
|
+
while (!success) {
|
|
2619
|
+
try {
|
|
2620
|
+
const urlParams = new URLSearchParams();
|
|
2621
|
+
if (queryParamOpts?.from !== undefined) {
|
|
2622
|
+
urlParams.append("from", queryParamOpts?.from.toString());
|
|
2623
|
+
}
|
|
2624
|
+
if (queryParamOpts?.to !== undefined) {
|
|
2625
|
+
urlParams.append("to", queryParamOpts?.to.toString());
|
|
2626
|
+
}
|
|
2627
|
+
if (queryParamOpts?.pricesAtAsc !== undefined) {
|
|
2628
|
+
urlParams.append("prices-at-asc", queryParamOpts?.pricesAtAsc.toString());
|
|
2629
|
+
}
|
|
2630
|
+
let startTime;
|
|
2631
|
+
if (this.debug) {
|
|
2632
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2633
|
+
}
|
|
2634
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/pricing/historical_by_addresses_v2/${chainName}/${quoteCurrency}/${contractAddress}/?${urlParams}`, {
|
|
2635
|
+
headers: {
|
|
2636
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
2637
|
+
"X-Requested-With": userAgent
|
|
2638
|
+
}
|
|
2639
|
+
}));
|
|
2640
|
+
debugOutput(response.url, response.status, startTime);
|
|
2641
|
+
if (response.status === 429) {
|
|
2642
|
+
try {
|
|
2643
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
2644
|
+
}
|
|
2645
|
+
catch (error) {
|
|
2646
|
+
success = true;
|
|
2647
|
+
return {
|
|
2648
|
+
data: null,
|
|
2649
|
+
error: true,
|
|
2650
|
+
error_code: response.status,
|
|
2651
|
+
error_message: error.message
|
|
2652
|
+
};
|
|
2653
|
+
}
|
|
2654
|
+
}
|
|
2655
|
+
else {
|
|
2656
|
+
data = await response.json();
|
|
2657
|
+
}
|
|
2658
|
+
const res = [];
|
|
2659
|
+
data.data.forEach((e) => {
|
|
2660
|
+
const dataClass = new TokenPricesResponse(e);
|
|
2661
|
+
checkAndModifyResponse(dataClass);
|
|
2662
|
+
res.push(dataClass);
|
|
2663
|
+
});
|
|
2664
|
+
success = true;
|
|
2665
|
+
return {
|
|
2666
|
+
data: res,
|
|
2667
|
+
error: data.error,
|
|
2668
|
+
error_code: data ? data.error_code : response.status,
|
|
2669
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
catch (error) {
|
|
2673
|
+
success = true;
|
|
2674
|
+
return {
|
|
2675
|
+
data: null,
|
|
2676
|
+
error: true,
|
|
2677
|
+
error_code: data ? data.error_code : response.status,
|
|
2678
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
2679
|
+
};
|
|
2680
|
+
}
|
|
2681
|
+
}
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
|
|
2685
|
+
class TransactionResponse {
|
|
2686
|
+
constructor(data) {
|
|
2687
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
2688
|
+
this.chain_id = data.chain_id;
|
|
2689
|
+
this.chain_name = data.chain_name;
|
|
2690
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new Transaction(itemData)) : null;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
class Transaction {
|
|
2694
|
+
constructor(data) {
|
|
2695
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
2696
|
+
this.block_height = data.block_height;
|
|
2697
|
+
this.block_hash = data.block_hash;
|
|
2698
|
+
this.tx_hash = data.tx_hash;
|
|
2699
|
+
this.tx_offset = data.tx_offset;
|
|
2700
|
+
this.successful = data.successful;
|
|
2701
|
+
this.from_address = data.from_address;
|
|
2702
|
+
this.miner_address = data.miner_address;
|
|
2703
|
+
this.from_address_label = data.from_address_label;
|
|
2704
|
+
this.to_address = data.to_address;
|
|
2705
|
+
this.to_address_label = data.to_address_label;
|
|
2706
|
+
this.value = data.value && data.value !== null ? BigInt(data.value) : null;
|
|
2707
|
+
this.value_quote = data.value_quote;
|
|
2708
|
+
this.pretty_value_quote = data.pretty_value_quote;
|
|
2709
|
+
this.gas_offered = data.gas_offered;
|
|
2710
|
+
this.gas_spent = data.gas_spent;
|
|
2711
|
+
this.gas_price = data.gas_price;
|
|
2712
|
+
this.fees_paid = data.fees_paid && data.fees_paid !== null ? BigInt(data.fees_paid) : null;
|
|
2713
|
+
this.gas_quote = data.gas_quote;
|
|
2714
|
+
this.pretty_gas_quote = data.pretty_gas_quote;
|
|
2715
|
+
this.gas_quote_rate = data.gas_quote_rate;
|
|
2716
|
+
this.gas_metadata = data.gas_metadata && data.gas_metadata !== null ? new ContractMetadata(data.gas_metadata) : null;
|
|
2717
|
+
this.dex_details = data.dex_details && data.dex_details !== null ? new DexReport(data.dex_details) : null;
|
|
2718
|
+
this.nft_sale_details = data.nft_sale_details && data.nft_sale_details !== null ? new NftSalesReport(data.nft_sale_details) : null;
|
|
2719
|
+
this.lending_details = data.lending_details && data.lending_details !== null ? new LendingReport(data.lending_details) : null;
|
|
2720
|
+
this.log_events = data.log_events && data.log_events !== null ? data.log_events.map((itemData) => new LogEvent(itemData)) : null;
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
class ContractMetadata {
|
|
2724
|
+
constructor(data) {
|
|
2725
|
+
this.contract_decimals = data.contract_decimals;
|
|
2726
|
+
this.contract_name = data.contract_name;
|
|
2727
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
2728
|
+
this.contract_address = data.contract_address;
|
|
2729
|
+
this.supports_erc = data.supports_erc;
|
|
2730
|
+
this.logo_url = data.logo_url;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
class DexReport {
|
|
2734
|
+
constructor(data) {
|
|
2735
|
+
this.log_offset = data.log_offset;
|
|
2736
|
+
this.protocol_name = data.protocol_name;
|
|
2737
|
+
this.protocol_address = data.protocol_address;
|
|
2738
|
+
this.protocol_logo_url = data.protocol_logo_url;
|
|
2739
|
+
this.aggregator_name = data.aggregator_name;
|
|
2740
|
+
this.aggregator_address = data.aggregator_address;
|
|
2741
|
+
this.version = data.version;
|
|
2742
|
+
this.fork_version = data.fork_version;
|
|
2743
|
+
this.fork = data.fork;
|
|
2744
|
+
this.event = data.event;
|
|
2745
|
+
this.pair_address = data.pair_address;
|
|
2746
|
+
this.pair_lp_fee_bps = data.pair_lp_fee_bps;
|
|
2747
|
+
this.lp_token_address = data.lp_token_address;
|
|
2748
|
+
this.lp_token_ticker = data.lp_token_ticker;
|
|
2749
|
+
this.lp_token_num_decimals = data.lp_token_num_decimals;
|
|
2750
|
+
this.lp_token_name = data.lp_token_name;
|
|
2751
|
+
this.lp_token_value = data.lp_token_value;
|
|
2752
|
+
this.exchange_rate_usd = data.exchange_rate_usd;
|
|
2753
|
+
this.token_0_address = data.token_0_address;
|
|
2754
|
+
this.token_0_ticker = data.token_0_ticker;
|
|
2755
|
+
this.token_0_num_decimals = data.token_0_num_decimals;
|
|
2756
|
+
this.token_0_name = data.token_0_name;
|
|
2757
|
+
this.token_1_address = data.token_1_address;
|
|
2758
|
+
this.token_1_ticker = data.token_1_ticker;
|
|
2759
|
+
this.token_1_num_decimals = data.token_1_num_decimals;
|
|
2760
|
+
this.token_1_name = data.token_1_name;
|
|
2761
|
+
this.token_0_amount = data.token_0_amount;
|
|
2762
|
+
this.token_0_quote_rate = data.token_0_quote_rate;
|
|
2763
|
+
this.token_0_usd_quote = data.token_0_usd_quote;
|
|
2764
|
+
this.pretty_token_0_usd_quote = data.pretty_token_0_usd_quote;
|
|
2765
|
+
this.token_0_logo_url = data.token_0_logo_url;
|
|
2766
|
+
this.token_1_amount = data.token_1_amount;
|
|
2767
|
+
this.token_1_quote_rate = data.token_1_quote_rate;
|
|
2768
|
+
this.token_1_usd_quote = data.token_1_usd_quote;
|
|
2769
|
+
this.pretty_token_1_usd_quote = data.pretty_token_1_usd_quote;
|
|
2770
|
+
this.token_1_logo_url = data.token_1_logo_url;
|
|
2771
|
+
this.sender = data.sender;
|
|
2772
|
+
this.recipient = data.recipient;
|
|
2773
|
+
}
|
|
2774
|
+
}
|
|
2775
|
+
class NftSalesReport {
|
|
2776
|
+
constructor(data) {
|
|
2777
|
+
this.log_offset = data.log_offset;
|
|
2778
|
+
this.topic0 = data.topic0;
|
|
2779
|
+
this.protocol_contract_address = data.protocol_contract_address;
|
|
2780
|
+
this.protocol_name = data.protocol_name;
|
|
2781
|
+
this.protocol_logo_url = data.protocol_logo_url;
|
|
2782
|
+
this.to = data.to;
|
|
2783
|
+
this.from = data.from;
|
|
2784
|
+
this.maker = data.maker;
|
|
2785
|
+
this.taker = data.taker;
|
|
2786
|
+
this.token_id = data.token_id;
|
|
2787
|
+
this.collection_address = data.collection_address;
|
|
2788
|
+
this.collection_name = data.collection_name;
|
|
2789
|
+
this.token_address = data.token_address;
|
|
2790
|
+
this.token_name = data.token_name;
|
|
2791
|
+
this.ticker_symbol = data.ticker_symbol;
|
|
2792
|
+
this.num_decimals = data.num_decimals;
|
|
2793
|
+
this.contract_quote_rate = data.contract_quote_rate;
|
|
2794
|
+
this.nft_token_price = data.nft_token_price;
|
|
2795
|
+
this.nft_token_price_usd = data.nft_token_price_usd;
|
|
2796
|
+
this.pretty_nft_token_price_usd = data.pretty_nft_token_price_usd;
|
|
2797
|
+
this.nft_token_price_native = data.nft_token_price_native;
|
|
2798
|
+
this.pretty_nft_token_price_native = data.pretty_nft_token_price_native;
|
|
2799
|
+
this.token_count = data.token_count;
|
|
2800
|
+
this.num_token_ids_sold_per_sale = data.num_token_ids_sold_per_sale;
|
|
2801
|
+
this.num_token_ids_sold_per_tx = data.num_token_ids_sold_per_tx;
|
|
2802
|
+
this.num_collections_sold_per_sale = data.num_collections_sold_per_sale;
|
|
2803
|
+
this.num_collections_sold_per_tx = data.num_collections_sold_per_tx;
|
|
2804
|
+
this.trade_type = data.trade_type;
|
|
2805
|
+
this.trade_group_type = data.trade_group_type;
|
|
2806
|
+
}
|
|
2807
|
+
}
|
|
2808
|
+
class LendingReport {
|
|
2809
|
+
constructor(data) {
|
|
2810
|
+
this.log_offset = data.log_offset;
|
|
2811
|
+
this.protocol_name = data.protocol_name;
|
|
2812
|
+
this.protocol_address = data.protocol_address;
|
|
2813
|
+
this.protocol_logo_url = data.protocol_logo_url;
|
|
2814
|
+
this.version = data.version;
|
|
2815
|
+
this.fork = data.fork;
|
|
2816
|
+
this.fork_version = data.fork_version;
|
|
2817
|
+
this.event = data.event;
|
|
2818
|
+
this.lp_token_name = data.lp_token_name;
|
|
2819
|
+
this.lp_decimals = data.lp_decimals;
|
|
2820
|
+
this.lp_ticker_symbol = data.lp_ticker_symbol;
|
|
2821
|
+
this.lp_token_address = data.lp_token_address;
|
|
2822
|
+
this.lp_token_amount = data.lp_token_amount;
|
|
2823
|
+
this.lp_token_price = data.lp_token_price;
|
|
2824
|
+
this.exchange_rate = data.exchange_rate;
|
|
2825
|
+
this.exchange_rate_usd = data.exchange_rate_usd;
|
|
2826
|
+
this.token_name_in = data.token_name_in;
|
|
2827
|
+
this.token_decimal_in = data.token_decimal_in;
|
|
2828
|
+
this.token_address_in = data.token_address_in;
|
|
2829
|
+
this.token_ticker_in = data.token_ticker_in;
|
|
2830
|
+
this.token_logo_in = data.token_logo_in;
|
|
2831
|
+
this.token_amount_in = data.token_amount_in;
|
|
2832
|
+
this.amount_in_usd = data.amount_in_usd;
|
|
2833
|
+
this.pretty_amount_in_usd = data.pretty_amount_in_usd;
|
|
2834
|
+
this.token_name_out = data.token_name_out;
|
|
2835
|
+
this.token_decimals_out = data.token_decimals_out;
|
|
2836
|
+
this.token_address_out = data.token_address_out;
|
|
2837
|
+
this.token_ticker_out = data.token_ticker_out;
|
|
2838
|
+
this.token_logo_out = data.token_logo_out;
|
|
2839
|
+
this.token_amount_out = data.token_amount_out;
|
|
2840
|
+
this.amount_out_usd = data.amount_out_usd;
|
|
2841
|
+
this.pretty_amount_out_usd = data.pretty_amount_out_usd;
|
|
2842
|
+
this.borrow_rate_mode = data.borrow_rate_mode;
|
|
2843
|
+
this.borrow_rate = data.borrow_rate;
|
|
2844
|
+
this.on_behalf_of = data.on_behalf_of;
|
|
2845
|
+
this.liquidator = data.liquidator;
|
|
2846
|
+
this.user = data.user;
|
|
2847
|
+
}
|
|
2848
|
+
}
|
|
2849
|
+
class LogEvent {
|
|
2850
|
+
constructor(data) {
|
|
2851
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
2852
|
+
this.block_height = data.block_height;
|
|
2853
|
+
this.tx_offset = data.tx_offset;
|
|
2854
|
+
this.log_offset = data.log_offset;
|
|
2855
|
+
this.tx_hash = data.tx_hash;
|
|
2856
|
+
this.raw_log_topics = data.raw_log_topics;
|
|
2857
|
+
this.sender_contract_decimals = data.sender_contract_decimals;
|
|
2858
|
+
this.sender_name = data.sender_name;
|
|
2859
|
+
this.sender_contract_ticker_symbol = data.sender_contract_ticker_symbol;
|
|
2860
|
+
this.sender_address = data.sender_address;
|
|
2861
|
+
this.sender_address_label = data.sender_address_label;
|
|
2862
|
+
this.sender_logo_url = data.sender_logo_url;
|
|
2863
|
+
this.raw_log_data = data.raw_log_data;
|
|
2864
|
+
this.decoded = data.decoded && data.decoded !== null ? new DecodedItem(data.decoded) : null;
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
class DecodedItem {
|
|
2868
|
+
constructor(data) {
|
|
2869
|
+
this.name = data.name;
|
|
2870
|
+
this.signature = data.signature;
|
|
2871
|
+
this.params = data.params && data.params !== null ? data.params.map((itemData) => new Param(itemData)) : null;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
class Param {
|
|
2875
|
+
constructor(data) {
|
|
2876
|
+
this.name = data.name;
|
|
2877
|
+
this.type = data.type;
|
|
2878
|
+
this.indexed = data.indexed;
|
|
2879
|
+
this.decoded = data.decoded;
|
|
2880
|
+
this.value = data.value;
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
class TransactionsBlockResponse {
|
|
2884
|
+
constructor(data) {
|
|
2885
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
2886
|
+
this.chain_id = data.chain_id;
|
|
2887
|
+
this.chain_name = data.chain_name;
|
|
2888
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new Transaction(itemData)) : null;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
class TransactionsSummaryResponse {
|
|
2892
|
+
constructor(data) {
|
|
2893
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
2894
|
+
this.address = data.address;
|
|
2895
|
+
this.chain_id = data.chain_id;
|
|
2896
|
+
this.chain_name = data.chain_name;
|
|
2897
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new TransactionsSummary(itemData)) : null;
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
class TransactionsSummary {
|
|
2901
|
+
constructor(data) {
|
|
2902
|
+
this.total_count = data.total_count;
|
|
2903
|
+
this.earliest_transaction = data.earliest_transaction && data.earliest_transaction !== null ? new TransactionSummary(data.earliest_transaction) : null;
|
|
2904
|
+
this.latest_transaction = data.latest_transaction && data.latest_transaction !== null ? new TransactionSummary(data.latest_transaction) : null;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
class TransactionSummary {
|
|
2908
|
+
constructor(data) {
|
|
2909
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
2910
|
+
this.tx_hash = data.tx_hash;
|
|
2911
|
+
this.tx_detail_link = data.tx_detail_link;
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
/**
|
|
2915
|
+
* Transactions APIs
|
|
2916
|
+
*
|
|
2917
|
+
*/
|
|
2918
|
+
async function* paginateEndpoint(url, apiKey, urlsParams, debug, threadCount) {
|
|
2919
|
+
let hasNext = true;
|
|
2920
|
+
let response;
|
|
2921
|
+
let data;
|
|
2922
|
+
const backoff = new ExponentialBackoff(apiKey, debug);
|
|
2923
|
+
const LIMIT = pLimit$1(threadCount);
|
|
2924
|
+
while (hasNext) {
|
|
2925
|
+
try {
|
|
2926
|
+
let startTime;
|
|
2927
|
+
if (debug) {
|
|
2928
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
2929
|
+
}
|
|
2930
|
+
response = await LIMIT(() => fetch(`${url}?${urlsParams}`, {
|
|
2931
|
+
headers: {
|
|
2932
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
2933
|
+
"X-Requested-With": userAgent
|
|
2934
|
+
}
|
|
2935
|
+
}));
|
|
2936
|
+
debugOutput(response.url, response.status, startTime);
|
|
2937
|
+
if (response.status === 429) {
|
|
2938
|
+
try {
|
|
2939
|
+
data = await LIMIT(() => backoff.backOff(response.url));
|
|
2940
|
+
}
|
|
2941
|
+
catch (error) {
|
|
2942
|
+
hasNext = false;
|
|
2943
|
+
throw new Error(`An error occurred ${response.status}: ${error.message}`);
|
|
2944
|
+
}
|
|
2945
|
+
}
|
|
2946
|
+
else {
|
|
2947
|
+
data = await response.json();
|
|
2948
|
+
}
|
|
2949
|
+
for (const tx of data.data.items) {
|
|
2950
|
+
const dataClass = new Transaction(tx);
|
|
2951
|
+
checkAndModifyResponse(dataClass);
|
|
2952
|
+
yield dataClass;
|
|
2953
|
+
}
|
|
2954
|
+
backoff.setNumAttempts(1);
|
|
2955
|
+
if (!data.error) {
|
|
2956
|
+
if ((data.data !== null) && data.data.links.prev === null) {
|
|
2957
|
+
hasNext = false;
|
|
2958
|
+
}
|
|
2959
|
+
url = data.data !== null ? data.data.links.prev : "";
|
|
2960
|
+
}
|
|
2961
|
+
else {
|
|
2962
|
+
hasNext = false;
|
|
2963
|
+
}
|
|
2964
|
+
}
|
|
2965
|
+
catch (error) {
|
|
2966
|
+
hasNext = false;
|
|
2967
|
+
if (error.message.includes("An error occurred 429")) {
|
|
2968
|
+
throw new Error(error.message);
|
|
2969
|
+
}
|
|
2970
|
+
throw new Error(`An error occurred ${data ? data.error_code : response.status}: ${data ? data.error_message : "401 Authorization Required"}`);
|
|
2971
|
+
}
|
|
2972
|
+
}
|
|
2973
|
+
}
|
|
2974
|
+
class TransactionService {
|
|
2975
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
2976
|
+
this.apiKey = apiKey;
|
|
2977
|
+
this.debug = debug;
|
|
2978
|
+
this.threadCount = threadCount;
|
|
2979
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
2980
|
+
}
|
|
2981
|
+
/**
|
|
2982
|
+
*
|
|
2983
|
+
* Commonly used to fetch and render a single transaction including its decoded log events. Additionally return semantically decoded information for DEX trades, lending and NFT sales.
|
|
2984
|
+
*
|
|
2985
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
2986
|
+
* @param {string} txHash - The transaction hash.
|
|
2987
|
+
* @param {GetTransactionQueryParamOpts} queryParamOpts
|
|
2988
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
2989
|
+
* - `noLogs`: Omit log events.
|
|
2990
|
+
* - `withDex`: Decoded DEX details including protocol (e.g. Uniswap), event (e.g 'add_liquidity') and tokens involved with historical prices. Additional 0.05 credits charged if data available.
|
|
2991
|
+
* - `withNftSales`: Decoded NFT sales details including marketplace (e.g. Opensea) and cached media links. Additional 0.05 credits charged if data available.
|
|
2992
|
+
* - `withLending`: Decoded lending details including protocol (e.g. Aave), event (e.g. 'deposit') and tokens involved with prices. Additional 0.05 credits charged if data available.
|
|
2993
|
+
*
|
|
2994
|
+
*/
|
|
2995
|
+
async getTransaction(chainName, txHash, queryParamOpts) {
|
|
2996
|
+
let success = false;
|
|
2997
|
+
let data;
|
|
2998
|
+
let response;
|
|
2999
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3000
|
+
while (!success) {
|
|
3001
|
+
try {
|
|
3002
|
+
const urlParams = new URLSearchParams();
|
|
3003
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
3004
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
3005
|
+
}
|
|
3006
|
+
if (queryParamOpts?.noLogs !== undefined) {
|
|
3007
|
+
urlParams.append("no-logs", queryParamOpts?.noLogs.toString());
|
|
3008
|
+
}
|
|
3009
|
+
if (queryParamOpts?.withDex !== undefined) {
|
|
3010
|
+
urlParams.append("with-dex", queryParamOpts?.withDex.toString());
|
|
3011
|
+
}
|
|
3012
|
+
if (queryParamOpts?.withNftSales !== undefined) {
|
|
3013
|
+
urlParams.append("with-nft-sales", queryParamOpts?.withNftSales.toString());
|
|
3014
|
+
}
|
|
3015
|
+
if (queryParamOpts?.withLending !== undefined) {
|
|
3016
|
+
urlParams.append("with-lending", queryParamOpts?.withLending.toString());
|
|
3017
|
+
}
|
|
3018
|
+
let startTime;
|
|
3019
|
+
if (this.debug) {
|
|
3020
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3021
|
+
}
|
|
3022
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/transaction_v2/${txHash}/?${urlParams}`, {
|
|
3023
|
+
headers: {
|
|
3024
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3025
|
+
"X-Requested-With": userAgent
|
|
3026
|
+
}
|
|
3027
|
+
}));
|
|
3028
|
+
debugOutput(response.url, response.status, startTime);
|
|
3029
|
+
if (response.status === 429) {
|
|
3030
|
+
try {
|
|
3031
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3032
|
+
}
|
|
3033
|
+
catch (error) {
|
|
3034
|
+
success = true;
|
|
3035
|
+
return {
|
|
3036
|
+
data: null,
|
|
3037
|
+
error: true,
|
|
3038
|
+
error_code: response.status,
|
|
3039
|
+
error_message: error.message
|
|
3040
|
+
};
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
else {
|
|
3044
|
+
data = await response.json();
|
|
3045
|
+
}
|
|
3046
|
+
const dataClass = new TransactionResponse(data.data);
|
|
3047
|
+
checkAndModifyResponse(dataClass);
|
|
3048
|
+
success = true;
|
|
3049
|
+
return {
|
|
3050
|
+
data: dataClass,
|
|
3051
|
+
error: data.error,
|
|
3052
|
+
error_code: data ? data.error_code : response.status,
|
|
3053
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3054
|
+
};
|
|
3055
|
+
}
|
|
3056
|
+
catch (error) {
|
|
3057
|
+
success = true;
|
|
3058
|
+
return {
|
|
3059
|
+
data: null,
|
|
3060
|
+
error: true,
|
|
3061
|
+
error_code: data ? data.error_code : response.status,
|
|
3062
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
}
|
|
3066
|
+
}
|
|
3067
|
+
/**
|
|
3068
|
+
*
|
|
3069
|
+
* Commonly used to fetch and render the most recent transactions involving an address. Frequently seen in wallet applications.
|
|
3070
|
+
*
|
|
3071
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3072
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
3073
|
+
* @param {GetAllTransactionsForAddressQueryParamOpts} queryParamOpts
|
|
3074
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
3075
|
+
* - `noLogs`: Omit log events.
|
|
3076
|
+
* - `blockSignedAtAsc`: Sort the transactions in ascending chronological order. By default, it's set to `false` and returns transactions in descending chronological order.
|
|
3077
|
+
*
|
|
3078
|
+
*/
|
|
3079
|
+
async *getAllTransactionsForAddress(chainName, walletAddress, queryParamOpts) {
|
|
3080
|
+
let success = false;
|
|
3081
|
+
let tx;
|
|
3082
|
+
while (!success) {
|
|
3083
|
+
try {
|
|
3084
|
+
const urlParams = new URLSearchParams();
|
|
3085
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
3086
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
3087
|
+
}
|
|
3088
|
+
if (queryParamOpts?.noLogs !== undefined) {
|
|
3089
|
+
urlParams.append("no-logs", queryParamOpts?.noLogs.toString());
|
|
3090
|
+
}
|
|
3091
|
+
if (queryParamOpts?.blockSignedAtAsc !== undefined) {
|
|
3092
|
+
urlParams.append("block-signed-at-asc", queryParamOpts?.blockSignedAtAsc.toString());
|
|
3093
|
+
}
|
|
3094
|
+
for await (tx of paginateEndpoint(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/transactions_v3/`, this.apiKey, urlParams, this.debug, this.threadCount)) {
|
|
3095
|
+
yield tx;
|
|
3096
|
+
}
|
|
3097
|
+
success = true;
|
|
3098
|
+
}
|
|
3099
|
+
catch (error) {
|
|
3100
|
+
success = true;
|
|
3101
|
+
throw new Error(error.message);
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3105
|
+
/**
|
|
3106
|
+
*
|
|
3107
|
+
* Commonly used to fetch all transactions including their decoded log events in a block and further flag interesting wallets or transactions.
|
|
3108
|
+
*
|
|
3109
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3110
|
+
* @param {number} blockHeight - The requested block height.
|
|
3111
|
+
* @param {GetTransactionsForBlockQueryParamOpts} queryParamOpts
|
|
3112
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
3113
|
+
* - `noLogs`: Omit log events.
|
|
3114
|
+
*
|
|
3115
|
+
*/
|
|
3116
|
+
async getTransactionsForBlock(chainName, blockHeight, queryParamOpts) {
|
|
3117
|
+
let success = false;
|
|
3118
|
+
let data;
|
|
3119
|
+
let response;
|
|
3120
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3121
|
+
while (!success) {
|
|
3122
|
+
try {
|
|
3123
|
+
const urlParams = new URLSearchParams();
|
|
3124
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
3125
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
3126
|
+
}
|
|
3127
|
+
if (queryParamOpts?.noLogs !== undefined) {
|
|
3128
|
+
urlParams.append("no-logs", queryParamOpts?.noLogs.toString());
|
|
3129
|
+
}
|
|
3130
|
+
let startTime;
|
|
3131
|
+
if (this.debug) {
|
|
3132
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3133
|
+
}
|
|
3134
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/block/${blockHeight}/transactions_v3/?${urlParams}`, {
|
|
3135
|
+
headers: {
|
|
3136
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3137
|
+
"X-Requested-With": userAgent
|
|
3138
|
+
}
|
|
3139
|
+
}));
|
|
3140
|
+
debugOutput(response.url, response.status, startTime);
|
|
3141
|
+
if (response.status === 429) {
|
|
3142
|
+
try {
|
|
3143
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3144
|
+
}
|
|
3145
|
+
catch (error) {
|
|
3146
|
+
success = true;
|
|
3147
|
+
return {
|
|
3148
|
+
data: null,
|
|
3149
|
+
error: true,
|
|
3150
|
+
error_code: response.status,
|
|
3151
|
+
error_message: error.message
|
|
3152
|
+
};
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
else {
|
|
3156
|
+
data = await response.json();
|
|
3157
|
+
}
|
|
3158
|
+
const dataClass = new TransactionsBlockResponse(data.data);
|
|
3159
|
+
checkAndModifyResponse(dataClass);
|
|
3160
|
+
success = true;
|
|
3161
|
+
return {
|
|
3162
|
+
data: dataClass,
|
|
3163
|
+
error: data.error,
|
|
3164
|
+
error_code: data ? data.error_code : response.status,
|
|
3165
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3166
|
+
};
|
|
3167
|
+
}
|
|
3168
|
+
catch (error) {
|
|
3169
|
+
success = true;
|
|
3170
|
+
return {
|
|
3171
|
+
data: null,
|
|
3172
|
+
error: true,
|
|
3173
|
+
error_code: data ? data.error_code : response.status,
|
|
3174
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
3179
|
+
/**
|
|
3180
|
+
*
|
|
3181
|
+
* Commonly used to fetch the earliest and latest transactions, and the transaction count for a wallet. Calculate the age of the wallet and the time it has been idle and quickly gain insights into their engagement with web3.
|
|
3182
|
+
*
|
|
3183
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3184
|
+
* @param {string} walletAddress - The requested address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
3185
|
+
*
|
|
3186
|
+
*/
|
|
3187
|
+
async getTransactionSummary(chainName, walletAddress) {
|
|
3188
|
+
let success = false;
|
|
3189
|
+
let data;
|
|
3190
|
+
let response;
|
|
3191
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3192
|
+
while (!success) {
|
|
3193
|
+
try {
|
|
3194
|
+
const urlParams = new URLSearchParams();
|
|
3195
|
+
let startTime;
|
|
3196
|
+
if (this.debug) {
|
|
3197
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3198
|
+
}
|
|
3199
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/address/${walletAddress}/transactions_summary/?${urlParams}`, {
|
|
3200
|
+
headers: {
|
|
3201
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3202
|
+
"X-Requested-With": userAgent
|
|
3203
|
+
}
|
|
3204
|
+
}));
|
|
3205
|
+
debugOutput(response.url, response.status, startTime);
|
|
3206
|
+
if (response.status === 429) {
|
|
3207
|
+
try {
|
|
3208
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3209
|
+
}
|
|
3210
|
+
catch (error) {
|
|
3211
|
+
success = true;
|
|
3212
|
+
return {
|
|
3213
|
+
data: null,
|
|
3214
|
+
error: true,
|
|
3215
|
+
error_code: response.status,
|
|
3216
|
+
error_message: error.message
|
|
3217
|
+
};
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
else {
|
|
3221
|
+
data = await response.json();
|
|
3222
|
+
}
|
|
3223
|
+
const dataClass = new TransactionsSummaryResponse(data.data);
|
|
3224
|
+
checkAndModifyResponse(dataClass);
|
|
3225
|
+
success = true;
|
|
3226
|
+
return {
|
|
3227
|
+
data: dataClass,
|
|
3228
|
+
error: data.error,
|
|
3229
|
+
error_code: data ? data.error_code : response.status,
|
|
3230
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3231
|
+
};
|
|
3232
|
+
}
|
|
3233
|
+
catch (error) {
|
|
3234
|
+
success = true;
|
|
3235
|
+
return {
|
|
3236
|
+
data: null,
|
|
3237
|
+
error: true,
|
|
3238
|
+
error_code: data ? data.error_code : response.status,
|
|
3239
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
class PoolResponse {
|
|
3247
|
+
constructor(data) {
|
|
3248
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3249
|
+
this.chain_id = data.chain_id;
|
|
3250
|
+
this.chain_name = data.chain_name;
|
|
3251
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new Pool(itemData)) : null;
|
|
3252
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
class Pool {
|
|
3256
|
+
constructor(data) {
|
|
3257
|
+
this.exchange = data.exchange;
|
|
3258
|
+
this.swap_count_24h = data.swap_count_24h;
|
|
3259
|
+
this.total_liquidity_quote = data.total_liquidity_quote;
|
|
3260
|
+
this.volume_24h_quote = data.volume_24h_quote;
|
|
3261
|
+
this.fee_24h_quote = data.fee_24h_quote;
|
|
3262
|
+
this.total_supply = data.total_supply && data.total_supply !== null ? BigInt(data.total_supply) : null;
|
|
3263
|
+
this.quote_rate = data.quote_rate;
|
|
3264
|
+
this.chain_name = data.chain_name;
|
|
3265
|
+
this.chain_id = data.chain_id;
|
|
3266
|
+
this.dex_name = data.dex_name;
|
|
3267
|
+
this.volume_7d_quote = data.volume_7d_quote;
|
|
3268
|
+
this.annualized_fee = data.annualized_fee;
|
|
3269
|
+
this.token_0 = data.token_0 && data.token_0 !== null ? new Token(data.token_0) : null;
|
|
3270
|
+
this.token_1 = data.token_1 && data.token_1 !== null ? new Token(data.token_1) : null;
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
3273
|
+
class Pagination {
|
|
3274
|
+
constructor(data) {
|
|
3275
|
+
this.has_more = data.has_more;
|
|
3276
|
+
this.page_number = data.page_number;
|
|
3277
|
+
this.page_size = data.page_size;
|
|
3278
|
+
this.total_count = data.total_count;
|
|
3279
|
+
}
|
|
3280
|
+
}
|
|
3281
|
+
class Token {
|
|
3282
|
+
constructor(data) {
|
|
3283
|
+
this.contract_address = data.contract_address;
|
|
3284
|
+
this.contract_name = data.contract_name;
|
|
3285
|
+
this.volume_in_24h = data.volume_in_24h;
|
|
3286
|
+
this.volume_out_24h = data.volume_out_24h;
|
|
3287
|
+
this.quote_rate = data.quote_rate;
|
|
3288
|
+
this.reserve = data.reserve;
|
|
3289
|
+
this.logo_url = data.logo_url;
|
|
3290
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
3291
|
+
this.contract_decimals = data.contract_decimals;
|
|
3292
|
+
this.volume_in_7d = data.volume_in_7d;
|
|
3293
|
+
this.volume_out_7d = data.volume_out_7d;
|
|
3294
|
+
}
|
|
3295
|
+
}
|
|
3296
|
+
class PoolToDexResponse {
|
|
3297
|
+
constructor(data) {
|
|
3298
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3299
|
+
this.address = data.address;
|
|
3300
|
+
this.chain_id = data.chain_id;
|
|
3301
|
+
this.chain_name = data.chain_name;
|
|
3302
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new PoolToDexItem(itemData)) : null;
|
|
3303
|
+
}
|
|
3304
|
+
}
|
|
3305
|
+
class SupportedDex {
|
|
3306
|
+
constructor(data) {
|
|
3307
|
+
this.chain_id = data.chain_id;
|
|
3308
|
+
this.chain_name = data.chain_name;
|
|
3309
|
+
this.dex_name = data.dex_name;
|
|
3310
|
+
this.factory_contract_address = data.factory_contract_address;
|
|
3311
|
+
this.router_contract_addresses = data.router_contract_addresses;
|
|
3312
|
+
this.swap_fee = data.swap_fee;
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
class PoolToDexItem extends SupportedDex {
|
|
3316
|
+
constructor(data) {
|
|
3317
|
+
super(data);
|
|
3318
|
+
this.logo_url = data.logo_url;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
class PoolByAddressResponse {
|
|
3322
|
+
constructor(data) {
|
|
3323
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3324
|
+
this.chain_id = data.chain_id;
|
|
3325
|
+
this.chain_name = data.chain_name;
|
|
3326
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new PoolWithTimeseries(itemData)) : null;
|
|
3327
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
class PoolWithTimeseries {
|
|
3331
|
+
constructor(data) {
|
|
3332
|
+
this.exchange = data.exchange;
|
|
3333
|
+
this.swap_count_24h = data.swap_count_24h;
|
|
3334
|
+
this.total_liquidity_quote = data.total_liquidity_quote;
|
|
3335
|
+
this.volume_24h_quote = data.volume_24h_quote;
|
|
3336
|
+
this.fee_24h_quote = data.fee_24h_quote;
|
|
3337
|
+
this.total_supply = data.total_supply && data.total_supply !== null ? BigInt(data.total_supply) : null;
|
|
3338
|
+
this.quote_rate = data.quote_rate;
|
|
3339
|
+
this.chain_id = data.chain_id;
|
|
3340
|
+
this.dex_name = data.dex_name;
|
|
3341
|
+
this.volume_7d_quote = data.volume_7d_quote;
|
|
3342
|
+
this.annualized_fee = data.annualized_fee;
|
|
3343
|
+
this.token_0_reserve_quote = data.token_0_reserve_quote;
|
|
3344
|
+
this.token_1_reserve_quote = data.token_1_reserve_quote;
|
|
3345
|
+
this.token_0 = data.token_0 && data.token_0 !== null ? new Token(data.token_0) : null;
|
|
3346
|
+
this.token_1 = data.token_1 && data.token_1 !== null ? new Token(data.token_1) : null;
|
|
3347
|
+
this.volume_timeseries_7d = data.volume_timeseries_7d && data.volume_timeseries_7d !== null ? data.volume_timeseries_7d.map((itemData) => new VolumeTimeseries(itemData)) : null;
|
|
3348
|
+
this.volume_timeseries_30d = data.volume_timeseries_30d && data.volume_timeseries_30d !== null ? data.volume_timeseries_30d.map((itemData) => new VolumeTimeseries(itemData)) : null;
|
|
3349
|
+
this.liquidity_timeseries_7d = data.liquidity_timeseries_7d && data.liquidity_timeseries_7d !== null ? data.liquidity_timeseries_7d.map((itemData) => new LiquidityTimeseries(itemData)) : null;
|
|
3350
|
+
this.liquidity_timeseries_30d = data.liquidity_timeseries_30d && data.liquidity_timeseries_30d !== null ? data.liquidity_timeseries_30d.map((itemData) => new LiquidityTimeseries(itemData)) : null;
|
|
3351
|
+
this.price_timeseries_7d = data.price_timeseries_7d && data.price_timeseries_7d !== null ? data.price_timeseries_7d.map((itemData) => new PriceTimeseries(itemData)) : null;
|
|
3352
|
+
this.price_timeseries_30d = data.price_timeseries_30d && data.price_timeseries_30d !== null ? data.price_timeseries_30d.map((itemData) => new PriceTimeseries(itemData)) : null;
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
class VolumeTimeseries {
|
|
3356
|
+
constructor(data) {
|
|
3357
|
+
this.dex_name = data.dex_name;
|
|
3358
|
+
this.chain_id = data.chain_id;
|
|
3359
|
+
this.dt = data.dt;
|
|
3360
|
+
this.exchange = data.exchange;
|
|
3361
|
+
this.sum_amount_0_in = data.sum_amount_0_in;
|
|
3362
|
+
this.sum_amount_0_out = data.sum_amount_0_out;
|
|
3363
|
+
this.sum_amount_1_in = data.sum_amount_1_in;
|
|
3364
|
+
this.sum_amount_1_out = data.sum_amount_1_out;
|
|
3365
|
+
this.volume_quote = data.volume_quote;
|
|
3366
|
+
this.token_0_quote_rate = data.token_0_quote_rate;
|
|
3367
|
+
this.token_1_quote_rate = data.token_1_quote_rate;
|
|
3368
|
+
this.swap_count_24 = data.swap_count_24;
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
class LiquidityTimeseries {
|
|
3372
|
+
constructor(data) {
|
|
3373
|
+
this.dex_name = data.dex_name;
|
|
3374
|
+
this.chain_id = data.chain_id;
|
|
3375
|
+
this.dt = data.dt;
|
|
3376
|
+
this.exchange = data.exchange;
|
|
3377
|
+
this.r0_c = data.r0_c;
|
|
3378
|
+
this.r1_c = data.r1_c;
|
|
3379
|
+
this.liquidity_quote = data.liquidity_quote;
|
|
3380
|
+
this.token_0_quote_rate = data.token_0_quote_rate;
|
|
3381
|
+
this.token_1_quote_rate = data.token_1_quote_rate;
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
class PriceTimeseries {
|
|
3385
|
+
constructor(data) {
|
|
3386
|
+
this.dex_name = data.dex_name;
|
|
3387
|
+
this.chain_id = data.chain_id;
|
|
3388
|
+
this.dt = data.dt;
|
|
3389
|
+
this.exchange = data.exchange;
|
|
3390
|
+
this.price_of_token_0_in_token_1 = data.price_of_token_0_in_token_1;
|
|
3391
|
+
this.price_of_token_0_in_token_1_description = data.price_of_token_0_in_token_1_description;
|
|
3392
|
+
this.price_of_token_1_in_token_0 = data.price_of_token_1_in_token_0;
|
|
3393
|
+
this.price_of_token_1_in_token_0_description = data.price_of_token_1_in_token_0_description;
|
|
3394
|
+
this.quote_currency = data.quote_currency;
|
|
3395
|
+
this.price_of_token_0_in_quote_currency = data.price_of_token_0_in_quote_currency;
|
|
3396
|
+
this.price_of_token_1_in_quote_currency = data.price_of_token_1_in_quote_currency;
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
class PoolsDexDataResponse {
|
|
3400
|
+
constructor(data) {
|
|
3401
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3402
|
+
this.address = data.address;
|
|
3403
|
+
this.chain_id = data.chain_id;
|
|
3404
|
+
this.chain_name = data.chain_name;
|
|
3405
|
+
this.quote_currency = data.quote_currency;
|
|
3406
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new PoolsDexDataItem(itemData)) : null;
|
|
3407
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3408
|
+
}
|
|
3409
|
+
}
|
|
3410
|
+
class PoolsDexDataItem {
|
|
3411
|
+
constructor(data) {
|
|
3412
|
+
this.dex_name = data.dex_name;
|
|
3413
|
+
this.exchange = data.exchange;
|
|
3414
|
+
this.exchange_ticker_symbol = data.exchange_ticker_symbol;
|
|
3415
|
+
this.exchange_logo_url = data.exchange_logo_url;
|
|
3416
|
+
this.total_liquidity_quote = data.total_liquidity_quote;
|
|
3417
|
+
this.pretty_total_liquidity_quote = data.pretty_total_liquidity_quote;
|
|
3418
|
+
this.volume_24h_quote = data.volume_24h_quote;
|
|
3419
|
+
this.volume_7d_quote = data.volume_7d_quote;
|
|
3420
|
+
this.fee_24h_quote = data.fee_24h_quote;
|
|
3421
|
+
this.pretty_volume_24h_quote = data.pretty_volume_24h_quote;
|
|
3422
|
+
this.pretty_volume_7d_quote = data.pretty_volume_7d_quote;
|
|
3423
|
+
this.pretty_fee_24h_quote = data.pretty_fee_24h_quote;
|
|
3424
|
+
this.token_0 = data.token_0 && data.token_0 !== null ? new PoolsDexToken(data.token_0) : null;
|
|
3425
|
+
this.token_1 = data.token_1 && data.token_1 !== null ? new PoolsDexToken(data.token_1) : null;
|
|
3426
|
+
}
|
|
3427
|
+
}
|
|
3428
|
+
class PoolsDexToken {
|
|
3429
|
+
constructor(data) {
|
|
3430
|
+
this.reserve = data.reserve;
|
|
3431
|
+
this.contract_name = data.contract_name;
|
|
3432
|
+
this.contract_decimals = data.contract_decimals;
|
|
3433
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
3434
|
+
this.contract_address = data.contract_address;
|
|
3435
|
+
this.logo_url = data.logo_url;
|
|
3436
|
+
this.quote_rate = data.quote_rate;
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
class AddressExchangeBalancesResponse {
|
|
3440
|
+
constructor(data) {
|
|
3441
|
+
this.address = data.address;
|
|
3442
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3443
|
+
this.chain_id = data.chain_id;
|
|
3444
|
+
this.chain_name = data.chain_name;
|
|
3445
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new UniswapLikeBalanceItem(itemData)) : null;
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
class UniswapLikeBalanceItem {
|
|
3449
|
+
constructor(data) {
|
|
3450
|
+
this.token_0 = data.token_0 && data.token_0 !== null ? new UniswapLikeToken(data.token_0) : null;
|
|
3451
|
+
this.token_1 = data.token_1 && data.token_1 !== null ? new UniswapLikeToken(data.token_1) : null;
|
|
3452
|
+
this.pool_token = data.pool_token && data.pool_token !== null ? new UniswapLikeTokenWithSupply(data.pool_token) : null;
|
|
3453
|
+
}
|
|
3454
|
+
}
|
|
3455
|
+
class UniswapLikeToken {
|
|
3456
|
+
constructor(data) {
|
|
3457
|
+
this.contract_decimals = data.contract_decimals;
|
|
3458
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
3459
|
+
this.contract_address = data.contract_address;
|
|
3460
|
+
this.logo_url = data.logo_url;
|
|
3461
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
3462
|
+
this.quote = data.quote;
|
|
3463
|
+
this.quote_rate = data.quote_rate;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
class UniswapLikeTokenWithSupply {
|
|
3467
|
+
constructor(data) {
|
|
3468
|
+
this.contract_decimals = data.contract_decimals;
|
|
3469
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
3470
|
+
this.contract_address = data.contract_address;
|
|
3471
|
+
this.logo_url = data.logo_url;
|
|
3472
|
+
this.balance = data.balance && data.balance !== null ? BigInt(data.balance) : null;
|
|
3473
|
+
this.quote = data.quote;
|
|
3474
|
+
this.quote_rate = data.quote_rate;
|
|
3475
|
+
this.total_supply = data.total_supply && data.total_supply !== null ? BigInt(data.total_supply) : null;
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
class NetworkExchangeTokensResponse {
|
|
3479
|
+
constructor(data) {
|
|
3480
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3481
|
+
this.chain_id = data.chain_id;
|
|
3482
|
+
this.chain_name = data.chain_name;
|
|
3483
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new TokenV2Volume(itemData)) : null;
|
|
3484
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
class TokenV2Volume {
|
|
3488
|
+
constructor(data) {
|
|
3489
|
+
this.chain_name = data.chain_name;
|
|
3490
|
+
this.chain_id = data.chain_id;
|
|
3491
|
+
this.dex_name = data.dex_name;
|
|
3492
|
+
this.contract_address = data.contract_address;
|
|
3493
|
+
this.contract_name = data.contract_name;
|
|
3494
|
+
this.total_liquidity = data.total_liquidity;
|
|
3495
|
+
this.total_volume24h = data.total_volume24h;
|
|
3496
|
+
this.logo_url = data.logo_url;
|
|
3497
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
3498
|
+
this.contract_decimals = data.contract_decimals;
|
|
3499
|
+
this.swap_count_24h = data.swap_count_24h;
|
|
3500
|
+
this.quote_rate = data.quote_rate;
|
|
3501
|
+
this.total_liquidity_quote = data.total_liquidity_quote;
|
|
3502
|
+
this.total_volume_24h_quote = data.total_volume_24h_quote;
|
|
3503
|
+
}
|
|
3504
|
+
}
|
|
3505
|
+
class SupportedDexesResponse {
|
|
3506
|
+
constructor(data) {
|
|
3507
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3508
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new SupportedDex(itemData)) : null;
|
|
3509
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
class SingleNetworkExchangeTokenResponse {
|
|
3513
|
+
constructor(data) {
|
|
3514
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3515
|
+
this.chain_id = data.chain_id;
|
|
3516
|
+
this.chain_name = data.chain_name;
|
|
3517
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new PoolWithTimeseries(itemData)) : null;
|
|
3518
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
class TransactionsForAccountAddressResponse {
|
|
3522
|
+
constructor(data) {
|
|
3523
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3524
|
+
this.chain_id = data.chain_id;
|
|
3525
|
+
this.chain_name = data.chain_name;
|
|
3526
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ExchangeTransaction(itemData)) : null;
|
|
3527
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
class ExchangeTransaction {
|
|
3531
|
+
constructor(data) {
|
|
3532
|
+
this.block_signed_at = data.block_signed_at && data.block_signed_at !== null ? dateFns.parseISO(data.block_signed_at.toString()) : null;
|
|
3533
|
+
this.tx_hash = data.tx_hash;
|
|
3534
|
+
this.act = data.act;
|
|
3535
|
+
this.address = data.address;
|
|
3536
|
+
this.amount0 = data.amount0;
|
|
3537
|
+
this.amount1 = data.amount1;
|
|
3538
|
+
this.amount0_in = data.amount0_in;
|
|
3539
|
+
this.amount0_out = data.amount0_out;
|
|
3540
|
+
this.amount1_out = data.amount1_out;
|
|
3541
|
+
this.to_address = data.to_address;
|
|
3542
|
+
this.from_address = data.from_address;
|
|
3543
|
+
this.sender_address = data.sender_address;
|
|
3544
|
+
this.total_quote = data.total_quote;
|
|
3545
|
+
this.token_0_quote_rate = data.token_0_quote_rate;
|
|
3546
|
+
this.token_1_quote_rate = data.token_1_quote_rate;
|
|
3547
|
+
this.token_0 = data.token_0 && data.token_0 !== null ? new PoolToken(data.token_0) : null;
|
|
3548
|
+
this.token_1 = data.token_1 && data.token_1 !== null ? new PoolToken(data.token_1) : null;
|
|
3549
|
+
}
|
|
3550
|
+
}
|
|
3551
|
+
class PoolToken {
|
|
3552
|
+
constructor(data) {
|
|
3553
|
+
this.contract_decimals = data.contract_decimals;
|
|
3554
|
+
this.contract_name = data.contract_name;
|
|
3555
|
+
this.contract_ticker_symbol = data.contract_ticker_symbol;
|
|
3556
|
+
this.contract_address = data.contract_address;
|
|
3557
|
+
this.supports_erc = data.supports_erc;
|
|
3558
|
+
this.logo_url = data.logo_url;
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
class TransactionsForTokenAddressResponse {
|
|
3562
|
+
constructor(data) {
|
|
3563
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3564
|
+
this.chain_id = data.chain_id;
|
|
3565
|
+
this.chain_name = data.chain_name;
|
|
3566
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ExchangeTransaction(itemData)) : null;
|
|
3567
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
class TransactionsForExchangeResponse {
|
|
3571
|
+
constructor(data) {
|
|
3572
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3573
|
+
this.chain_id = data.chain_id;
|
|
3574
|
+
this.chain_name = data.chain_name;
|
|
3575
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new ExchangeTransaction(itemData)) : null;
|
|
3576
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
class EcosystemChartDataResponse {
|
|
3580
|
+
constructor(data) {
|
|
3581
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3582
|
+
this.chain_id = data.chain_id;
|
|
3583
|
+
this.chain_name = data.chain_name;
|
|
3584
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new UniswapLikeEcosystemCharts(itemData)) : null;
|
|
3585
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3588
|
+
class UniswapLikeEcosystemCharts {
|
|
3589
|
+
constructor(data) {
|
|
3590
|
+
this.dex_name = data.dex_name;
|
|
3591
|
+
this.chain_id = data.chain_id;
|
|
3592
|
+
this.quote_currency = data.quote_currency;
|
|
3593
|
+
this.gas_token_price_quote = data.gas_token_price_quote;
|
|
3594
|
+
this.total_swaps24h = data.total_swaps24h;
|
|
3595
|
+
this.total_active_pairs7d = data.total_active_pairs7d;
|
|
3596
|
+
this.total_fees24h = data.total_fees24h;
|
|
3597
|
+
this.volume_chart7d = data.volume_chart7d && data.volume_chart7d !== null ? data.volume_chart7d.map((itemData) => new VolumeEcosystemChart(itemData)) : null;
|
|
3598
|
+
this.volume_chart30d = data.volume_chart30d && data.volume_chart30d !== null ? data.volume_chart30d.map((itemData) => new VolumeEcosystemChart(itemData)) : null;
|
|
3599
|
+
this.liquidity_chart7d = data.liquidity_chart7d && data.liquidity_chart7d !== null ? data.liquidity_chart7d.map((itemData) => new LiquidityEcosystemChart(itemData)) : null;
|
|
3600
|
+
this.liquidity_chart30d = data.liquidity_chart30d && data.liquidity_chart30d !== null ? data.liquidity_chart30d.map((itemData) => new LiquidityEcosystemChart(itemData)) : null;
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
class VolumeEcosystemChart {
|
|
3604
|
+
constructor(data) {
|
|
3605
|
+
this.dex_name = data.dex_name;
|
|
3606
|
+
this.chain_id = data.chain_id;
|
|
3607
|
+
this.dt = data.dt && data.dt !== null ? dateFns.parseISO(data.dt.toString()) : null;
|
|
3608
|
+
this.quote_currency = data.quote_currency;
|
|
3609
|
+
this.volume_quote = data.volume_quote;
|
|
3610
|
+
this.swap_count_24 = data.swap_count_24;
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
class LiquidityEcosystemChart {
|
|
3614
|
+
constructor(data) {
|
|
3615
|
+
this.dex_name = data.dex_name;
|
|
3616
|
+
this.chain_id = data.chain_id;
|
|
3617
|
+
this.dt = data.dt && data.dt !== null ? dateFns.parseISO(data.dt.toString()) : null;
|
|
3618
|
+
this.quote_currency = data.quote_currency;
|
|
3619
|
+
this.liquidity_quote = data.liquidity_quote;
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
class HealthDataResponse {
|
|
3623
|
+
constructor(data) {
|
|
3624
|
+
this.updated_at = data.updated_at && data.updated_at !== null ? dateFns.parseISO(data.updated_at.toString()) : null;
|
|
3625
|
+
this.chain_id = data.chain_id;
|
|
3626
|
+
this.chain_name = data.chain_name;
|
|
3627
|
+
this.items = data.items && data.items !== null ? data.items.map((itemData) => new HealthData(itemData)) : null;
|
|
3628
|
+
this.pagination = data.pagination && data.pagination !== null ? new Pagination(data.pagination) : null;
|
|
3629
|
+
}
|
|
3630
|
+
}
|
|
3631
|
+
class HealthData {
|
|
3632
|
+
constructor(data) {
|
|
3633
|
+
this.synced_block_height = data.synced_block_height;
|
|
3634
|
+
this.synced_block_signed_at = data.synced_block_signed_at && data.synced_block_signed_at !== null ? dateFns.parseISO(data.synced_block_signed_at.toString()) : null;
|
|
3635
|
+
this.latest_block_height = data.latest_block_height;
|
|
3636
|
+
this.latest_block_signed_at = data.latest_block_signed_at && data.latest_block_signed_at !== null ? dateFns.parseISO(data.latest_block_signed_at.toString()) : null;
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3639
|
+
/**
|
|
3640
|
+
* XYK APIs
|
|
3641
|
+
*
|
|
3642
|
+
*/
|
|
3643
|
+
class XykService {
|
|
3644
|
+
constructor(apiKey, debug = false, threadCount = 3) {
|
|
3645
|
+
this.apiKey = apiKey;
|
|
3646
|
+
this.debug = debug;
|
|
3647
|
+
this.threadCount = threadCount;
|
|
3648
|
+
this.LIMIT = pLimit$1(this.threadCount);
|
|
3649
|
+
}
|
|
3650
|
+
/**
|
|
3651
|
+
*
|
|
3652
|
+
* Commonly used to get all the pools of a particular DEX. Supports most common DEXs (Uniswap, SushiSwap, etc), and returns detailed trading data (volume, liquidity, swap counts, fees, LP token prices).
|
|
3653
|
+
*
|
|
3654
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3655
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
3656
|
+
*
|
|
3657
|
+
*/
|
|
3658
|
+
async getPools(chainName, dexName) {
|
|
3659
|
+
let success = false;
|
|
3660
|
+
let data;
|
|
3661
|
+
let response;
|
|
3662
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3663
|
+
while (!success) {
|
|
3664
|
+
try {
|
|
3665
|
+
const urlParams = new URLSearchParams();
|
|
3666
|
+
let startTime;
|
|
3667
|
+
if (this.debug) {
|
|
3668
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3669
|
+
}
|
|
3670
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/pools/?${urlParams}`, {
|
|
3671
|
+
headers: {
|
|
3672
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3673
|
+
"X-Requested-With": userAgent
|
|
3674
|
+
}
|
|
3675
|
+
}));
|
|
3676
|
+
debugOutput(response.url, response.status, startTime);
|
|
3677
|
+
if (response.status === 429) {
|
|
3678
|
+
try {
|
|
3679
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3680
|
+
}
|
|
3681
|
+
catch (error) {
|
|
3682
|
+
success = true;
|
|
3683
|
+
return {
|
|
3684
|
+
data: null,
|
|
3685
|
+
error: true,
|
|
3686
|
+
error_code: response.status,
|
|
3687
|
+
error_message: error.message
|
|
3688
|
+
};
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
else {
|
|
3692
|
+
data = await response.json();
|
|
3693
|
+
}
|
|
3694
|
+
const dataClass = new PoolResponse(data.data);
|
|
3695
|
+
checkAndModifyResponse(dataClass);
|
|
3696
|
+
success = true;
|
|
3697
|
+
return {
|
|
3698
|
+
data: dataClass,
|
|
3699
|
+
error: data.error,
|
|
3700
|
+
error_code: data ? data.error_code : response.status,
|
|
3701
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3702
|
+
};
|
|
3703
|
+
}
|
|
3704
|
+
catch (error) {
|
|
3705
|
+
success = true;
|
|
3706
|
+
return {
|
|
3707
|
+
data: null,
|
|
3708
|
+
error: true,
|
|
3709
|
+
error_code: data ? data.error_code : response.status,
|
|
3710
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3711
|
+
};
|
|
3712
|
+
}
|
|
3713
|
+
}
|
|
3714
|
+
}
|
|
3715
|
+
/**
|
|
3716
|
+
*
|
|
3717
|
+
* Commonly used to get the corresponding supported DEX given a pool address, along with the swap fees, DEX's logo url, and factory addresses. Useful to identifying the specific DEX to which a pair address is associated.
|
|
3718
|
+
*
|
|
3719
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3720
|
+
* @param {string} poolAddress - The requested pool address.
|
|
3721
|
+
*
|
|
3722
|
+
*/
|
|
3723
|
+
async getDexForPoolAddress(chainName, poolAddress) {
|
|
3724
|
+
let success = false;
|
|
3725
|
+
let data;
|
|
3726
|
+
let response;
|
|
3727
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3728
|
+
while (!success) {
|
|
3729
|
+
try {
|
|
3730
|
+
const urlParams = new URLSearchParams();
|
|
3731
|
+
let startTime;
|
|
3732
|
+
if (this.debug) {
|
|
3733
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3734
|
+
}
|
|
3735
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/address/${poolAddress}/dex_name/?${urlParams}`, {
|
|
3736
|
+
headers: {
|
|
3737
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3738
|
+
"X-Requested-With": userAgent
|
|
3739
|
+
}
|
|
3740
|
+
}));
|
|
3741
|
+
debugOutput(response.url, response.status, startTime);
|
|
3742
|
+
if (response.status === 429) {
|
|
3743
|
+
try {
|
|
3744
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3745
|
+
}
|
|
3746
|
+
catch (error) {
|
|
3747
|
+
success = true;
|
|
3748
|
+
return {
|
|
3749
|
+
data: null,
|
|
3750
|
+
error: true,
|
|
3751
|
+
error_code: response.status,
|
|
3752
|
+
error_message: error.message
|
|
3753
|
+
};
|
|
3754
|
+
}
|
|
3755
|
+
}
|
|
3756
|
+
else {
|
|
3757
|
+
data = await response.json();
|
|
3758
|
+
}
|
|
3759
|
+
const dataClass = new PoolToDexResponse(data.data);
|
|
3760
|
+
checkAndModifyResponse(dataClass);
|
|
3761
|
+
success = true;
|
|
3762
|
+
return {
|
|
3763
|
+
data: dataClass,
|
|
3764
|
+
error: data.error,
|
|
3765
|
+
error_code: data ? data.error_code : response.status,
|
|
3766
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3767
|
+
};
|
|
3768
|
+
}
|
|
3769
|
+
catch (error) {
|
|
3770
|
+
success = true;
|
|
3771
|
+
return {
|
|
3772
|
+
data: null,
|
|
3773
|
+
error: true,
|
|
3774
|
+
error_code: data ? data.error_code : response.status,
|
|
3775
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3776
|
+
};
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
/**
|
|
3781
|
+
*
|
|
3782
|
+
* Commonly used to get the 7 day and 30 day time-series data (volume, liquidity, price) of a particular liquidity pool in a DEX. Useful for building time-series charts on DEX trading activity.
|
|
3783
|
+
*
|
|
3784
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3785
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
3786
|
+
* @param {string} poolAddress - The pool contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
3787
|
+
*
|
|
3788
|
+
*/
|
|
3789
|
+
async getPoolByAddress(chainName, dexName, poolAddress) {
|
|
3790
|
+
let success = false;
|
|
3791
|
+
let data;
|
|
3792
|
+
let response;
|
|
3793
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3794
|
+
while (!success) {
|
|
3795
|
+
try {
|
|
3796
|
+
const urlParams = new URLSearchParams();
|
|
3797
|
+
let startTime;
|
|
3798
|
+
if (this.debug) {
|
|
3799
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3800
|
+
}
|
|
3801
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/pools/address/${poolAddress}/?${urlParams}`, {
|
|
3802
|
+
headers: {
|
|
3803
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3804
|
+
"X-Requested-With": userAgent
|
|
3805
|
+
}
|
|
3806
|
+
}));
|
|
3807
|
+
debugOutput(response.url, response.status, startTime);
|
|
3808
|
+
if (response.status === 429) {
|
|
3809
|
+
try {
|
|
3810
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3811
|
+
}
|
|
3812
|
+
catch (error) {
|
|
3813
|
+
success = true;
|
|
3814
|
+
return {
|
|
3815
|
+
data: null,
|
|
3816
|
+
error: true,
|
|
3817
|
+
error_code: response.status,
|
|
3818
|
+
error_message: error.message
|
|
3819
|
+
};
|
|
3820
|
+
}
|
|
3821
|
+
}
|
|
3822
|
+
else {
|
|
3823
|
+
data = await response.json();
|
|
3824
|
+
}
|
|
3825
|
+
const dataClass = new PoolByAddressResponse(data.data);
|
|
3826
|
+
checkAndModifyResponse(dataClass);
|
|
3827
|
+
success = true;
|
|
3828
|
+
return {
|
|
3829
|
+
data: dataClass,
|
|
3830
|
+
error: data.error,
|
|
3831
|
+
error_code: data ? data.error_code : response.status,
|
|
3832
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3833
|
+
};
|
|
3834
|
+
}
|
|
3835
|
+
catch (error) {
|
|
3836
|
+
success = true;
|
|
3837
|
+
return {
|
|
3838
|
+
data: null,
|
|
3839
|
+
error: true,
|
|
3840
|
+
error_code: data ? data.error_code : response.status,
|
|
3841
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
/**
|
|
3847
|
+
*
|
|
3848
|
+
* Commonly used to get all pools and the supported DEX for a token. Useful for building a table of top pairs across all supported DEXes that the token is trading on.
|
|
3849
|
+
*
|
|
3850
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3851
|
+
* @param {string} tokenAddress - The token contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
3852
|
+
* @param {number} page - The requested 0-indexed page number.
|
|
3853
|
+
* @param {GetPoolsForTokenAddressQueryParamOpts} queryParamOpts
|
|
3854
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
3855
|
+
*
|
|
3856
|
+
*/
|
|
3857
|
+
async getPoolsForTokenAddress(chainName, tokenAddress, page, queryParamOpts) {
|
|
3858
|
+
let success = false;
|
|
3859
|
+
let data;
|
|
3860
|
+
let response;
|
|
3861
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3862
|
+
while (!success) {
|
|
3863
|
+
try {
|
|
3864
|
+
const urlParams = new URLSearchParams();
|
|
3865
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
3866
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
3867
|
+
}
|
|
3868
|
+
let startTime;
|
|
3869
|
+
if (this.debug) {
|
|
3870
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3871
|
+
}
|
|
3872
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/tokens/address/${tokenAddress}/pools/page/${page}/?${urlParams}`, {
|
|
3873
|
+
headers: {
|
|
3874
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3875
|
+
"X-Requested-With": userAgent
|
|
3876
|
+
}
|
|
3877
|
+
}));
|
|
3878
|
+
debugOutput(response.url, response.status, startTime);
|
|
3879
|
+
if (response.status === 429) {
|
|
3880
|
+
try {
|
|
3881
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3882
|
+
}
|
|
3883
|
+
catch (error) {
|
|
3884
|
+
success = true;
|
|
3885
|
+
return {
|
|
3886
|
+
data: null,
|
|
3887
|
+
error: true,
|
|
3888
|
+
error_code: response.status,
|
|
3889
|
+
error_message: error.message
|
|
3890
|
+
};
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
else {
|
|
3894
|
+
data = await response.json();
|
|
3895
|
+
}
|
|
3896
|
+
const dataClass = new PoolsDexDataResponse(data.data);
|
|
3897
|
+
checkAndModifyResponse(dataClass);
|
|
3898
|
+
success = true;
|
|
3899
|
+
return {
|
|
3900
|
+
data: dataClass,
|
|
3901
|
+
error: data.error,
|
|
3902
|
+
error_code: data ? data.error_code : response.status,
|
|
3903
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3904
|
+
};
|
|
3905
|
+
}
|
|
3906
|
+
catch (error) {
|
|
3907
|
+
success = true;
|
|
3908
|
+
return {
|
|
3909
|
+
data: null,
|
|
3910
|
+
error: true,
|
|
3911
|
+
error_code: data ? data.error_code : response.status,
|
|
3912
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3913
|
+
};
|
|
3914
|
+
}
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
/**
|
|
3918
|
+
*
|
|
3919
|
+
* Commonly used to return balance of a wallet/contract address on a specific DEX.
|
|
3920
|
+
*
|
|
3921
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3922
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
3923
|
+
* @param {string} accountAddress - The account address.
|
|
3924
|
+
*
|
|
3925
|
+
*/
|
|
3926
|
+
async getAddressExchangeBalances(chainName, dexName, accountAddress) {
|
|
3927
|
+
let success = false;
|
|
3928
|
+
let data;
|
|
3929
|
+
let response;
|
|
3930
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
3931
|
+
while (!success) {
|
|
3932
|
+
try {
|
|
3933
|
+
const urlParams = new URLSearchParams();
|
|
3934
|
+
let startTime;
|
|
3935
|
+
if (this.debug) {
|
|
3936
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
3937
|
+
}
|
|
3938
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/address/${accountAddress}/balances/?${urlParams}`, {
|
|
3939
|
+
headers: {
|
|
3940
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
3941
|
+
"X-Requested-With": userAgent
|
|
3942
|
+
}
|
|
3943
|
+
}));
|
|
3944
|
+
debugOutput(response.url, response.status, startTime);
|
|
3945
|
+
if (response.status === 429) {
|
|
3946
|
+
try {
|
|
3947
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
3948
|
+
}
|
|
3949
|
+
catch (error) {
|
|
3950
|
+
success = true;
|
|
3951
|
+
return {
|
|
3952
|
+
data: null,
|
|
3953
|
+
error: true,
|
|
3954
|
+
error_code: response.status,
|
|
3955
|
+
error_message: error.message
|
|
3956
|
+
};
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
else {
|
|
3960
|
+
data = await response.json();
|
|
3961
|
+
}
|
|
3962
|
+
const dataClass = new AddressExchangeBalancesResponse(data.data);
|
|
3963
|
+
checkAndModifyResponse(dataClass);
|
|
3964
|
+
success = true;
|
|
3965
|
+
return {
|
|
3966
|
+
data: dataClass,
|
|
3967
|
+
error: data.error,
|
|
3968
|
+
error_code: data ? data.error_code : response.status,
|
|
3969
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3970
|
+
};
|
|
3971
|
+
}
|
|
3972
|
+
catch (error) {
|
|
3973
|
+
success = true;
|
|
3974
|
+
return {
|
|
3975
|
+
data: null,
|
|
3976
|
+
error: true,
|
|
3977
|
+
error_code: data ? data.error_code : response.status,
|
|
3978
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
/**
|
|
3984
|
+
*
|
|
3985
|
+
* Commonly used to get all pools and supported DEX for a wallet. Useful for building a personal DEX UI showcasing pairs and supported DEXes associated to the wallet.
|
|
3986
|
+
*
|
|
3987
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
3988
|
+
* @param {string} walletAddress - The account address.
|
|
3989
|
+
* @param {number} page - The requested 0-indexed page number.
|
|
3990
|
+
* @param {GetPoolsForWalletAddressQueryParamOpts} queryParamOpts
|
|
3991
|
+
* - `tokenAddress`: The token contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
3992
|
+
* - `quoteCurrency`: The currency to convert. Supports `USD`, `CAD`, `EUR`, `SGD`, `INR`, `JPY`, `VND`, `CNY`, `KRW`, `RUB`, `TRY`, `NGN`, `ARS`, `AUD`, `CHF`, and `GBP`.
|
|
3993
|
+
*
|
|
3994
|
+
*/
|
|
3995
|
+
async getPoolsForWalletAddress(chainName, walletAddress, page, queryParamOpts) {
|
|
3996
|
+
let success = false;
|
|
3997
|
+
let data;
|
|
3998
|
+
let response;
|
|
3999
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4000
|
+
while (!success) {
|
|
4001
|
+
try {
|
|
4002
|
+
const urlParams = new URLSearchParams();
|
|
4003
|
+
if (queryParamOpts?.tokenAddress !== undefined) {
|
|
4004
|
+
urlParams.append("token-address", queryParamOpts?.tokenAddress.toString());
|
|
4005
|
+
}
|
|
4006
|
+
if (queryParamOpts?.quoteCurrency !== undefined) {
|
|
4007
|
+
urlParams.append("quote-currency", queryParamOpts?.quoteCurrency.toString());
|
|
4008
|
+
}
|
|
4009
|
+
let startTime;
|
|
4010
|
+
if (this.debug) {
|
|
4011
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4012
|
+
}
|
|
4013
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/address/${walletAddress}/pools/page/${page}/?${urlParams}`, {
|
|
4014
|
+
headers: {
|
|
4015
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4016
|
+
"X-Requested-With": userAgent
|
|
4017
|
+
}
|
|
4018
|
+
}));
|
|
4019
|
+
debugOutput(response.url, response.status, startTime);
|
|
4020
|
+
if (response.status === 429) {
|
|
4021
|
+
try {
|
|
4022
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4023
|
+
}
|
|
4024
|
+
catch (error) {
|
|
4025
|
+
success = true;
|
|
4026
|
+
return {
|
|
4027
|
+
data: null,
|
|
4028
|
+
error: true,
|
|
4029
|
+
error_code: response.status,
|
|
4030
|
+
error_message: error.message
|
|
4031
|
+
};
|
|
4032
|
+
}
|
|
4033
|
+
}
|
|
4034
|
+
else {
|
|
4035
|
+
data = await response.json();
|
|
4036
|
+
}
|
|
4037
|
+
const dataClass = new PoolsDexDataResponse(data.data);
|
|
4038
|
+
checkAndModifyResponse(dataClass);
|
|
4039
|
+
success = true;
|
|
4040
|
+
return {
|
|
4041
|
+
data: dataClass,
|
|
4042
|
+
error: data.error,
|
|
4043
|
+
error_code: data ? data.error_code : response.status,
|
|
4044
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4045
|
+
};
|
|
4046
|
+
}
|
|
4047
|
+
catch (error) {
|
|
4048
|
+
success = true;
|
|
4049
|
+
return {
|
|
4050
|
+
data: null,
|
|
4051
|
+
error: true,
|
|
4052
|
+
error_code: data ? data.error_code : response.status,
|
|
4053
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4054
|
+
};
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
}
|
|
4058
|
+
/**
|
|
4059
|
+
*
|
|
4060
|
+
* Commonly used to retrieve all network exchange tokens for a specific DEX. Useful for building a top tokens table by total liquidity within a particular DEX.
|
|
4061
|
+
*
|
|
4062
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4063
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4064
|
+
*
|
|
4065
|
+
*/
|
|
4066
|
+
async getNetworkExchangeTokens(chainName, dexName) {
|
|
4067
|
+
let success = false;
|
|
4068
|
+
let data;
|
|
4069
|
+
let response;
|
|
4070
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4071
|
+
while (!success) {
|
|
4072
|
+
try {
|
|
4073
|
+
const urlParams = new URLSearchParams();
|
|
4074
|
+
let startTime;
|
|
4075
|
+
if (this.debug) {
|
|
4076
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4077
|
+
}
|
|
4078
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/tokens/?${urlParams}`, {
|
|
4079
|
+
headers: {
|
|
4080
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4081
|
+
"X-Requested-With": userAgent
|
|
4082
|
+
}
|
|
4083
|
+
}));
|
|
4084
|
+
debugOutput(response.url, response.status, startTime);
|
|
4085
|
+
if (response.status === 429) {
|
|
4086
|
+
try {
|
|
4087
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4088
|
+
}
|
|
4089
|
+
catch (error) {
|
|
4090
|
+
success = true;
|
|
4091
|
+
return {
|
|
4092
|
+
data: null,
|
|
4093
|
+
error: true,
|
|
4094
|
+
error_code: response.status,
|
|
4095
|
+
error_message: error.message
|
|
4096
|
+
};
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
else {
|
|
4100
|
+
data = await response.json();
|
|
4101
|
+
}
|
|
4102
|
+
const dataClass = new NetworkExchangeTokensResponse(data.data);
|
|
4103
|
+
checkAndModifyResponse(dataClass);
|
|
4104
|
+
success = true;
|
|
4105
|
+
return {
|
|
4106
|
+
data: dataClass,
|
|
4107
|
+
error: data.error,
|
|
4108
|
+
error_code: data ? data.error_code : response.status,
|
|
4109
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4110
|
+
};
|
|
4111
|
+
}
|
|
4112
|
+
catch (error) {
|
|
4113
|
+
success = true;
|
|
4114
|
+
return {
|
|
4115
|
+
data: null,
|
|
4116
|
+
error: true,
|
|
4117
|
+
error_code: data ? data.error_code : response.status,
|
|
4118
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4119
|
+
};
|
|
4120
|
+
}
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
/**
|
|
4124
|
+
*
|
|
4125
|
+
* Commonly used to get all the supported DEXs available for the xy=k endpoints, along with the swap fees and factory addresses.
|
|
4126
|
+
*
|
|
4127
|
+
*
|
|
4128
|
+
*/
|
|
4129
|
+
async getSupportedDEXes() {
|
|
4130
|
+
let success = false;
|
|
4131
|
+
let data;
|
|
4132
|
+
let response;
|
|
4133
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4134
|
+
while (!success) {
|
|
4135
|
+
try {
|
|
4136
|
+
const urlParams = new URLSearchParams();
|
|
4137
|
+
let startTime;
|
|
4138
|
+
if (this.debug) {
|
|
4139
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4140
|
+
}
|
|
4141
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/xy=k/supported_dexes/?${urlParams}`, {
|
|
4142
|
+
headers: {
|
|
4143
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4144
|
+
"X-Requested-With": userAgent
|
|
4145
|
+
}
|
|
4146
|
+
}));
|
|
4147
|
+
debugOutput(response.url, response.status, startTime);
|
|
4148
|
+
if (response.status === 429) {
|
|
4149
|
+
try {
|
|
4150
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4151
|
+
}
|
|
4152
|
+
catch (error) {
|
|
4153
|
+
success = true;
|
|
4154
|
+
return {
|
|
4155
|
+
data: null,
|
|
4156
|
+
error: true,
|
|
4157
|
+
error_code: response.status,
|
|
4158
|
+
error_message: error.message
|
|
4159
|
+
};
|
|
4160
|
+
}
|
|
4161
|
+
}
|
|
4162
|
+
else {
|
|
4163
|
+
data = await response.json();
|
|
4164
|
+
}
|
|
4165
|
+
const dataClass = new SupportedDexesResponse(data.data);
|
|
4166
|
+
checkAndModifyResponse(dataClass);
|
|
4167
|
+
success = true;
|
|
4168
|
+
return {
|
|
4169
|
+
data: dataClass,
|
|
4170
|
+
error: data.error,
|
|
4171
|
+
error_code: data ? data.error_code : response.status,
|
|
4172
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4173
|
+
};
|
|
4174
|
+
}
|
|
4175
|
+
catch (error) {
|
|
4176
|
+
success = true;
|
|
4177
|
+
return {
|
|
4178
|
+
data: null,
|
|
4179
|
+
error: true,
|
|
4180
|
+
error_code: data ? data.error_code : response.status,
|
|
4181
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4182
|
+
};
|
|
4183
|
+
}
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
/**
|
|
4187
|
+
*
|
|
4188
|
+
* Commonly used to get historical daily swap count for a single network exchange token.
|
|
4189
|
+
*
|
|
4190
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4191
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4192
|
+
* @param {string} tokenAddress - The token contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
4193
|
+
*
|
|
4194
|
+
*/
|
|
4195
|
+
async getSingleNetworkExchangeToken(chainName, dexName, tokenAddress) {
|
|
4196
|
+
let success = false;
|
|
4197
|
+
let data;
|
|
4198
|
+
let response;
|
|
4199
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4200
|
+
while (!success) {
|
|
4201
|
+
try {
|
|
4202
|
+
const urlParams = new URLSearchParams();
|
|
4203
|
+
let startTime;
|
|
4204
|
+
if (this.debug) {
|
|
4205
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4206
|
+
}
|
|
4207
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/tokens/address/${tokenAddress}/?${urlParams}`, {
|
|
4208
|
+
headers: {
|
|
4209
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4210
|
+
"X-Requested-With": userAgent
|
|
4211
|
+
}
|
|
4212
|
+
}));
|
|
4213
|
+
debugOutput(response.url, response.status, startTime);
|
|
4214
|
+
if (response.status === 429) {
|
|
4215
|
+
try {
|
|
4216
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4217
|
+
}
|
|
4218
|
+
catch (error) {
|
|
4219
|
+
success = true;
|
|
4220
|
+
return {
|
|
4221
|
+
data: null,
|
|
4222
|
+
error: true,
|
|
4223
|
+
error_code: response.status,
|
|
4224
|
+
error_message: error.message
|
|
4225
|
+
};
|
|
4226
|
+
}
|
|
4227
|
+
}
|
|
4228
|
+
else {
|
|
4229
|
+
data = await response.json();
|
|
4230
|
+
}
|
|
4231
|
+
const dataClass = new SingleNetworkExchangeTokenResponse(data.data);
|
|
4232
|
+
checkAndModifyResponse(dataClass);
|
|
4233
|
+
success = true;
|
|
4234
|
+
return {
|
|
4235
|
+
data: dataClass,
|
|
4236
|
+
error: data.error,
|
|
4237
|
+
error_code: data ? data.error_code : response.status,
|
|
4238
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4239
|
+
};
|
|
4240
|
+
}
|
|
4241
|
+
catch (error) {
|
|
4242
|
+
success = true;
|
|
4243
|
+
return {
|
|
4244
|
+
data: null,
|
|
4245
|
+
error: true,
|
|
4246
|
+
error_code: data ? data.error_code : response.status,
|
|
4247
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4248
|
+
};
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
/**
|
|
4253
|
+
*
|
|
4254
|
+
* Commonly used to get all the DEX transactions of a wallet. Useful for building tables of DEX activity segmented by wallet.
|
|
4255
|
+
*
|
|
4256
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4257
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4258
|
+
* @param {string} accountAddress - The account address. Passing in an `ENS` or `RNS` resolves automatically.
|
|
4259
|
+
*
|
|
4260
|
+
*/
|
|
4261
|
+
async getTransactionsForAccountAddress(chainName, dexName, accountAddress) {
|
|
4262
|
+
let success = false;
|
|
4263
|
+
let data;
|
|
4264
|
+
let response;
|
|
4265
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4266
|
+
while (!success) {
|
|
4267
|
+
try {
|
|
4268
|
+
const urlParams = new URLSearchParams();
|
|
4269
|
+
let startTime;
|
|
4270
|
+
if (this.debug) {
|
|
4271
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4272
|
+
}
|
|
4273
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/address/${accountAddress}/transactions/?${urlParams}`, {
|
|
4274
|
+
headers: {
|
|
4275
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4276
|
+
"X-Requested-With": userAgent
|
|
4277
|
+
}
|
|
4278
|
+
}));
|
|
4279
|
+
debugOutput(response.url, response.status, startTime);
|
|
4280
|
+
if (response.status === 429) {
|
|
4281
|
+
try {
|
|
4282
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4283
|
+
}
|
|
4284
|
+
catch (error) {
|
|
4285
|
+
success = true;
|
|
4286
|
+
return {
|
|
4287
|
+
data: null,
|
|
4288
|
+
error: true,
|
|
4289
|
+
error_code: response.status,
|
|
4290
|
+
error_message: error.message
|
|
4291
|
+
};
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
else {
|
|
4295
|
+
data = await response.json();
|
|
4296
|
+
}
|
|
4297
|
+
const dataClass = new TransactionsForAccountAddressResponse(data.data);
|
|
4298
|
+
checkAndModifyResponse(dataClass);
|
|
4299
|
+
success = true;
|
|
4300
|
+
return {
|
|
4301
|
+
data: dataClass,
|
|
4302
|
+
error: data.error,
|
|
4303
|
+
error_code: data ? data.error_code : response.status,
|
|
4304
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4305
|
+
};
|
|
4306
|
+
}
|
|
4307
|
+
catch (error) {
|
|
4308
|
+
success = true;
|
|
4309
|
+
return {
|
|
4310
|
+
data: null,
|
|
4311
|
+
error: true,
|
|
4312
|
+
error_code: data ? data.error_code : response.status,
|
|
4313
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4314
|
+
};
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
/**
|
|
4319
|
+
*
|
|
4320
|
+
* Commonly used to get all the transactions of a token within a particular DEX. Useful for getting a per-token view of DEX activity.
|
|
4321
|
+
*
|
|
4322
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4323
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4324
|
+
* @param {string} tokenAddress - The token contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
4325
|
+
*
|
|
4326
|
+
*/
|
|
4327
|
+
async getTransactionsForTokenAddress(chainName, dexName, tokenAddress) {
|
|
4328
|
+
let success = false;
|
|
4329
|
+
let data;
|
|
4330
|
+
let response;
|
|
4331
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4332
|
+
while (!success) {
|
|
4333
|
+
try {
|
|
4334
|
+
const urlParams = new URLSearchParams();
|
|
4335
|
+
let startTime;
|
|
4336
|
+
if (this.debug) {
|
|
4337
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4338
|
+
}
|
|
4339
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/tokens/address/${tokenAddress}/transactions/?${urlParams}`, {
|
|
4340
|
+
headers: {
|
|
4341
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4342
|
+
"X-Requested-With": userAgent
|
|
4343
|
+
}
|
|
4344
|
+
}));
|
|
4345
|
+
debugOutput(response.url, response.status, startTime);
|
|
4346
|
+
if (response.status === 429) {
|
|
4347
|
+
try {
|
|
4348
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4349
|
+
}
|
|
4350
|
+
catch (error) {
|
|
4351
|
+
success = true;
|
|
4352
|
+
return {
|
|
4353
|
+
data: null,
|
|
4354
|
+
error: true,
|
|
4355
|
+
error_code: response.status,
|
|
4356
|
+
error_message: error.message
|
|
4357
|
+
};
|
|
4358
|
+
}
|
|
4359
|
+
}
|
|
4360
|
+
else {
|
|
4361
|
+
data = await response.json();
|
|
4362
|
+
}
|
|
4363
|
+
const dataClass = new TransactionsForTokenAddressResponse(data.data);
|
|
4364
|
+
checkAndModifyResponse(dataClass);
|
|
4365
|
+
success = true;
|
|
4366
|
+
return {
|
|
4367
|
+
data: dataClass,
|
|
4368
|
+
error: data.error,
|
|
4369
|
+
error_code: data ? data.error_code : response.status,
|
|
4370
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4371
|
+
};
|
|
4372
|
+
}
|
|
4373
|
+
catch (error) {
|
|
4374
|
+
success = true;
|
|
4375
|
+
return {
|
|
4376
|
+
data: null,
|
|
4377
|
+
error: true,
|
|
4378
|
+
error_code: data ? data.error_code : response.status,
|
|
4379
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4380
|
+
};
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
/**
|
|
4385
|
+
*
|
|
4386
|
+
* Commonly used for getting all the transactions of a particular DEX liquidity pool. Useful for building a transactions history table for an individual pool.
|
|
4387
|
+
*
|
|
4388
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4389
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4390
|
+
* @param {string} poolAddress - The pool contract address. Passing in an `ENS`, `RNS`, `Lens Handle`, or an `Unstoppable Domain` resolves automatically.
|
|
4391
|
+
*
|
|
4392
|
+
*/
|
|
4393
|
+
async getTransactionsForExchange(chainName, dexName, poolAddress) {
|
|
4394
|
+
let success = false;
|
|
4395
|
+
let data;
|
|
4396
|
+
let response;
|
|
4397
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4398
|
+
while (!success) {
|
|
4399
|
+
try {
|
|
4400
|
+
const urlParams = new URLSearchParams();
|
|
4401
|
+
let startTime;
|
|
4402
|
+
if (this.debug) {
|
|
4403
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4404
|
+
}
|
|
4405
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/pools/address/${poolAddress}/transactions/?${urlParams}`, {
|
|
4406
|
+
headers: {
|
|
4407
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4408
|
+
"X-Requested-With": userAgent
|
|
4409
|
+
}
|
|
4410
|
+
}));
|
|
4411
|
+
debugOutput(response.url, response.status, startTime);
|
|
4412
|
+
if (response.status === 429) {
|
|
4413
|
+
try {
|
|
4414
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4415
|
+
}
|
|
4416
|
+
catch (error) {
|
|
4417
|
+
success = true;
|
|
4418
|
+
return {
|
|
4419
|
+
data: null,
|
|
4420
|
+
error: true,
|
|
4421
|
+
error_code: response.status,
|
|
4422
|
+
error_message: error.message
|
|
4423
|
+
};
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
else {
|
|
4427
|
+
data = await response.json();
|
|
4428
|
+
}
|
|
4429
|
+
const dataClass = new TransactionsForExchangeResponse(data.data);
|
|
4430
|
+
checkAndModifyResponse(dataClass);
|
|
4431
|
+
success = true;
|
|
4432
|
+
return {
|
|
4433
|
+
data: dataClass,
|
|
4434
|
+
error: data.error,
|
|
4435
|
+
error_code: data ? data.error_code : response.status,
|
|
4436
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4437
|
+
};
|
|
4438
|
+
}
|
|
4439
|
+
catch (error) {
|
|
4440
|
+
success = true;
|
|
4441
|
+
return {
|
|
4442
|
+
data: null,
|
|
4443
|
+
error: true,
|
|
4444
|
+
error_code: data ? data.error_code : response.status,
|
|
4445
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4446
|
+
};
|
|
4447
|
+
}
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
/**
|
|
4451
|
+
*
|
|
4452
|
+
* Commonly used to get a 7d and 30d time-series chart of DEX activity. Includes volume and swap count.
|
|
4453
|
+
*
|
|
4454
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4455
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4456
|
+
*
|
|
4457
|
+
*/
|
|
4458
|
+
async getEcosystemChartData(chainName, dexName) {
|
|
4459
|
+
let success = false;
|
|
4460
|
+
let data;
|
|
4461
|
+
let response;
|
|
4462
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4463
|
+
while (!success) {
|
|
4464
|
+
try {
|
|
4465
|
+
const urlParams = new URLSearchParams();
|
|
4466
|
+
let startTime;
|
|
4467
|
+
if (this.debug) {
|
|
4468
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4469
|
+
}
|
|
4470
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/ecosystem/?${urlParams}`, {
|
|
4471
|
+
headers: {
|
|
4472
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4473
|
+
"X-Requested-With": userAgent
|
|
4474
|
+
}
|
|
4475
|
+
}));
|
|
4476
|
+
debugOutput(response.url, response.status, startTime);
|
|
4477
|
+
if (response.status === 429) {
|
|
4478
|
+
try {
|
|
4479
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4480
|
+
}
|
|
4481
|
+
catch (error) {
|
|
4482
|
+
success = true;
|
|
4483
|
+
return {
|
|
4484
|
+
data: null,
|
|
4485
|
+
error: true,
|
|
4486
|
+
error_code: response.status,
|
|
4487
|
+
error_message: error.message
|
|
4488
|
+
};
|
|
4489
|
+
}
|
|
4490
|
+
}
|
|
4491
|
+
else {
|
|
4492
|
+
data = await response.json();
|
|
4493
|
+
}
|
|
4494
|
+
const dataClass = new EcosystemChartDataResponse(data.data);
|
|
4495
|
+
checkAndModifyResponse(dataClass);
|
|
4496
|
+
success = true;
|
|
4497
|
+
return {
|
|
4498
|
+
data: dataClass,
|
|
4499
|
+
error: data.error,
|
|
4500
|
+
error_code: data ? data.error_code : response.status,
|
|
4501
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4502
|
+
};
|
|
4503
|
+
}
|
|
4504
|
+
catch (error) {
|
|
4505
|
+
success = true;
|
|
4506
|
+
return {
|
|
4507
|
+
data: null,
|
|
4508
|
+
error: true,
|
|
4509
|
+
error_code: data ? data.error_code : response.status,
|
|
4510
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4511
|
+
};
|
|
4512
|
+
}
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
/**
|
|
4516
|
+
*
|
|
4517
|
+
* Commonly used to ping the health of xy=k endpoints to get the synced block height per chain.
|
|
4518
|
+
*
|
|
4519
|
+
* @param {string} chainName - The chain name eg: `eth-mainnet`.
|
|
4520
|
+
* @param {string} dexName - The DEX name eg: `uniswap_v2`.
|
|
4521
|
+
*
|
|
4522
|
+
*/
|
|
4523
|
+
async getHealthData(chainName, dexName) {
|
|
4524
|
+
let success = false;
|
|
4525
|
+
let data;
|
|
4526
|
+
let response;
|
|
4527
|
+
const backoff = new ExponentialBackoff(this.apiKey, this.debug);
|
|
4528
|
+
while (!success) {
|
|
4529
|
+
try {
|
|
4530
|
+
const urlParams = new URLSearchParams();
|
|
4531
|
+
let startTime;
|
|
4532
|
+
if (this.debug) {
|
|
4533
|
+
startTime = typeof performance !== 'undefined' ? performance.now() : process.hrtime();
|
|
4534
|
+
}
|
|
4535
|
+
response = await this.LIMIT(() => fetch(`https://api.covalenthq.com/v1/${chainName}/xy=k/${dexName}/health/?${urlParams}`, {
|
|
4536
|
+
headers: {
|
|
4537
|
+
"Authorization": `Bearer ${this.apiKey}`,
|
|
4538
|
+
"X-Requested-With": userAgent
|
|
4539
|
+
}
|
|
4540
|
+
}));
|
|
4541
|
+
debugOutput(response.url, response.status, startTime);
|
|
4542
|
+
if (response.status === 429) {
|
|
4543
|
+
try {
|
|
4544
|
+
data = await this.LIMIT(() => backoff.backOff(response.url));
|
|
4545
|
+
}
|
|
4546
|
+
catch (error) {
|
|
4547
|
+
success = true;
|
|
4548
|
+
return {
|
|
4549
|
+
data: null,
|
|
4550
|
+
error: true,
|
|
4551
|
+
error_code: response.status,
|
|
4552
|
+
error_message: error.message
|
|
4553
|
+
};
|
|
4554
|
+
}
|
|
4555
|
+
}
|
|
4556
|
+
else {
|
|
4557
|
+
data = await response.json();
|
|
4558
|
+
}
|
|
4559
|
+
const dataClass = new HealthDataResponse(data.data);
|
|
4560
|
+
checkAndModifyResponse(dataClass);
|
|
4561
|
+
success = true;
|
|
4562
|
+
return {
|
|
4563
|
+
data: dataClass,
|
|
4564
|
+
error: data.error,
|
|
4565
|
+
error_code: data ? data.error_code : response.status,
|
|
4566
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4567
|
+
};
|
|
4568
|
+
}
|
|
4569
|
+
catch (error) {
|
|
4570
|
+
success = true;
|
|
4571
|
+
return {
|
|
4572
|
+
data: null,
|
|
4573
|
+
error: true,
|
|
4574
|
+
error_code: data ? data.error_code : response.status,
|
|
4575
|
+
error_message: data ? data.error_message : "401 Authorization Required"
|
|
4576
|
+
};
|
|
4577
|
+
}
|
|
4578
|
+
}
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
|
|
4582
|
+
const userAgent = "com.covalenthq.sdk.typescript/0.4.2";
|
|
4583
|
+
/**
|
|
4584
|
+
* CovalentClient Class
|
|
4585
|
+
*/
|
|
4586
|
+
class CovalentClient {
|
|
4587
|
+
constructor(apiKey, settings) {
|
|
4588
|
+
const { debug = false, threadCount = 3 } = settings || {};
|
|
4589
|
+
this.SecurityService = new SecurityService(apiKey, debug, threadCount);
|
|
4590
|
+
this.BalanceService = new BalanceService(apiKey, debug, threadCount);
|
|
4591
|
+
this.BaseService = new BaseService(apiKey, debug, threadCount);
|
|
4592
|
+
this.NftService = new NftService(apiKey, debug, threadCount);
|
|
4593
|
+
this.PricingService = new PricingService(apiKey, debug, threadCount);
|
|
4594
|
+
this.TransactionService = new TransactionService(apiKey, debug, threadCount);
|
|
4595
|
+
this.XykService = new XykService(apiKey, debug, threadCount);
|
|
4596
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
/**
|
|
4599
|
+
* @deprecated
|
|
4600
|
+
* Please use {@link CovalentClient} going forward! This method will be removed after Oct 31, 2023.
|
|
4601
|
+
* @see #CovalentClient
|
|
4602
|
+
* CovalentClient Class
|
|
4603
|
+
*/
|
|
4604
|
+
class Client {
|
|
4605
|
+
constructor(apiKey, settings) {
|
|
4606
|
+
const { debug = false, threadCount = 3 } = settings || {};
|
|
4607
|
+
this.SecurityService = new SecurityService(apiKey, debug, threadCount);
|
|
4608
|
+
this.BalanceService = new BalanceService(apiKey, debug, threadCount);
|
|
4609
|
+
this.BaseService = new BaseService(apiKey, debug, threadCount);
|
|
4610
|
+
this.NftService = new NftService(apiKey, debug, threadCount);
|
|
4611
|
+
this.PricingService = new PricingService(apiKey, debug, threadCount);
|
|
4612
|
+
this.TransactionService = new TransactionService(apiKey, debug, threadCount);
|
|
4613
|
+
this.XykService = new XykService(apiKey, debug, threadCount);
|
|
4614
|
+
}
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
exports.Client = Client;
|
|
4618
|
+
exports.CovalentClient = CovalentClient;
|
|
4619
|
+
//# sourceMappingURL=index.js.map
|