tapimo 0.4.4 → 0.5.1

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 (229) hide show
  1. package/dist/App.d.ts +4701 -3416
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +24 -2
  4. package/dist/App.js.map +1 -1
  5. package/dist/Assets.js +3 -3
  6. package/dist/Assets.js.map +1 -1
  7. package/dist/Scope.d.ts +18 -1
  8. package/dist/Scope.d.ts.map +1 -1
  9. package/dist/Scope.js +23 -3
  10. package/dist/Scope.js.map +1 -1
  11. package/dist/Webhooks.d.ts +1 -1
  12. package/dist/Webhooks.d.ts.map +1 -1
  13. package/dist/Webhooks.js +5 -10
  14. package/dist/Webhooks.js.map +1 -1
  15. package/dist/admin/App.d.ts +6 -34
  16. package/dist/admin/App.d.ts.map +1 -1
  17. package/dist/admin/apps/api-keys.d.ts +3 -3
  18. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  19. package/dist/admin/apps/api-keys.js +4 -1
  20. package/dist/admin/apps/api-keys.js.map +1 -1
  21. package/dist/admin/apps/scopes.d.ts +6 -34
  22. package/dist/admin/apps/scopes.d.ts.map +1 -1
  23. package/dist/admin/apps/scopes.js +2 -2
  24. package/dist/admin/apps/scopes.js.map +1 -1
  25. package/dist/admin/apps/verified-tokens.d.ts +57 -57
  26. package/dist/admin/ui.generated.d.ts +1 -1
  27. package/dist/admin/ui.generated.js +33 -33
  28. package/dist/admin/ui.generated.js.map +1 -1
  29. package/dist/apps/data/App.d.ts +4574 -4277
  30. package/dist/apps/data/App.d.ts.map +1 -1
  31. package/dist/apps/data/App.js +155 -77
  32. package/dist/apps/data/App.js.map +1 -1
  33. package/dist/apps/data/FundingQuoteProviders.d.ts +109 -0
  34. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -0
  35. package/dist/apps/data/FundingQuoteProviders.js +464 -0
  36. package/dist/apps/data/FundingQuoteProviders.js.map +1 -0
  37. package/dist/apps/data/index.d.ts +1 -1
  38. package/dist/apps/data/index.js +1 -1
  39. package/dist/apps/data/routes/activities.d.ts +26 -26
  40. package/dist/apps/data/routes/addresses.d.ts +38 -38
  41. package/dist/apps/data/routes/balances.d.ts +45 -45
  42. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  43. package/dist/apps/data/routes/balances.js +67 -149
  44. package/dist/apps/data/routes/balances.js.map +1 -1
  45. package/dist/apps/data/routes/blocks.d.ts +2 -3
  46. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  47. package/dist/apps/data/routes/blocks.js +3 -5
  48. package/dist/apps/data/routes/blocks.js.map +1 -1
  49. package/dist/apps/data/routes/coingecko.d.ts +177 -176
  50. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  51. package/dist/apps/data/routes/coingecko.js +3 -8
  52. package/dist/apps/data/routes/coingecko.js.map +1 -1
  53. package/dist/apps/data/routes/funding.d.ts +131 -228
  54. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  55. package/dist/apps/data/routes/funding.js +152 -219
  56. package/dist/apps/data/routes/funding.js.map +1 -1
  57. package/dist/apps/data/routes/indexer.d.ts +34 -34
  58. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  59. package/dist/apps/data/routes/indexer.js +9 -2
  60. package/dist/apps/data/routes/indexer.js.map +1 -1
  61. package/dist/apps/data/routes/receipts.d.ts +228 -228
  62. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  63. package/dist/apps/data/routes/rpc.js +86 -16
  64. package/dist/apps/data/routes/rpc.js.map +1 -1
  65. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  66. package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
  67. package/dist/apps/data/routes/webhooks.d.ts +340 -0
  68. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  69. package/dist/apps/data/routes/webhooks.js +13 -1
  70. package/dist/apps/data/routes/webhooks.js.map +1 -1
  71. package/dist/apps/index.d.ts +1 -1
  72. package/dist/apps/index.js +1 -1
  73. package/dist/apps/management/App.d.ts +1833 -851
  74. package/dist/apps/management/App.d.ts.map +1 -1
  75. package/dist/apps/management/App.js +4 -0
  76. package/dist/apps/management/App.js.map +1 -1
  77. package/dist/apps/management/routes/api-keys.d.ts +41 -41
  78. package/dist/apps/management/routes/api-keys.js +2 -2
  79. package/dist/apps/management/routes/api-keys.js.map +1 -1
  80. package/dist/apps/management/routes/billing.d.ts +48 -48
  81. package/dist/apps/management/routes/invitations.d.ts +132 -132
  82. package/dist/apps/management/routes/invite-links.d.ts +1100 -0
  83. package/dist/apps/management/routes/invite-links.d.ts.map +1 -0
  84. package/dist/apps/management/routes/invite-links.js +411 -0
  85. package/dist/apps/management/routes/invite-links.js.map +1 -0
  86. package/dist/apps/management/routes/members.d.ts +41 -41
  87. package/dist/apps/management/routes/orgs.d.ts +92 -92
  88. package/dist/apps/management/routes/projects.d.ts +9 -9
  89. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  90. package/dist/apps/management/routes/scopes.js +2 -2
  91. package/dist/apps/management/routes/scopes.js.map +1 -1
  92. package/dist/apps/management/routes/usage.d.ts +24 -24
  93. package/dist/apps/mcp.js +2 -2
  94. package/dist/apps/mcp.js.map +1 -1
  95. package/dist/apps/relay/App.d.ts +2 -2
  96. package/dist/apps/relay/App.d.ts.map +1 -1
  97. package/dist/apps/relay/App.js +44 -6
  98. package/dist/apps/relay/App.js.map +1 -1
  99. package/dist/db/Db.d.ts +3 -0
  100. package/dist/db/Db.d.ts.map +1 -1
  101. package/dist/db/Db.js +57 -0
  102. package/dist/db/Db.js.map +1 -1
  103. package/dist/db/Schema.d.ts +31 -0
  104. package/dist/db/Schema.d.ts.map +1 -1
  105. package/dist/db/Schema.js +31 -0
  106. package/dist/db/Schema.js.map +1 -1
  107. package/dist/db/tables/inviteLinks.d.ts +42 -0
  108. package/dist/db/tables/inviteLinks.d.ts.map +1 -0
  109. package/dist/db/tables/inviteLinks.js +148 -0
  110. package/dist/db/tables/inviteLinks.js.map +1 -0
  111. package/dist/db/tables/organizations.d.ts.map +1 -1
  112. package/dist/db/tables/organizations.js +2 -0
  113. package/dist/db/tables/organizations.js.map +1 -1
  114. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  115. package/dist/db/tables/sponsoredTransactions.js +6 -2
  116. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  117. package/dist/handlers/relay.d.ts.map +1 -1
  118. package/dist/handlers/relay.js +13 -3
  119. package/dist/handlers/relay.js.map +1 -1
  120. package/dist/internal/Auth.d.ts +9 -1
  121. package/dist/internal/Auth.d.ts.map +1 -1
  122. package/dist/internal/Auth.js +138 -10
  123. package/dist/internal/Auth.js.map +1 -1
  124. package/dist/internal/EdgeCache.d.ts +3 -1
  125. package/dist/internal/EdgeCache.d.ts.map +1 -1
  126. package/dist/internal/EdgeCache.js +17 -2
  127. package/dist/internal/EdgeCache.js.map +1 -1
  128. package/dist/internal/{FundingRoutes.d.ts → FundingQuotes.d.ts} +240 -369
  129. package/dist/internal/FundingQuotes.d.ts.map +1 -0
  130. package/dist/internal/{FundingRoutes.js → FundingQuotes.js} +144 -183
  131. package/dist/internal/FundingQuotes.js.map +1 -0
  132. package/dist/internal/Log.d.ts +18 -12
  133. package/dist/internal/Log.d.ts.map +1 -1
  134. package/dist/internal/Log.js +2 -0
  135. package/dist/internal/Log.js.map +1 -1
  136. package/dist/internal/Tidx.d.ts +9 -3
  137. package/dist/internal/Tidx.d.ts.map +1 -1
  138. package/dist/internal/Tidx.js +13 -7
  139. package/dist/internal/Tidx.js.map +1 -1
  140. package/dist/internal/Viem.d.ts +17 -2
  141. package/dist/internal/Viem.d.ts.map +1 -1
  142. package/dist/internal/Viem.js +30 -3
  143. package/dist/internal/Viem.js.map +1 -1
  144. package/dist/internal/index.d.ts +1 -1
  145. package/dist/internal/index.js +1 -1
  146. package/package.json +2 -2
  147. package/src/ApiKeys.test.ts +25 -0
  148. package/src/App.test-d.ts +2 -0
  149. package/src/App.test.ts +13 -2
  150. package/src/App.ts +37 -5
  151. package/src/Assets.ts +3 -3
  152. package/src/Client.test-d.ts +21 -11
  153. package/src/Scope.test.ts +1 -0
  154. package/src/Scope.ts +32 -4
  155. package/src/Webhooks.ts +5 -10
  156. package/src/admin/apps/api-keys.test.ts +27 -0
  157. package/src/admin/apps/api-keys.ts +8 -1
  158. package/src/admin/apps/scopes.test.ts +7 -2
  159. package/src/admin/apps/scopes.ts +2 -2
  160. package/src/admin/ui/src/components/Dialog.tsx +8 -2
  161. package/src/admin/ui/src/lib/scopes.test.ts +19 -0
  162. package/src/admin/ui/src/lib/scopes.ts +12 -0
  163. package/src/admin/ui/src/routes/api-keys.tsx +128 -27
  164. package/src/admin/ui.generated.ts +33 -33
  165. package/src/apps/composition.test.ts +77 -0
  166. package/src/apps/data/App.test.ts +354 -0
  167. package/src/apps/data/App.ts +178 -91
  168. package/src/apps/data/FundingQuoteProviders.test.ts +577 -0
  169. package/src/apps/data/FundingQuoteProviders.ts +633 -0
  170. package/src/apps/data/index.ts +1 -1
  171. package/src/apps/data/routes/balances.test.ts +64 -18
  172. package/src/apps/data/routes/balances.ts +76 -177
  173. package/src/apps/data/routes/blocks.ts +3 -5
  174. package/src/apps/data/routes/coingecko.ts +3 -8
  175. package/src/apps/data/routes/funding.test.ts +304 -192
  176. package/src/apps/data/routes/funding.ts +166 -286
  177. package/src/apps/data/routes/indexer.test.ts +173 -15
  178. package/src/apps/data/routes/indexer.ts +8 -2
  179. package/src/apps/data/routes/rpc.test.ts +219 -0
  180. package/src/apps/data/routes/rpc.ts +92 -17
  181. package/src/apps/data/routes/webhooks.test.ts +21 -0
  182. package/src/apps/data/routes/webhooks.ts +13 -1
  183. package/src/apps/index.ts +1 -1
  184. package/src/apps/management/App.ts +4 -0
  185. package/src/apps/management/Billing.test.ts +2 -2
  186. package/src/apps/management/routes/api-keys.test.ts +47 -3
  187. package/src/apps/management/routes/api-keys.ts +2 -2
  188. package/src/apps/management/routes/invite-links.test.ts +385 -0
  189. package/src/apps/management/routes/invite-links.ts +570 -0
  190. package/src/apps/management/routes/scopes.test.ts +3 -2
  191. package/src/apps/management/routes/scopes.ts +4 -2
  192. package/src/apps/mcp.test.ts +18 -0
  193. package/src/apps/mcp.ts +2 -2
  194. package/src/apps/relay/App.test.ts +328 -7
  195. package/src/apps/relay/App.ts +42 -6
  196. package/src/apps/relay/Sponsorships.test.ts +2 -2
  197. package/src/db/Db.test.ts +5 -5
  198. package/src/db/Db.ts +65 -0
  199. package/src/db/Schema.ts +39 -0
  200. package/src/db/tables/billingSettings.test.ts +2 -2
  201. package/src/db/tables/inviteLinks.ts +187 -0
  202. package/src/db/tables/organizations.test.ts +2 -2
  203. package/src/db/tables/organizations.ts +2 -0
  204. package/src/db/tables/sponsoredTransactions.test.ts +19 -2
  205. package/src/db/tables/sponsoredTransactions.ts +21 -14
  206. package/src/db/tables/stripeCustomers.test.ts +2 -2
  207. package/src/handlers/relay.ts +16 -4
  208. package/src/internal/Auth.test.ts +132 -22
  209. package/src/internal/Auth.ts +181 -14
  210. package/src/internal/EdgeCache.test.ts +24 -3
  211. package/src/internal/EdgeCache.ts +18 -2
  212. package/src/internal/FundingQuotes.test.ts +268 -0
  213. package/src/internal/{FundingRoutes.ts → FundingQuotes.ts} +216 -277
  214. package/src/internal/Log.ts +21 -14
  215. package/src/internal/Tidx.test.ts +48 -0
  216. package/src/internal/Tidx.ts +21 -7
  217. package/src/internal/Viem.test.ts +46 -0
  218. package/src/internal/Viem.ts +48 -6
  219. package/src/internal/index.test.ts +1 -1
  220. package/src/internal/index.ts +1 -1
  221. package/dist/apps/data/FundingRouteProviders.d.ts +0 -36
  222. package/dist/apps/data/FundingRouteProviders.d.ts.map +0 -1
  223. package/dist/apps/data/FundingRouteProviders.js +0 -245
  224. package/dist/apps/data/FundingRouteProviders.js.map +0 -1
  225. package/dist/internal/FundingRoutes.d.ts.map +0 -1
  226. package/dist/internal/FundingRoutes.js.map +0 -1
  227. package/src/apps/data/FundingRouteProviders.test.ts +0 -225
  228. package/src/apps/data/FundingRouteProviders.ts +0 -312
  229. package/src/internal/FundingRoutes.test.ts +0 -213
