tapimo 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/App.d.ts +4887 -5074
- package/dist/App.d.ts.map +1 -1
- package/dist/Webhooks.d.ts +21 -20
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +66 -23
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +168 -168
- package/dist/apps/Zones.d.ts +34 -22
- package/dist/apps/Zones.d.ts.map +1 -1
- package/dist/apps/Zones.js +9 -8
- package/dist/apps/Zones.js.map +1 -1
- package/dist/apps/data/App.d.ts +5198 -5099
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/FxOracle.d.ts +4 -5
- package/dist/apps/data/FxOracle.d.ts.map +1 -1
- package/dist/apps/data/FxOracle.js +19 -4
- package/dist/apps/data/FxOracle.js.map +1 -1
- package/dist/apps/data/routes/activities.d.ts +270 -270
- package/dist/apps/data/routes/activities.d.ts.map +1 -1
- package/dist/apps/data/routes/activities.js +32 -27
- package/dist/apps/data/routes/activities.js.map +1 -1
- package/dist/apps/data/routes/addresses.d.ts +52 -52
- package/dist/apps/data/routes/balances.d.ts +36 -36
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +135 -81
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +125 -125
- package/dist/apps/data/routes/coingecko.d.ts +54 -54
- package/dist/apps/data/routes/earn.d.ts +512 -58
- package/dist/apps/data/routes/earn.d.ts.map +1 -1
- package/dist/apps/data/routes/earn.js +368 -44
- package/dist/apps/data/routes/earn.js.map +1 -1
- package/dist/apps/data/routes/exchanges.d.ts +120 -120
- package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
- package/dist/apps/data/routes/exchanges.js +114 -118
- package/dist/apps/data/routes/exchanges.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts.map +1 -1
- package/dist/apps/data/routes/receipts.js +68 -47
- package/dist/apps/data/routes/receipts.js.map +1 -1
- package/dist/apps/data/routes/rpc.d.ts +31 -31
- package/dist/apps/data/routes/tokens.d.ts +461 -459
- package/dist/apps/data/routes/tokens.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.d.ts +59 -51
- package/dist/apps/data/routes/transactions.d.ts.map +1 -1
- package/dist/apps/data/routes/transactions.js +25 -23
- package/dist/apps/data/routes/transactions.js.map +1 -1
- package/dist/apps/data/routes/transfers.d.ts +108 -86
- package/dist/apps/data/routes/transfers.d.ts.map +1 -1
- package/dist/apps/data/routes/transfers.js +618 -105
- package/dist/apps/data/routes/transfers.js.map +1 -1
- package/dist/apps/data/routes/valuation.d.ts +21 -21
- package/dist/apps/data/routes/valuation.d.ts.map +1 -1
- package/dist/apps/data/routes/valuation.js +2 -2
- package/dist/apps/data/routes/valuation.js.map +1 -1
- package/dist/apps/data/routes/verified-tokens.d.ts +37 -37
- package/dist/apps/data/routes/webhooks.d.ts +102 -505
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +484 -342
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/data/routes/zones.d.ts +12 -12
- package/dist/apps/data/routes/zones.d.ts.map +1 -1
- package/dist/apps/data/routes/zones.js +3 -1
- package/dist/apps/data/routes/zones.js.map +1 -1
- package/dist/apps/funding/App.d.ts +96 -96
- package/dist/apps/funding/routes/deposit-addresses.d.ts +52 -52
- package/dist/apps/funding/routes/quotes.d.ts +89 -89
- package/dist/apps/funding/routes/transfers.d.ts +4 -4
- package/dist/apps/management/App.d.ts +429 -727
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +24 -24
- package/dist/apps/management/routes/billing.d.ts +72 -72
- package/dist/apps/management/routes/faucet.d.ts +6 -6
- package/dist/apps/management/routes/invitations.d.ts +134 -134
- package/dist/apps/management/routes/invite-links.d.ts +38 -38
- package/dist/apps/management/routes/me.d.ts +6 -6
- package/dist/apps/management/routes/members.d.ts +30 -30
- package/dist/apps/management/routes/orgs.d.ts +98 -98
- package/dist/apps/management/routes/projects.d.ts +20 -20
- package/dist/apps/management/routes/usage.d.ts +24 -24
- package/dist/apps/management/routes/verified-token-requests.d.ts +83 -83
- package/dist/apps/management/routes/webhooks.d.ts +158 -573
- package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/mpp/App.d.ts +56 -44
- package/dist/apps/mpp/App.d.ts.map +1 -1
- package/dist/apps/mpp/Mpp.d.ts +3 -0
- package/dist/apps/mpp/Mpp.d.ts.map +1 -1
- package/dist/apps/mpp/Mpp.js +3 -0
- package/dist/apps/mpp/Mpp.js.map +1 -1
- package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
- package/dist/apps/mpp/internal/Adapter.js +9 -2
- package/dist/apps/mpp/internal/Adapter.js.map +1 -1
- package/dist/db/Db.d.ts +2 -2
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +17 -15
- package/dist/db/Db.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +4 -1
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/db/tables/webhookSubscriptions.d.ts +56 -3
- package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
- package/dist/db/tables/webhookSubscriptions.js +76 -3
- package/dist/db/tables/webhookSubscriptions.js.map +1 -1
- package/dist/internal/MetricSink.d.ts +112 -3
- package/dist/internal/MetricSink.d.ts.map +1 -1
- package/dist/internal/MetricSink.js +116 -3
- package/dist/internal/MetricSink.js.map +1 -1
- package/dist/internal/Schema.js +1 -1
- package/dist/internal/Schema.js.map +1 -1
- package/dist/internal/Tidx.d.ts +1 -3
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +1 -3
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +2 -1
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/WebhookDestination.d.ts +2 -0
- package/dist/internal/WebhookDestination.d.ts.map +1 -1
- package/dist/internal/WebhookDestination.js +11 -0
- package/dist/internal/WebhookDestination.js.map +1 -1
- package/dist/internal/WebhookTransfer.d.ts +55 -0
- package/dist/internal/WebhookTransfer.d.ts.map +1 -0
- package/dist/internal/WebhookTransfer.js +296 -0
- package/dist/internal/WebhookTransfer.js.map +1 -0
- package/dist/internal/Webhooks.d.ts +37 -0
- package/dist/internal/Webhooks.d.ts.map +1 -1
- package/dist/internal/Webhooks.js +87 -13
- package/dist/internal/Webhooks.js.map +1 -1
- package/dist/internal/funding/Provider.d.ts +4 -0
- package/dist/internal/funding/Provider.d.ts.map +1 -1
- package/dist/internal/funding/Provider.js +11 -7
- package/dist/internal/funding/Provider.js.map +1 -1
- package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
- package/dist/internal/funding/Reconciliation.js +128 -0
- package/dist/internal/funding/Reconciliation.js.map +1 -1
- package/dist/internal/funding/providers/relay.d.ts +3 -0
- package/dist/internal/funding/providers/relay.d.ts.map +1 -1
- package/dist/internal/funding/providers/relay.js +12 -1
- package/dist/internal/funding/providers/relay.js.map +1 -1
- package/package.json +3 -3
- package/src/Client.test-d.ts +60 -5
- package/src/Webhooks.bench.ts +714 -0
- package/src/Webhooks.memory.bench.ts +250 -0
- package/src/Webhooks.test.ts +77 -6
- package/src/Webhooks.ts +83 -29
- package/src/apps/Zones.test.ts +5 -4
- package/src/apps/Zones.ts +9 -8
- package/src/apps/data/FxOracle.test.ts +18 -0
- package/src/apps/data/FxOracle.ts +28 -5
- package/src/apps/data/routes/activities.test.ts +19 -0
- package/src/apps/data/routes/activities.ts +34 -30
- package/src/apps/data/routes/balances.test.ts +119 -10
- package/src/apps/data/routes/balances.ts +154 -95
- package/src/apps/data/routes/blocks.test.ts +12 -6
- package/src/apps/data/routes/earn.test.ts +197 -0
- package/src/apps/data/routes/earn.ts +486 -44
- package/src/apps/data/routes/exchanges.test.ts +7 -6
- package/src/apps/data/routes/exchanges.ts +124 -117
- package/src/apps/data/routes/receipts.test.ts +24 -7
- package/src/apps/data/routes/receipts.ts +67 -50
- package/src/apps/data/routes/tokens.test.ts +51 -0
- package/src/apps/data/routes/transactions.test.ts +42 -0
- package/src/apps/data/routes/transactions.ts +44 -39
- package/src/apps/data/routes/transfers.test.ts +402 -24
- package/src/apps/data/routes/transfers.ts +708 -101
- package/src/apps/data/routes/valuation.test.ts +26 -0
- package/src/apps/data/routes/valuation.ts +6 -2
- package/src/apps/data/routes/webhooks.test.ts +414 -130
- package/src/apps/data/routes/webhooks.ts +603 -419
- package/src/apps/data/routes/zones.ts +6 -1
- package/src/apps/funding/routes/quotes.test.ts +1 -1
- package/src/apps/mpp/Mpp.test.ts +13 -1
- package/src/apps/mpp/Mpp.ts +8 -0
- package/src/apps/mpp/internal/Adapter.ts +10 -2
- package/src/db/Db.test.ts +40 -6
- package/src/db/Db.ts +33 -19
- package/src/db/tables/sponsoredTransactions.ts +9 -2
- package/src/db/tables/webhookSubscriptions.ts +116 -4
- package/src/internal/EarnVaults.test.ts +2 -2
- package/src/internal/MetricSink.test.ts +518 -0
- package/src/internal/MetricSink.ts +266 -9
- package/src/internal/Schema.ts +1 -1
- package/src/internal/Tidx.test.ts +4 -4
- package/src/internal/Tidx.ts +1 -3
- package/src/internal/Viem.test.ts +8 -0
- package/src/internal/Viem.ts +2 -1
- package/src/internal/WebhookDestination.test.ts +20 -0
- package/src/internal/WebhookDestination.ts +10 -0
- package/src/internal/WebhookTransfer.ts +426 -0
- package/src/internal/Webhooks.test.ts +137 -0
- package/src/internal/Webhooks.ts +131 -17
- package/src/internal/funding/Provider.test.ts +47 -7
- package/src/internal/funding/Provider.ts +12 -7
- package/src/internal/funding/Reconciliation.local.test.ts +3 -1
- package/src/internal/funding/Reconciliation.test.ts +1240 -0
- package/src/internal/funding/Reconciliation.ts +136 -0
- package/src/internal/funding/SourceObservation.test.ts +1 -0
- package/src/internal/funding/providers/relay.test.ts +1 -4
- package/src/internal/funding/providers/relay.ts +16 -1
|
@@ -51,10 +51,10 @@ export declare namespace schema {
|
|
|
51
51
|
symbol: z.ZodMiniString<string>;
|
|
52
52
|
verified: z.ZodMiniBoolean<boolean>;
|
|
53
53
|
}, z.core.$strip>;
|
|
54
|
-
valuation: z.ZodMiniNullable<z.ZodMiniObject<{
|
|
54
|
+
valuation: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniObject<{
|
|
55
55
|
amount: z.ZodMiniString<string>;
|
|
56
56
|
currency: z.ZodMiniString<string>;
|
|
57
|
-
}, z.core.$strip
|
|
57
|
+
}, z.core.$strip>>>;
|
|
58
58
|
}, z.core.$strip>;
|
|
59
59
|
/** Page-level resources: opt-in counts plus valuation rate provenance. */
|
|
60
60
|
const Meta: z.ZodMiniObject<{
|
|
@@ -85,10 +85,10 @@ export declare namespace schema {
|
|
|
85
85
|
symbol: z.ZodMiniString<string>;
|
|
86
86
|
verified: z.ZodMiniBoolean<boolean>;
|
|
87
87
|
}, z.core.$strip>;
|
|
88
|
-
valuation: z.ZodMiniNullable<z.ZodMiniObject<{
|
|
88
|
+
valuation: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniObject<{
|
|
89
89
|
amount: z.ZodMiniString<string>;
|
|
90
90
|
currency: z.ZodMiniString<string>;
|
|
91
|
-
}, z.core.$strip
|
|
91
|
+
}, z.core.$strip>>>;
|
|
92
92
|
}, z.core.$strip>>;
|
|
93
93
|
meta: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
94
94
|
valuation: z.ZodMiniOptional<z.ZodMiniObject<{
|
|
@@ -135,10 +135,10 @@ export declare namespace schema {
|
|
|
135
135
|
symbol: z.ZodMiniString<string>;
|
|
136
136
|
verified: z.ZodMiniBoolean<boolean>;
|
|
137
137
|
}, z.core.$strip>;
|
|
138
|
-
valuation: z.ZodMiniNullable<z.ZodMiniObject<{
|
|
138
|
+
valuation: z.ZodMiniOptional<z.ZodMiniNullable<z.ZodMiniObject<{
|
|
139
139
|
amount: z.ZodMiniString<string>;
|
|
140
140
|
currency: z.ZodMiniString<string>;
|
|
141
|
-
}, z.core.$strip
|
|
141
|
+
}, z.core.$strip>>>;
|
|
142
142
|
}, z.core.$strip>;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
@@ -172,14 +172,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
172
172
|
} | {
|
|
173
173
|
output: {
|
|
174
174
|
error: {
|
|
175
|
-
code: "
|
|
175
|
+
code: "upstream_error";
|
|
176
176
|
details?: readonly Response.error.Detail[] | undefined;
|
|
177
177
|
message: string;
|
|
178
178
|
};
|
|
179
179
|
requestId: string;
|
|
180
180
|
};
|
|
181
181
|
outputFormat: "json";
|
|
182
|
-
status:
|
|
182
|
+
status: 502;
|
|
183
183
|
input: {
|
|
184
184
|
param: {
|
|
185
185
|
address: `0x${string}`;
|
|
@@ -200,14 +200,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
200
200
|
} | {
|
|
201
201
|
output: {
|
|
202
202
|
error: {
|
|
203
|
-
code: "
|
|
203
|
+
code: "api_key_malformed";
|
|
204
204
|
details?: readonly Response.error.Detail[] | undefined;
|
|
205
205
|
message: string;
|
|
206
206
|
};
|
|
207
207
|
requestId: string;
|
|
208
208
|
};
|
|
209
209
|
outputFormat: "json";
|
|
210
|
-
status:
|
|
210
|
+
status: 400;
|
|
211
211
|
input: {
|
|
212
212
|
param: {
|
|
213
213
|
address: `0x${string}`;
|
|
@@ -228,14 +228,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
228
228
|
} | {
|
|
229
229
|
output: {
|
|
230
230
|
error: {
|
|
231
|
-
code: "
|
|
231
|
+
code: "api_key_invalid" | "api_key_missing";
|
|
232
232
|
details?: readonly Response.error.Detail[] | undefined;
|
|
233
233
|
message: string;
|
|
234
234
|
};
|
|
235
235
|
requestId: string;
|
|
236
236
|
};
|
|
237
237
|
outputFormat: "json";
|
|
238
|
-
status:
|
|
238
|
+
status: 401;
|
|
239
239
|
input: {
|
|
240
240
|
param: {
|
|
241
241
|
address: `0x${string}`;
|
|
@@ -256,14 +256,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
256
256
|
} | {
|
|
257
257
|
output: {
|
|
258
258
|
error: {
|
|
259
|
-
code: "
|
|
259
|
+
code: "api_key_forbidden" | "api_key_ip_forbidden";
|
|
260
260
|
details?: readonly Response.error.Detail[] | undefined;
|
|
261
261
|
message: string;
|
|
262
262
|
};
|
|
263
263
|
requestId: string;
|
|
264
264
|
};
|
|
265
265
|
outputFormat: "json";
|
|
266
|
-
status:
|
|
266
|
+
status: 403;
|
|
267
267
|
input: {
|
|
268
268
|
param: {
|
|
269
269
|
address: `0x${string}`;
|
|
@@ -284,14 +284,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
284
284
|
} | {
|
|
285
285
|
output: {
|
|
286
286
|
error: {
|
|
287
|
-
code: "
|
|
287
|
+
code: "payment_required" | "rate_limit_exceeded";
|
|
288
288
|
details?: readonly Response.error.Detail[] | undefined;
|
|
289
289
|
message: string;
|
|
290
290
|
};
|
|
291
291
|
requestId: string;
|
|
292
292
|
};
|
|
293
293
|
outputFormat: "json";
|
|
294
|
-
status:
|
|
294
|
+
status: 429;
|
|
295
295
|
input: {
|
|
296
296
|
param: {
|
|
297
297
|
address: `0x${string}`;
|
|
@@ -312,14 +312,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
312
312
|
} | {
|
|
313
313
|
output: {
|
|
314
314
|
error: {
|
|
315
|
-
code: "
|
|
315
|
+
code: "address_invalid";
|
|
316
316
|
details?: readonly Response.error.Detail[] | undefined;
|
|
317
317
|
message: string;
|
|
318
318
|
};
|
|
319
319
|
requestId: string;
|
|
320
320
|
};
|
|
321
321
|
outputFormat: "json";
|
|
322
|
-
status:
|
|
322
|
+
status: 400;
|
|
323
323
|
input: {
|
|
324
324
|
param: {
|
|
325
325
|
address: `0x${string}`;
|
|
@@ -340,7 +340,7 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
340
340
|
} | {
|
|
341
341
|
output: {
|
|
342
342
|
error: {
|
|
343
|
-
code: "
|
|
343
|
+
code: "query_invalid";
|
|
344
344
|
details?: readonly Response.error.Detail[] | undefined;
|
|
345
345
|
message: string;
|
|
346
346
|
};
|
|
@@ -384,10 +384,10 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
384
384
|
symbol: string;
|
|
385
385
|
verified: boolean;
|
|
386
386
|
};
|
|
387
|
-
valuation
|
|
387
|
+
valuation?: {
|
|
388
388
|
amount: string;
|
|
389
389
|
currency: string;
|
|
390
|
-
} | null;
|
|
390
|
+
} | null | undefined;
|
|
391
391
|
}[];
|
|
392
392
|
meta?: {
|
|
393
393
|
valuation?: {
|
|
@@ -441,14 +441,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
441
441
|
} | {
|
|
442
442
|
output: {
|
|
443
443
|
error: {
|
|
444
|
-
code: "
|
|
444
|
+
code: "upstream_error";
|
|
445
445
|
details?: readonly Response.error.Detail[] | undefined;
|
|
446
446
|
message: string;
|
|
447
447
|
};
|
|
448
448
|
requestId: string;
|
|
449
449
|
};
|
|
450
450
|
outputFormat: "json";
|
|
451
|
-
status:
|
|
451
|
+
status: 502;
|
|
452
452
|
input: {
|
|
453
453
|
param: {
|
|
454
454
|
address: `0x${string}`;
|
|
@@ -463,14 +463,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
463
463
|
} | {
|
|
464
464
|
output: {
|
|
465
465
|
error: {
|
|
466
|
-
code: "
|
|
466
|
+
code: "api_key_malformed";
|
|
467
467
|
details?: readonly Response.error.Detail[] | undefined;
|
|
468
468
|
message: string;
|
|
469
469
|
};
|
|
470
470
|
requestId: string;
|
|
471
471
|
};
|
|
472
472
|
outputFormat: "json";
|
|
473
|
-
status:
|
|
473
|
+
status: 400;
|
|
474
474
|
input: {
|
|
475
475
|
param: {
|
|
476
476
|
address: `0x${string}`;
|
|
@@ -485,14 +485,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
485
485
|
} | {
|
|
486
486
|
output: {
|
|
487
487
|
error: {
|
|
488
|
-
code: "
|
|
488
|
+
code: "api_key_invalid" | "api_key_missing";
|
|
489
489
|
details?: readonly Response.error.Detail[] | undefined;
|
|
490
490
|
message: string;
|
|
491
491
|
};
|
|
492
492
|
requestId: string;
|
|
493
493
|
};
|
|
494
494
|
outputFormat: "json";
|
|
495
|
-
status:
|
|
495
|
+
status: 401;
|
|
496
496
|
input: {
|
|
497
497
|
param: {
|
|
498
498
|
address: `0x${string}`;
|
|
@@ -507,14 +507,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
507
507
|
} | {
|
|
508
508
|
output: {
|
|
509
509
|
error: {
|
|
510
|
-
code: "
|
|
510
|
+
code: "api_key_forbidden" | "api_key_ip_forbidden";
|
|
511
511
|
details?: readonly Response.error.Detail[] | undefined;
|
|
512
512
|
message: string;
|
|
513
513
|
};
|
|
514
514
|
requestId: string;
|
|
515
515
|
};
|
|
516
516
|
outputFormat: "json";
|
|
517
|
-
status:
|
|
517
|
+
status: 403;
|
|
518
518
|
input: {
|
|
519
519
|
param: {
|
|
520
520
|
address: `0x${string}`;
|
|
@@ -529,14 +529,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
529
529
|
} | {
|
|
530
530
|
output: {
|
|
531
531
|
error: {
|
|
532
|
-
code: "
|
|
532
|
+
code: "payment_required" | "rate_limit_exceeded";
|
|
533
533
|
details?: readonly Response.error.Detail[] | undefined;
|
|
534
534
|
message: string;
|
|
535
535
|
};
|
|
536
536
|
requestId: string;
|
|
537
537
|
};
|
|
538
538
|
outputFormat: "json";
|
|
539
|
-
status:
|
|
539
|
+
status: 429;
|
|
540
540
|
input: {
|
|
541
541
|
param: {
|
|
542
542
|
address: `0x${string}`;
|
|
@@ -551,14 +551,14 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
551
551
|
} | {
|
|
552
552
|
output: {
|
|
553
553
|
error: {
|
|
554
|
-
code: "
|
|
554
|
+
code: "address_invalid";
|
|
555
555
|
details?: readonly Response.error.Detail[] | undefined;
|
|
556
556
|
message: string;
|
|
557
557
|
};
|
|
558
558
|
requestId: string;
|
|
559
559
|
};
|
|
560
560
|
outputFormat: "json";
|
|
561
|
-
status:
|
|
561
|
+
status: 400;
|
|
562
562
|
input: {
|
|
563
563
|
param: {
|
|
564
564
|
address: `0x${string}`;
|
|
@@ -573,7 +573,7 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
573
573
|
} | {
|
|
574
574
|
output: {
|
|
575
575
|
error: {
|
|
576
|
-
code: "
|
|
576
|
+
code: "query_invalid";
|
|
577
577
|
details?: readonly Response.error.Detail[] | undefined;
|
|
578
578
|
message: string;
|
|
579
579
|
};
|
|
@@ -610,10 +610,10 @@ export declare function addresses(options?: addresses.Options): import("hono/hon
|
|
|
610
610
|
symbol: string;
|
|
611
611
|
verified: boolean;
|
|
612
612
|
};
|
|
613
|
-
valuation
|
|
613
|
+
valuation?: {
|
|
614
614
|
amount: string;
|
|
615
615
|
currency: string;
|
|
616
|
-
} | null;
|
|
616
|
+
} | null | undefined;
|
|
617
617
|
};
|
|
618
618
|
outputFormat: "json";
|
|
619
619
|
status: 200;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balances.d.ts","sourceRoot":"","sources":["../../../../src/apps/data/routes/balances.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAA;AAK3C,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AAOzD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAQ3C,iDAAiD;AACjD,yBAAiB,MAAM,CAAC;IACtB,oDAAoD;IACpD,UAAiB,kBAAkB,CAAC;QAClC,oDAAoD;QAC7C,MAAM,MAAM;;yBAM6D,CAAA;QAEhF,qDAAqD;QAC9C,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"balances.d.ts","sourceRoot":"","sources":["../../../../src/apps/data/routes/balances.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAA;AAK3C,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AAOzD,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAA;AAQ3C,iDAAiD;AACjD,yBAAiB,MAAM,CAAC;IACtB,oDAAoD;IACpD,UAAiB,kBAAkB,CAAC;QAClC,oDAAoD;QAC7C,MAAM,MAAM;;yBAM6D,CAAA;QAEhF,qDAAqD;QAC9C,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;0BA+Cf,CAAA;QAEH,kGAAkG;QAC3F,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;yBAoEnB,CAAA;QAED,0EAA0E;QACnE,MAAM,IAAI;;;;;;;;yBAasD,CAAA;QAEvE,sFAAsF;QAC/E,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yBAUwD,CAAA;KAC9E;IAED,mDAAmD;IACnD,UAAiB,iBAAiB,CAAC;QACjC,4DAA4D;QACrD,MAAM,MAAM;;;yBAO2D,CAAA;QAE9E,6DAA6D;QACtD,MAAM,KAAK;;;;;;0BAU6D,CAAA;QAE/E,wDAAwD;QACjD,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;yBAEpB,CAAA;KACF;CACF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,SAAS,CAAC,OAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDAsMxD;AAED,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IACjC,uDAAuD;IACvD,KAAK,OAAO,GAAG;QACb,kDAAkD;QAClD,EAAE,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,EAAE,GAAG,SAAS,CAAA;KACxC,CAAA;CACF"}
|
|
@@ -51,7 +51,8 @@ export var schema;
|
|
|
51
51
|
include: Schema.totalCountInclude,
|
|
52
52
|
limit: Schema.Limit,
|
|
53
53
|
page: Schema.Page,
|
|
54
|
-
'valuation.currency': Schema.Denomination,
|
|
54
|
+
'valuation.currency': Schema.Denomination.check(z.describe('When present, include each holding’s nominal value in this denomination. ' +
|
|
55
|
+
'Case-insensitive and must be priced by the configured FX oracle.')),
|
|
55
56
|
verified: z
|
|
56
57
|
.optional(Schema.booleanQuery())
|
|
57
58
|
.check(z.describe('When `true`, include only tokens from Tempo’s curated verified token list.'), z.meta({ examples: [true] })),
|
|
@@ -83,9 +84,9 @@ export var schema;
|
|
|
83
84
|
.check(z.describe('A stable resource ID for this balance, equal to the token contract address.'), z.meta({ examples: ['0x20c0000000000000000000008f5425160ebe5525'] })),
|
|
84
85
|
token: Tokens.schema.Token,
|
|
85
86
|
valuation: z
|
|
86
|
-
.nullable(Valuation.schema.Value)
|
|
87
|
-
.check(z.describe('The holding’s nominal value
|
|
88
|
-
'token is unverified, its display currency has no rate, or rates were unavailable.')),
|
|
87
|
+
.optional(z.nullable(Valuation.schema.Value))
|
|
88
|
+
.check(z.describe('The holding’s nominal value when `valuation.currency` is requested, or `null` when ' +
|
|
89
|
+
'the token is unverified, its display currency has no rate, or rates were unavailable.')),
|
|
89
90
|
}), 'One TIP-20 token balance held by this account, with both raw and human-readable amounts.');
|
|
90
91
|
/** Page-level resources: opt-in counts plus valuation rate provenance. */
|
|
91
92
|
getAddressBalances.Meta = z
|
|
@@ -125,7 +126,8 @@ export var schema;
|
|
|
125
126
|
getAddressBalance.Query = z
|
|
126
127
|
.strictObject({
|
|
127
128
|
chainId: Schema.ChainIdQuery,
|
|
128
|
-
'valuation.currency': Schema.Denomination,
|
|
129
|
+
'valuation.currency': Schema.Denomination.check(z.describe('When present, include the holding’s nominal value in this denomination. ' +
|
|
130
|
+
'Case-insensitive and must be priced by the configured FX oracle.')),
|
|
129
131
|
})
|
|
130
132
|
.check(z.describe('Query parameters for reading one account token balance.'));
|
|
131
133
|
/** A single TIP-20 token balance held by an address. */
|
|
@@ -146,7 +148,7 @@ export function addresses(options = {}) {
|
|
|
146
148
|
code: 'query_invalid',
|
|
147
149
|
message: 'Invalid query parameters',
|
|
148
150
|
}), OpenApi.describeRoute({
|
|
149
|
-
description: 'Lists how much of each TIP-20 token an account holds, ordered from largest to smallest balance. Amounts are returned in raw base units and human-readable form
|
|
151
|
+
description: 'Lists how much of each TIP-20 token an account holds, ordered from largest to smallest balance. Amounts are returned in raw base units and human-readable form. Pass `valuation.currency` to include nominal values.',
|
|
150
152
|
operationId: 'getAddressBalances',
|
|
151
153
|
responses: OpenApi.responses({
|
|
152
154
|
errors: { 502: 'Could not read balance or token data from an upstream service.' },
|
|
@@ -182,26 +184,13 @@ export function addresses(options = {}) {
|
|
|
182
184
|
// `verified=true` from the caller's perspective.
|
|
183
185
|
const verified = query.verified || query.currency !== undefined;
|
|
184
186
|
const feeEligible = query.feeEligible ?? false;
|
|
185
|
-
// The fee-token set powers both the per-row `feeEligible` flag (always)
|
|
186
|
-
// and the optional `feeEligible=true` page restriction. It is memoized
|
|
187
|
-
// per chain (a near-constant), so one read feeds the page, the count,
|
|
188
|
-
// and the row enrichment. It is a best-effort enrichment: a lookup
|
|
189
|
-
// failure omits `feeEligible` rather than failing the page — unless the
|
|
190
|
-
// caller explicitly asked to filter by `feeEligible`, where the filter
|
|
191
|
-
// can't be honored, so the failure surfaces as the declared `502`.
|
|
192
|
-
const feeTokens = await FeeAmm.feeTokenSet(c, chainId).catch((cause) => {
|
|
193
|
-
if (feeEligible)
|
|
194
|
-
throw cause;
|
|
195
|
-
return undefined;
|
|
196
|
-
});
|
|
197
187
|
const balances = await getAddressBalances(c, {
|
|
198
188
|
address,
|
|
199
189
|
chainId,
|
|
200
190
|
currency: query.currency,
|
|
201
191
|
cursor: query.cursor,
|
|
202
|
-
denomination: query['valuation.currency']
|
|
192
|
+
denomination: query['valuation.currency'],
|
|
203
193
|
feeEligible,
|
|
204
|
-
feeTokens,
|
|
205
194
|
includeTotalCount: query.include.includes('totalCount'),
|
|
206
195
|
limit: query.limit,
|
|
207
196
|
oracle,
|
|
@@ -260,9 +249,24 @@ export function addresses(options = {}) {
|
|
|
260
249
|
const { address, token } = c.req.valid('param');
|
|
261
250
|
const query = c.req.valid('query');
|
|
262
251
|
const chainId = query.chainId ?? c.get('chainId');
|
|
252
|
+
const denomination = query['valuation.currency'];
|
|
263
253
|
try {
|
|
264
|
-
const
|
|
265
|
-
|
|
254
|
+
const rates = denomination
|
|
255
|
+
? await Valuation.rateSet(c, oracle)
|
|
256
|
+
.then((rates) => {
|
|
257
|
+
if (denomination !== rates.base && rates.rates[denomination] === undefined)
|
|
258
|
+
throw new Valuation.UnsupportedDenominationError(denomination, oracle.name);
|
|
259
|
+
return rates;
|
|
260
|
+
})
|
|
261
|
+
.catch((cause) => {
|
|
262
|
+
if (cause instanceof Valuation.UnsupportedDenominationError)
|
|
263
|
+
throw cause;
|
|
264
|
+
return undefined;
|
|
265
|
+
})
|
|
266
|
+
: undefined;
|
|
267
|
+
const snapshotPromise = VerifiedTokens.snapshot(c, chainId);
|
|
268
|
+
const resolvedTokenPromise = snapshotPromise.then((snapshot) => Timing.time(c, 'token', () => Tokens.resolveToken(c, { address: token, chainId, include: [], snapshot })));
|
|
269
|
+
const [balance, feeTokens, snapshot, resolvedToken] = await Promise.all([
|
|
266
270
|
Timing.time(c, 'balance_rpc', async () => {
|
|
267
271
|
const result = await Actions.token.getBalance(c.get('getClient')(chainId), {
|
|
268
272
|
account: address,
|
|
@@ -270,15 +274,10 @@ export function addresses(options = {}) {
|
|
|
270
274
|
});
|
|
271
275
|
return result.amount;
|
|
272
276
|
}),
|
|
273
|
-
|
|
277
|
+
FeeAmm.feeTokenSet(c, chainId).catch(() => undefined),
|
|
278
|
+
snapshotPromise,
|
|
279
|
+
resolvedTokenPromise,
|
|
274
280
|
]);
|
|
275
|
-
const denomination = query['valuation.currency'] ?? 'USD';
|
|
276
|
-
const rates = await Valuation.ratesFor(c, {
|
|
277
|
-
currencies: snapshot.byAddress.has(token) ? [resolvedToken.currency] : [],
|
|
278
|
-
denomination,
|
|
279
|
-
oracle,
|
|
280
|
-
});
|
|
281
|
-
const feeTokens = await FeeAmm.feeTokenSet(c, chainId).catch(() => undefined);
|
|
282
281
|
return c.json(Response.validated(schema.getAddressBalance.Response, {
|
|
283
282
|
amount: balance.toString(),
|
|
284
283
|
currency: resolvedToken.currency,
|
|
@@ -287,12 +286,16 @@ export function addresses(options = {}) {
|
|
|
287
286
|
formatted: core_Value.format(balance, resolvedToken.decimals),
|
|
288
287
|
id: token,
|
|
289
288
|
token: resolvedToken,
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
289
|
+
...(denomination
|
|
290
|
+
? {
|
|
291
|
+
valuation: Valuation.valuationFor({
|
|
292
|
+
amount: balance,
|
|
293
|
+
denomination,
|
|
294
|
+
rates,
|
|
295
|
+
token: snapshot.byAddress.get(token),
|
|
296
|
+
}),
|
|
297
|
+
}
|
|
298
|
+
: {}),
|
|
296
299
|
}), 200);
|
|
297
300
|
}
|
|
298
301
|
catch (cause) {
|
|
@@ -309,12 +312,14 @@ export function addresses(options = {}) {
|
|
|
309
312
|
});
|
|
310
313
|
}
|
|
311
314
|
async function getAddressBalances(c, options) {
|
|
312
|
-
const { address, chainId, currency, denomination, feeEligible,
|
|
315
|
+
const { address, chainId, currency, denomination, feeEligible, includeTotalCount, limit, oracle, verified, } = options;
|
|
313
316
|
const tidx = c.get('getTidx')(chainId);
|
|
314
317
|
const cursor = options.cursor ? Cursor.decode(options.cursor, ['uint', 'address']) : undefined;
|
|
315
318
|
const offset = options.page !== undefined && options.page > 1 ? (options.page - 1) * limit : 0;
|
|
316
|
-
// Validate
|
|
317
|
-
|
|
319
|
+
// Validate an explicit denomination before balance discovery and correction
|
|
320
|
+
// so dependency failures cannot mask a caller error.
|
|
321
|
+
if (denomination)
|
|
322
|
+
await Valuation.ratesFor(c, { currencies: [], denomination, oracle });
|
|
318
323
|
// Build the optional `token IN (…)` restriction before hitting TIDX. The
|
|
319
324
|
// verified/`currency` filter and the `feeEligible` filter each contribute a set
|
|
320
325
|
// of allowed addresses (`currency` matched case-insensitively so callers can
|
|
@@ -322,16 +327,31 @@ async function getAddressBalances(c, options) {
|
|
|
322
327
|
// intersection. If any active filter rules every token out, return an empty
|
|
323
328
|
// page without a round trip. The snapshot is reused for the page enrichment
|
|
324
329
|
// below.
|
|
325
|
-
const
|
|
326
|
-
|
|
330
|
+
const snapshotPromise = VerifiedTokens.snapshot(c, chainId);
|
|
331
|
+
// Fee filtering can fail before the concurrently started snapshot is awaited.
|
|
332
|
+
// Observing this branch prevents an unhandled rejection; the later await still propagates it.
|
|
333
|
+
void snapshotPromise.catch(() => undefined);
|
|
334
|
+
const [snapshot_filter, feeTokens_filter] = await Promise.all([
|
|
335
|
+
verified ? snapshotPromise : Promise.resolve(undefined),
|
|
336
|
+
feeEligible ? FeeAmm.feeTokenSet(c, chainId) : Promise.resolve(undefined),
|
|
337
|
+
]);
|
|
338
|
+
const allowed = allowedTokens({
|
|
339
|
+
currency,
|
|
340
|
+
feeEligible,
|
|
341
|
+
feeTokens: feeTokens_filter,
|
|
342
|
+
snapshot: snapshot_filter,
|
|
343
|
+
verified,
|
|
344
|
+
});
|
|
327
345
|
const tokenFilter = allowed?.map((address) => `'${address}'`);
|
|
328
|
-
if (tokenFilter?.length === 0)
|
|
346
|
+
if (tokenFilter?.length === 0) {
|
|
347
|
+
await snapshotPromise;
|
|
329
348
|
return {
|
|
330
349
|
data: [],
|
|
331
350
|
...(includeTotalCount ? { meta: { totalCount: 0, totalCountCapped: false } } : {}),
|
|
332
351
|
nextCursor: null,
|
|
333
352
|
};
|
|
334
|
-
|
|
353
|
+
}
|
|
354
|
+
const holdingsPromise = Timing.time(c, 'balances_discovery', async () => {
|
|
335
355
|
const tokenIn = tokenFilter ? ` AND token IN (${tokenFilter.join(', ')})` : '';
|
|
336
356
|
const result = await tidx.fetch({
|
|
337
357
|
chainId,
|
|
@@ -349,33 +369,49 @@ async function getAddressBalances(c, options) {
|
|
|
349
369
|
return token.success ? [{ address: token.data }] : [];
|
|
350
370
|
});
|
|
351
371
|
});
|
|
352
|
-
|
|
372
|
+
// Correction starts as soon as discovery completes. Snapshot and fee-token
|
|
373
|
+
// cache misses continue concurrently until enrichment needs their results.
|
|
374
|
+
const correctedPromise = holdingsPromise.then(async (holdings) => {
|
|
375
|
+
if (holdings.length === 0)
|
|
376
|
+
return [];
|
|
377
|
+
const client = c.get('getClient')(chainId);
|
|
378
|
+
return Timing.time(c, 'balances_rpc', async () => {
|
|
379
|
+
// Concurrent reads enter viem's shared batch window and become one
|
|
380
|
+
// deployless multicall. A failed read fails the request rather than serving
|
|
381
|
+
// a stale or partial balance page.
|
|
382
|
+
const results = await Promise.all(holdings.map(async (holding) => {
|
|
383
|
+
const { amount } = await Actions.token.getBalance(client, {
|
|
384
|
+
account: address,
|
|
385
|
+
token: holding.address,
|
|
386
|
+
});
|
|
387
|
+
return amount === 0n ? undefined : { address: holding.address, amount: amount.toString() };
|
|
388
|
+
}));
|
|
389
|
+
const rows = results.filter((holding) => holding !== undefined);
|
|
390
|
+
rows.sort((a, b) => {
|
|
391
|
+
const delta = BigInt(b.amount) - BigInt(a.amount);
|
|
392
|
+
if (delta !== 0n)
|
|
393
|
+
return delta > 0n ? 1 : -1;
|
|
394
|
+
return a.address < b.address ? -1 : a.address > b.address ? 1 : 0;
|
|
395
|
+
});
|
|
396
|
+
return rows;
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
const feeTokensPromise = feeEligible
|
|
400
|
+
? Promise.resolve(feeTokens_filter)
|
|
401
|
+
: holdingsPromise.then((holdings) => holdings.length === 0 ? undefined : FeeAmm.feeTokenSet(c, chainId).catch(() => undefined));
|
|
402
|
+
const [holdings, snapshot, feeTokens, corrected] = await Promise.all([
|
|
403
|
+
holdingsPromise,
|
|
404
|
+
snapshotPromise,
|
|
405
|
+
feeTokensPromise,
|
|
406
|
+
correctedPromise,
|
|
407
|
+
]);
|
|
408
|
+
if (holdings.length === 0) {
|
|
353
409
|
return {
|
|
354
410
|
data: [],
|
|
355
411
|
...(includeTotalCount ? { meta: { totalCount: 0, totalCountCapped: false } } : {}),
|
|
356
412
|
nextCursor: null,
|
|
357
413
|
};
|
|
358
|
-
|
|
359
|
-
const corrected = await Timing.time(c, 'balances_rpc', async () => {
|
|
360
|
-
// Concurrent reads enter viem's shared batch window and become one
|
|
361
|
-
// deployless multicall. A failed read fails the request rather than serving
|
|
362
|
-
// a stale or partial balance page.
|
|
363
|
-
const results = await Promise.all(holdings.map(async (holding) => {
|
|
364
|
-
const { amount } = await Actions.token.getBalance(client, {
|
|
365
|
-
account: address,
|
|
366
|
-
token: holding.address,
|
|
367
|
-
});
|
|
368
|
-
return amount === 0n ? undefined : { address: holding.address, amount: amount.toString() };
|
|
369
|
-
}));
|
|
370
|
-
const rows = results.filter((holding) => holding !== undefined);
|
|
371
|
-
rows.sort((a, b) => {
|
|
372
|
-
const delta = BigInt(b.amount) - BigInt(a.amount);
|
|
373
|
-
if (delta !== 0n)
|
|
374
|
-
return delta > 0n ? 1 : -1;
|
|
375
|
-
return a.address < b.address ? -1 : a.address > b.address ? 1 : 0;
|
|
376
|
-
});
|
|
377
|
-
return rows;
|
|
378
|
-
});
|
|
414
|
+
}
|
|
379
415
|
const positioned = (() => {
|
|
380
416
|
if (!cursor)
|
|
381
417
|
return corrected.slice(offset);
|
|
@@ -389,7 +425,7 @@ async function getAddressBalances(c, options) {
|
|
|
389
425
|
limit,
|
|
390
426
|
key: (holding) => [holding.amount, holding.address],
|
|
391
427
|
});
|
|
392
|
-
if (page.rows.length === 0)
|
|
428
|
+
if (page.rows.length === 0) {
|
|
393
429
|
return {
|
|
394
430
|
data: [],
|
|
395
431
|
...(includeTotalCount
|
|
@@ -397,18 +433,31 @@ async function getAddressBalances(c, options) {
|
|
|
397
433
|
: {}),
|
|
398
434
|
nextCursor: page.nextCursor,
|
|
399
435
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
436
|
+
}
|
|
437
|
+
const ratesPromise = denomination
|
|
438
|
+
? Valuation.ratesFor(c, {
|
|
439
|
+
currencies: page.rows.flatMap((row) => {
|
|
440
|
+
const held = snapshot.byAddress.get(row.address.toLowerCase())?.currency;
|
|
441
|
+
return held === undefined ? [] : [held];
|
|
442
|
+
}),
|
|
443
|
+
denomination,
|
|
444
|
+
oracle,
|
|
445
|
+
})
|
|
446
|
+
: Promise.resolve(undefined);
|
|
408
447
|
// Balance tokens retain their logo and verification metadata by default.
|
|
409
|
-
const
|
|
448
|
+
const resolvedPromise = Timing.time(c, 'tokens', () => Promise.all(page.rows.map(async (holding) => {
|
|
410
449
|
try {
|
|
411
450
|
const token = Schema.Address.parse(holding.address.toLowerCase());
|
|
451
|
+
const verifiedToken = snapshot.byAddress.get(token);
|
|
452
|
+
// The curated list owns verified-token metadata, but uploaded logos live only in the asset store.
|
|
453
|
+
if (verifiedToken)
|
|
454
|
+
return {
|
|
455
|
+
amount: holding.amount,
|
|
456
|
+
logoUri: verifiedToken.logoUri ??
|
|
457
|
+
(await Timing.time(c, 'token_logo', () => Tokens.getTokenLogo(c, { address: token, chainId })).catch(() => undefined)),
|
|
458
|
+
metadata: verifiedToken,
|
|
459
|
+
token,
|
|
460
|
+
};
|
|
412
461
|
const [logoUri, metadata] = await Promise.all([
|
|
413
462
|
Timing.time(c, 'token_logo', () => Tokens.getTokenLogo(c, { address: token, chainId })).catch(() => undefined),
|
|
414
463
|
Timing.time(c, 'token_metadata', () => Tokens.getTokenMetadata(c, { address: token, chainId })),
|
|
@@ -419,6 +468,7 @@ async function getAddressBalances(c, options) {
|
|
|
419
468
|
return undefined;
|
|
420
469
|
}
|
|
421
470
|
})));
|
|
471
|
+
const [rates, resolved] = await Promise.all([ratesPromise, resolvedPromise]);
|
|
422
472
|
const data = [];
|
|
423
473
|
for (const entry of resolved) {
|
|
424
474
|
if (!entry)
|
|
@@ -442,12 +492,16 @@ async function getAddressBalances(c, options) {
|
|
|
442
492
|
symbol: entry.metadata.symbol,
|
|
443
493
|
verified: snapshot.byAddress.has(entry.token),
|
|
444
494
|
},
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
495
|
+
...(denomination
|
|
496
|
+
? {
|
|
497
|
+
valuation: Valuation.valuationFor({
|
|
498
|
+
amount: BigInt(entry.amount),
|
|
499
|
+
denomination,
|
|
500
|
+
rates,
|
|
501
|
+
token: snapshot.byAddress.get(entry.token),
|
|
502
|
+
}),
|
|
503
|
+
}
|
|
504
|
+
: {}),
|
|
451
505
|
});
|
|
452
506
|
}
|
|
453
507
|
const meta = {
|