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.
Files changed (198) hide show
  1. package/dist/App.d.ts +4887 -5074
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/Webhooks.d.ts +21 -20
  4. package/dist/Webhooks.d.ts.map +1 -1
  5. package/dist/Webhooks.js +66 -23
  6. package/dist/Webhooks.js.map +1 -1
  7. package/dist/admin/apps/verified-tokens.d.ts +168 -168
  8. package/dist/apps/Zones.d.ts +34 -22
  9. package/dist/apps/Zones.d.ts.map +1 -1
  10. package/dist/apps/Zones.js +9 -8
  11. package/dist/apps/Zones.js.map +1 -1
  12. package/dist/apps/data/App.d.ts +5198 -5099
  13. package/dist/apps/data/App.d.ts.map +1 -1
  14. package/dist/apps/data/FxOracle.d.ts +4 -5
  15. package/dist/apps/data/FxOracle.d.ts.map +1 -1
  16. package/dist/apps/data/FxOracle.js +19 -4
  17. package/dist/apps/data/FxOracle.js.map +1 -1
  18. package/dist/apps/data/routes/activities.d.ts +270 -270
  19. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  20. package/dist/apps/data/routes/activities.js +32 -27
  21. package/dist/apps/data/routes/activities.js.map +1 -1
  22. package/dist/apps/data/routes/addresses.d.ts +52 -52
  23. package/dist/apps/data/routes/balances.d.ts +36 -36
  24. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  25. package/dist/apps/data/routes/balances.js +135 -81
  26. package/dist/apps/data/routes/balances.js.map +1 -1
  27. package/dist/apps/data/routes/blocks.d.ts +125 -125
  28. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  29. package/dist/apps/data/routes/earn.d.ts +512 -58
  30. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  31. package/dist/apps/data/routes/earn.js +368 -44
  32. package/dist/apps/data/routes/earn.js.map +1 -1
  33. package/dist/apps/data/routes/exchanges.d.ts +120 -120
  34. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  35. package/dist/apps/data/routes/exchanges.js +114 -118
  36. package/dist/apps/data/routes/exchanges.js.map +1 -1
  37. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  38. package/dist/apps/data/routes/receipts.js +68 -47
  39. package/dist/apps/data/routes/receipts.js.map +1 -1
  40. package/dist/apps/data/routes/rpc.d.ts +31 -31
  41. package/dist/apps/data/routes/tokens.d.ts +461 -459
  42. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  43. package/dist/apps/data/routes/transactions.d.ts +59 -51
  44. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  45. package/dist/apps/data/routes/transactions.js +25 -23
  46. package/dist/apps/data/routes/transactions.js.map +1 -1
  47. package/dist/apps/data/routes/transfers.d.ts +108 -86
  48. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  49. package/dist/apps/data/routes/transfers.js +618 -105
  50. package/dist/apps/data/routes/transfers.js.map +1 -1
  51. package/dist/apps/data/routes/valuation.d.ts +21 -21
  52. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  53. package/dist/apps/data/routes/valuation.js +2 -2
  54. package/dist/apps/data/routes/valuation.js.map +1 -1
  55. package/dist/apps/data/routes/verified-tokens.d.ts +37 -37
  56. package/dist/apps/data/routes/webhooks.d.ts +102 -505
  57. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  58. package/dist/apps/data/routes/webhooks.js +484 -342
  59. package/dist/apps/data/routes/webhooks.js.map +1 -1
  60. package/dist/apps/data/routes/zones.d.ts +12 -12
  61. package/dist/apps/data/routes/zones.d.ts.map +1 -1
  62. package/dist/apps/data/routes/zones.js +3 -1
  63. package/dist/apps/data/routes/zones.js.map +1 -1
  64. package/dist/apps/funding/App.d.ts +96 -96
  65. package/dist/apps/funding/routes/deposit-addresses.d.ts +52 -52
  66. package/dist/apps/funding/routes/quotes.d.ts +89 -89
  67. package/dist/apps/funding/routes/transfers.d.ts +4 -4
  68. package/dist/apps/management/App.d.ts +429 -727
  69. package/dist/apps/management/App.d.ts.map +1 -1
  70. package/dist/apps/management/routes/api-keys.d.ts +24 -24
  71. package/dist/apps/management/routes/billing.d.ts +72 -72
  72. package/dist/apps/management/routes/faucet.d.ts +6 -6
  73. package/dist/apps/management/routes/invitations.d.ts +134 -134
  74. package/dist/apps/management/routes/invite-links.d.ts +38 -38
  75. package/dist/apps/management/routes/me.d.ts +6 -6
  76. package/dist/apps/management/routes/members.d.ts +30 -30
  77. package/dist/apps/management/routes/orgs.d.ts +98 -98
  78. package/dist/apps/management/routes/projects.d.ts +20 -20
  79. package/dist/apps/management/routes/usage.d.ts +24 -24
  80. package/dist/apps/management/routes/verified-token-requests.d.ts +83 -83
  81. package/dist/apps/management/routes/webhooks.d.ts +158 -573
  82. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  83. package/dist/apps/mpp/App.d.ts +56 -44
  84. package/dist/apps/mpp/App.d.ts.map +1 -1
  85. package/dist/apps/mpp/Mpp.d.ts +3 -0
  86. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  87. package/dist/apps/mpp/Mpp.js +3 -0
  88. package/dist/apps/mpp/Mpp.js.map +1 -1
  89. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  90. package/dist/apps/mpp/internal/Adapter.js +9 -2
  91. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  92. package/dist/db/Db.d.ts +2 -2
  93. package/dist/db/Db.d.ts.map +1 -1
  94. package/dist/db/Db.js +17 -15
  95. package/dist/db/Db.js.map +1 -1
  96. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  97. package/dist/db/tables/sponsoredTransactions.js +4 -1
  98. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  99. package/dist/db/tables/webhookSubscriptions.d.ts +56 -3
  100. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  101. package/dist/db/tables/webhookSubscriptions.js +76 -3
  102. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  103. package/dist/internal/MetricSink.d.ts +112 -3
  104. package/dist/internal/MetricSink.d.ts.map +1 -1
  105. package/dist/internal/MetricSink.js +116 -3
  106. package/dist/internal/MetricSink.js.map +1 -1
  107. package/dist/internal/Schema.js +1 -1
  108. package/dist/internal/Schema.js.map +1 -1
  109. package/dist/internal/Tidx.d.ts +1 -3
  110. package/dist/internal/Tidx.d.ts.map +1 -1
  111. package/dist/internal/Tidx.js +1 -3
  112. package/dist/internal/Tidx.js.map +1 -1
  113. package/dist/internal/Viem.d.ts.map +1 -1
  114. package/dist/internal/Viem.js +2 -1
  115. package/dist/internal/Viem.js.map +1 -1
  116. package/dist/internal/WebhookDestination.d.ts +2 -0
  117. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  118. package/dist/internal/WebhookDestination.js +11 -0
  119. package/dist/internal/WebhookDestination.js.map +1 -1
  120. package/dist/internal/WebhookTransfer.d.ts +55 -0
  121. package/dist/internal/WebhookTransfer.d.ts.map +1 -0
  122. package/dist/internal/WebhookTransfer.js +296 -0
  123. package/dist/internal/WebhookTransfer.js.map +1 -0
  124. package/dist/internal/Webhooks.d.ts +37 -0
  125. package/dist/internal/Webhooks.d.ts.map +1 -1
  126. package/dist/internal/Webhooks.js +87 -13
  127. package/dist/internal/Webhooks.js.map +1 -1
  128. package/dist/internal/funding/Provider.d.ts +4 -0
  129. package/dist/internal/funding/Provider.d.ts.map +1 -1
  130. package/dist/internal/funding/Provider.js +11 -7
  131. package/dist/internal/funding/Provider.js.map +1 -1
  132. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  133. package/dist/internal/funding/Reconciliation.js +128 -0
  134. package/dist/internal/funding/Reconciliation.js.map +1 -1
  135. package/dist/internal/funding/providers/relay.d.ts +3 -0
  136. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  137. package/dist/internal/funding/providers/relay.js +12 -1
  138. package/dist/internal/funding/providers/relay.js.map +1 -1
  139. package/package.json +3 -3
  140. package/src/Client.test-d.ts +60 -5
  141. package/src/Webhooks.bench.ts +714 -0
  142. package/src/Webhooks.memory.bench.ts +250 -0
  143. package/src/Webhooks.test.ts +77 -6
  144. package/src/Webhooks.ts +83 -29
  145. package/src/apps/Zones.test.ts +5 -4
  146. package/src/apps/Zones.ts +9 -8
  147. package/src/apps/data/FxOracle.test.ts +18 -0
  148. package/src/apps/data/FxOracle.ts +28 -5
  149. package/src/apps/data/routes/activities.test.ts +19 -0
  150. package/src/apps/data/routes/activities.ts +34 -30
  151. package/src/apps/data/routes/balances.test.ts +119 -10
  152. package/src/apps/data/routes/balances.ts +154 -95
  153. package/src/apps/data/routes/blocks.test.ts +12 -6
  154. package/src/apps/data/routes/earn.test.ts +197 -0
  155. package/src/apps/data/routes/earn.ts +486 -44
  156. package/src/apps/data/routes/exchanges.test.ts +7 -6
  157. package/src/apps/data/routes/exchanges.ts +124 -117
  158. package/src/apps/data/routes/receipts.test.ts +24 -7
  159. package/src/apps/data/routes/receipts.ts +67 -50
  160. package/src/apps/data/routes/tokens.test.ts +51 -0
  161. package/src/apps/data/routes/transactions.test.ts +42 -0
  162. package/src/apps/data/routes/transactions.ts +44 -39
  163. package/src/apps/data/routes/transfers.test.ts +402 -24
  164. package/src/apps/data/routes/transfers.ts +708 -101
  165. package/src/apps/data/routes/valuation.test.ts +26 -0
  166. package/src/apps/data/routes/valuation.ts +6 -2
  167. package/src/apps/data/routes/webhooks.test.ts +414 -130
  168. package/src/apps/data/routes/webhooks.ts +603 -419
  169. package/src/apps/data/routes/zones.ts +6 -1
  170. package/src/apps/funding/routes/quotes.test.ts +1 -1
  171. package/src/apps/mpp/Mpp.test.ts +13 -1
  172. package/src/apps/mpp/Mpp.ts +8 -0
  173. package/src/apps/mpp/internal/Adapter.ts +10 -2
  174. package/src/db/Db.test.ts +40 -6
  175. package/src/db/Db.ts +33 -19
  176. package/src/db/tables/sponsoredTransactions.ts +9 -2
  177. package/src/db/tables/webhookSubscriptions.ts +116 -4
  178. package/src/internal/EarnVaults.test.ts +2 -2
  179. package/src/internal/MetricSink.test.ts +518 -0
  180. package/src/internal/MetricSink.ts +266 -9
  181. package/src/internal/Schema.ts +1 -1
  182. package/src/internal/Tidx.test.ts +4 -4
  183. package/src/internal/Tidx.ts +1 -3
  184. package/src/internal/Viem.test.ts +8 -0
  185. package/src/internal/Viem.ts +2 -1
  186. package/src/internal/WebhookDestination.test.ts +20 -0
  187. package/src/internal/WebhookDestination.ts +10 -0
  188. package/src/internal/WebhookTransfer.ts +426 -0
  189. package/src/internal/Webhooks.test.ts +137 -0
  190. package/src/internal/Webhooks.ts +131 -17
  191. package/src/internal/funding/Provider.test.ts +47 -7
  192. package/src/internal/funding/Provider.ts +12 -7
  193. package/src/internal/funding/Reconciliation.local.test.ts +3 -1
  194. package/src/internal/funding/Reconciliation.test.ts +1240 -0
  195. package/src/internal/funding/Reconciliation.ts +136 -0
  196. package/src/internal/funding/SourceObservation.test.ts +1 -0
  197. package/src/internal/funding/providers/relay.test.ts +1 -4
  198. 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: "api_key_malformed";
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: 400;
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: "api_key_invalid" | "api_key_missing";
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: 401;
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: "api_key_forbidden" | "api_key_ip_forbidden";
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: 403;
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: "payment_required" | "rate_limit_exceeded";
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: 429;
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: "query_invalid";
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: 400;
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: "upstream_error";
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: 502;
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: "address_invalid";
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: "api_key_malformed";
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: 400;
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: "api_key_invalid" | "api_key_missing";
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: 401;
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: "api_key_forbidden" | "api_key_ip_forbidden";
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: 403;
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: "payment_required" | "rate_limit_exceeded";
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: 429;
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: "query_invalid";
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: 400;
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: "upstream_error";
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: 502;
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: "address_invalid";
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;;;;;;;;;;;;;;;;;;;;;0BA0Cf,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;;;;;;0BAK6D,CAAA;QAE/E,wDAAwD;QACjD,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;yBAEpB,CAAA;KACF;CACF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,SAAS,CAAC,OAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kDAqMxD;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"}
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 in the requested `valuation.currency`, or `null` when the ' +
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, and each verified holding carries its nominal value in the requested denomination.',
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'] ?? 'USD',
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 snapshot = await VerifiedTokens.snapshot(c, chainId);
265
- const [balance, resolvedToken] = await Promise.all([
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
- Timing.time(c, 'token', () => Tokens.resolveToken(c, { address: token, chainId, include: [], snapshot })),
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
- valuation: Valuation.valuationFor({
291
- amount: balance,
292
- denomination,
293
- rates,
294
- token: snapshot.byAddress.get(token),
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, feeTokens, includeTotalCount, limit, oracle, verified, } = options;
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 the requested denomination independently of the current page.
317
- await Valuation.ratesFor(c, { currencies: [], denomination, oracle });
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 snapshot = await VerifiedTokens.snapshot(c, chainId);
326
- const allowed = allowedTokens({ currency, feeEligible, feeTokens, snapshot, verified });
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
- const holdings = await Timing.time(c, 'balances_discovery', async () => {
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
- if (holdings.length === 0)
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
- const client = c.get('getClient')(chainId);
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
- const rates = await Valuation.ratesFor(c, {
401
- currencies: page.rows.flatMap((row) => {
402
- const held = snapshot.byAddress.get(row.address.toLowerCase())?.currency;
403
- return held === undefined ? [] : [held];
404
- }),
405
- denomination,
406
- oracle,
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 resolved = await Timing.time(c, 'tokens', () => Promise.all(page.rows.map(async (holding) => {
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
- valuation: Valuation.valuationFor({
446
- amount: BigInt(entry.amount),
447
- denomination,
448
- rates,
449
- token: snapshot.byAddress.get(entry.token),
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 = {