tapimo 0.5.3 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/dist/App.d.ts +15830 -7220
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +9 -1
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +4 -0
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +5 -0
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/admin/App.d.ts +1011 -412
  10. package/dist/admin/App.d.ts.map +1 -1
  11. package/dist/admin/App.js +4 -0
  12. package/dist/admin/App.js.map +1 -1
  13. package/dist/admin/apps/api-keys.d.ts +2 -1
  14. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  15. package/dist/admin/apps/early-access.d.ts +148 -0
  16. package/dist/admin/apps/early-access.d.ts.map +1 -0
  17. package/dist/admin/apps/early-access.js +133 -0
  18. package/dist/admin/apps/early-access.js.map +1 -0
  19. package/dist/admin/apps/organizations.d.ts +124 -1
  20. package/dist/admin/apps/organizations.d.ts.map +1 -1
  21. package/dist/admin/apps/organizations.js +97 -6
  22. package/dist/admin/apps/organizations.js.map +1 -1
  23. package/dist/admin/apps/verified-tokens.d.ts +526 -1
  24. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  25. package/dist/admin/apps/verified-tokens.js +214 -1
  26. package/dist/admin/apps/verified-tokens.js.map +1 -1
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.d.ts.map +1 -1
  29. package/dist/admin/ui.generated.js +95 -75
  30. package/dist/admin/ui.generated.js.map +1 -1
  31. package/dist/analytics/Analytics.d.ts.map +1 -1
  32. package/dist/analytics/Analytics.js +20 -0
  33. package/dist/analytics/Analytics.js.map +1 -1
  34. package/dist/analytics/tables/requestEvents.d.ts +18 -0
  35. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  36. package/dist/analytics/tables/requestEvents.js +36 -7
  37. package/dist/analytics/tables/requestEvents.js.map +1 -1
  38. package/dist/apps/data/App.d.ts +6260 -4924
  39. package/dist/apps/data/App.d.ts.map +1 -1
  40. package/dist/apps/data/App.js +11 -6
  41. package/dist/apps/data/App.js.map +1 -1
  42. package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
  43. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
  44. package/dist/apps/data/FundingQuoteProviders.js +194 -16
  45. package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
  46. package/dist/apps/data/FxOracle.d.ts +71 -0
  47. package/dist/apps/data/FxOracle.d.ts.map +1 -0
  48. package/dist/apps/data/FxOracle.js +97 -0
  49. package/dist/apps/data/FxOracle.js.map +1 -0
  50. package/dist/apps/data/index.d.ts +1 -0
  51. package/dist/apps/data/index.d.ts.map +1 -1
  52. package/dist/apps/data/index.js +1 -0
  53. package/dist/apps/data/index.js.map +1 -1
  54. package/dist/apps/data/routes/activities.d.ts +3599 -1382
  55. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  56. package/dist/apps/data/routes/activities.js +250 -88
  57. package/dist/apps/data/routes/activities.js.map +1 -1
  58. package/dist/apps/data/routes/addresses.d.ts +872 -251
  59. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  60. package/dist/apps/data/routes/addresses.js +11 -9
  61. package/dist/apps/data/routes/addresses.js.map +1 -1
  62. package/dist/apps/data/routes/balances.d.ts +77 -26
  63. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  64. package/dist/apps/data/routes/balances.js +88 -45
  65. package/dist/apps/data/routes/balances.js.map +1 -1
  66. package/dist/apps/data/routes/blocks.d.ts +39 -39
  67. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  68. package/dist/apps/data/routes/exchanges.d.ts +856 -105
  69. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  70. package/dist/apps/data/routes/exchanges.js +518 -76
  71. package/dist/apps/data/routes/exchanges.js.map +1 -1
  72. package/dist/apps/data/routes/fee-amm.d.ts +81 -67
  73. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  74. package/dist/apps/data/routes/fee-amm.js +76 -91
  75. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  76. package/dist/apps/data/routes/funding.d.ts +80 -36
  77. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  78. package/dist/apps/data/routes/funding.js +65 -31
  79. package/dist/apps/data/routes/funding.js.map +1 -1
  80. package/dist/apps/data/routes/receipts.d.ts +392 -315
  81. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  82. package/dist/apps/data/routes/receipts.js +152 -77
  83. package/dist/apps/data/routes/receipts.js.map +1 -1
  84. package/dist/apps/data/routes/tokens.d.ts +167 -174
  85. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  86. package/dist/apps/data/routes/tokens.js +15 -13
  87. package/dist/apps/data/routes/tokens.js.map +1 -1
  88. package/dist/apps/data/routes/transactions.d.ts +277 -536
  89. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  90. package/dist/apps/data/routes/transactions.js +96 -77
  91. package/dist/apps/data/routes/transactions.js.map +1 -1
  92. package/dist/apps/data/routes/transfers.d.ts +157 -81
  93. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  94. package/dist/apps/data/routes/transfers.js +272 -130
  95. package/dist/apps/data/routes/transfers.js.map +1 -1
  96. package/dist/apps/data/routes/valuation.d.ts +307 -0
  97. package/dist/apps/data/routes/valuation.d.ts.map +1 -0
  98. package/dist/apps/data/routes/valuation.js +292 -0
  99. package/dist/apps/data/routes/valuation.js.map +1 -0
  100. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  101. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  102. package/dist/apps/data/routes/verified-tokens.js +7 -5
  103. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  104. package/dist/apps/data/routes/webhooks.d.ts +103 -123
  105. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  106. package/dist/apps/data/routes/webhooks.js +124 -25
  107. package/dist/apps/data/routes/webhooks.js.map +1 -1
  108. package/dist/apps/index.d.ts +2 -1
  109. package/dist/apps/index.d.ts.map +1 -1
  110. package/dist/apps/index.js +2 -1
  111. package/dist/apps/index.js.map +1 -1
  112. package/dist/apps/management/App.d.ts +8554 -1692
  113. package/dist/apps/management/App.d.ts.map +1 -1
  114. package/dist/apps/management/App.js +12 -1
  115. package/dist/apps/management/App.js.map +1 -1
  116. package/dist/apps/management/routes/api-keys.d.ts +7 -0
  117. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  118. package/dist/apps/management/routes/api-keys.js +17 -3
  119. package/dist/apps/management/routes/api-keys.js.map +1 -1
  120. package/dist/apps/management/routes/billing.d.ts +157 -162
  121. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  122. package/dist/apps/management/routes/billing.js +31 -23
  123. package/dist/apps/management/routes/billing.js.map +1 -1
  124. package/dist/apps/management/routes/faucet.d.ts +232 -0
  125. package/dist/apps/management/routes/faucet.d.ts.map +1 -0
  126. package/dist/apps/management/routes/faucet.js +154 -0
  127. package/dist/apps/management/routes/faucet.js.map +1 -0
  128. package/dist/apps/management/routes/invitations.d.ts +60 -60
  129. package/dist/apps/management/routes/invite-links.d.ts +49 -20
  130. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  131. package/dist/apps/management/routes/invite-links.js +26 -1
  132. package/dist/apps/management/routes/invite-links.js.map +1 -1
  133. package/dist/apps/management/routes/me.d.ts +6 -6
  134. package/dist/apps/management/routes/members.d.ts +6 -6
  135. package/dist/apps/management/routes/orgs.d.ts +42 -42
  136. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  137. package/dist/apps/management/routes/orgs.js +5 -0
  138. package/dist/apps/management/routes/orgs.js.map +1 -1
  139. package/dist/apps/management/routes/projects.d.ts +44 -44
  140. package/dist/apps/management/routes/usage.d.ts +3 -0
  141. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  142. package/dist/apps/management/routes/usage.js +4 -0
  143. package/dist/apps/management/routes/usage.js.map +1 -1
  144. package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
  145. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
  146. package/dist/apps/management/routes/verified-token-requests.js +271 -0
  147. package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
  148. package/dist/apps/management/routes/webhooks.d.ts +6977 -0
  149. package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
  150. package/dist/apps/management/routes/webhooks.js +573 -0
  151. package/dist/apps/management/routes/webhooks.js.map +1 -0
  152. package/dist/apps/mpp/App.d.ts +363 -0
  153. package/dist/apps/mpp/App.d.ts.map +1 -0
  154. package/dist/apps/mpp/App.js +72 -0
  155. package/dist/apps/mpp/App.js.map +1 -0
  156. package/dist/apps/mpp/Mpp.d.ts +178 -0
  157. package/dist/apps/mpp/Mpp.d.ts.map +1 -0
  158. package/dist/apps/mpp/Mpp.js +183 -0
  159. package/dist/apps/mpp/Mpp.js.map +1 -0
  160. package/dist/apps/mpp/index.d.ts +3 -0
  161. package/dist/apps/mpp/index.d.ts.map +1 -0
  162. package/dist/apps/mpp/index.js +3 -0
  163. package/dist/apps/mpp/index.js.map +1 -0
  164. package/dist/apps/relay/App.d.ts.map +1 -1
  165. package/dist/apps/relay/App.js +56 -9
  166. package/dist/apps/relay/App.js.map +1 -1
  167. package/dist/db/Db.d.ts +6 -0
  168. package/dist/db/Db.d.ts.map +1 -1
  169. package/dist/db/Db.js +110 -0
  170. package/dist/db/Db.js.map +1 -1
  171. package/dist/db/Schema.d.ts +53 -0
  172. package/dist/db/Schema.d.ts.map +1 -1
  173. package/dist/db/Schema.js +56 -0
  174. package/dist/db/Schema.js.map +1 -1
  175. package/dist/db/tables/earlyAccess.d.ts +50 -0
  176. package/dist/db/tables/earlyAccess.d.ts.map +1 -0
  177. package/dist/db/tables/earlyAccess.js +63 -0
  178. package/dist/db/tables/earlyAccess.js.map +1 -0
  179. package/dist/db/tables/enabledBillingSources.d.ts +73 -0
  180. package/dist/db/tables/enabledBillingSources.d.ts.map +1 -0
  181. package/dist/db/tables/enabledBillingSources.js +69 -0
  182. package/dist/db/tables/enabledBillingSources.js.map +1 -0
  183. package/dist/db/tables/invitations.d.ts.map +1 -1
  184. package/dist/db/tables/invitations.js +3 -0
  185. package/dist/db/tables/invitations.js.map +1 -1
  186. package/dist/db/tables/inviteLinks.d.ts +10 -2
  187. package/dist/db/tables/inviteLinks.d.ts.map +1 -1
  188. package/dist/db/tables/inviteLinks.js +10 -1
  189. package/dist/db/tables/inviteLinks.js.map +1 -1
  190. package/dist/db/tables/organizations.d.ts +5 -2
  191. package/dist/db/tables/organizations.d.ts.map +1 -1
  192. package/dist/db/tables/organizations.js +13 -2
  193. package/dist/db/tables/organizations.js.map +1 -1
  194. package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
  195. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  196. package/dist/db/tables/sponsoredTransactions.js +2 -0
  197. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  198. package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
  199. package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
  200. package/dist/db/tables/verifiedTokenRequests.js +120 -0
  201. package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
  202. package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
  203. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  204. package/dist/db/tables/webhookSubscriptions.js +16 -0
  205. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  206. package/dist/handlers/internal/utils.d.ts +1 -16
  207. package/dist/handlers/internal/utils.d.ts.map +1 -1
  208. package/dist/handlers/internal/utils.js +17 -6
  209. package/dist/handlers/internal/utils.js.map +1 -1
  210. package/dist/handlers/relay.d.ts.map +1 -1
  211. package/dist/handlers/relay.js +37 -5
  212. package/dist/handlers/relay.js.map +1 -1
  213. package/dist/internal/Auth.d.ts +11 -2
  214. package/dist/internal/Auth.d.ts.map +1 -1
  215. package/dist/internal/Auth.js +14 -47
  216. package/dist/internal/Auth.js.map +1 -1
  217. package/dist/internal/FundingQuotes.d.ts +147 -47
  218. package/dist/internal/FundingQuotes.d.ts.map +1 -1
  219. package/dist/internal/FundingQuotes.js +119 -33
  220. package/dist/internal/FundingQuotes.js.map +1 -1
  221. package/dist/internal/Log.d.ts +37 -5
  222. package/dist/internal/Log.d.ts.map +1 -1
  223. package/dist/internal/Log.js +52 -3
  224. package/dist/internal/Log.js.map +1 -1
  225. package/dist/internal/MetricSink.d.ts.map +1 -1
  226. package/dist/internal/MetricSink.js +24 -0
  227. package/dist/internal/MetricSink.js.map +1 -1
  228. package/dist/internal/OpenApi.d.ts +2 -2
  229. package/dist/internal/OpenApi.d.ts.map +1 -1
  230. package/dist/internal/OpenApi.js +3 -0
  231. package/dist/internal/OpenApi.js.map +1 -1
  232. package/dist/internal/Response.d.ts +2 -2
  233. package/dist/internal/Response.d.ts.map +1 -1
  234. package/dist/internal/Response.js +12 -4
  235. package/dist/internal/Response.js.map +1 -1
  236. package/dist/internal/Schema.d.ts +14 -5
  237. package/dist/internal/Schema.d.ts.map +1 -1
  238. package/dist/internal/Schema.js +23 -5
  239. package/dist/internal/Schema.js.map +1 -1
  240. package/dist/internal/Value.d.ts +18 -0
  241. package/dist/internal/Value.d.ts.map +1 -1
  242. package/dist/internal/Value.js +11 -1
  243. package/dist/internal/Value.js.map +1 -1
  244. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  245. package/dist/internal/VerifiedTokens.js +10 -1
  246. package/dist/internal/VerifiedTokens.js.map +1 -1
  247. package/dist/internal/Webhooks.d.ts +24 -3
  248. package/dist/internal/Webhooks.d.ts.map +1 -1
  249. package/dist/internal/Webhooks.js +34 -8
  250. package/dist/internal/Webhooks.js.map +1 -1
  251. package/package.json +7 -2
  252. package/src/App.test.ts +9 -4
  253. package/src/App.ts +23 -3
  254. package/src/Client.test-d.ts +733 -20
  255. package/src/Scope.ts +5 -0
  256. package/src/admin/App.test.ts +4 -0
  257. package/src/admin/App.ts +4 -0
  258. package/src/admin/apps/early-access.test.ts +125 -0
  259. package/src/admin/apps/early-access.ts +176 -0
  260. package/src/admin/apps/organizations.test.ts +86 -2
  261. package/src/admin/apps/organizations.ts +155 -31
  262. package/src/admin/apps/scopes.test.ts +5 -0
  263. package/src/admin/apps/verified-tokens.test.ts +201 -0
  264. package/src/admin/apps/verified-tokens.ts +532 -286
  265. package/src/admin/ui/plugin.ts +2 -1
  266. package/src/admin/ui/src/lib/early-access.ts +63 -0
  267. package/src/admin/ui/src/lib/organizations.test.ts +81 -1
  268. package/src/admin/ui/src/lib/organizations.ts +92 -0
  269. package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
  270. package/src/admin/ui/src/routeTree.gen.ts +33 -2
  271. package/src/admin/ui/src/routes/__root.tsx +2 -1
  272. package/src/admin/ui/src/routes/api-keys.tsx +1 -1
  273. package/src/admin/ui/src/routes/early-access.tsx +162 -0
  274. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +103 -0
  275. package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
  276. package/src/admin/ui.generated.ts +95 -94
  277. package/src/analytics/Analytics.test.ts +83 -0
  278. package/src/analytics/Analytics.ts +20 -0
  279. package/src/analytics/tables/requestEvents.ts +60 -7
  280. package/src/apps/composition.test.ts +11 -2
  281. package/src/apps/data/App.test.ts +1 -1
  282. package/src/apps/data/App.ts +22 -14
  283. package/src/apps/data/FundingQuoteProviders.test.ts +297 -4
  284. package/src/apps/data/FundingQuoteProviders.ts +255 -29
  285. package/src/apps/data/FxOracle.test.ts +118 -0
  286. package/src/apps/data/FxOracle.ts +153 -0
  287. package/src/apps/data/index.ts +1 -0
  288. package/src/apps/data/routes/activities.test.ts +177 -3
  289. package/src/apps/data/routes/activities.ts +441 -132
  290. package/src/apps/data/routes/addresses.ts +19 -9
  291. package/src/apps/data/routes/balances.test.ts +148 -11
  292. package/src/apps/data/routes/balances.ts +140 -51
  293. package/src/apps/data/routes/exchanges.test.ts +544 -9
  294. package/src/apps/data/routes/exchanges.ts +690 -103
  295. package/src/apps/data/routes/fee-amm.test.ts +47 -23
  296. package/src/apps/data/routes/fee-amm.ts +98 -119
  297. package/src/apps/data/routes/funding.test.ts +113 -8
  298. package/src/apps/data/routes/funding.ts +77 -51
  299. package/src/apps/data/routes/receipts.test.ts +129 -23
  300. package/src/apps/data/routes/receipts.ts +205 -100
  301. package/src/apps/data/routes/tokens.test.ts +43 -0
  302. package/src/apps/data/routes/tokens.ts +28 -13
  303. package/src/apps/data/routes/transactions.test.ts +72 -19
  304. package/src/apps/data/routes/transactions.ts +162 -92
  305. package/src/apps/data/routes/transfers.test.ts +341 -31
  306. package/src/apps/data/routes/transfers.ts +358 -158
  307. package/src/apps/data/routes/valuation.test.ts +437 -0
  308. package/src/apps/data/routes/valuation.ts +423 -0
  309. package/src/apps/data/routes/verified-tokens.ts +14 -2
  310. package/src/apps/data/routes/webhooks.test.ts +56 -8
  311. package/src/apps/data/routes/webhooks.ts +144 -27
  312. package/src/apps/index.ts +2 -1
  313. package/src/apps/management/App.ts +13 -0
  314. package/src/apps/management/routes/api-keys.test.ts +14 -0
  315. package/src/apps/management/routes/api-keys.ts +27 -3
  316. package/src/apps/management/routes/billing.test.ts +152 -20
  317. package/src/apps/management/routes/billing.ts +34 -18
  318. package/src/apps/management/routes/faucet.test.ts +87 -0
  319. package/src/apps/management/routes/faucet.ts +201 -0
  320. package/src/apps/management/routes/invite-links.test.ts +117 -0
  321. package/src/apps/management/routes/invite-links.ts +43 -1
  322. package/src/apps/management/routes/me.test.ts +9 -99
  323. package/src/apps/management/routes/orgs.test.ts +45 -2
  324. package/src/apps/management/routes/orgs.ts +6 -0
  325. package/src/apps/management/routes/scopes.test.ts +1 -0
  326. package/src/apps/management/routes/usage.test.ts +6 -0
  327. package/src/apps/management/routes/usage.ts +7 -0
  328. package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
  329. package/src/apps/management/routes/verified-token-requests.ts +397 -0
  330. package/src/apps/management/routes/webhooks.test.ts +426 -0
  331. package/src/apps/management/routes/webhooks.ts +672 -0
  332. package/src/apps/mpp/App.ts +86 -0
  333. package/src/apps/mpp/Mpp.test.ts +193 -0
  334. package/src/apps/mpp/Mpp.ts +353 -0
  335. package/src/apps/mpp/index.ts +2 -0
  336. package/src/apps/mpp/internal/Adapter.ts +11 -0
  337. package/src/apps/mpp/internal/Error.ts +9 -0
  338. package/src/apps/mpp/internal/Idempotency.ts +7 -0
  339. package/src/apps/mpp/internal/Screening.ts +10 -0
  340. package/src/apps/relay/App.test.ts +88 -6
  341. package/src/apps/relay/App.ts +61 -9
  342. package/src/db/Db.test.ts +19 -0
  343. package/src/db/Db.ts +125 -0
  344. package/src/db/Schema.ts +68 -0
  345. package/src/db/tables/earlyAccess.ts +86 -0
  346. package/src/db/tables/enabledBillingSources.test.ts +303 -0
  347. package/src/db/tables/enabledBillingSources.ts +118 -0
  348. package/src/db/tables/invitations.ts +3 -0
  349. package/src/db/tables/inviteLinks.ts +22 -3
  350. package/src/db/tables/organizations.test.ts +103 -0
  351. package/src/db/tables/organizations.ts +18 -2
  352. package/src/db/tables/sponsoredTransactions.ts +4 -0
  353. package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
  354. package/src/db/tables/verifiedTokenRequests.ts +182 -0
  355. package/src/db/tables/webhookSubscriptions.ts +31 -0
  356. package/src/handlers/internal/utils.ts +22 -6
  357. package/src/handlers/relay.errors.test.ts +153 -0
  358. package/src/handlers/relay.ts +42 -7
  359. package/src/internal/Auth.test.ts +3 -3
  360. package/src/internal/Auth.ts +15 -47
  361. package/src/internal/FundingQuotes.test.ts +161 -6
  362. package/src/internal/FundingQuotes.ts +141 -39
  363. package/src/internal/Log.test-d.ts +21 -0
  364. package/src/internal/Log.test.ts +141 -0
  365. package/src/internal/Log.ts +93 -6
  366. package/src/internal/MetricSink.test.ts +215 -0
  367. package/src/internal/MetricSink.ts +24 -0
  368. package/src/internal/OpenApi.ts +3 -0
  369. package/src/internal/Response.test.ts +28 -0
  370. package/src/internal/Response.ts +12 -4
  371. package/src/internal/Schema.ts +50 -5
  372. package/src/internal/Value.test.ts +20 -0
  373. package/src/internal/Value.ts +24 -1
  374. package/src/internal/VerifiedTokens.ts +9 -1
  375. package/src/internal/Webhooks.test.ts +140 -0
  376. package/src/internal/Webhooks.ts +53 -9
