tapimo 0.0.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (422) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +119 -0
  3. package/dist/ApiKey.d.ts +65 -0
  4. package/dist/ApiKey.d.ts.map +1 -0
  5. package/dist/ApiKey.js +105 -0
  6. package/dist/ApiKey.js.map +1 -0
  7. package/dist/ApiKeySource.d.ts +166 -0
  8. package/dist/ApiKeySource.d.ts.map +1 -0
  9. package/dist/ApiKeySource.js +234 -0
  10. package/dist/ApiKeySource.js.map +1 -0
  11. package/dist/App.d.ts +19317 -0
  12. package/dist/App.d.ts.map +1 -0
  13. package/dist/App.js +612 -0
  14. package/dist/App.js.map +1 -0
  15. package/dist/Assets.d.ts +44 -0
  16. package/dist/Assets.d.ts.map +1 -0
  17. package/dist/Assets.js +23 -0
  18. package/dist/Assets.js.map +1 -0
  19. package/dist/Auth.d.ts +2 -0
  20. package/dist/Auth.d.ts.map +1 -0
  21. package/dist/Auth.js +2 -0
  22. package/dist/Auth.js.map +1 -0
  23. package/dist/Cli.d.ts +21 -0
  24. package/dist/Cli.d.ts.map +1 -0
  25. package/dist/Cli.js +13 -0
  26. package/dist/Cli.js.map +1 -0
  27. package/dist/Client.d.ts +20 -0
  28. package/dist/Client.d.ts.map +1 -0
  29. package/dist/Client.js +24 -0
  30. package/dist/Client.js.map +1 -0
  31. package/dist/Metrics.d.ts +70 -0
  32. package/dist/Metrics.d.ts.map +1 -0
  33. package/dist/Metrics.js +91 -0
  34. package/dist/Metrics.js.map +1 -0
  35. package/dist/Scope.d.ts +35 -0
  36. package/dist/Scope.d.ts.map +1 -0
  37. package/dist/Scope.js +38 -0
  38. package/dist/Scope.js.map +1 -0
  39. package/dist/Webhooks.d.ts +79 -0
  40. package/dist/Webhooks.d.ts.map +1 -0
  41. package/dist/Webhooks.js +107 -0
  42. package/dist/Webhooks.js.map +1 -0
  43. package/dist/admin/Access.d.ts +41 -0
  44. package/dist/admin/Access.d.ts.map +1 -0
  45. package/dist/admin/Access.js +75 -0
  46. package/dist/admin/Access.js.map +1 -0
  47. package/dist/admin/App.d.ts +1221 -0
  48. package/dist/admin/App.d.ts.map +1 -0
  49. package/dist/admin/App.js +113 -0
  50. package/dist/admin/App.js.map +1 -0
  51. package/dist/admin/apps/api-keys.d.ts +209 -0
  52. package/dist/admin/apps/api-keys.d.ts.map +1 -0
  53. package/dist/admin/apps/api-keys.js +129 -0
  54. package/dist/admin/apps/api-keys.js.map +1 -0
  55. package/dist/admin/apps/scopes.d.ts +46 -0
  56. package/dist/admin/apps/scopes.d.ts.map +1 -0
  57. package/dist/admin/apps/scopes.js +41 -0
  58. package/dist/admin/apps/scopes.js.map +1 -0
  59. package/dist/admin/apps/verified-tokens.d.ts +1206 -0
  60. package/dist/admin/apps/verified-tokens.d.ts.map +1 -0
  61. package/dist/admin/apps/verified-tokens.js +485 -0
  62. package/dist/admin/apps/verified-tokens.js.map +1 -0
  63. package/dist/admin/index.d.ts +3 -0
  64. package/dist/admin/index.d.ts.map +1 -0
  65. package/dist/admin/index.js +3 -0
  66. package/dist/admin/index.js.map +1 -0
  67. package/dist/admin/ui.generated.d.ts +11 -0
  68. package/dist/admin/ui.generated.d.ts.map +1 -0
  69. package/dist/admin/ui.generated.js +43 -0
  70. package/dist/admin/ui.generated.js.map +1 -0
  71. package/dist/apps/activities.d.ts +18725 -0
  72. package/dist/apps/activities.d.ts.map +1 -0
  73. package/dist/apps/activities.js +3138 -0
  74. package/dist/apps/activities.js.map +1 -0
  75. package/dist/apps/addresses.d.ts +3662 -0
  76. package/dist/apps/addresses.d.ts.map +1 -0
  77. package/dist/apps/addresses.js +22 -0
  78. package/dist/apps/addresses.js.map +1 -0
  79. package/dist/apps/balances.d.ts +342 -0
  80. package/dist/apps/balances.d.ts.map +1 -0
  81. package/dist/apps/balances.js +393 -0
  82. package/dist/apps/balances.js.map +1 -0
  83. package/dist/apps/blocks.d.ts +931 -0
  84. package/dist/apps/blocks.d.ts.map +1 -0
  85. package/dist/apps/blocks.js +689 -0
  86. package/dist/apps/blocks.js.map +1 -0
  87. package/dist/apps/coingecko.d.ts +1053 -0
  88. package/dist/apps/coingecko.d.ts.map +1 -0
  89. package/dist/apps/coingecko.js +1015 -0
  90. package/dist/apps/coingecko.js.map +1 -0
  91. package/dist/apps/exchanges.d.ts +3000 -0
  92. package/dist/apps/exchanges.d.ts.map +1 -0
  93. package/dist/apps/exchanges.js +3570 -0
  94. package/dist/apps/exchanges.js.map +1 -0
  95. package/dist/apps/fee-amm.d.ts +640 -0
  96. package/dist/apps/fee-amm.d.ts.map +1 -0
  97. package/dist/apps/fee-amm.js +815 -0
  98. package/dist/apps/fee-amm.js.map +1 -0
  99. package/dist/apps/indexer.d.ts +116 -0
  100. package/dist/apps/indexer.d.ts.map +1 -0
  101. package/dist/apps/indexer.js +270 -0
  102. package/dist/apps/indexer.js.map +1 -0
  103. package/dist/apps/receipts.d.ts +1438 -0
  104. package/dist/apps/receipts.d.ts.map +1 -0
  105. package/dist/apps/receipts.js +874 -0
  106. package/dist/apps/receipts.js.map +1 -0
  107. package/dist/apps/rpc.d.ts +173 -0
  108. package/dist/apps/rpc.d.ts.map +1 -0
  109. package/dist/apps/rpc.js +191 -0
  110. package/dist/apps/rpc.js.map +1 -0
  111. package/dist/apps/tokenlist.d.ts +192 -0
  112. package/dist/apps/tokenlist.d.ts.map +1 -0
  113. package/dist/apps/tokenlist.js +153 -0
  114. package/dist/apps/tokenlist.js.map +1 -0
  115. package/dist/apps/tokens.d.ts +2246 -0
  116. package/dist/apps/tokens.d.ts.map +1 -0
  117. package/dist/apps/tokens.js +1789 -0
  118. package/dist/apps/tokens.js.map +1 -0
  119. package/dist/apps/transactions.d.ts +2327 -0
  120. package/dist/apps/transactions.d.ts.map +1 -0
  121. package/dist/apps/transactions.js +975 -0
  122. package/dist/apps/transactions.js.map +1 -0
  123. package/dist/apps/transfers.d.ts +589 -0
  124. package/dist/apps/transfers.d.ts.map +1 -0
  125. package/dist/apps/transfers.js +769 -0
  126. package/dist/apps/transfers.js.map +1 -0
  127. package/dist/apps/verified-tokens.d.ts +544 -0
  128. package/dist/apps/verified-tokens.d.ts.map +1 -0
  129. package/dist/apps/verified-tokens.js +234 -0
  130. package/dist/apps/verified-tokens.js.map +1 -0
  131. package/dist/apps/webhooks.d.ts +7684 -0
  132. package/dist/apps/webhooks.d.ts.map +1 -0
  133. package/dist/apps/webhooks.js +2112 -0
  134. package/dist/apps/webhooks.js.map +1 -0
  135. package/dist/cloudflare.d.ts +32 -0
  136. package/dist/cloudflare.d.ts.map +1 -0
  137. package/dist/cloudflare.js +45 -0
  138. package/dist/cloudflare.js.map +1 -0
  139. package/dist/index.d.ts +16 -0
  140. package/dist/index.d.ts.map +1 -0
  141. package/dist/index.js +16 -0
  142. package/dist/index.js.map +1 -0
  143. package/dist/internal/Auth.d.ts +298 -0
  144. package/dist/internal/Auth.d.ts.map +1 -0
  145. package/dist/internal/Auth.js +618 -0
  146. package/dist/internal/Auth.js.map +1 -0
  147. package/dist/internal/Cache.d.ts +74 -0
  148. package/dist/internal/Cache.d.ts.map +1 -0
  149. package/dist/internal/Cache.js +215 -0
  150. package/dist/internal/Cache.js.map +1 -0
  151. package/dist/internal/Cursor.d.ts +79 -0
  152. package/dist/internal/Cursor.d.ts.map +1 -0
  153. package/dist/internal/Cursor.js +116 -0
  154. package/dist/internal/Cursor.js.map +1 -0
  155. package/dist/internal/EdgeCache.d.ts +59 -0
  156. package/dist/internal/EdgeCache.d.ts.map +1 -0
  157. package/dist/internal/EdgeCache.js +174 -0
  158. package/dist/internal/EdgeCache.js.map +1 -0
  159. package/dist/internal/Log.d.ts +104 -0
  160. package/dist/internal/Log.d.ts.map +1 -0
  161. package/dist/internal/Log.js +118 -0
  162. package/dist/internal/Log.js.map +1 -0
  163. package/dist/internal/MetricSink.d.ts +65 -0
  164. package/dist/internal/MetricSink.d.ts.map +1 -0
  165. package/dist/internal/MetricSink.js +146 -0
  166. package/dist/internal/MetricSink.js.map +1 -0
  167. package/dist/internal/Mpp.d.ts +71 -0
  168. package/dist/internal/Mpp.d.ts.map +1 -0
  169. package/dist/internal/Mpp.js +105 -0
  170. package/dist/internal/Mpp.js.map +1 -0
  171. package/dist/internal/OpenApi.d.ts +313 -0
  172. package/dist/internal/OpenApi.d.ts.map +1 -0
  173. package/dist/internal/OpenApi.fonts.d.ts +2 -0
  174. package/dist/internal/OpenApi.fonts.d.ts.map +1 -0
  175. package/dist/internal/OpenApi.fonts.js +39 -0
  176. package/dist/internal/OpenApi.fonts.js.map +1 -0
  177. package/dist/internal/OpenApi.js +335 -0
  178. package/dist/internal/OpenApi.js.map +1 -0
  179. package/dist/internal/OpenApi.logo.d.ts +6 -0
  180. package/dist/internal/OpenApi.logo.d.ts.map +1 -0
  181. package/dist/internal/OpenApi.logo.js +19 -0
  182. package/dist/internal/OpenApi.logo.js.map +1 -0
  183. package/dist/internal/Path.d.ts +5 -0
  184. package/dist/internal/Path.d.ts.map +1 -0
  185. package/dist/internal/Path.js +16 -0
  186. package/dist/internal/Path.js.map +1 -0
  187. package/dist/internal/RateLimit.d.ts +60 -0
  188. package/dist/internal/RateLimit.d.ts.map +1 -0
  189. package/dist/internal/RateLimit.js +48 -0
  190. package/dist/internal/RateLimit.js.map +1 -0
  191. package/dist/internal/Response.d.ts +132 -0
  192. package/dist/internal/Response.d.ts.map +1 -0
  193. package/dist/internal/Response.js +72 -0
  194. package/dist/internal/Response.js.map +1 -0
  195. package/dist/internal/Schema.d.ts +257 -0
  196. package/dist/internal/Schema.d.ts.map +1 -0
  197. package/dist/internal/Schema.js +360 -0
  198. package/dist/internal/Schema.js.map +1 -0
  199. package/dist/internal/Store.d.ts +204 -0
  200. package/dist/internal/Store.d.ts.map +1 -0
  201. package/dist/internal/Store.js +291 -0
  202. package/dist/internal/Store.js.map +1 -0
  203. package/dist/internal/Tidx.d.ts +120 -0
  204. package/dist/internal/Tidx.d.ts.map +1 -0
  205. package/dist/internal/Tidx.js +156 -0
  206. package/dist/internal/Tidx.js.map +1 -0
  207. package/dist/internal/Timing.d.ts +22 -0
  208. package/dist/internal/Timing.d.ts.map +1 -0
  209. package/dist/internal/Timing.js +32 -0
  210. package/dist/internal/Timing.js.map +1 -0
  211. package/dist/internal/Ttl.d.ts +25 -0
  212. package/dist/internal/Ttl.d.ts.map +1 -0
  213. package/dist/internal/Ttl.js +49 -0
  214. package/dist/internal/Ttl.js.map +1 -0
  215. package/dist/internal/Value.d.ts +47 -0
  216. package/dist/internal/Value.d.ts.map +1 -0
  217. package/dist/internal/Value.js +122 -0
  218. package/dist/internal/Value.js.map +1 -0
  219. package/dist/internal/VerifiedTokens.d.ts +228 -0
  220. package/dist/internal/VerifiedTokens.d.ts.map +1 -0
  221. package/dist/internal/VerifiedTokens.js +450 -0
  222. package/dist/internal/VerifiedTokens.js.map +1 -0
  223. package/dist/internal/Viem.d.ts +2082 -0
  224. package/dist/internal/Viem.d.ts.map +1 -0
  225. package/dist/internal/Viem.js +63 -0
  226. package/dist/internal/Viem.js.map +1 -0
  227. package/dist/internal/WebhookDestination.d.ts +198 -0
  228. package/dist/internal/WebhookDestination.d.ts.map +1 -0
  229. package/dist/internal/WebhookDestination.js +170 -0
  230. package/dist/internal/WebhookDestination.js.map +1 -0
  231. package/dist/internal/Webhooks.d.ts +433 -0
  232. package/dist/internal/Webhooks.d.ts.map +1 -0
  233. package/dist/internal/Webhooks.js +489 -0
  234. package/dist/internal/Webhooks.js.map +1 -0
  235. package/dist/internal/webhookDestinations/betterStack.d.ts +26 -0
  236. package/dist/internal/webhookDestinations/betterStack.d.ts.map +1 -0
  237. package/dist/internal/webhookDestinations/betterStack.js +76 -0
  238. package/dist/internal/webhookDestinations/betterStack.js.map +1 -0
  239. package/dist/internal/webhookDestinations/slack.d.ts +59 -0
  240. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -0
  241. package/dist/internal/webhookDestinations/slack.js +422 -0
  242. package/dist/internal/webhookDestinations/slack.js.map +1 -0
  243. package/dist/internal/webhookDestinations/url.d.ts +17 -0
  244. package/dist/internal/webhookDestinations/url.d.ts.map +1 -0
  245. package/dist/internal/webhookDestinations/url.js +130 -0
  246. package/dist/internal/webhookDestinations/url.js.map +1 -0
  247. package/dist/openrpc.json +5302 -0
  248. package/package.json +46 -4
  249. package/seeds/31318/icons/0x20c0000000000000000000000000000000000000.svg +1 -0
  250. package/seeds/31318/icons/0x20c0000000000000000000000000000000000001.svg +1 -0
  251. package/seeds/31318/icons/0x20c0000000000000000000000000000000000002.svg +1 -0
  252. package/seeds/31318/icons/0x20c0000000000000000000000000000000000003.svg +1 -0
  253. package/seeds/31318/verified-tokens.json +30 -0
  254. package/seeds/4217/icons/0x20c0000000000000000000000000000000000000.svg +25 -0
  255. package/seeds/4217/icons/0x20c000000000000000000000048c8f36df1c9a4a.svg +1 -0
  256. package/seeds/4217/icons/0x20c0000000000000000000000520792dcccccccc.svg +1 -0
  257. package/seeds/4217/icons/0x20c0000000000000000000000a6da882d075a4c3.svg +4 -0
  258. package/seeds/4217/icons/0x20c000000000000000000000111111111e910f0f.svg +30 -0
  259. package/seeds/4217/icons/0x20c00000000000000000000014f22ca97301eb73.svg +1 -0
  260. package/seeds/4217/icons/0x20c0000000000000000000001621e21f71cf12fb.svg +1 -0
  261. package/seeds/4217/icons/0x20c0000000000000000000002f52d5cc21a3207b.svg +1 -0
  262. package/seeds/4217/icons/0x20c0000000000000000000003158081efd85bfc2.svg +11 -0
  263. package/seeds/4217/icons/0x20c0000000000000000000003554d28269e0f3c2.svg +1 -0
  264. package/seeds/4217/icons/0x20c000000000000000000000383a23bacb546ab9.svg +1 -0
  265. package/seeds/4217/icons/0x20c00000000000000000000042109aef2f8b28e1.png +0 -0
  266. package/seeds/4217/icons/0x20c0000000000000000000005c0bac7cef389a11.svg +1 -0
  267. package/seeds/4217/icons/0x20c0000000000000000000006fd9a167923ba194.png +0 -0
  268. package/seeds/4217/icons/0x20c0000000000000000000007f7ba549dd0251b9.svg +1 -0
  269. package/seeds/4217/icons/0x20c0000000000000000000008191667423f70e67.svg +5 -0
  270. package/seeds/4217/icons/0x20c0000000000000000000008ee4fcff88888888.svg +1 -0
  271. package/seeds/4217/icons/0x20c0000000000000000000009a4a4b17e0dc6651.svg +1 -0
  272. package/seeds/4217/icons/0x20c000000000000000000000ab02d39df30bd17e.svg +1 -0
  273. package/seeds/4217/icons/0x20c000000000000000000000ae247a1130450f09.svg +1 -0
  274. package/seeds/4217/icons/0x20c000000000000000000000aeed2ec36a54d0e5.svg +1 -0
  275. package/seeds/4217/icons/0x20c000000000000000000000b9537d11c60e8b50.svg +1 -0
  276. package/seeds/4217/icons/0x20c000000000000000000000bd95bfb69fbe6ce3.svg +1 -0
  277. package/seeds/4217/icons/0x20c000000000000000000000c412ec89d0c08be5.svg +1 -0
  278. package/seeds/4217/icons/0x20c000000000000000000000f047dd7018e50367.png +0 -0
  279. package/seeds/4217/verified-tokens.json +177 -0
  280. package/seeds/42431/icons/0x20c0000000000000000000000000000000000000.svg +25 -0
  281. package/seeds/42431/icons/0x20c0000000000000000000000000000000000001.svg +1 -0
  282. package/seeds/42431/icons/0x20c0000000000000000000000000000000000002.svg +1 -0
  283. package/seeds/42431/icons/0x20c0000000000000000000000000000000000003.svg +1 -0
  284. package/seeds/42431/icons/0x20c0000000000000000000009e8d7eb59b783726.svg +1 -0
  285. package/seeds/42431/icons/0x20c000000000000000000000d72572838bbee59c.svg +1 -0
  286. package/seeds/42431/verified-tokens.json +44 -0
  287. package/seeds/openrpc/README.md +27 -0
  288. package/seeds/openrpc/execution-apis.json +8989 -0
  289. package/src/ApiKey.test.ts +91 -0
  290. package/src/ApiKey.ts +122 -0
  291. package/src/ApiKeySource.test-d.ts +11 -0
  292. package/src/ApiKeySource.test.ts +295 -0
  293. package/src/ApiKeySource.ts +303 -0
  294. package/src/App.test-d.ts +38 -0
  295. package/src/App.test.ts +65927 -0
  296. package/src/App.ts +855 -0
  297. package/src/Assets.ts +58 -0
  298. package/src/Auth.ts +1 -0
  299. package/src/Cli.test.ts +81 -0
  300. package/src/Cli.ts +38 -0
  301. package/src/Client.test-d.ts +1438 -0
  302. package/src/Client.test.ts +134 -0
  303. package/src/Client.ts +45 -0
  304. package/src/Metrics.ts +154 -0
  305. package/src/Scope.ts +50 -0
  306. package/src/Webhooks.test.ts +49 -0
  307. package/src/Webhooks.ts +172 -0
  308. package/src/admin/Access.test.ts +130 -0
  309. package/src/admin/Access.ts +87 -0
  310. package/src/admin/App.test.ts +225 -0
  311. package/src/admin/App.ts +216 -0
  312. package/src/admin/apps/api-keys.test.ts +156 -0
  313. package/src/admin/apps/api-keys.ts +157 -0
  314. package/src/admin/apps/scopes.test.ts +52 -0
  315. package/src/admin/apps/scopes.ts +47 -0
  316. package/src/admin/apps/verified-tokens.test.ts +415 -0
  317. package/src/admin/apps/verified-tokens.ts +566 -0
  318. package/src/admin/index.ts +2 -0
  319. package/src/admin/ui/plugin.ts +135 -0
  320. package/src/admin/ui/src/components/Checkbox.tsx +22 -0
  321. package/src/admin/ui/src/components/Dialog.tsx +32 -0
  322. package/src/admin/ui/src/components/MobileProfile.tsx +31 -0
  323. package/src/admin/ui/src/components/Page.tsx +53 -0
  324. package/src/admin/ui/src/components/TempoLogo.tsx +37 -0
  325. package/src/admin/ui/src/fonts/Pilat-Demi.woff2 +0 -0
  326. package/src/admin/ui/src/fonts/Pilat-Regular.woff2 +0 -0
  327. package/src/admin/ui/src/lib/api-keys.ts +63 -0
  328. package/src/admin/ui/src/lib/client.ts +15 -0
  329. package/src/admin/ui/src/lib/config.ts +57 -0
  330. package/src/admin/ui/src/lib/query-client.ts +26 -0
  331. package/src/admin/ui/src/lib/scopes.ts +25 -0
  332. package/src/admin/ui/src/lib/verified-tokens.ts +89 -0
  333. package/src/admin/ui/src/lib/wagmi.ts +18 -0
  334. package/src/admin/ui/src/routeTree.gen.ts +104 -0
  335. package/src/admin/ui/src/router.tsx +25 -0
  336. package/src/admin/ui/src/routes/__root.tsx +219 -0
  337. package/src/admin/ui/src/routes/api-keys.tsx +329 -0
  338. package/src/admin/ui/src/routes/index.tsx +7 -0
  339. package/src/admin/ui/src/routes/verified-tokens.tsx +331 -0
  340. package/src/admin/ui/src/styles.css +20 -0
  341. package/src/admin/ui/tsconfig.json +16 -0
  342. package/src/admin/ui/vite.config.ts +29 -0
  343. package/src/admin/ui.generated.ts +60 -0
  344. package/src/apps/activities.test.ts +1020 -0
  345. package/src/apps/activities.ts +3934 -0
  346. package/src/apps/addresses.ts +24 -0
  347. package/src/apps/balances.test.ts +274 -0
  348. package/src/apps/balances.ts +533 -0
  349. package/src/apps/blocks.test.ts +385 -0
  350. package/src/apps/blocks.ts +896 -0
  351. package/src/apps/coingecko.test.ts +218 -0
  352. package/src/apps/coingecko.ts +1383 -0
  353. package/src/apps/exchanges.test.ts +958 -0
  354. package/src/apps/exchanges.ts +4773 -0
  355. package/src/apps/fee-amm.test.ts +321 -0
  356. package/src/apps/fee-amm.ts +1121 -0
  357. package/src/apps/indexer.test.ts +153 -0
  358. package/src/apps/indexer.ts +330 -0
  359. package/src/apps/receipts.test.ts +285 -0
  360. package/src/apps/receipts.ts +1193 -0
  361. package/src/apps/rpc.test.ts +302 -0
  362. package/src/apps/rpc.ts +222 -0
  363. package/src/apps/tokenlist.test.ts +80 -0
  364. package/src/apps/tokenlist.ts +207 -0
  365. package/src/apps/tokens.test.ts +1062 -0
  366. package/src/apps/tokens.ts +2292 -0
  367. package/src/apps/transactions.test.ts +408 -0
  368. package/src/apps/transactions.ts +1363 -0
  369. package/src/apps/transfers.test.ts +371 -0
  370. package/src/apps/transfers.ts +1116 -0
  371. package/src/apps/verified-tokens.test.ts +114 -0
  372. package/src/apps/verified-tokens.ts +295 -0
  373. package/src/apps/webhooks.test.ts +1937 -0
  374. package/src/apps/webhooks.ts +2926 -0
  375. package/src/cloudflare.ts +55 -0
  376. package/src/index.ts +15 -0
  377. package/src/internal/Auth.test.ts +980 -0
  378. package/src/internal/Auth.ts +1012 -0
  379. package/src/internal/Cache.test.ts +240 -0
  380. package/src/internal/Cache.ts +262 -0
  381. package/src/internal/Cursor.test.ts +100 -0
  382. package/src/internal/Cursor.ts +149 -0
  383. package/src/internal/EdgeCache.test.ts +234 -0
  384. package/src/internal/EdgeCache.ts +224 -0
  385. package/src/internal/Errors.ts +14 -0
  386. package/src/internal/Log.test.ts +244 -0
  387. package/src/internal/Log.ts +216 -0
  388. package/src/internal/MetricSink.ts +220 -0
  389. package/src/internal/Mpp.test.ts +64 -0
  390. package/src/internal/Mpp.ts +141 -0
  391. package/src/internal/OpenApi.fonts.ts +38 -0
  392. package/src/internal/OpenApi.logo.ts +18 -0
  393. package/src/internal/OpenApi.ts +488 -0
  394. package/src/internal/Path.test.ts +14 -0
  395. package/src/internal/Path.ts +15 -0
  396. package/src/internal/RateLimit.test.ts +93 -0
  397. package/src/internal/RateLimit.ts +93 -0
  398. package/src/internal/Response.ts +131 -0
  399. package/src/internal/Schema.test.ts +34 -0
  400. package/src/internal/Schema.ts +523 -0
  401. package/src/internal/Store.test.ts +545 -0
  402. package/src/internal/Store.ts +526 -0
  403. package/src/internal/Tidx.local.test.ts +33 -0
  404. package/src/internal/Tidx.test.ts +294 -0
  405. package/src/internal/Tidx.ts +238 -0
  406. package/src/internal/Timing.test.ts +22 -0
  407. package/src/internal/Timing.ts +62 -0
  408. package/src/internal/Ttl.test.ts +18 -0
  409. package/src/internal/Ttl.ts +59 -0
  410. package/src/internal/Value.ts +114 -0
  411. package/src/internal/VerifiedTokens.test.ts +333 -0
  412. package/src/internal/VerifiedTokens.ts +645 -0
  413. package/src/internal/Viem.test.ts +115 -0
  414. package/src/internal/Viem.ts +165 -0
  415. package/src/internal/WebhookDestination.test.ts +648 -0
  416. package/src/internal/WebhookDestination.ts +331 -0
  417. package/src/internal/Webhooks.test.ts +668 -0
  418. package/src/internal/Webhooks.ts +940 -0
  419. package/src/internal/webhookDestinations/betterStack.ts +91 -0
  420. package/src/internal/webhookDestinations/slack.ts +496 -0
  421. package/src/internal/webhookDestinations/url.ts +128 -0
  422. package/src/openrpc.json +5302 -0