@@ -31,30 +31,6 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
31
31
  logs?: string | string[];
32
32
  } | undefined;
33
33
  };
34
- } | {
35
- output: {
36
- error: {
37
- code: "upstream_error";
38
- details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
39
- message: string;
40
- };
41
- requestId: string;
42
- };
43
- outputFormat: "json";
44
- status: 502;
45
- input: {
46
- param: {
47
- address: `0x${string}`;
48
- };
49
- } & {
50
- query?: {
51
- chainId?: string | string[];
52
- cursor?: string | string[];
53
- group?: string | string[];
54
- limit?: string | string[];
55
- logs?: string | string[];
56
- } | undefined;
57
- };
58
34
  } | {
59
35
  output: {
60
36
  error: {
@@ -154,7 +130,7 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
154
130
  } | {
155
131
  output: {
156
132
  error: {
157
- code: "query_invalid";
133
+ code: "address_invalid";
158
134
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
159
135
  message: string;
160
136
  };
@@ -178,7 +154,7 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
178
154
  } | {
179
155
  output: {
180
156
  error: {
181
- code: "address_invalid";
157
+ code: "query_invalid";
182
158
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
183
159
  message: string;
184
160
  };
@@ -3401,6 +3377,30 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3401
3377
  logs?: string | string[];
3402
3378
  } | undefined;
3403
3379
  };
3380
+ } | {
3381
+ output: {
3382
+ error: {
3383
+ code: "upstream_error";
3384
+ details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3385
+ message: string;
3386
+ };
3387
+ requestId: string;
3388
+ };
3389
+ outputFormat: "json";
3390
+ status: 502;
3391
+ input: {
3392
+ param: {
3393
+ address: `0x${string}`;
3394
+ };
3395
+ } & {
3396
+ query?: {
3397
+ chainId?: string | string[];
3398
+ cursor?: string | string[];
3399
+ group?: string | string[];
3400
+ limit?: string | string[];
3401
+ logs?: string | string[];
3402
+ } | undefined;
3403
+ };
3404
3404
  };
3405
3405
  };
3406
3406
  }, "/"> | import("hono/types").MergeSchemaPath<{
@@ -3428,14 +3428,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3428
3428
  } | {
3429
3429
  output: {
3430
3430
  error: {
3431
- code: "upstream_error";
3431
+ code: "api_key_malformed";
3432
3432
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3433
3433
  message: string;
3434
3434
  };
3435
3435
  requestId: string;
3436
3436
  };
3437
3437
  outputFormat: "json";
3438
- status: 502;
3438
+ status: 400;
3439
3439
  input: {
3440
3440
  param: {
3441
3441
  address: `0x${string}`;
@@ -3455,14 +3455,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3455
3455
  } | {
3456
3456
  output: {
3457
3457
  error: {
3458
- code: "api_key_malformed";
3458
+ code: "api_key_invalid" | "api_key_missing";
3459
3459
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3460
3460
  message: string;
3461
3461
  };
3462
3462
  requestId: string;
3463
3463
  };
3464
3464
  outputFormat: "json";
3465
- status: 400;
3465
+ status: 401;
3466
3466
  input: {
3467
3467
  param: {
3468
3468
  address: `0x${string}`;
@@ -3482,14 +3482,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3482
3482
  } | {
3483
3483
  output: {
3484
3484
  error: {
3485
- code: "api_key_invalid" | "api_key_missing";
3485
+ code: "api_key_forbidden";
3486
3486
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3487
3487
  message: string;
3488
3488
  };
3489
3489
  requestId: string;
3490
3490
  };
3491
3491
  outputFormat: "json";
3492
- status: 401;
3492
+ status: 403;
3493
3493
  input: {
3494
3494
  param: {
3495
3495
  address: `0x${string}`;
@@ -3509,14 +3509,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3509
3509
  } | {
3510
3510
  output: {
3511
3511
  error: {
3512
- code: "api_key_forbidden";
3512
+ code: "payment_required" | "rate_limit_exceeded";
3513
3513
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3514
3514
  message: string;
3515
3515
  };
3516
3516
  requestId: string;
3517
3517
  };
3518
3518
  outputFormat: "json";
3519
- status: 403;
3519
+ status: 429;
3520
3520
  input: {
3521
3521
  param: {
3522
3522
  address: `0x${string}`;
@@ -3536,14 +3536,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3536
3536
  } | {
3537
3537
  output: {
3538
3538
  error: {
3539
- code: "payment_required" | "rate_limit_exceeded";
3539
+ code: "address_invalid";
3540
3540
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3541
3541
  message: string;
3542
3542
  };
3543
3543
  requestId: string;
3544
3544
  };
3545
3545
  outputFormat: "json";
3546
- status: 429;
3546
+ status: 400;
3547
3547
  input: {
3548
3548
  param: {
3549
3549
  address: `0x${string}`;
@@ -3590,14 +3590,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
3590
3590
  } | {
3591
3591
  output: {
3592
3592
  error: {
3593
- code: "address_invalid";
3593
+ code: "upstream_error";
3594
3594
  details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
3595
3595
  message: string;
3596
3596
  };
3597
3597
  requestId: string;
3598
3598
  };
3599
3599
  outputFormat: "json";
3600
- status: 400;
3600
+ status: 502;
3601
3601
  input: {
3602
3602
  param: {
3603
3603
  address: `0x${string}`;
@@ -86,9 +86,31 @@ export declare namespace schema {
86
86
  export declare function addresses(): import("hono/hono-base").HonoBase<App.Environment, {
87
87
  "/v1/addresses/:address/balances": {
88
88
  $get: {
89
- output: null;
90
- outputFormat: "body";
91
- status: 402;
89
+ output: {
90
+ data: {
91
+ amount: string;
92
+ formatted: string;
93
+ id: string;
94
+ feeEligible?: boolean | undefined;
95
+ token: {
96
+ address: `0x${string}`;
97
+ currency: string;
98
+ decimals: number;
99
+ id: string;
100
+ logoUri?: string | undefined;
101
+ name: string;
102
+ symbol: string;
103
+ verified: boolean;
104
+ };
105
+ }[];
106
+ meta?: {
107
+ totalCountCapped: boolean;
108
+ totalCount: number;
109
+ } | undefined;
110
+ nextCursor: string | null;
111
+ };
112
+ outputFormat: "json";
113
+ status: 200;
92
114
  input: {
93
115
  param: {
94
116
  address: `0x${string}`;
@@ -135,14 +157,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
135
157
  } | {
136
158
  output: {
137
159
  error: {
138
- code: "api_key_invalid" | "api_key_missing";
160
+ code: "query_invalid";
139
161
  details?: readonly Response.error.Detail[] | undefined;
140
162
  message: string;
141
163
  };
142
164
  requestId: string;
143
165
  };
144
166
  outputFormat: "json";
145
- status: 401;
167
+ status: 400;
146
168
  input: {
147
169
  param: {
148
170
  address: `0x${string}`;
@@ -162,14 +184,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
162
184
  } | {
163
185
  output: {
164
186
  error: {
165
- code: "api_key_forbidden";
187
+ code: "address_invalid";
166
188
  details?: readonly Response.error.Detail[] | undefined;
167
189
  message: string;
168
190
  };
169
191
  requestId: string;
170
192
  };
171
193
  outputFormat: "json";
172
- status: 403;
194
+ status: 400;
173
195
  input: {
174
196
  param: {
175
197
  address: `0x${string}`;
@@ -189,14 +211,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
189
211
  } | {
190
212
  output: {
191
213
  error: {
192
- code: "payment_required" | "rate_limit_exceeded";
214
+ code: "api_key_invalid" | "api_key_missing";
193
215
  details?: readonly Response.error.Detail[] | undefined;
194
216
  message: string;
195
217
  };
196
218
  requestId: string;
197
219
  };
198
220
  outputFormat: "json";
199
- status: 429;
221
+ status: 401;
200
222
  input: {
201
223
  param: {
202
224
  address: `0x${string}`;
@@ -214,16 +236,9 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
214
236
  } | undefined;
215
237
  };
216
238
  } | {
217
- output: {
218
- error: {
219
- code: "query_invalid";
220
- details?: readonly Response.error.Detail[] | undefined;
221
- message: string;
222
- };
223
- requestId: string;
224
- };
225
- outputFormat: "json";
226
- status: 400;
239
+ output: null;
240
+ outputFormat: "body";
241
+ status: 402;
227
242
  input: {
228
243
  param: {
229
244
  address: `0x${string}`;
@@ -243,14 +258,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
243
258
  } | {
244
259
  output: {
245
260
  error: {
246
- code: "upstream_error";
261
+ code: "api_key_forbidden";
247
262
  details?: readonly Response.error.Detail[] | undefined;
248
263
  message: string;
249
264
  };
250
265
  requestId: string;
251
266
  };
252
267
  outputFormat: "json";
253
- status: 502;
268
+ status: 403;
254
269
  input: {
255
270
  param: {
256
271
  address: `0x${string}`;
@@ -270,14 +285,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
270
285
  } | {
271
286
  output: {
272
287
  error: {
273
- code: "address_invalid";
288
+ code: "payment_required" | "rate_limit_exceeded";
274
289
  details?: readonly Response.error.Detail[] | undefined;
275
290
  message: string;
276
291
  };
277
292
  requestId: string;
278
293
  };
279
294
  outputFormat: "json";
280
- status: 400;
295
+ status: 429;
281
296
  input: {
282
297
  param: {
283
298
  address: `0x${string}`;
@@ -296,30 +311,15 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
296
311
  };
297
312
  } | {
298
313
  output: {
299
- data: {
300
- amount: string;
301
- formatted: string;
302
- id: string;
303
- feeEligible?: boolean | undefined;
304
- token: {
305
- address: `0x${string}`;
306
- currency: string;
307
- decimals: number;
308
- id: string;
309
- logoUri?: string | undefined;
310
- name: string;
311
- symbol: string;
312
- verified: boolean;
313
- };
314
- }[];
315
- meta?: {
316
- totalCountCapped: boolean;
317
- totalCount: number;
318
- } | undefined;
319
- nextCursor: string | null;
314
+ error: {
315
+ code: "upstream_error";
316
+ details?: readonly Response.error.Detail[] | undefined;
317
+ message: string;
318
+ };
319
+ requestId: string;
320
320
  };
321
321
  outputFormat: "json";
322
- status: 200;
322
+ status: 502;
323
323
  input: {
324
324
  param: {
325
325
  address: `0x${string}`;
@@ -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;AAezD,iDAAiD;AACjD,yBAAiB,MAAM,CAAC;IACtB,oDAAoD;IACpD,UAAiB,kBAAkB,CAAC;QAClC,oDAAoD;QAC7C,MAAM,MAAM;;yBAM6D,CAAA;QAEhF,qDAAqD;QAC9C,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;0BAyCf,CAAA;QAEH;;;;;WAKG;QACI,MAAM,OAAO;;;;;;;;;;;;;;;yBA0CnB,CAAA;QAED,sFAAsF;QAC/E,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;yBAUwD,CAAA;KAC9E;CACF;AAED;;;GAGG;AACH,wBAAgB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CA0GxB"}
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;AAazD,iDAAiD;AACjD,yBAAiB,MAAM,CAAC;IACtB,oDAAoD;IACpD,UAAiB,kBAAkB,CAAC;QAClC,oDAAoD;QAC7C,MAAM,MAAM;;yBAM6D,CAAA;QAEhF,qDAAqD;QAC9C,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;0BAyCf,CAAA;QAEH;;;;;WAKG;QACI,MAAM,OAAO;;;;;;;;;;;;;;;yBA0CnB,CAAA;QAED,sFAAsF;QAC/E,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;yBAUwD,CAAA;KAC9E;CACF;AAED;;;GAGG;AACH,wBAAgB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAqFxB"}
@@ -1,5 +1,5 @@
1
1
  import { Hono } from 'hono';
2
- import { Hex, Value as core_Value } from 'ox';
2
+ import { Value as core_Value } from 'ox';
3
3
  import { Actions } from 'viem/tempo';
4
4
  import * as z from 'zod/mini';
5
5
  import * as Auth from '../../../internal/Auth.js';
@@ -9,15 +9,13 @@ import * as OpenApi from '../../../internal/OpenApi.js';
9
9
  import * as Response from '../../../internal/Response.js';
10
10
  import * as Schema from '../../../internal/Schema.js';
11
11
  import * as Timing from '../../../internal/Timing.js';
12
- import * as Value from '../../../internal/Value.js';
13
12
  import * as VerifiedTokens from '../../../internal/VerifiedTokens.js';
14
13
  import * as FeeAmm from './fee-amm.js';
15
14
  import * as Tokens from './tokens.js';
16
15
  // TIP-20 tokens are minted by the TIP-20 factory and live at deterministic
17
16
  // `0x20c0…`-prefixed addresses (e.g. pathUSD `0x20c0…0000`). The indexer's
18
- // `token_balances_snapshot` view, by contrast, records balances for every
19
- // Transfer-emitting contract, so balance queries filter on this prefix to keep
20
- // non-TIP-20 tokens (which have no resolvable TIP-20 metadata) out of results.
17
+ // balance sources include every Transfer-emitting contract, so discovery
18
+ // filters on this prefix to keep non-TIP-20 tokens out of results.
21
19
  const tip20AddressPrefix = '0x20c0';
22
20
  /** Zod schemas owned by the balance handlers. */
23
21
  export var schema;
@@ -155,19 +153,6 @@ export function addresses() {
155
153
  throw cause;
156
154
  return undefined;
157
155
  });
158
- // `totalCount` (the number of matching holdings) is opt-in and shares
159
- // the page's filters; run it concurrently with the page. Best-effort: a
160
- // count failure omits `meta` rather than failing the page.
161
- const countPromise = query.include.includes('totalCount')
162
- ? countAddressBalances(c, {
163
- address,
164
- chainId,
165
- currency: query.currency,
166
- feeEligible,
167
- feeTokens,
168
- verified,
169
- }).catch(() => undefined)
170
- : undefined;
171
156
  const balances = await getAddressBalances(c, {
172
157
  address,
173
158
  chainId,
@@ -175,15 +160,12 @@ export function addresses() {
175
160
  cursor: query.cursor,
176
161
  feeEligible,
177
162
  feeTokens,
163
+ includeTotalCount: query.include.includes('totalCount'),
178
164
  limit: query.limit,
179
165
  page: query.page,
180
166
  verified,
181
167
  });
182
- const meta = countPromise ? await countPromise : undefined;
183
- return c.json(Response.validated(schema.getAddressBalances.Response, {
184
- ...balances,
185
- ...(meta ? { meta } : {}),
186
- }), 200);
168
+ return c.json(Response.validated(schema.getAddressBalances.Response, balances), 200);
187
169
  }
188
170
  catch (cause) {
189
171
  return Response.upstream(c, cause);
@@ -191,17 +173,10 @@ export function addresses() {
191
173
  });
192
174
  }
193
175
  async function getAddressBalances(c, options) {
194
- const { address, chainId, currency, feeEligible, feeTokens, limit, verified } = options;
176
+ const { address, chainId, currency, feeEligible, feeTokens, includeTotalCount, limit, verified } = options;
195
177
  const tidx = c.get('getTidx')(chainId);
196
- // Keyset pagination on `(balance, token)`: balance is descending and `token`
197
- // is a stable tiebreaker for the many holdings sharing a balance. A malformed
198
- // cursor falls back to the head page. Note: because `balance` is mutable, this
199
- // is best-effort across balance changes (the inherent limit of ranking feeds).
200
178
  const cursor = options.cursor ? Cursor.decode(options.cursor, ['uint', 'address']) : undefined;
201
- // Bounded positional lane (exclusive with `cursor` at the schema): page 1 is
202
- // the head page, so it shares the head's SQL and cache entries; deeper pages
203
- // translate to a SQL OFFSET of `(page - 1) * limit` rows.
204
- const offset = options.page !== undefined && options.page > 1 ? (options.page - 1) * limit : undefined;
179
+ const offset = options.page !== undefined && options.page > 1 ? (options.page - 1) * limit : 0;
205
180
  // Build the optional `token IN (…)` restriction before hitting TIDX. The
206
181
  // verified/`currency` filter and the `feeEligible` filter each contribute a set
207
182
  // of allowed addresses (`currency` matched case-insensitively so callers can
@@ -213,90 +188,48 @@ async function getAddressBalances(c, options) {
213
188
  const allowed = allowedTokens({ currency, feeEligible, feeTokens, snapshot, verified });
214
189
  const tokenFilter = allowed?.map((address) => `'${address}'`);
215
190
  if (tokenFilter?.length === 0)
216
- return { data: [], nextCursor: null };
217
- const holdings = await Timing.time(c, 'address_balances', async () => {
218
- // A held token is one this address holds a positive amount of. Read the
219
- // live `address_balances` view (`holder`-keyed: one row per
220
- // `(holder, token, balance)`), which aggregates `address_holder_deltas`
221
- // directly so balances reflect the indexer's chain head (no periodic
222
- // snapshot refresh — see the indexer's `address_holder_deltas` MV). The
223
- // `holder` equality prunes the view by its leading sort key, so this stays
224
- // a bounded read per request. Fetch one extra row to detect `hasMore`
225
- // without a separate count query. `startsWith` restricts results to TIP-20
226
- // tokens (see `tip20AddressPrefix`) before pagination, so `hasMore`/page
227
- // sizes stay correct and every returned token has resolvable metadata. The
228
- // inline query is cast to `string` so TIDX treats it as a dynamic
229
- // ClickHouse query that needs no event signature for the
230
- // `address_balances` view.
231
- //
232
- // Let upstream failures propagate: this is a dedicated endpoint, so a
233
- // failure should surface as the declared `502` rather than masquerade as
234
- // an address holding zero tokens.
235
- const keyset = cursor !== undefined
236
- ? ` AND ${Cursor.keyset([
237
- { literal: Cursor.literal(cursor[0], 'uint'), name: 'balance', order: 'desc' },
238
- { literal: Cursor.literal(cursor[1], 'address'), name: 'token', order: 'asc' },
239
- ])}`
240
- : '';
191
+ return {
192
+ data: [],
193
+ ...(includeTotalCount ? { meta: { totalCount: 0, totalCountCapped: false } } : {}),
194
+ nextCursor: null,
195
+ };
196
+ const holdings = await Timing.time(c, 'balances_discovery', async () => {
241
197
  const tokenIn = tokenFilter ? ` AND token IN (${tokenFilter.join(', ')})` : '';
242
198
  const result = await tidx.fetch({
243
199
  chainId,
244
200
  engine: 'clickhouse',
245
- // `balance` is UInt256; SELECT it as a string so values > 2^53
246
- // survive JSON without precision loss. The keyset cursor encodes the
247
- // row's exact balance, so any rounding would re-include the cursor
248
- // row on the next page. Alias is `balance_str` (not `balance`)
249
- // because TIDX rejects expression aliases that shadow the source
250
- // column (422).
201
+ // Discovery tolerates stale and reorged rows: RPC removes candidates
202
+ // with no current balance, so avoid the cost of `FINAL` and aggregation.
251
203
  query: `
252
- SELECT token, toString(balance) AS balance_str
253
- FROM address_balances
254
- WHERE holder = '${address}' AND startsWith(token, '${tip20AddressPrefix}') AND balance > 0${tokenIn}${keyset}
255
- ORDER BY balance DESC, token ASC
256
- LIMIT ${limit + 1}${offset !== undefined ? ` OFFSET ${offset}` : ''}
204
+ SELECT DISTINCT token
205
+ FROM address_holder_deltas
206
+ WHERE holder = '${address}' AND startsWith(token, '${tip20AddressPrefix}')${tokenIn}
257
207
  `,
258
208
  });
259
- // The next page anchors below the last fetched row's `(balance, token)`.
260
- const page = Cursor.paginate({
261
- rows: result.rows,
262
- limit,
263
- key: (row) => {
264
- const balance = Value.toIntegerString(row['balance_str']);
265
- const token = Schema.Address.safeParse(row['token']);
266
- return balance !== undefined && token.success ? [balance, token.data] : undefined;
267
- },
268
- });
269
- const data = [];
270
- for (const row of page.rows) {
209
+ return result.rows.flatMap((row) => {
271
210
  const token = Schema.Address.safeParse(row['token']);
272
- const amount = Value.toIntegerString(row['balance_str']);
273
- if (token.success && amount !== undefined)
274
- data.push({ address: token.data, amount });
275
- }
276
- return { data, nextCursor: page.nextCursor };
211
+ return token.success ? [{ address: token.data }] : [];
212
+ });
277
213
  });
278
- if (holdings.data.length === 0)
279
- return { data: [], nextCursor: holdings.nextCursor };
214
+ if (holdings.length === 0)
215
+ return {
216
+ data: [],
217
+ ...(includeTotalCount ? { meta: { totalCount: 0, totalCountCapped: false } } : {}),
218
+ nextCursor: null,
219
+ };
280
220
  const client = c.get('getClient')(chainId);
281
- // TODO: remove once https://github.com/tempoxyz/tidx/commit/2f37b44172d381fd00234ef23f79ed1e1d69c470 deployed.
282
221
  const corrected = await Timing.time(c, 'balances_rpc', async () => {
283
- const results = await client
284
- .multicall({
285
- allowFailure: true,
286
- contracts: holdings.data.map((holding) => Actions.token.getBalance.call(client, { account: address, token: holding.address })),
287
- })
288
- .catch(() => undefined);
289
- const rows = [];
290
- for (const [index, holding] of holdings.data.entries()) {
291
- const result = results?.[index];
292
- if (!result || result.status !== 'success' || typeof result.result !== 'bigint') {
293
- rows.push(holding);
294
- continue;
295
- }
296
- if (result.result === 0n)
297
- continue;
298
- rows.push({ address: holding.address, amount: result.result.toString() });
299
- }
222
+ // Concurrent reads enter viem's shared batch window and become one
223
+ // deployless multicall. A failed read fails the request rather than serving
224
+ // a stale or partial balance page.
225
+ const results = await Promise.all(holdings.map(async (holding) => {
226
+ const { amount } = await Actions.token.getBalance(client, {
227
+ account: address,
228
+ token: holding.address,
229
+ });
230
+ return amount === 0n ? undefined : { address: holding.address, amount: amount.toString() };
231
+ }));
232
+ const rows = results.filter((holding) => holding !== undefined);
300
233
  rows.sort((a, b) => {
301
234
  const delta = BigInt(b.amount) - BigInt(a.amount);
302
235
  if (delta !== 0n)
@@ -305,8 +238,27 @@ async function getAddressBalances(c, options) {
305
238
  });
306
239
  return rows;
307
240
  });
308
- if (corrected.length === 0)
309
- return { data: [], nextCursor: holdings.nextCursor };
241
+ const positioned = (() => {
242
+ if (!cursor)
243
+ return corrected.slice(offset);
244
+ const amount = BigInt(cursor[0]);
245
+ const address = String(cursor[1]);
246
+ return corrected.filter((holding) => BigInt(holding.amount) < amount ||
247
+ (BigInt(holding.amount) === amount && holding.address > address));
248
+ })();
249
+ const page = Cursor.paginate({
250
+ rows: positioned,
251
+ limit,
252
+ key: (holding) => [holding.amount, holding.address],
253
+ });
254
+ if (page.rows.length === 0)
255
+ return {
256
+ data: [],
257
+ ...(includeTotalCount
258
+ ? { meta: { totalCount: corrected.length, totalCountCapped: false } }
259
+ : {}),
260
+ nextCursor: page.nextCursor,
261
+ };
310
262
  // Resolve token metadata for each balance. The endpoint's contract is a
311
263
  // balance with its `token` reference inlined per row (and `formatted` needs
312
264
  // the token `decimals`), so a row whose metadata cannot be resolved is
@@ -317,7 +269,7 @@ async function getAddressBalances(c, options) {
317
269
  // The verified `snapshot` fetched above is reused across the page instead of
318
270
  // re-resolved per row. `createdAt` is not part of this endpoint's response,
319
271
  // so it is never fetched here.
320
- const resolved = await Timing.time(c, 'tokens', () => Promise.all(corrected.map((holding) => Tokens.resolveToken(c, {
272
+ const resolved = await Timing.time(c, 'tokens', () => Promise.all(page.rows.map((holding) => Tokens.resolveToken(c, {
321
273
  address: holding.address,
322
274
  chainId,
323
275
  snapshot,
@@ -347,7 +299,13 @@ async function getAddressBalances(c, options) {
347
299
  },
348
300
  });
349
301
  }
350
- return { data, nextCursor: holdings.nextCursor };
302
+ return {
303
+ data,
304
+ ...(includeTotalCount
305
+ ? { meta: { totalCount: corrected.length, totalCountCapped: false } }
306
+ : {}),
307
+ nextCursor: page.nextCursor,
308
+ };
351
309
  }
352
310
  /**
353
311
  * Computes the optional set of allowed token addresses for the page's
@@ -381,44 +339,4 @@ function allowedTokens(options) {
381
339
  }
382
340
  return allowed;
383
341
  }
384
- /**
385
- * Exact count of an address's matching TIP-20 holdings, sharing
386
- * {@link getAddressBalances}'s `holder`/`verified`/`currency` filters (minus
387
- * pagination) so the count matches the page it annotates. The `holder` equality
388
- * prunes the `token_balances_snapshot` view by its sort key, so ClickHouse
389
- * counts via the sparse primary index without a row scan — the count is exact
390
- * and cheap with no cap (`totalCountCapped` is always `false`), verified at
391
- * ~370k holdings in <1s. Feeds the opt-in `meta.totalCount`.
392
- */
393
- async function countAddressBalances(c, options) {
394
- const { address, chainId, currency, feeEligible, feeTokens, verified } = options;
395
- const tidx = c.get('getTidx')(chainId);
396
- // Same verified/currency/feeEligible `token IN (…)` restriction as the page; an
397
- // empty filter means nothing matches, so the count is zero without a round
398
- // trip.
399
- const snapshot = await VerifiedTokens.snapshot(c, chainId);
400
- const allowed = allowedTokens({ currency, feeEligible, feeTokens, snapshot, verified });
401
- const tokenFilter = allowed?.map((address) => `'${address}'`);
402
- if (tokenFilter?.length === 0)
403
- return { totalCountCapped: false, totalCount: 0 };
404
- const tokenIn = tokenFilter ? ` AND token IN (${tokenFilter.join(', ')})` : '';
405
- return Timing.time(c, 'address_balances_count', async () => {
406
- // Exact count over the holder-pruned `address_balances` rows (mirrors the
407
- // page's WHERE, minus the keyset cursor). The `holder` sort-key prune lets
408
- // ClickHouse count via the sparse index, so no cap is needed. The inline
409
- // query is cast to `string` so TIDX treats it as a dynamic ClickHouse
410
- // query needing no signature.
411
- const result = await tidx.fetch({
412
- chainId,
413
- engine: 'clickhouse',
414
- query: `
415
- SELECT count(*) AS total
416
- FROM address_balances
417
- WHERE holder = '${address}' AND startsWith(token, '${tip20AddressPrefix}') AND balance > 0${tokenIn}
418
- `,
419
- });
420
- const totalCount = Value.toNumber(result.rows[0]?.['total']) ?? 0;
421
- return { totalCountCapped: false, totalCount };
422
- });
423
- }
424
342
  //# sourceMappingURL=balances.js.map