@@ -1,6 +1,7 @@
1
1
  import { Hono } from 'hono';
2
2
  import { Address, Hex } from 'ox';
3
3
  import { parseEventLogs, zeroAddress } from 'viem';
4
+ import { token as viem_Token } from 'viem/actions';
4
5
  import { Abis, Addresses } from 'viem/tempo';
5
6
  import * as z from 'zod/mini';
6
7
  import * as Auth from '../../../internal/Auth.js';
@@ -14,10 +15,17 @@ import * as Store from '../../../internal/Store.js';
14
15
  import * as Timing from '../../../internal/Timing.js';
15
16
  import * as Ttl from '../../../internal/Ttl.js';
16
17
  import * as Value from '../../../internal/Value.js';
18
+ import * as VerifiedTokens from '../../../internal/VerifiedTokens.js';
19
+ import * as FxOracle from '../FxOracle.js';
17
20
  import * as Tokens from './tokens.js';
18
21
  import * as Transfers from './transfers.js';
22
+ import * as Valuation from './valuation.js';
19
23
  /** Example transaction hash surfaced in OpenAPI docs. */
20
24
  const exampleHash = '0x4845ae2098724ab26a5d89370dce5124d044be6a5acc164afc348662de67d474';
25
+ const tokenFields = ['token.logoUri', 'token.verified'];
26
+ // TIP-20 tokens live at deterministic `0x20c0…` addresses. Other contracts
27
+ // can emit the same `Transfer` signature but do not expose TIP-20 metadata.
28
+ const tip20AddressPrefix = '0x20c0';
21
29
  /** Zod schemas owned by the activity handlers. */