@@ -0,0 +1,975 @@
1
+ import { Hono } from 'hono';
2
+ import { Hex } from 'ox';
3
+ import * as z from 'zod/mini';
4
+ import * as Auth from '../internal/Auth.js';
5
+ import * as Cache from '../internal/Cache.js';
6
+ import * as Cursor from '../internal/Cursor.js';
7
+ import * as OpenApi from '../internal/OpenApi.js';
8
+ import * as Response from '../internal/Response.js';
9
+ import * as Schema from '../internal/Schema.js';
10
+ import * as Store from '../internal/Store.js';
11
+ import * as Timing from '../internal/Timing.js';
12
+ import * as Ttl from '../internal/Ttl.js';
13
+ import * as Value from '../internal/Value.js';
14
+ import * as VerifiedTokens from '../internal/VerifiedTokens.js';
15
+ import * as Receipts from './receipts.js';
16
+ import * as Tokens from './tokens.js';
17
+ /** Example transaction hash surfaced in OpenAPI docs. */
18
+ const exampleHash = '0x515801d7f9a5ac705e793e85904c9c69b3f1694b465cc8fb6ba3f0298dc82665';
19
+ /**
20
+ * Maps a transaction `type` byte (as a number) to its human-readable name. The
21
+ * raw `0x…` byte is always preserved under `rpc.type`.
22
+ */
23
+ const transactionTypeByNumber = {
24
+ 0: 'legacy',
25
+ 1: 'eip2930',
26
+ 2: 'eip1559',
27
+ 3: 'eip4844',
28
+ 4: 'eip7702',
29
+ 118: 'tempo',
30
+ };
31
+ /** Decodes a transaction `type` (hex string or number) into its name. */
32
+ export function decodeTransactionType(value) {
33
+ const byte = typeof value === 'number' ? value : Value.hexToNumber(value);
34
+ return (byte !== undefined && transactionTypeByNumber[byte]) || 'unknown';
35
+ }
36
+ /** Zod schemas owned by the transaction handlers. */
37
+ export var schema;
38
+ (function (schema) {
39
+ // TODO(ox/zod): replace with the zod schema for `ox`'s `AccessList.Item` once
40
+ // ox ships a `zod` entrypoint.
41
+ /** One EIP-2930 access list entry (RPC format). */
42
+ schema.AccessListItem = z
43
+ .looseObject({
44
+ address: Schema.Address.check(z.describe('The account whose storage slots are listed in this access-list entry.')),
45
+ storageKeys: z
46
+ .array(Schema.Hash)
47
+ .check(z.describe('The storage slot keys the transaction plans to access.')),
48
+ })
49
+ .check(z.describe('One EIP-2930 access-list entry that predeclares an account and storage slots.'));
50
+ // TODO(ox/zod): replace with the zod schema for the RPC `Call` in `ox/tempo`'s
51
+ // `TxEnvelopeTempo`/`Transaction` types once ox ships a `zod` entrypoint.
52
+ /** One call within a Tempo account-abstraction transaction (RPC format). */
53
+ schema.Call = z
54
+ .looseObject({
55
+ data: z
56
+ .nullish(Schema.Hex)
57
+ .check(z.describe('Call data for this call; this is the same bytes as `input` when both are present.'), z.meta({ examples: ['0xdeadbeef'] })),
58
+ input: z
59
+ .nullish(Schema.Hex)
60
+ .check(z.describe('Call data sent to the contract, as `0x`-prefixed bytes.'), z.meta({ examples: ['0xdeadbeef'] })),
61
+ to: z
62
+ .nullish(Schema.Address)
63
+ .check(z.describe('The address this call targets, or `null` when the call creates a contract.')),
64
+ value: z
65
+ .nullish(Schema.Quantity)
66
+ .check(z.describe('Native value sent with this call, as a hex quantity.')),
67
+ })
68
+ .check(z.describe('One operation inside a Tempo account-abstraction transaction.'));
69
+ // TODO(ox/zod): replace with the zod schema for `ox/tempo`'s
70
+ // `SignatureEnvelope.Rpc` (the secp256k1 / p256 / webAuthn / keychain union)
71
+ // once ox ships a `zod` entrypoint.
72
+ /**
73
+ * A signature envelope (RPC format), passed through verbatim. Every field is
74
+ * optional because the envelope is a union (secp256k1 / p256 / webAuthn /
75
+ * keychain) whose shape — including whether a `type` discriminator is present —
76
+ * varies; the loose object preserves whatever the RPC returns.
77
+ */
78
+ schema.SignatureEnvelope = z
79
+ .looseObject({
80
+ type: z
81
+ .optional(z.string())
82
+ .check(z.describe('The signature scheme used by this envelope, such as `secp256k1`, `p256`, or `keychain` when the RPC includes it.'), z.meta({ examples: ['secp256k1'] })),
83
+ })
84
+ .check(z.describe('The signature envelope exactly as returned by JSON-RPC.'));
85
+ /** The verbatim JSON-RPC payloads, surfaced under each resource's `rpc` field. */
86
+ let Rpc;
87
+ (function (Rpc) {
88
+ // TODO(ox/zod): replace with the zod schema for `ox/tempo`'s
89
+ // `Transaction.Rpc` union once ox ships a `zod` entrypoint.
90
+ /** A JSON-RPC transaction, passed through verbatim. */
91
+ Rpc.Transaction = z
92
+ .looseObject({
93
+ aaAuthorizationList: z
94
+ .optional(z.array(z.looseObject({})))
95
+ .check(z.describe('Tempo account-abstraction authorizations attached to the transaction.')),
96
+ accessList: z
97
+ .optional(z.array(schema.AccessListItem))
98
+ .check(z.describe('EIP-2930 access list that predeclares accounts and storage slots for the transaction.')),
99
+ authorizationList: z
100
+ .optional(z.array(z.looseObject({})))
101
+ .check(z.describe('EIP-7702 authorizations attached to the transaction.')),
102
+ blobVersionedHashes: z
103
+ .optional(z.array(Schema.Hash))
104
+ .check(z.describe('Versioned blob hashes for EIP-4844 blob data.')),
105
+ blockHash: z
106
+ .nullable(Schema.Hash)
107
+ .check(z.describe('The block hash once included, or `null` while the transaction is pending.')),
108
+ blockNumber: z
109
+ .nullable(Schema.Quantity)
110
+ .check(z.describe('The block number once included, or `null` while the transaction is pending.')),
111
+ blockTimestamp: z
112
+ .nullish(Schema.Quantity)
113
+ .check(z.describe('The block timestamp for the block that included this transaction.')),
114
+ calls: z
115
+ .optional(z.union([
116
+ z.array(schema.Call).check(z.meta({
117
+ examples: [[{ data: '0xdeadbeef', input: '0xdeadbeef', to: null, value: '0x0' }]],
118
+ })),
119
+ z.null().check(z.meta({ examples: [null] })),
120
+ ]))
121
+ .check(z.describe('Decoded calls for Tempo account-abstraction transactions.'), z.meta({
122
+ examples: [[{ data: '0xdeadbeef', input: '0xdeadbeef', to: null, value: '0x0' }]],
123
+ })),
124
+ chainId: z
125
+ .optional(Schema.Quantity)
126
+ .check(z.describe('The chain ID that the transaction is valid on; legacy transactions may omit it.')),
127
+ feePayerSignature: z
128
+ .nullish(schema.SignatureEnvelope)
129
+ .check(z.describe('Signature from the account that paid the transaction fee.'), z.meta({ examples: [{ type: 'secp256k1' }] })),
130
+ feeToken: z
131
+ .nullish(Schema.Address)
132
+ .check(z.describe('The fee token requested by the transaction; Tempo fees are paid in USD stablecoins such as `pathUSD`.')),
133
+ from: Schema.Address.check(z.describe('The address that submitted or authorized the transaction.')),
134
+ gas: Schema.Quantity.check(z.describe('Maximum gas the transaction is allowed to use.')),
135
+ gasPrice: z
136
+ .optional(Schema.Quantity)
137
+ .check(z.describe('Gas price for legacy-style transactions, expressed as a decimal string when humanized.')),
138
+ hash: Schema.Hash.check(z.describe('A 32-byte hash, `0x`-prefixed and returned in lowercase, that identifies this transaction.')),
139
+ input: z
140
+ .optional(Schema.Hex)
141
+ .check(z.describe('Call data for non-Tempo transaction formats, as `0x`-prefixed bytes.'), z.meta({ examples: ['0xdeadbeef'] })),
142
+ keyAuthorization: z
143
+ .nullish(z.looseObject({}))
144
+ .check(z.describe('Key authorization data attached to this Tempo transaction.'), z.meta({ examples: [{}] })),
145
+ maxFeePerBlobGas: z
146
+ .optional(Schema.Quantity)
147
+ .check(z.describe('Maximum fee per blob gas for EIP-4844 blob data.')),
148
+ maxFeePerGas: z
149
+ .optional(Schema.Quantity)
150
+ .check(z.describe('Maximum total fee per gas the sender is willing to pay.')),
151
+ maxPriorityFeePerGas: z
152
+ .optional(Schema.Quantity)
153
+ .check(z.describe('Maximum priority fee per gas for EIP-1559-style transactions.')),
154
+ nonce: Schema.Quantity.check(z.describe('Nonce from the sender account that orders and de-duplicates transactions.')),
155
+ nonceKey: z
156
+ .optional(Schema.Quantity)
157
+ .check(z.describe('Tempo two-dimensional nonce key used to group nonce sequences.')),
158
+ r: z
159
+ .optional(Schema.Quantity)
160
+ .check(z.describe('The `r` value from the transaction ECDSA signature.')),
161
+ s: z
162
+ .optional(Schema.Quantity)
163
+ .check(z.describe('The `s` value from the transaction ECDSA signature.')),
164
+ signature: z
165
+ .optional(schema.SignatureEnvelope)
166
+ .check(z.describe('Signature from the sender authorizing this transaction.')),
167
+ to: z
168
+ .nullish(Schema.Address)
169
+ .check(z.describe('The recipient address, or `null` when the transaction creates a contract.')),
170
+ transactionIndex: z
171
+ .nullable(Schema.Quantity)
172
+ .check(z.describe('The transaction position within its block, or `null` while pending.')),
173
+ type: Schema.Hex.check(z.describe('Raw transaction type byte, such as `0x2` for EIP-1559 or `0x76` for Tempo.'), z.meta({ examples: ['0x2'] })),
174
+ v: z
175
+ .optional(Schema.Quantity)
176
+ .check(z.describe('The `v` recovery value from the transaction ECDSA signature.')),
177
+ validAfter: z
178
+ .nullish(Schema.Quantity)
179
+ .check(z.describe('Earliest Unix timestamp when this Tempo transaction may be included.'), z.meta({ examples: ['0x0'] })),
180
+ validBefore: z
181
+ .nullish(Schema.Quantity)
182
+ .check(z.describe('Latest Unix timestamp when this Tempo transaction may be included.'), z.meta({ examples: ['0xffffffff'] })),
183
+ value: z
184
+ .optional(Schema.Quantity)
185
+ .check(z.describe('Native value sent by non-Tempo transaction formats.')),
186
+ yParity: z
187
+ .optional(Schema.Quantity)
188
+ .check(z.describe('The y-parity value from the transaction signature.')),
189
+ })
190
+ .check(z.describe('The transaction exactly as returned by JSON-RPC.'));
191
+ })(Rpc = schema.Rpc || (schema.Rpc = {}));
192
+ /**
193
+ * Metadata for a transaction: the verbatim JSON-RPC transaction (always
194
+ * present) plus resources embedded on demand via `include`.
195
+ *
196
+ * The `feeToken` and `receipt` schemas are wrapped in `z.lazy` because
197
+ * `tokens.ts`/`receipts.ts` and `transactions.ts` mutually reference each
198
+ * other's schemas; deferring these lookups avoids the import-cycle crash
199
+ * during module init.
200
+ */
201
+ schema.TransactionMeta = z
202
+ .object({
203
+ feeToken: z
204
+ .optional(z.lazy(() => Tokens.schema.getToken.Response))
205
+ .check(z.describe('Fee-token details included only when you request `include=feeToken`.')),
206
+ receipt: z
207
+ .optional(z.lazy(() => Receipts.schema.Receipt))
208
+ .check(z.describe('The transaction outcome included only when you request `include=receipt`.')),
209
+ rpc: Rpc.Transaction.check(z.describe('The original JSON-RPC transaction payload.')),
210
+ })
211
+ .check(z.describe('Metadata for this transaction: the original JSON-RPC payload plus any requested `include` resources.'));
212
+ /** Decoded transaction `type`; the raw `0x…` byte stays under `rpc.type`. */
213
+ schema.TransactionType = z
214
+ .enum(['legacy', 'eip2930', 'eip1559', 'eip4844', 'eip7702', 'tempo', 'unknown'])
215
+ .check(z.describe('Human-readable transaction type decoded from the raw JSON-RPC `type` byte.'), z.meta({ examples: ['eip1559'] }));
216
+ /** One humanized call within a Tempo account-abstraction transaction. */
217
+ schema.HumanCall = z
218
+ .object({
219
+ data: z
220
+ .optional(Schema.Hex)
221
+ .check(z.describe('Call data sent to the contract, as `0x`-prefixed bytes.'), z.meta({ examples: ['0xdeadbeef'] })),
222
+ to: z
223
+ .nullable(Schema.Address)
224
+ .check(z.describe('The address this call targets, or `null` when it creates a contract.')),
225
+ })
226
+ .check(z.describe('One decoded call inside a Tempo account-abstraction transaction.'));
227
+ /**
228
+ * A humanized transaction: decoded `type`, decimal-string amounts, ISO 8601
229
+ * timestamps, and plain-number block fields. The verbatim JSON-RPC transaction
230
+ * is always available under `meta.rpc`.
231
+ */
232
+ schema.Transaction = z
233
+ .object({
234
+ blockHash: z
235
+ .nullable(Schema.Hash)
236
+ .check(z.describe('The block hash once included, or `null` while the transaction is pending.')),
237
+ blockNumber: z
238
+ .nullable(z.number().check(z.int(), z.nonnegative()))
239
+ .check(z.describe('The block number once included, or `null` while the transaction is pending.'), z.meta({ examples: [23456789] })),
240
+ calls: z
241
+ .optional(z.array(schema.HumanCall))
242
+ .check(z.describe('Decoded calls for Tempo account-abstraction transactions.'), z.meta({ examples: [[{ data: '0xdeadbeef', to: null }]] })),
243
+ chainId: z
244
+ .optional(z.number().check(z.int(), z.nonnegative()))
245
+ .check(z.describe('The chain ID that this transaction belongs to.'), z.meta({ examples: [4217] })),
246
+ feeToken: z
247
+ .optional(Schema.Address)
248
+ .check(z.describe('The fee token requested by the transaction; Tempo fees are paid in USD stablecoins such as `pathUSD`.')),
249
+ gas: z
250
+ .number()
251
+ .check(z.int(), z.nonnegative(), z.describe('Maximum gas the transaction is allowed to use.'), z.meta({ examples: [21000] })),
252
+ gasPrice: z
253
+ .optional(Schema.DecimalString)
254
+ .check(z.describe('Gas price for legacy-style transactions, expressed as a decimal string when humanized.')),
255
+ hash: Schema.Hash.check(z.describe('A 32-byte hash, `0x`-prefixed and returned in lowercase, that identifies this transaction.')),
256
+ id: Schema.Hash.check(z.describe('Stable resource ID for this API response; it is the transaction hash.')),
257
+ input: z
258
+ .optional(Schema.Hex)
259
+ .check(z.describe('Call data for non-Tempo transaction formats, as `0x`-prefixed bytes.'), z.meta({ examples: ['0xdeadbeef'] })),
260
+ maxFeePerGas: z
261
+ .optional(Schema.DecimalString)
262
+ .check(z.describe('Maximum total fee per gas the sender is willing to pay.')),
263
+ maxPriorityFeePerGas: z
264
+ .optional(Schema.DecimalString)
265
+ .check(z.describe('Maximum priority fee per gas for EIP-1559-style transactions.')),
266
+ meta: schema.TransactionMeta.check(z.describe('The original JSON-RPC payload plus any resources requested with `include`.')),
267
+ nonce: z
268
+ .number()
269
+ .check(z.int(), z.nonnegative(), z.describe('Nonce from the sender account that orders and de-duplicates transactions.'), z.meta({ examples: [0] })),
270
+ nonceKey: z
271
+ .optional(Schema.Hex)
272
+ .check(z.describe('Tempo two-dimensional nonce key used by Tempo transactions.'), z.meta({ examples: ['0x0'] })),
273
+ recipient: z
274
+ .nullable(Schema.Address)
275
+ .check(z.describe('The recipient address, or `null` when the transaction creates a contract.')),
276
+ sender: Schema.Address.check(z.describe('The address that submitted or authorized the transaction.')),
277
+ timestamp: z
278
+ .nullable(z.iso.datetime())
279
+ .check(z.describe('The block timestamp as ISO 8601, or `null` while the transaction is pending.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })),
280
+ transactionIndex: z
281
+ .nullable(z.number().check(z.int(), z.nonnegative()))
282
+ .check(z.describe('The transaction position within its block, or `null` while pending.'), z.meta({ examples: [0] })),
283
+ type: schema.TransactionType,
284
+ validAfter: z
285
+ .nullish(z.iso.datetime())
286
+ .check(z.describe('Earliest ISO 8601 time when this Tempo transaction may be included.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })),
287
+ validBefore: z
288
+ .nullish(z.iso.datetime())
289
+ .check(z.describe('Latest ISO 8601 time when this Tempo transaction may be included.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })),
290
+ value: Schema.DecimalString.check(z.describe('Native value transferred by this transaction, as a decimal string.')),
291
+ })
292
+ .check(z.describe('A transaction formatted for API clients, with decoded fields and the original JSON-RPC payload under `meta.rpc`.'));
293
+ /** Schemas for the getTransaction operation. */
294
+ let getTransaction;
295
+ (function (getTransaction) {
296
+ /** Path parameters for transaction requests. */
297
+ getTransaction.Params = z
298
+ .object({
299
+ transactionHash: Schema.Hash.check(z.describe('A 32-byte hash, `0x`-prefixed and returned in lowercase, that identifies this transaction.'), z.meta({ examples: [exampleHash] })),
300
+ })
301
+ .check(z.describe('Path parameters used to look up a transaction.'));
302
+ /** Optional related resource that callers opt into via `include`. */
303
+ getTransaction.Include = z
304
+ .enum(['feeToken', 'receipt'])
305
+ .check(z.describe('Related resource you can opt into with the `include` query parameter.'));
306
+ /**
307
+ * Parses a comma-separated `include` query value into a list of optional
308
+ * resources to embed. Extra lookups (e.g. fee-token metadata, the receipt)
309
+ * only run when explicitly requested, keeping the base transaction response
310
+ * fast.
311
+ */
312
+ getTransaction.includeQuery = Schema.includeQuery(getTransaction.Include, 'Comma-separated related resources to include, such as `feeToken,receipt`.');
313
+ /** Query parameters for transaction requests. */
314
+ getTransaction.Query = z
315
+ .strictObject({
316
+ chainId: Schema.ChainIdQuery,
317
+ include: getTransaction.includeQuery,
318
+ })
319
+ .check(z.describe('Query parameters for looking up a transaction.'));
320
+ /** A humanized transaction, with the verbatim JSON-RPC payload under `rpc`. */
321
+ getTransaction.Response = schema.Transaction;
322
+ })(getTransaction = schema.getTransaction || (schema.getTransaction = {}));
323
+ /** Schemas for the getTransactions (list) operation. */
324
+ let getTransactions;
325
+ (function (getTransactions) {
326
+ /**
327
+ * Optional resources for the transaction list: the per-row `feeToken` /
328
+ * `receipt` embeds plus the response-wide capped `totalCount`. The detail
329
+ * route keeps its own {@link getTransaction.Include}.
330
+ */
331
+ getTransactions.Include = z
332
+ .enum(['feeToken', 'receipt', 'totalCount'])
333
+ .check(z.describe('Related resources to include in each transaction row or in response metadata.'));
334
+ /** Parses the comma-separated `include` value for the transaction list. */
335
+ getTransactions.includeQuery = Schema.includeQuery(getTransactions.Include, 'Comma-separated related resources to include, such as `feeToken,receipt,totalCount`.');
336
+ /** Query parameters for transaction list requests. */
337
+ getTransactions.Query = z
338
+ .strictObject({
339
+ address: z
340
+ .optional(Schema.Address)
341
+ .check(z.describe('Filter to transactions where this address is either the sender or recipient.')),
342
+ 'blockNumber.from': Schema.blockNumberBound('transactions', 'from'),
343
+ 'blockNumber.to': Schema.blockNumberBound('transactions', 'to'),
344
+ chainId: Schema.ChainIdQuery,
345
+ cursor: Schema.Cursor,
346
+ feePayer: z
347
+ .optional(Schema.Address)
348
+ .check(z.describe('Filter to transactions whose fee payer is this address.')),
349
+ feeToken: z
350
+ .optional(Schema.TokenAddress)
351
+ .check(z.describe('Filter to transactions whose fee was paid in this token address.')),
352
+ include: getTransactions.includeQuery,
353
+ limit: Schema.Limit,
354
+ order: Schema.Order,
355
+ page: Schema.Page,
356
+ recipient: z
357
+ .optional(Schema.Address)
358
+ .check(z.describe('Filter to transactions sent to this recipient address.')),
359
+ sender: z
360
+ .optional(Schema.Address)
361
+ .check(z.describe('Filter to transactions sent by this sender address.')),
362
+ status: z
363
+ .optional(z.enum(['success', 'reverted']))
364
+ .check(z.describe('Filter to transactions whose receipt shows this execution status.'), z.meta({ examples: ['success'] })),
365
+ 'timestamp.from': Schema.timestampBound('transactions', 'from'),
366
+ 'timestamp.to': Schema.timestampBound('transactions', 'to'),
367
+ })
368
+ .check(...Schema.pageChecks(), z.describe('Query parameters for listing transactions.'));
369
+ /**
370
+ * Page of transactions. Each item reuses the humanized transaction returned
371
+ * by `GET /transactions/:transactionHash`, so the list and detail endpoints
372
+ * expose one identical shape. Indexed list rows omit fields the indexer does
373
+ * not store (signatures, access list), reflected in their `rpc` payload.
374
+ */
375
+ getTransactions.Response = z
376
+ .object({
377
+ data: z.array(getTransaction.Response).check(z.describe('Transactions on this page.')),
378
+ meta: z
379
+ .optional(Schema.CountMeta)
380
+ .check(z.describe('Response-level metadata requested with `include`, such as `totalCount`.')),
381
+ nextCursor: Schema.NextCursor,
382
+ })
383
+ .check(z.describe('A page of transactions ordered by block number and transaction position.'));
384
+ })(getTransactions = schema.getTransactions || (schema.getTransactions = {}));
385
+ })(schema || (schema = {}));
386
+ /** Creates transaction handlers. */
387
+ export function transactions() {
388
+ return new Hono()
389
+ .get('/', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.getTransactions.Query, {
390
+ code: 'query_invalid',
391
+ message: 'Invalid query parameters',
392
+ }), OpenApi.describeRoute({
393
+ description: 'List transactions across Tempo, with filters for addresses, blocks, timestamps, fees, and status.',
394
+ operationId: 'getTransactions',
395
+ responses: OpenApi.responses({
396
+ errors: { 502: 'Could not read indexed transaction data from TIDX.' },
397
+ success: {
398
+ description: 'A page of transactions.',
399
+ schema: schema.getTransactions.Response,
400
+ },
401
+ }),
402
+ summary: 'List transactions',
403
+ tags: ['Transactions'],
404
+ }), Cache.response({
405
+ cacheControl: Cache.policies.feed,
406
+ name: 'tempo-api:transactions:v1',
407
+ key: (c) => Cache.urlKey(c, schema.getTransactions.Query),
408
+ }), async (c) => {
409
+ if (Auth.narrowAccess)
410
+ return Auth.paidAccessError(c);
411
+ if (OpenApi.narrowValidation)
412
+ return OpenApi.validationError(c, {
413
+ code: 'query_invalid',
414
+ message: 'Invalid query parameters',
415
+ });
416
+ const query = c.req.valid('query');
417
+ const chainId = query.chainId ?? c.get('chainId');
418
+ // A cursor page is anchored below the head, so its contents are
419
+ // append-only and effectively immutable; cache it aggressively. The head
420
+ // page (no cursor) keeps the route's short `feed` default.
421
+ if (query.cursor !== undefined)
422
+ Cache.setPolicy(c, Cache.policies.immutable);
423
+ try {
424
+ // `totalCount` is opt-in and shares the page's filters; run it
425
+ // concurrently with the page. Best-effort: a count failure omits
426
+ // `meta` rather than failing the page.
427
+ const countPromise = query.include.includes('totalCount')
428
+ ? countTransactions(c, {
429
+ address: query.address,
430
+ chainId,
431
+ feePayer: query.feePayer,
432
+ feeToken: query.feeToken,
433
+ fromBlock: query['blockNumber.from'],
434
+ fromTimestamp: query['timestamp.from'],
435
+ recipient: query.recipient,
436
+ sender: query.sender,
437
+ status: query.status,
438
+ toBlock: query['blockNumber.to'],
439
+ toTimestamp: query['timestamp.to'],
440
+ }).catch(() => undefined)
441
+ : undefined;
442
+ const transactions = await listTransactions(c, {
443
+ address: query.address,
444
+ chainId,
445
+ cursor: query.cursor,
446
+ feePayer: query.feePayer,
447
+ feeToken: query.feeToken,
448
+ fromBlock: query['blockNumber.from'],
449
+ fromTimestamp: query['timestamp.from'],
450
+ include: query.include.filter((resource) => resource !== 'totalCount'),
451
+ limit: query.limit,
452
+ order: query.order,
453
+ page: query.page,
454
+ recipient: query.recipient,
455
+ sender: query.sender,
456
+ status: query.status,
457
+ toBlock: query['blockNumber.to'],
458
+ toTimestamp: query['timestamp.to'],
459
+ });
460
+ const meta = countPromise ? await countPromise : undefined;
461
+ return c.json(Response.validated(schema.getTransactions.Response, {
462
+ ...transactions,
463
+ ...(meta ? { meta } : {}),
464
+ }), 200);
465
+ }
466
+ catch (cause) {
467
+ return Response.upstream(c, cause);
468
+ }
469
+ })
470
+ .get('/:transactionHash', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('param', schema.getTransaction.Params, {
471
+ code: 'transaction_invalid',
472
+ message: 'Invalid transaction hash',
473
+ }), OpenApi.validate('query', schema.getTransaction.Query, {
474
+ code: 'query_invalid',
475
+ message: 'Invalid query parameters',
476
+ }), OpenApi.describeRoute({
477
+ description: 'Get one transaction by its 32-byte transaction hash.',
478
+ operationId: 'getTransaction',
479
+ responses: OpenApi.responses({
480
+ errors: {
481
+ 404: {
482
+ description: 'No transaction was found for that hash.',
483
+ codes: ['transaction_not_found'],
484
+ },
485
+ 502: 'Could not read transaction data from the upstream JSON-RPC node.',
486
+ },
487
+ success: {
488
+ description: 'A single transaction with decoded fields and original JSON-RPC data.',
489
+ schema: schema.getTransaction.Response,
490
+ },
491
+ }),
492
+ summary: 'Get a transaction by hash',
493
+ tags: ['Transactions'],
494
+ }), Cache.response({
495
+ // Default to no-store: a pending (or not-found) transaction must not be
496
+ // cached, or it would mask the mined result. The handler upgrades a mined
497
+ // transaction to `immutable` below.
498
+ cacheControl: Cache.policies.noStore,
499
+ name: 'tempo-api:transactions:v1',
500
+ key: (c) => Cache.urlKey(c, schema.getTransaction.Query),
501
+ }), async (c) => {
502
+ if (Auth.narrowAccess)
503
+ return Auth.paidAccessError(c);
504
+ if (OpenApi.narrowValidation)
505
+ return OpenApi.validationError(c, {
506
+ code: 'transaction_invalid',
507
+ message: 'Invalid request parameters',
508
+ });
509
+ if (OpenApi.narrowValidation)
510
+ return OpenApi.validationError(c, {
511
+ code: 'query_invalid',
512
+ message: 'Invalid request parameters',
513
+ });
514
+ const { transactionHash } = c.req.valid('param');
515
+ const query = c.req.valid('query');
516
+ const chainId = query.chainId ?? c.get('chainId');
517
+ const client = c.get('getClient')(chainId);
518
+ // `Schema.Hash` lowercases to a plain string; re-narrow to the hex
519
+ // template literal viem requires at the RPC boundary.
520
+ const hash = transactionHash;
521
+ try {
522
+ // Fetch the JSON-RPC transaction; a `null` result means the
523
+ // transaction is unknown rather than an error. The verbatim payload is
524
+ // surfaced under `rpc`, with humanized fields layered on top. Unmined
525
+ // lookups (pending or unknown hash) are deliberately never cached —
526
+ // confirmation polling must observe the mined result the moment the
527
+ // node does.
528
+ const rpc = await Timing.time(c, 'transaction', () => client.request({ method: 'eth_getTransactionByHash', params: [hash] }));
529
+ if (!rpc)
530
+ return Response.error(c, {
531
+ code: 'transaction_not_found',
532
+ message: 'Transaction not found',
533
+ status: 404,
534
+ });
535
+ let data = humanizeTransaction(Response.validated(schema.Rpc.Transaction, rpc));
536
+ // A mined transaction is immutable, so it can be cached aggressively; a
537
+ // pending one (no block yet) keeps the route's default no-store policy.
538
+ if (data.blockNumber !== null)
539
+ Cache.setPolicy(c, Cache.policies.immutable);
540
+ // The receipt is opt-in: fetching it is an extra RPC, so it only runs
541
+ // when requested via `include=receipt` and the transaction is mined.
542
+ // A null receipt (still pending) is simply omitted.
543
+ if (query.include.includes('receipt') && data.blockNumber !== null) {
544
+ const receipt = await Timing.time(c, 'receipt', () => client.request({ method: 'eth_getTransactionReceipt', params: [hash] }));
545
+ if (receipt) {
546
+ const humanized = Receipts.humanizeReceipt(Response.validated(Receipts.schema.Rpc.Receipt, receipt));
547
+ data = { ...data, meta: { ...data.meta, receipt: humanized } };
548
+ }
549
+ }
550
+ // Fee-token metadata is opt-in: resolving it is an extra RPC, so it
551
+ // only runs when requested via `include=feeToken` and the transaction
552
+ // declares a fee token (Tempo AA transactions).
553
+ const feeToken = data.feeToken;
554
+ if (query.include.includes('feeToken') && feeToken !== undefined) {
555
+ const token = await Timing.time(c, 'fee_token', () => Tokens.resolveToken(c, { address: feeToken, chainId }).catch(() => undefined));
556
+ if (token)
557
+ data = { ...data, meta: { ...data.meta, feeToken: token } };
558
+ }
559
+ return c.json(Response.validated(schema.getTransaction.Response, data), 200);
560
+ }
561
+ catch (cause) {
562
+ return Response.upstream(c, cause);
563
+ }
564
+ });
565
+ }
566
+ /**
567
+ * Lists humanized transactions and embeds opt-in `include` resources
568
+ * (`feeToken`, `receipt`). A `status` filter routes the page through the
569
+ * receipts list instead of the `txs` scan, since execution status lives on
570
+ * receipts.
571
+ */
572
+ export async function listTransactions(c, options) {
573
+ const { include, ...rest } = options;
574
+ // `status` filters on the receipt's execution status, which `txs` does not
575
+ // store: page the receipts list (which already supports `status`) and hydrate
576
+ // each receipt's underlying transaction. The receipts `(block_num, tx_idx)`
577
+ // keyset cursor spans the same domain as the transactions `(block_num, idx)`
578
+ // cursor, so cursors stay interchangeable between the two paths.
579
+ const receiptPage = rest.status === undefined
580
+ ? undefined
581
+ : await Receipts.getReceipts(c, {
582
+ address: rest.address,
583
+ chainId: rest.chainId,
584
+ cursor: rest.cursor,
585
+ feePayer: rest.feePayer,
586
+ feeToken: rest.feeToken,
587
+ fromBlock: rest.fromBlock,
588
+ fromTimestamp: rest.fromTimestamp,
589
+ limit: rest.limit,
590
+ order: rest.order,
591
+ page: rest.page,
592
+ recipient: rest.recipient,
593
+ sender: rest.sender,
594
+ status: rest.status,
595
+ toBlock: rest.toBlock,
596
+ toTimestamp: rest.toTimestamp,
597
+ });
598
+ const page = receiptPage
599
+ ? {
600
+ data: await transactionsForReceipts(c, {
601
+ chainId: rest.chainId,
602
+ receipts: receiptPage.data,
603
+ }),
604
+ nextCursor: receiptPage.nextCursor,
605
+ }
606
+ : await getTransactions(c, rest);
607
+ let data = page.data;
608
+ if (include.includes('receipt') && data.length > 0) {
609
+ const receipts = await Receipts.embedReceipts(c, {
610
+ chainId: rest.chainId,
611
+ receipts: receiptPage?.data,
612
+ rows: data,
613
+ });
614
+ data = data.map((row) => {
615
+ const receipt = receipts.get(row.hash.toLowerCase());
616
+ return receipt ? { ...row, meta: { ...row.meta, receipt } } : row;
617
+ });
618
+ }
619
+ if (include.includes('feeToken'))
620
+ data = await embedFeeTokens(c, data, rest.chainId);
621
+ return { ...page, data };
622
+ }
623
+ /**
624
+ * Fetches the underlying transactions for a page of receipts in one indexed
625
+ * `txs` query and returns them humanized, ordered to match the receipt page.
626
+ * Receipts whose transaction row is missing (not yet indexed) are skipped.
627
+ * Backs the `status`-filtered transactions list, which pages receipts first.
628
+ */
629
+ async function transactionsForReceipts(c, options) {
630
+ const { chainId, receipts } = options;
631
+ if (receipts.length === 0)
632
+ return [];
633
+ const tidx = c.get('getTidx')(chainId);
634
+ const blocks = [...new Set(receipts.map((receipt) => receipt.blockNumber))];
635
+ const hashes = [...new Set(receipts.map((receipt) => receipt.transactionHash))];
636
+ // `txs` is sorted by `(block_num, idx)` with no hash index, so the hash list
637
+ // must be paired with the page's block numbers — a bare `hash IN` full-scans
638
+ // the table. Raw-table query, so the inline SQL is cast to `string`.
639
+ const result = await Timing.time(c, 'transactions', () => tidx.fetch({
640
+ chainId,
641
+ query: `SELECT ${transactionColumns} FROM txs WHERE block_num IN (${blocks.join(', ')}) AND hash IN (${hashes.map((hash) => `'${hash}'`).join(', ')})`,
642
+ }));
643
+ const byHash = new Map();
644
+ for (const row of result.rows) {
645
+ const rpc = schema.Rpc.Transaction.safeParse(toRpcTransaction(row));
646
+ if (rpc.success)
647
+ byHash.set(rpc.data.hash.toLowerCase(), humanizeTransaction(rpc.data));
648
+ }
649
+ return receipts
650
+ .map((receipt) => byHash.get(receipt.transactionHash.toLowerCase()))
651
+ .filter((transaction) => transaction !== undefined);
652
+ }
653
+ /**
654
+ * Resolves fee-token metadata for each row and embeds it under `meta.feeToken`,
655
+ * sharing a single verified-token fetch. Best-effort: a row whose fee token
656
+ * can't be resolved (or that has none) is returned unchanged. Shared by the
657
+ * transaction and receipt list endpoints (and their address-scoped variants),
658
+ * whose rows all carry an optional `feeToken` address and a `meta` object.
659
+ */
660
+ export async function embedFeeTokens(c, rows, chainId) {
661
+ if (rows.length === 0)
662
+ return rows;
663
+ const uniqueTokens = Array.from(new Set(rows.map((row) => row.feeToken).filter((address) => address != null)));
664
+ if (uniqueTokens.length === 0)
665
+ return rows;
666
+ const snapshot = await VerifiedTokens.snapshot(c, chainId);
667
+ const resolved = await Timing.time(c, 'tokens', () => Promise.all(uniqueTokens.map((token) => Tokens.resolveToken(c, {
668
+ address: token,
669
+ chainId,
670
+ snapshot,
671
+ })
672
+ .then((metadata) => [token, metadata])
673
+ .catch(() => [token, undefined]))));
674
+ const tokensByAddress = new Map(resolved);
675
+ return rows.map((row) => {
676
+ const token = row.feeToken == null ? undefined : tokensByAddress.get(row.feeToken);
677
+ // The runtime shape stays `row`; the generic object spread just can't prove
678
+ // the override keeps it assignable to `row`.
679
+ return (token ? { ...row, meta: { ...row.meta, feeToken: token } } : row);
680
+ });
681
+ }
682
+ export function getTransactions(c, options) {
683
+ const { chainId } = options;
684
+ const store = c.get('store');
685
+ const tidx = c.get('getTidx')(chainId);
686
+ const cursor = options.cursor ? Cursor.decode(options.cursor, ['int', 'int']) : undefined;
687
+ return Timing.time(c, 'transactions', () => Store.memoize(async () => {
688
+ const page = await scanTransactions({ tidx }, options);
689
+ return {
690
+ data: page.items.map((item) => item.data),
691
+ nextCursor: page.nextCursor,
692
+ };
693
+ }, {
694
+ key: `transactions:v1:${chainId}:${options.order}:${options.address ?? ''}:${options.sender ?? ''}:${options.recipient ?? ''}:${options.feePayer ?? ''}:${options.feeToken ?? ''}:${options.fromBlock ?? ''}:${options.toBlock ?? ''}:${options.fromTimestamp ?? ''}:${options.toTimestamp ?? ''}:${cursor ? `cursor:${cursor[0]}:${cursor[1]}` : options.page !== undefined && options.page > 1 ? `page:${options.page}` : 'head'}:${options.limit}`,
695
+ store,
696
+ ttl: Ttl.seconds(15),
697
+ }));
698
+ }
699
+ /**
700
+ * Context-free core of {@link getTransactions}: builds the `txs` query (with the
701
+ * address-scoped `UNION` planner workaround), applies keyset pagination on
702
+ * `(block_num, idx)`, and reconstructs each row through the same
703
+ * `toRpcTransaction` → `humanizeTransaction` path the detail endpoint uses. Used
704
+ * by the Hono routes (via {@link getTransactions}, which adds Server-Timing +
705
+ * memoization) and by the webhook poller (uncached, ascending, per-row cursors).
706
+ */
707
+ export async function scanTransactions(deps, options) {
708
+ const { address, chainId, feePayer, feeToken, fromBlock, fromTimestamp, includeCallRecipients, limit, order, recipient, sender, toBlock, toTimestamp, } = options;
709
+ const { tidx } = deps;
710
+ const sortDirection = order === 'asc' ? 'ASC' : 'DESC';
711
+ // Keyset pagination: anchor the page below the previous row's `(block, idx)`
712
+ // position instead of a numeric offset, so rows arriving at the head can't
713
+ // shift items across pages. A malformed cursor decodes to `undefined` and
714
+ // falls back to the head page.
715
+ const cursor = options.cursor ? Cursor.decode(options.cursor, ['int', 'int']) : undefined;
716
+ // Bounded positional lane (exclusive with `cursor` at the schema): page 1 is
717
+ // the head page, so it shares the head's SQL and cache entries; deeper pages
718
+ // translate to a SQL OFFSET of `(page - 1) * limit` rows.
719
+ const offset = options.page !== undefined && options.page > 1 ? (options.page - 1) * limit : undefined;
720
+ // Raw transactions from the `txs` table (Postgres engine). `txs` is a
721
+ // standard table, not a signature-decoded CTE, so the inline query is
722
+ // cast to `string` and needs no `signatures`. Order by block then
723
+ // in-block index so transactions stay stable across pages, and fetch one
724
+ // extra row to detect `hasMore` without a separate count query.
725
+ //
726
+ // Build the shared filters once (everything except the address-scope
727
+ // predicate); the `address` filter is special-cased below because the
728
+ // TIDX engine errors out on `(from = X OR to = X) ORDER BY ...` for
729
+ // contracts with non-trivial traffic and an index-friendly `UNION`
730
+ // over the two sides plans cleanly.
731
+ const filters = [];
732
+ if (sender !== undefined)
733
+ filters.push(`"from" = '${sender}'`);
734
+ if (recipient !== undefined)
735
+ // For Tempo AA transactions the meaningful recipient is often an inner call
736
+ // target, so `includeCallRecipients` also matches `calls[].to` (a JSONB array
737
+ // of `{ to, value, input }`). The `@>` containment hits the partial GIN index
738
+ // on `calls`; the root `"to"` branch covers non-AA and single-call AA txs
739
+ // (whose `"to"` mirrors `calls[0].to` and which the partial index omits).
740
+ filters.push(includeCallRecipients
741
+ ? `("to" = '${recipient}' OR calls @> '[{"to": "${recipient}"}]')`
742
+ : `"to" = '${recipient}'`);
743
+ if (feePayer !== undefined)
744
+ filters.push(`fee_payer = '${feePayer}'`);
745
+ if (feeToken !== undefined)
746
+ filters.push(`fee_token = '${feeToken}'`);
747
+ if (fromBlock !== undefined)
748
+ filters.push(`block_num >= ${fromBlock}`);
749
+ if (toBlock !== undefined)
750
+ filters.push(`block_num <= ${toBlock}`);
751
+ if (fromTimestamp !== undefined)
752
+ filters.push(`block_timestamp >= '${fromTimestamp}'`);
753
+ if (toTimestamp !== undefined)
754
+ filters.push(`block_timestamp <= '${toTimestamp}'`);
755
+ if (cursor !== undefined)
756
+ filters.push(Cursor.keyset([
757
+ { literal: Cursor.literal(cursor[0], 'int'), name: 'block_num', order },
758
+ { literal: Cursor.literal(cursor[1], 'int'), name: 'idx', order },
759
+ ]));
760
+ // For address-scoped queries, run one branch per side and `UNION` so
761
+ // each branch can use its own (`from`/`to`) index. The `ORDER BY` and
762
+ // `LIMIT` must live *inside* each branch — TIDX's planner crashes on
763
+ // a UNION whose outer query orders by `block_num, idx` for
764
+ // high-traffic contracts (and on the `(from = X OR to = X) ORDER BY`
765
+ // form). Pushing the sort+limit down means each branch returns at
766
+ // most `limit + 1` index-ordered rows, the outer query re-merges,
767
+ // and plain `UNION` dedupes the self-transfer case where
768
+ // `from = to = address`.
769
+ // In the offset lane each branch must over-fetch the full window
770
+ // (`offset + limit + 1` rows) because the skip applies to the merged set:
771
+ // the outer query re-sorts the union and discards the first `offset` rows.
772
+ const sideQuery = (side, addr) => {
773
+ const where = [`"${side}" = '${addr}'`, ...filters].join(' AND ');
774
+ return `(SELECT ${transactionColumns} FROM txs WHERE ${where} ORDER BY block_num ${sortDirection}, idx ${sortDirection} LIMIT ${(offset ?? 0) + limit + 1})`;
775
+ };
776
+ const skip = offset !== undefined ? ` OFFSET ${offset}` : '';
777
+ const query = address !== undefined
778
+ ? `
779
+ ${sideQuery('from', address)}
780
+ UNION
781
+ ${sideQuery('to', address)}
782
+ ORDER BY block_num ${sortDirection}, idx ${sortDirection}
783
+ LIMIT ${limit + 1}${skip}
784
+ `
785
+ : `
786
+ SELECT ${transactionColumns}
787
+ FROM txs
788
+ ${filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : ''}
789
+ ORDER BY block_num ${sortDirection}, idx ${sortDirection}
790
+ LIMIT ${limit + 1}${skip}
791
+ `;
792
+ const result = await tidx.fetch({ chainId, query: query });
793
+ // The next page anchors below the last fetched row's `(block, idx)`.
794
+ const page = Cursor.paginate({
795
+ rows: result.rows,
796
+ limit,
797
+ key: (row) => {
798
+ const block = Value.toNumber(row['block_num']);
799
+ const index = Value.toNumber(row['idx']);
800
+ return block !== undefined && index !== undefined ? [block, index] : undefined;
801
+ },
802
+ });
803
+ // Reconstruct the RPC shape from the indexed columns, then humanize it
804
+ // through the same path as the detail endpoint so the list and detail
805
+ // responses are identical. Rows that fail to reconstruct are skipped.
806
+ const items = [];
807
+ for (const row of page.rows) {
808
+ const rpc = schema.Rpc.Transaction.safeParse(toRpcTransaction(row));
809
+ const block = Value.toNumber(row['block_num']);
810
+ const index = Value.toNumber(row['idx']);
811
+ if (rpc.success && block !== undefined && index !== undefined)
812
+ items.push({ cursor: [block, index], data: humanizeTransaction(rpc.data) });
813
+ }
814
+ return { hasMore: page.hasMore, items, limit, nextCursor: page.nextCursor };
815
+ }
816
+ /**
817
+ * Builds the non-cursor, non-address-scope `txs` filters shared by the page
818
+ * ({@link scanTransactions}) and the capped count ({@link countTransactions}),
819
+ * so the count always matches the page it annotates. The address scope is
820
+ * handled separately (it `UNION`s the two sides, as the page does).
821
+ */
822
+ function countFilters(options) {
823
+ const filters = [];
824
+ if (options.sender !== undefined)
825
+ filters.push(`"from" = '${options.sender}'`);
826
+ if (options.recipient !== undefined)
827
+ filters.push(`"to" = '${options.recipient}'`);
828
+ if (options.feePayer !== undefined)
829
+ filters.push(`fee_payer = '${options.feePayer}'`);
830
+ if (options.feeToken !== undefined)
831
+ filters.push(`fee_token = '${options.feeToken}'`);
832
+ if (options.fromBlock !== undefined)
833
+ filters.push(`block_num >= ${options.fromBlock}`);
834
+ if (options.toBlock !== undefined)
835
+ filters.push(`block_num <= ${options.toBlock}`);
836
+ if (options.fromTimestamp !== undefined)
837
+ filters.push(`block_timestamp >= '${options.fromTimestamp}'`);
838
+ if (options.toTimestamp !== undefined)
839
+ filters.push(`block_timestamp <= '${options.toTimestamp}'`);
840
+ return filters;
841
+ }
842
+ /**
843
+ * Capped total count of transactions matching the same filters as the page.
844
+ *
845
+ * A `status` filter is delegated to {@link Receipts.countReceipts}, mirroring
846
+ * the page's receipts-driven `status` path (execution status lives on receipts,
847
+ * not `txs`). The address scope reuses the page's `UNION` of the two sides —
848
+ * each side hits its own (`from`/`to`) index, and the deduped keyset count
849
+ * avoids double-counting self-transactions (`from = to`). `totalCountCapped: true` is a
850
+ * lower bound — at least {@link Schema.countCap} matches.
851
+ */
852
+ export function countTransactions(c, options) {
853
+ // Status lives on receipts, so route the count through the same path the page
854
+ // uses: count receipts under the identical filters.
855
+ if (options.status !== undefined)
856
+ return Receipts.countReceipts(c, options);
857
+ const { address, chainId } = options;
858
+ const store = c.get('store');
859
+ const tidx = c.get('getTidx')(chainId);
860
+ return Timing.time(c, 'transactions_count', () => Store.memoize(async () => {
861
+ const filters = countFilters(options);
862
+ let query;
863
+ if (address !== undefined) {
864
+ const fromWhere = [`"from" = '${address}'`, ...filters].join(' AND ');
865
+ const toWhere = [`"to" = '${address}'`, ...filters].join(' AND ');
866
+ query = `
867
+ SELECT count(*) AS total
868
+ FROM (
869
+ (SELECT block_num, idx FROM txs WHERE ${fromWhere} LIMIT ${Schema.countCap})
870
+ UNION
871
+ (SELECT block_num, idx FROM txs WHERE ${toWhere} LIMIT ${Schema.countCap})
872
+ ) AS capped
873
+ `;
874
+ }
875
+ else {
876
+ const where = filters.length > 0 ? `WHERE ${filters.join(' AND ')}` : '';
877
+ query = `
878
+ SELECT count(*) AS total
879
+ FROM (
880
+ SELECT 1 FROM txs ${where} LIMIT ${Schema.countCap}
881
+ ) AS capped
882
+ `;
883
+ }
884
+ const result = await tidx.fetch({ chainId, query: query });
885
+ const totalCount = Value.toNumber(result.rows[0]?.['total']) ?? 0;
886
+ return { totalCountCapped: totalCount >= Schema.countCap, totalCount };
887
+ }, {
888
+ key: `transactions-count:v1:${chainId}:${address ?? ''}:${options.sender ?? ''}:${options.recipient ?? ''}:${options.feePayer ?? ''}:${options.feeToken ?? ''}:${options.fromBlock ?? ''}:${options.toBlock ?? ''}:${options.fromTimestamp ?? ''}:${options.toTimestamp ?? ''}`,
889
+ store,
890
+ ttl: Ttl.seconds(15),
891
+ }));
892
+ }
893
+ /**
894
+ * The `txs` columns {@link toRpcTransaction} reconstructs a transaction from.
895
+ * Shared by the list scan and the receipt-driven `status` path so the two
896
+ * queries cannot drift from the reconstruction.
897
+ */
898
+ const transactionColumns = `block_num, block_timestamp, idx, hash, type, "from", "to", value, input,
899
+ gas_limit, max_fee_per_gas, max_priority_fee_per_gas,
900
+ nonce_key, nonce, fee_token, fee_payer, valid_before, valid_after`;
901
+ /**
902
+ * Re-encodes a TIDX `txs` row into the JSON-RPC transaction shape, which becomes
903
+ * the `rpc` payload that the list endpoint humanizes through the same path as
904
+ * the detail endpoint. Numeric columns become `0x` quantities; fields the
905
+ * indexer does not store (signatures, access list) are omitted, and `blockHash`
906
+ * is null since the schema requires it. The all-zero `nonce_key` that the
907
+ * indexer records for non-Tempo transactions is dropped to match the RPC
908
+ * response, which omits it.
909
+ */
910
+ function toRpcTransaction(row) {
911
+ const timestamp = Value.toIsoDateTime(row['block_timestamp']);
912
+ const nonceKey = row['nonce_key'];
913
+ return {
914
+ blockHash: null,
915
+ blockNumber: Value.toHex(row['block_num']) ?? null,
916
+ blockTimestamp: timestamp ? Value.toHex(Math.floor(Date.parse(timestamp) / 1000)) : undefined,
917
+ feeToken: typeof row['fee_token'] === 'string' ? row['fee_token'] : undefined,
918
+ from: row['from'],
919
+ gas: Value.toHex(row['gas_limit']),
920
+ hash: row['hash'],
921
+ input: typeof row['input'] === 'string' ? row['input'] : undefined,
922
+ maxFeePerGas: Value.toHex(row['max_fee_per_gas']),
923
+ maxPriorityFeePerGas: Value.toHex(row['max_priority_fee_per_gas']),
924
+ nonce: Value.toHex(row['nonce']),
925
+ nonceKey: typeof nonceKey === 'string' && !/^0x0+$/.test(nonceKey) ? nonceKey : undefined,
926
+ to: typeof row['to'] === 'string' ? row['to'] : undefined,
927
+ transactionIndex: Value.toHex(row['idx']) ?? null,
928
+ type: Value.toHex(row['type']),
929
+ validAfter: Value.toHex(row['valid_after']),
930
+ validBefore: Value.toHex(row['valid_before']),
931
+ value: Value.toHex(row['value']),
932
+ };
933
+ }
934
+ /** Humanizes one call within a Tempo account-abstraction transaction. */
935
+ function humanizeCall(call) {
936
+ return {
937
+ data: call.input ?? call.data ?? undefined,
938
+ to: call.to ?? null,
939
+ };
940
+ }
941
+ /**
942
+ * Humanizes a JSON-RPC transaction: decodes `type`, converts hex quantities to
943
+ * decimal strings, hex block fields to numbers, and timestamps to ISO 8601,
944
+ * while preserving the verbatim payload under `rpc`. The same function serves
945
+ * the detail endpoint (RPC source) and the list endpoint (reconstructed from the
946
+ * indexer), so both expose an identical shape.
947
+ */
948
+ export function humanizeTransaction(rpc) {
949
+ return {
950
+ blockHash: rpc.blockHash,
951
+ blockNumber: Value.hexToNumber(rpc.blockNumber) ?? null,
952
+ calls: rpc.calls?.map(humanizeCall),
953
+ chainId: Value.hexToNumber(rpc.chainId),
954
+ feeToken: rpc.feeToken ?? undefined,
955
+ gas: Value.hexToNumber(rpc.gas) ?? 0,
956
+ gasPrice: Value.fromHex(rpc.gasPrice),
957
+ hash: rpc.hash,
958
+ id: rpc.hash,
959
+ input: rpc.input,
960
+ maxFeePerGas: Value.fromHex(rpc.maxFeePerGas),
961
+ maxPriorityFeePerGas: Value.fromHex(rpc.maxPriorityFeePerGas),
962
+ meta: { rpc },
963
+ nonce: Value.hexToNumber(rpc.nonce) ?? 0,
964
+ nonceKey: rpc.nonceKey,
965
+ recipient: rpc.to ?? null,
966
+ sender: rpc.from,
967
+ timestamp: Value.hexSecondsToIso(rpc.blockTimestamp) ?? null,
968
+ transactionIndex: Value.hexToNumber(rpc.transactionIndex) ?? null,
969
+ type: decodeTransactionType(rpc.type),
970
+ validAfter: rpc.validAfter == null ? undefined : Value.hexSecondsToIso(rpc.validAfter),
971
+ validBefore: rpc.validBefore == null ? undefined : Value.hexSecondsToIso(rpc.validBefore),
972
+ value: Value.fromHex(rpc.value) ?? '0',
973
+ };
974
+ }
975
+ //# sourceMappingURL=transactions.js.map