22
30
  export var schema;
23
31
  (function (schema) {
@@ -25,19 +33,31 @@ export var schema;
25
33
  const Signer = z
26
34
  .union([z.literal('self'), Schema.Address])
27
35
  .check(z.describe('Who signed the activity: `self`, or the access-key address used to sign it.'));
28
- /**
29
- * A token and the amount that moved, in the same shape as the API's transfer
30
- * resource (`Transfers.schema.SourceToken`): a contract `address` and a
31
- * decimal-integer `amount`, plus best-effort `decimals`/`symbol` metadata when
32
- * the token has been resolved.
33
- */
34
- schema.Token = Transfers.schema.SourceToken;
35
- /**
36
- * A token transfer as classified by the feed: the `/transfers` row shape
37
- * plus the feed-only, subject-relative fields (`direction`, `signer`) that
38
- * the unscoped resource cannot carry, with `memo`/`attribution` always
39
- * resolved (the feed already decodes the underlying events).
40
- */
36
+ /** A token with required RPC metadata and optional curated fields. */
37
+ schema.Token = Schema.describe(Tokens.schema.TokenReference, 'A token referenced by an activity item.');
38
+ /** A token amount carrying its nominal value in the requested denomination. */
39
+ const ValuedAmount = z.extend(Schema.TokenAmount, {
40
+ valuation: z
41
+ .optional(z.nullable(Valuation.schema.Value))
42
+ .check(z.describe('The amount’s nominal value in the requested `denomination`. `null` when the token is ' +
43
+ 'unverified, its display currency has no rate, or rates were unavailable.')),
44
+ });
45
+ /** Self-contained amount for a destination token. */
46
+ const DestinationAmount = ValuedAmount.check(z.describe('Amount associated with `destinationToken`.'));
47
+ /** Self-contained amount for a refunded token. */
48
+ const RefundAmount = ValuedAmount.check(z.describe('Amount associated with `refund`.'));
49
+ /** Self-contained amount for a source token. */
50
+ const SourceAmount = ValuedAmount.check(z.describe('Amount associated with `sourceToken`.'));
51
+ /** Page-level resources: valuation rate provenance. */
52
+ schema.Meta = z
53
+ .object({
54
+ pricing: z
55
+ .optional(Valuation.schema.Pricing)
56
+ .check(z.describe('Rate provenance for amount valuations. Present when conversion rates were ' +
57
+ 'consulted; absent when every value was identity-valued or rates were unavailable.')),
58
+ })
59
+ .check(z.describe('Page-level resources attached to this response.'));
60
+ /** A token transfer with subject-relative direction and signer fields. */
41
61
  schema.Transfer = z
42
62
  .object({
43
63
  attribution: z
@@ -46,9 +66,12 @@ export var schema;
46
66
  blockNumber: z
47
67
  .number()
48
68
  .check(z.int(), z.nonnegative(), z.describe('Block number where this transfer was included.'), z.meta({ examples: [12345678] })),
69
+ destinationAmount: z
70
+ .optional(DestinationAmount)
71
+ .check(z.describe('Amount delivered to the recipient for a cross-token transfer. Omitted with `destinationToken` for a same-token transfer.')),
49
72
  destinationToken: z
50
73
  .optional(schema.Token)
51
- .check(z.describe('Token and amount delivered to the recipient when it differs from the source token — a cross-token transfer routed through the DEX. Omitted for a same-token transfer.')),
74
+ .check(z.describe('Token delivered to the recipient when it differs from the source token. Omitted for a same-token transfer.')),
52
75
  direction: z
53
76
  .enum(['in', 'out'])
54
77
  .check(z.describe('The address’s side of the transfer: `in` means received, and `out` means sent.')),
@@ -60,13 +83,17 @@ export var schema;
60
83
  signer: z
61
84
  .optional(Signer)
62
85
  .check(z.describe('For outbound transfers, who signed it: `self` or the access-key address. Omitted for inbound transfers.')),
63
- sourceToken: schema.Token.check(z.describe('Token and amount that moved in the transfer.')),
86
+ sourceAmount: SourceAmount,
87
+ sourceToken: schema.Token.check(z.describe('Token that moved in the transfer.')),
64
88
  timestamp: z
65
89
  .iso.datetime()
66
90
  .check(z.describe('Block timestamp for the transfer.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })), // prettier-ignore
67
91
  transactionHash: Schema.Hash.check(z.describe('Transaction hash that contains this transfer.')),
68
92
  })
69
- .check(z.describe('One token transfer involving the requested address.'));
93
+ .check(z.refine((data) => (data.destinationToken === undefined) === (data.destinationAmount === undefined), {
94
+ error: '`destinationAmount` and `destinationToken` must be returned together.',
95
+ path: ['destinationAmount'],
96
+ }), z.describe('One token transfer involving the requested address.'));
70
97
  /**
71
98
  * One transaction log, decoded into a known Tempo event when possible. The
72
99
  * raw fields (`address`/`data`/`logIndex`/`topics`) are always present so no
@@ -126,7 +153,7 @@ export var schema;
126
153
  z
127
154
  .object({
128
155
  ...base,
129
- data: schema.Transfer.check(z.describe('Transfer details, using the `/transfers` shape plus feed-only fields such as direction and signer.')),
156
+ data: schema.Transfer.check(z.describe('Transfer details with feed-relative direction and signer fields.')),
130
157
  type: z
131
158
  .literal('transfer')
132
159
  .check(z.describe('Activity type that tells you which `data` shape this entry uses.')),
@@ -138,7 +165,8 @@ export var schema;
138
165
  data: z
139
166
  .object({
140
167
  recipient: Schema.Address.check(z.describe('Address that received the transfer.')),
141
- sourceToken: schema.Token.check(z.describe('Token and amount that were minted.')),
168
+ sourceAmount: SourceAmount,
169
+ sourceToken: schema.Token.check(z.describe('Token that was minted.')),
142
170
  })
143
171
  .check(z.describe('A token mint activity.')),
144
172
  type: z
@@ -153,7 +181,8 @@ export var schema;
153
181
  .object({
154
182
  sender: Schema.Address.check(z.describe('Address whose token balance was burned.')),
155
183
  signer: Signer,
156
- sourceToken: schema.Token.check(z.describe('Token and amount that were burned.')),
184
+ sourceAmount: SourceAmount,
185
+ sourceToken: schema.Token.check(z.describe('Token that was burned.')),
157
186
  })
158
187
  .check(z.describe('A token burn activity.')),
159
188
  type: z
@@ -166,8 +195,10 @@ export var schema;
166
195
  ...base,
167
196
  data: z
168
197
  .object({
198
+ destinationAmount: DestinationAmount,
169
199
  destinationToken: schema.Token.check(z.describe('Token the address received in the swap.')),
170
200
  signer: Signer,
201
+ sourceAmount: SourceAmount,
171
202
  sourceToken: schema.Token.check(z.describe('Token the address sent into the swap.')),
172
203
  })
173
204
  .check(z.describe('Swap inferred from token transfers through the DEX precompile. This feed entry is a summary, so per-fill details, route, and rate are not included.')),
@@ -182,7 +213,8 @@ export var schema;
182
213
  data: z
183
214
  .object({
184
215
  signer: Signer,
185
- sourceToken: schema.Token.check(z.describe('Token and allowance amount approved for spending.')),
216
+ sourceAmount: SourceAmount,
217
+ sourceToken: schema.Token.check(z.describe('Token approved for spending.')),
186
218
  spender: Schema.Address.check(z.describe('Address allowed to spend the approved amount.')),
187
219
  })
188
220
  .check(z.describe('A token allowance approval activity.')),
@@ -199,9 +231,15 @@ export var schema;
199
231
  refund: z
200
232
  .optional(schema.Token)
201
233
  .check(z.describe('Token refunded to the address when the session closed, if any.')),
234
+ refundAmount: z
235
+ .optional(RefundAmount)
236
+ .check(z.describe('Amount refunded to the address when the session closed, if any.')),
202
237
  signer: Signer,
203
238
  })
204
- .check(z.describe('A payment-channel session close activity.')),
239
+ .check(z.refine((data) => (data.refund === undefined) === (data.refundAmount === undefined), {
240
+ error: '`refundAmount` and `refund` must be returned together.',
241
+ path: ['refundAmount'],
242
+ }), z.describe('A payment-channel session close activity.')),
205
243
  type: z
206
244
  .literal('session-closed')
207
245
  .check(z.describe('Activity type that tells you which `data` shape this entry uses.')),
@@ -266,7 +304,8 @@ export var schema;
266
304
  .object({
267
305
  sender: Schema.Address.check(z.describe('Address whose blocked balance was burned by policy.')),
268
306
  signer: Signer,
269
- sourceToken: schema.Token.check(z.describe('Token and amount that were burned.')),
307
+ sourceAmount: SourceAmount,
308
+ sourceToken: schema.Token.check(z.describe('Token that was burned.')),
270
309
  })
271
310
  .check(z.describe('A compliance burn of funds the receive policy blocked, distinct from a normal burn.')),
272
311
  type: z
@@ -283,7 +322,8 @@ export var schema;
283
322
  payee: Schema.Address.check(z.describe('Address that receives payments from the channel.')),
284
323
  payer: Schema.Address.check(z.describe('Address that funds the channel.')),
285
324
  signer: Signer,
286
- sourceToken: schema.Token.check(z.describe('Token and deposit amount locked into the channel.')),
325
+ sourceAmount: SourceAmount,
326
+ sourceToken: schema.Token.check(z.describe('Token locked into the channel.')),
287
327
  })
288
328
  .check(z.describe('A payment channel was opened and funded.')),
289
329
  type: z
@@ -298,7 +338,8 @@ export var schema;
298
338
  .object({
299
339
  channelId: Schema.Hex.check(z.describe('Identifier of the payment channel.')),
300
340
  signer: Signer,
301
- sourceToken: schema.Token.check(z.describe('Token and amount added to the channel deposit.')),
341
+ sourceAmount: SourceAmount,
342
+ sourceToken: schema.Token.check(z.describe('Token added to the channel deposit.')),
302
343
  })
303
344
  .check(z.describe('A payment channel deposit was topped up.')),
304
345
  type: z
@@ -315,7 +356,8 @@ export var schema;
315
356
  payee: Schema.Address.check(z.describe('Address that received the settled payment.')),
316
357
  payer: Schema.Address.check(z.describe('Address that funded the channel.')),
317
358
  signer: Signer,
318
- sourceToken: schema.Token.check(z.describe('Token and amount paid out in this settlement.')),
359
+ sourceAmount: SourceAmount,
360
+ sourceToken: schema.Token.check(z.describe('Token paid out in this settlement.')),
319
361
  })
320
362
  .check(z.describe('An incremental payment-channel settlement to the payee.')),
321
363
  type: z
@@ -333,13 +375,25 @@ export var schema;
333
375
  payer: Schema.Address.check(z.describe('Address that funded the channel.')),
334
376
  refund: z
335
377
  .optional(schema.Token)
336
- .check(z.describe('Token and amount refunded to the payer on close, if any.')),
378
+ .check(z.describe('Token refunded to the payer on close, if any.')),
379
+ refundAmount: z
380
+ .optional(RefundAmount)
381
+ .check(z.describe('Amount refunded to the payer on close, if any.')),
337
382
  signer: Signer,
383
+ sourceAmount: z
384
+ .optional(SourceAmount)
385
+ .check(z.describe('Final amount paid to the payee on close, if any.')),
338
386
  sourceToken: z
339
387
  .optional(schema.Token)
340
- .check(z.describe('Token and final amount paid out to the payee on close, if any.')),
388
+ .check(z.describe('Token paid out to the payee on close, if any.')),
341
389
  })
342
- .check(z.describe('A payment channel was closed, paying out the payee and refunding the payer.')),
390
+ .check(z.refine((data) => (data.refund === undefined) === (data.refundAmount === undefined), {
391
+ error: '`refundAmount` and `refund` must be returned together.',
392
+ path: ['refundAmount'],
393
+ }), z.refine((data) => (data.sourceToken === undefined) === (data.sourceAmount === undefined), {
394
+ error: '`sourceAmount` and `sourceToken` must be returned together.',
395
+ path: ['sourceAmount'],
396
+ }), z.describe('A payment channel was closed, paying out the payee and refunding the payer.')),
343
397
  type: z
344
398
  .literal('channel-closed')
345
399
  .check(z.describe('Activity type that tells you which `data` shape this entry uses.')),
@@ -371,7 +425,8 @@ export var schema;
371
425
  .enum(['bid', 'ask'])
372
426
  .check(z.describe('Order side: `bid` buys the base token, `ask` sells it.'), z.meta({ examples: ['bid'] })), // prettier-ignore
373
427
  signer: Signer,
374
- sourceToken: schema.Token.check(z.describe('Token and amount escrowed for the order.')),
428
+ sourceAmount: SourceAmount,
429
+ sourceToken: schema.Token.check(z.describe('Token escrowed for the order.')),
375
430
  tick: z
376
431
  .number()
377
432
  .check(z.int(), z.describe('Price tick the order was placed at.'), z.meta({ examples: [0] })),
@@ -402,7 +457,8 @@ export var schema;
402
457
  data: z
403
458
  .object({
404
459
  signer: Signer,
405
- sourceToken: schema.Token.check(z.describe('Token and amount of fees distributed.')),
460
+ sourceAmount: SourceAmount,
461
+ sourceToken: schema.Token.check(z.describe('Token used for the distributed fees.')),
406
462
  validator: Schema.Address.check(z.describe('Validator that received the distributed fees.')),
407
463
  })
408
464
  .check(z.describe('Accrued validator fees were distributed.')),
@@ -416,9 +472,11 @@ export var schema;
416
472
  ...base,
417
473
  data: z
418
474
  .object({
419
- destinationToken: schema.Token.check(z.describe('Token and amount received from the fee AMM.')),
475
+ destinationAmount: DestinationAmount,
476
+ destinationToken: schema.Token.check(z.describe('Token received from the fee AMM.')),
420
477
  signer: Signer,
421
- sourceToken: schema.Token.check(z.describe('Token and amount sent into the fee AMM.')),
478
+ sourceAmount: SourceAmount,
479
+ sourceToken: schema.Token.check(z.describe('Token sent into the fee AMM.')),
422
480
  swapper: Schema.Address.check(z.describe('Address that performed the rebalance swap.')),
423
481
  })
424
482
  .check(z.describe('A fee-AMM rebalance swap between a validator and user token.')),
@@ -434,7 +492,8 @@ export var schema;
434
492
  .object({
435
493
  funder: Schema.Address.check(z.describe('Address that funded the reward pool.')),
436
494
  signer: Signer,
437
- sourceToken: schema.Token.check(z.describe('Token and amount added to the reward pool.')),
495
+ sourceAmount: SourceAmount,
496
+ sourceToken: schema.Token.check(z.describe('Token added to the reward pool.')),
438
497
  })
439
498
  .check(z.describe('A token reward pool was funded.')),
440
499
  type: z
@@ -465,7 +524,8 @@ export var schema;
465
524
  account: Schema.Address.check(z.describe('Account the access key belongs to.')),
466
525
  publicKey: Schema.Address.check(z.describe('Public key of the access key whose limit changed.')),
467
526
  signer: Signer,
468
- sourceToken: schema.Token.check(z.describe('Token and new spending limit set for the access key.')),
527
+ sourceAmount: SourceAmount,
528
+ sourceToken: schema.Token.check(z.describe('Token whose spending limit was updated.')),
469
529
  })
470
530
  .check(z.describe('An access key’s per-token spending limit was updated.')),
471
531
  type: z
@@ -507,7 +567,8 @@ export var schema;
507
567
  .enum(['bid', 'ask'])
508
568
  .check(z.describe('Side of the flipped order: `bid` buys the base token, `ask` sells it.'), z.meta({ examples: ['bid'] })), // prettier-ignore
509
569
  signer: Signer,
510
- sourceToken: schema.Token.check(z.describe('Token and amount the flipped order rests with.')),
570
+ sourceAmount: SourceAmount,
571
+ sourceToken: schema.Token.check(z.describe('Token the flipped order rests with.')),
511
572
  tick: z
512
573
  .number()
513
574
  .check(z.int(), z.describe('Price tick the original order filled at.'), z.meta({ examples: [0] })),
@@ -1085,6 +1146,12 @@ export var schema;
1085
1146
  schema.Entry = z
1086
1147
  .union([...schema.items, schema.Group])
1087
1148
  .check(z.describe('Either one activity item, or a grouped set of access-key activity items.'));
1149
+ /** Optional token fields that require sources beyond RPC metadata. */
1150
+ schema.Include = z
1151
+ .enum(tokenFields)
1152
+ .check(z.describe('Additional token fields to include in activity responses.'));
1153
+ /** Parses comma-separated optional token fields. */
1154
+ schema.includeQuery = Schema.includeQuery(schema.Include, 'Comma-separated token fields to include, such as `token.logoUri,token.verified`.');
1088
1155
  /** Schemas for the getAddressActivities operation. */
1089
1156
  let getAddressActivities;
1090
1157
  (function (getAddressActivities) {
@@ -1099,10 +1166,12 @@ export var schema;
1099
1166
  .strictObject({
1100
1167
  chainId: Schema.ChainIdQuery,
1101
1168
  cursor: Schema.Cursor,
1169
+ denomination: Schema.Denomination,
1102
1170
  // Folding is opt-in: by default every item is returned at the root.
1103
1171
  group: z
1104
1172
  ._default(Schema.booleanQuery(), false)
1105
1173
  .check(z.describe('Set to `true` to fold consecutive items signed by the same access key on the same UTC day into `group` entries. Defaults to `false`, which returns every item separately.'), z.meta({ examples: [true] })),
1174
+ include: schema.includeQuery,
1106
1175
  limit: Schema.Limit,
1107
1176
  // Raw-log capture is opt-in: it can add a large `events` array to every
1108
1177
  // item, so the default feed stays lean.
@@ -1120,6 +1189,9 @@ export var schema;
1120
1189
  getAddressActivities.Response = z
1121
1190
  .object({
1122
1191
  data: z.array(schema.Entry).check(z.describe('Activity feed entries for the address.')),
1192
+ meta: z
1193
+ .optional(schema.Meta)
1194
+ .check(z.describe('Page-level resources, such as valuation rate provenance.')),
1123
1195
  nextCursor: Schema.NextCursor,
1124
1196
  })
1125
1197
  .check(z.describe('A page of human-readable activity for the address.'));
@@ -1137,6 +1209,8 @@ export var schema;
1137
1209
  getTransactionActivities.Query = z
1138
1210
  .strictObject({
1139
1211
  chainId: Schema.ChainIdQuery,
1212
+ denomination: Schema.Denomination,
1213
+ include: schema.includeQuery,
1140
1214
  // Raw-log capture is opt-in: it can add a large `events` array to every
1141
1215
  // item, so the default response stays lean.
1142
1216
  logs: z
@@ -1153,6 +1227,9 @@ export var schema;
1153
1227
  getTransactionActivities.Response = z
1154
1228
  .object({
1155
1229
  data: z.array(schema.Item).check(z.describe('Activity items classified from the transaction.')),
1230
+ meta: z
1231
+ .optional(schema.Meta)
1232
+ .check(z.describe('Page-level resources, such as valuation rate provenance.')),
1156
1233
  })
1157
1234
  .check(z.describe('The human-readable activity that happened on a transaction.'));
1158
1235
  })(getTransactionActivities = schema.getTransactionActivities || (schema.getTransactionActivities = {}));
@@ -1308,6 +1385,11 @@ const minGroupEntries = 5;
1308
1385
  const maxGroupSize = 50;
1309
1386
  /** Token-bearing keys on an item's `data` payload, walked for enrichment. */
1310
1387
  const tokenKeys = ['destinationToken', 'refund', 'sourceToken'];
1388
+ const amountKeyByTokenKey = {
1389
+ destinationToken: 'destinationAmount',
1390
+ refund: 'refundAmount',
1391
+ sourceToken: 'sourceAmount',
1392
+ };
1311
1393
  /** Builds common public activity fields from the normalized transaction hash and representative log. */
1312
1394
  function baseFor(options) {
1313
1395
  return {
@@ -1336,7 +1418,8 @@ function baseFor(options) {
1336
1418
  * consecutive access-key-signed items into `group` entries. Pagination uses the
1337
1419
  * same `(block_num, tx_idx)` keyset cursor the pipeline emits.
1338
1420
  */
1339
- export function addresses() {
1421
+ export function addresses(options = {}) {
1422
+ const oracle = options.fx?.oracle ?? FxOracle.ecb();
1340
1423
  return new Hono().get('/v1/addresses/:address/activities', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('param', schema.getAddressActivities.Params, {
1341
1424
  code: 'address_invalid',
1342
1425
  message: 'Check the account address and try again.',
@@ -1347,7 +1430,7 @@ export function addresses() {
1347
1430
  description: 'Get a human-readable feed of what an address has been doing onchain, including payments sent and received, swaps, approvals, and more.',
1348
1431
  operationId: 'getAddressActivities',
1349
1432
  responses: OpenApi.responses({
1350
- errors: { 502: 'Tempo could not read activity data from the upstream indexer.' },
1433
+ errors: { 502: 'Tempo could not read activity or token data from an upstream service.' },
1351
1434
  success: {
1352
1435
  description: 'A page of address activity entries.',
1353
1436
  schema: schema.getAddressActivities.Response,
@@ -1374,15 +1457,13 @@ export function addresses() {
1374
1457
  });
1375
1458
  const { address } = c.req.valid('param');
1376
1459
  const query = c.req.valid('query');
1377
- // Cursor pages are anchored below the head and effectively immutable, so
1378
- // cache them aggressively; the head page keeps the route's short `feed`
1379
- // default.
1460
+ // Cursor pages carry current valuations and curated verification data.
1380
1461
  if (query.cursor !== undefined)
1381
- Cache.setPolicy(c, Cache.policies.immutable);
1462
+ Cache.setPolicy(c, Cache.policies.metadata);
1382
1463
  try {
1383
1464
  const chainId = query.chainId ?? c.get('chainId');
1384
1465
  const provider = tidx({ chainId, tidx: c.get('getTidx')(chainId) });
1385
- const { items, nextCursor } = await Timing.time(c, 'address_activities', () => Store.memoize(() => list(provider, {
1466
+ const { items: unenrichedItems, nextCursor } = await Timing.time(c, 'address_activities', () => Store.memoize(() => list(provider, {
1386
1467
  address: address,
1387
1468
  cursor: query.cursor,
1388
1469
  group: query.group,
@@ -1394,20 +1475,26 @@ export function addresses() {
1394
1475
  store: c.get('store'),
1395
1476
  ttl: Ttl.seconds(15),
1396
1477
  }));
1397
- // Resolve token metadata for every token referenced across the page and
1398
- // spread it into each item's stub tokens. Goes through the shared
1399
- // `Tokens.getTokenMetadata` path so it reuses the `token:v1:…` cache with
1400
- // `/tokens` and `/transfers` instead of a parallel metadata fetch.
1401
- await enrichTokens(c, { chainId, items });
1478
+ // Build immutable token and structured amount copies from RPC metadata.
1479
+ const { items, rates } = await enrichTokens(c, {
1480
+ chainId,
1481
+ denomination: query.denomination ?? 'USD',
1482
+ include: query.include,
1483
+ items: unenrichedItems,
1484
+ oracle,
1485
+ });
1402
1486
  // Fold consecutive access-key-signed items into `group` entries only
1403
1487
  // when requested; otherwise every item is returned at the root.
1404
1488
  const data = query.group ? groupByAccessKey(items) : items;
1405
1489
  return c.json(Response.validated(schema.getAddressActivities.Response, {
1406
1490
  data,
1491
+ ...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
1407
1492
  nextCursor,
1408
1493
  }), 200);
1409
1494
  }
1410
1495
  catch (cause) {
1496
+ if (cause instanceof Valuation.UnsupportedDenominationError)
1497
+ return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
1411
1498
  return Response.upstream(c, cause);
1412
1499
  }
1413
1500
  });
@@ -1422,7 +1509,8 @@ export function addresses() {
1422
1509
  * classified item(s) — usually one headline activity — with the full per-tx
1423
1510
  * event set available via `logs=true`.
1424
1511
  */
1425
- export function transactions() {
1512
+ export function transactions(options = {}) {
1513
+ const oracle = options.fx?.oracle ?? FxOracle.ecb();
1426
1514
  return new Hono().get('/v1/transactions/:transactionHash/activities', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('param', schema.getTransactionActivities.Params, {
1427
1515
  code: 'transaction_invalid',
1428
1516
  message: 'Check the transaction hash and try again.',
@@ -1438,7 +1526,7 @@ export function transactions() {
1438
1526
  description: 'No mined transaction was found for that hash.',
1439
1527
  codes: ['transaction_not_found'],
1440
1528
  },
1441
- 502: 'Tempo could not read activity data from the upstream indexer.',
1529
+ 502: 'Tempo could not read activity or token data from an upstream service.',
1442
1530
  },
1443
1531
  success: {
1444
1532
  description: 'The classified activity for the transaction.',
@@ -1448,10 +1536,8 @@ export function transactions() {
1448
1536
  summary: 'List transaction activities',
1449
1537
  tags: ['Activities'],
1450
1538
  }), Cache.response({
1451
- // Activity exists only once the transaction is mined; once mined it is
1452
- // immutable. Default to no-store so a 404 (unknown / not-yet-mined hash)
1453
- // is not cached with a long header that would mask the eventual result;
1454
- // the handler upgrades the 200 to `immutable` below.
1539
+ // Default to no-store so a 404 does not mask the eventual mined result.
1540
+ // Successful responses use the metadata policy for current valuations.
1455
1541
  cacheControl: Cache.policies.noStore,
1456
1542
  name: 'tempo-api:transactions:v1',
1457
1543
  key: (c) => Cache.urlKey(c, schema.getTransactionActivities.Query),
@@ -1472,7 +1558,7 @@ export function transactions() {
1472
1558
  const query = c.req.valid('query');
1473
1559
  const chainId = query.chainId ?? c.get('chainId');
1474
1560
  try {
1475
- const items = await Timing.time(c, 'transaction_activities', () => Store.memoize(() => getTransactionActivities({
1561
+ const unenrichedItems = await Timing.time(c, 'transaction_activities', () => Store.memoize(() => getTransactionActivities({
1476
1562
  chainId,
1477
1563
  logs: query.logs,
1478
1564
  store: c.get('store'),
@@ -1483,20 +1569,30 @@ export function transactions() {
1483
1569
  store: c.get('store'),
1484
1570
  ttl: Ttl.seconds(15),
1485
1571
  }));
1486
- if (items === null)
1572
+ if (unenrichedItems === null)
1487
1573
  return Response.error(c, {
1488
1574
  code: 'transaction_not_found',
1489
1575
  message: 'Transaction not found',
1490
1576
  status: 404,
1491
1577
  });
1492
- // A mined transaction's activity is final, so cache it aggressively.
1493
- Cache.setPolicy(c, Cache.policies.immutable);
1494
- // Resolve token metadata for every token referenced and spread it into
1495
- // each item's stub tokens (shared `token:v1:…` cache path).
1496
- await enrichTokens(c, { chainId, items });
1497
- return c.json(Response.validated(schema.getTransactionActivities.Response, { data: items }), 200);
1578
+ // Mined activity still carries current valuations and verification data.
1579
+ Cache.setPolicy(c, Cache.policies.metadata);
1580
+ // Build immutable token and structured amount copies from RPC metadata.
1581
+ const { items, rates } = await enrichTokens(c, {
1582
+ chainId,
1583
+ denomination: query.denomination ?? 'USD',
1584
+ include: query.include,
1585
+ items: unenrichedItems,
1586
+ oracle,
1587
+ });
1588
+ return c.json(Response.validated(schema.getTransactionActivities.Response, {
1589
+ data: items,
1590
+ ...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
1591
+ }), 200);
1498
1592
  }
1499
1593
  catch (cause) {
1594
+ if (cause instanceof Valuation.UnsupportedDenominationError)
1595
+ return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
1500
1596
  return Response.upstream(c, cause);
1501
1597
  }
1502
1598
  });
@@ -1595,7 +1691,7 @@ export async function list(provider, options) {
1595
1691
  allItems.push(...page.flatMap((txGroup) => classifyGroup(txGroup, viewer, fingerprintMap, logs).map(withTitle)));
1596
1692
  lastGroup = page[page.length - 1];
1597
1693
  const enough = group
1598
- ? groupByAccessKey(allItems).length >= minGroupEntries
1694
+ ? groupByAccessKeyItems(allItems).length >= minGroupEntries
1599
1695
  : allItems.length >= limit;
1600
1696
  if (enough || !hasMore)
1601
1697
  break;
@@ -1605,8 +1701,8 @@ export async function list(provider, options) {
1605
1701
  let nextCursor = null;
1606
1702
  if (hasMore && lastGroup)
1607
1703
  nextCursor = provider.cursorForGroup(lastGroup);
1608
- // Items carry stub tokens (`address`/`amount`); the caller enriches them with
1609
- // metadata via {@link enrichTokens}.
1704
+ // Items carry private `address`/`amount` stubs; the caller splits them into
1705
+ // public token references and structured amounts via {@link enrichTokens}.
1610
1706
  return { items: allItems, nextCursor };
1611
1707
  }
1612
1708
  /**
@@ -3014,7 +3110,7 @@ function lowerOrNull(value) {
3014
3110
  const text = Value.toText(value);
3015
3111
  return text ? text.toLowerCase() : null;
3016
3112
  }
3017
- /** Builds a stub token; `decimals`/`symbol` are filled by {@link enrichItem}. */
3113
+ /** Builds a token stub whose metadata is filled by {@link enrichItem}. */
3018
3114
  function token(amount, address) {
3019
3115
  return { address: address.toLowerCase(), amount: (amount ?? 0n).toString() };
3020
3116
  }
@@ -3027,48 +3123,110 @@ function collectTokens(item, set) {
3027
3123
  set.add(t.address.toLowerCase());
3028
3124
  }
3029
3125
  }
3030
- /**
3031
- * Resolves metadata for every token referenced across a page of items and
3032
- * spreads it into each item's stub tokens, in place. Routes through the shared
3033
- * {@link Tokens.getTokenMetadata} (one `token.getMetadata` RPC per token,
3034
- * memoized under the `token:v1:…` key shared with `/tokens` and `/transfers`)
3035
- * instead of a parallel metadata fetch. Resolution is best-effort: a token
3036
- * whose metadata is unavailable keeps just `address`/`amount`.
3037
- */
3126
+ /** Resolves TIP-20 metadata or the standard ERC-20 subset used by activity transfers. */
3127
+ function getActivityTokenMetadata(c, options) {
3128
+ const { address, chainId } = options;
3129
+ if (address.startsWith(tip20AddressPrefix))
3130
+ return Tokens.getTokenMetadata(c, { address, chainId });
3131
+ return Store.memoize(async () => {
3132
+ const metadata = await viem_Token.getMetadata(c.get('getClient')(chainId), { token: address });
3133
+ // ERC-20 has no currency field; its symbol is the amount's unit label.
3134
+ return {
3135
+ currency: metadata.symbol,
3136
+ decimals: metadata.decimals,
3137
+ name: metadata.name,
3138
+ symbol: metadata.symbol,
3139
+ };
3140
+ }, { key: `token:erc20:v1:${chainId}:${address}:metadata`, store: c.get('store'), ttl: Ttl.minutes(1) });
3141
+ }
3142
+ /** Resolves core metadata into immutable items. Optional logo and verification sources are best-effort. */
3038
3143
  async function enrichTokens(c, options) {
3039
- const { chainId, items } = options;
3144
+ const { chainId, denomination, include, items, oracle } = options;
3040
3145
  const addresses = new Set();
3041
3146
  for (const item of items)
3042
3147
  collectTokens(item, addresses);
3148
+ // Valuation keys off the curated snapshot; a snapshot failure degrades the
3149
+ // values to `null` rather than failing the feed.
3150
+ const snapshot = addresses.size > 0
3151
+ ? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
3152
+ : undefined;
3153
+ const rates = await Valuation.ratesFor(c, {
3154
+ currencies: snapshot
3155
+ ? [...addresses].flatMap((address) => {
3156
+ const held = snapshot.byAddress.get(address)?.currency;
3157
+ return held === undefined ? [] : [held];
3158
+ })
3159
+ : [],
3160
+ denomination,
3161
+ oracle,
3162
+ });
3043
3163
  if (addresses.size === 0)
3044
- return;
3045
- const resolved = await Timing.time(c, 'tokens', () => Promise.all([...addresses].map((address) => Tokens.getTokenMetadata(c, { address, chainId })
3046
- .then((metadata) => [address.toLowerCase(), metadata])
3047
- .catch(() => [address.toLowerCase(), undefined]))));
3164
+ return { items: items, rates };
3165
+ const includeLogoUri = include.includes('token.logoUri');
3166
+ const includeVerified = include.includes('token.verified');
3167
+ const resolved = await Timing.time(c, 'tokens', () => Promise.all([...addresses].map(async (address) => {
3168
+ const [logoUri, metadata] = await Promise.all([
3169
+ includeLogoUri
3170
+ ? Tokens.getTokenLogo(c, { address, chainId }).catch(() => undefined)
3171
+ : undefined,
3172
+ getActivityTokenMetadata(c, { address, chainId }),
3173
+ ]);
3174
+ return [
3175
+ address.toLowerCase(),
3176
+ {
3177
+ currency: metadata.currency,
3178
+ decimals: metadata.decimals,
3179
+ logoUri: includeLogoUri
3180
+ ? (logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri)
3181
+ : undefined,
3182
+ name: metadata.name,
3183
+ symbol: metadata.symbol,
3184
+ verified: includeVerified && snapshot ? snapshot.byAddress.has(address) : undefined,
3185
+ },
3186
+ ];
3187
+ })));
3048
3188
  const byAddress = new Map(resolved);
3049
- for (const item of items)
3050
- enrichItem(item, byAddress);
3189
+ return {
3190
+ items: items.map((item) => enrichItem(item, byAddress, { denomination, rates, snapshot })),
3191
+ rates,
3192
+ };
3051
3193
  }
3052
- /** Spreads resolved token metadata into an item's stub tokens, in place. */
3053
- function enrichItem(item, byAddress) {
3054
- const data = item.data;
3194
+ /** Returns an enriched copy of an item without mutating its cached token stubs. */
3195
+ function enrichItem(item, byAddress, valuation) {
3196
+ const source = item.data;
3197
+ const data = { ...item.data };
3055
3198
  for (const key of tokenKeys) {
3056
- const t = data[key];
3199
+ const t = source[key];
3057
3200
  if (!t)
3058
3201
  continue;
3059
3202
  const meta = byAddress.get(t.address.toLowerCase());
3060
3203
  if (!meta)
3061
- continue;
3062
- // Carry only the per-row token fields the `Token` (SourceToken) shape
3063
- // declares; `address`/`amount` come from the stub.
3204
+ throw new Error(`Token metadata unavailable for ${t.address}`);
3205
+ data[amountKeyByTokenKey[key]] = {
3206
+ ...Value.tokenAmount({
3207
+ baseUnits: t.amount,
3208
+ currency: meta.currency,
3209
+ decimals: meta.decimals,
3210
+ }),
3211
+ // Valued via the curated display currency, never the on-chain metadata.
3212
+ valuation: Valuation.valuationFor({
3213
+ amount: BigInt(t.amount),
3214
+ denomination: valuation.denomination,
3215
+ rates: valuation.rates,
3216
+ token: valuation.snapshot?.byAddress.get(t.address.toLowerCase()),
3217
+ }),
3218
+ };
3064
3219
  data[key] = {
3065
- ...t,
3220
+ address: t.address,
3066
3221
  currency: meta.currency,
3067
3222
  decimals: meta.decimals,
3223
+ ...(meta.logoUri !== undefined ? { logoUri: meta.logoUri } : {}),
3068
3224
  name: meta.name,
3069
3225
  symbol: meta.symbol,
3226
+ ...(meta.verified !== undefined ? { verified: meta.verified } : {}),
3070
3227
  };
3071
3228
  }
3229
+ return { ...item, data };
3072
3230
  }
3073
3231
  /**
3074
3232
  * Folds adjacent items signed by the same access key on the same UTC calendar
@@ -3076,6 +3234,10 @@ function enrichItem(item, byAddress) {
3076
3234
  * Must be called once over the full, timestamp-sorted item list.
3077
3235
  */
3078
3236
  export function groupByAccessKey(items) {
3237
+ return groupByAccessKeyItems(items);
3238
+ }
3239
+ /** Groups items while preserving whether their token data has been enriched. */
3240
+ function groupByAccessKeyItems(items) {
3079
3241
  const entries = [];
3080
3242
  let currentGroup = null;
3081
3243
  for (const item of items) {