tapimo 0.10.2 → 0.12.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 (386) hide show
  1. package/dist/App.d.ts +4896 -2166
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +2 -2
  4. package/dist/App.js.map +1 -1
  5. package/dist/Assets.d.ts +15 -0
  6. package/dist/Assets.d.ts.map +1 -1
  7. package/dist/Assets.js +7 -0
  8. package/dist/Assets.js.map +1 -1
  9. package/dist/Webhooks.d.ts +0 -75
  10. package/dist/Webhooks.d.ts.map +1 -1
  11. package/dist/Webhooks.js +1 -143
  12. package/dist/Webhooks.js.map +1 -1
  13. package/dist/admin/App.d.ts +127 -78
  14. package/dist/admin/App.d.ts.map +1 -1
  15. package/dist/admin/apps/earn-vaults.d.ts +115 -1
  16. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  17. package/dist/admin/apps/earn-vaults.js +59 -6
  18. package/dist/admin/apps/earn-vaults.js.map +1 -1
  19. package/dist/admin/apps/organizations.d.ts +3 -3
  20. package/dist/admin/apps/organizations.d.ts.map +1 -1
  21. package/dist/admin/apps/organizations.js +4 -2
  22. package/dist/admin/apps/organizations.js.map +1 -1
  23. package/dist/admin/apps/verified-tokens.d.ts +83 -83
  24. package/dist/admin/ui.generated.d.ts +1 -1
  25. package/dist/admin/ui.generated.d.ts.map +1 -1
  26. package/dist/admin/ui.generated.js +151 -151
  27. package/dist/admin/ui.generated.js.map +1 -1
  28. package/dist/apps/data/App.d.ts +5924 -4310
  29. package/dist/apps/data/App.d.ts.map +1 -1
  30. package/dist/apps/data/App.js +61 -9
  31. package/dist/apps/data/App.js.map +1 -1
  32. package/dist/apps/data/ZoneSelection.d.ts +62 -0
  33. package/dist/apps/data/ZoneSelection.d.ts.map +1 -0
  34. package/dist/apps/data/ZoneSelection.js +44 -0
  35. package/dist/apps/data/ZoneSelection.js.map +1 -0
  36. package/dist/apps/data/routes/activities.d.ts +2368 -5
  37. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  38. package/dist/apps/data/routes/activities.js +423 -114
  39. package/dist/apps/data/routes/activities.js.map +1 -1
  40. package/dist/apps/data/routes/addresses.d.ts +131 -0
  41. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  42. package/dist/apps/data/routes/balances.d.ts +25 -25
  43. package/dist/apps/data/routes/balances.js +1 -1
  44. package/dist/apps/data/routes/balances.js.map +1 -1
  45. package/dist/apps/data/routes/blocks.d.ts +1 -1
  46. package/dist/apps/data/routes/blocks.js +1 -1
  47. package/dist/apps/data/routes/blocks.js.map +1 -1
  48. package/dist/apps/data/routes/earn.d.ts +135 -10
  49. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  50. package/dist/apps/data/routes/earn.js +157 -25
  51. package/dist/apps/data/routes/earn.js.map +1 -1
  52. package/dist/apps/data/routes/exchanges.d.ts +829 -123
  53. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  54. package/dist/apps/data/routes/exchanges.js +16 -13
  55. package/dist/apps/data/routes/exchanges.js.map +1 -1
  56. package/dist/apps/data/routes/fee-amm.d.ts +26 -26
  57. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  58. package/dist/apps/data/routes/fee-amm.js +9 -11
  59. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  60. package/dist/apps/data/routes/receipts.d.ts +54 -54
  61. package/dist/apps/data/routes/receipts.js +1 -1
  62. package/dist/apps/data/routes/receipts.js.map +1 -1
  63. package/dist/apps/data/routes/rpc.js +24 -10
  64. package/dist/apps/data/routes/rpc.js.map +1 -1
  65. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  66. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  67. package/dist/apps/data/routes/tokenlist.js +16 -15
  68. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  69. package/dist/apps/data/routes/tokens.d.ts +17 -3
  70. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  71. package/dist/apps/data/routes/tokens.js +34 -15
  72. package/dist/apps/data/routes/tokens.js.map +1 -1
  73. package/dist/apps/data/routes/transactions.d.ts +1 -1
  74. package/dist/apps/data/routes/transactions.js +1 -1
  75. package/dist/apps/data/routes/transactions.js.map +1 -1
  76. package/dist/apps/data/routes/transfers.d.ts +13 -13
  77. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  78. package/dist/apps/data/routes/transfers.js +7 -9
  79. package/dist/apps/data/routes/transfers.js.map +1 -1
  80. package/dist/apps/data/routes/valuation.d.ts +21 -21
  81. package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
  82. package/dist/apps/data/routes/webhooks.d.ts +1011 -151
  83. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  84. package/dist/apps/data/routes/webhooks.js +126 -739
  85. package/dist/apps/data/routes/webhooks.js.map +1 -1
  86. package/dist/apps/data/routes/zones.d.ts +15 -15
  87. package/dist/apps/funding/App.d.ts +27 -27
  88. package/dist/apps/funding/routes/chains.d.ts.map +1 -1
  89. package/dist/apps/funding/routes/chains.js +5 -4
  90. package/dist/apps/funding/routes/chains.js.map +1 -1
  91. package/dist/apps/funding/routes/deposit-addresses.d.ts +18 -18
  92. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  93. package/dist/apps/funding/routes/deposit-addresses.js +8 -8
  94. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  95. package/dist/apps/funding/routes/providers.d.ts.map +1 -1
  96. package/dist/apps/funding/routes/providers.js +3 -2
  97. package/dist/apps/funding/routes/providers.js.map +1 -1
  98. package/dist/apps/funding/routes/quotes.d.ts.map +1 -1
  99. package/dist/apps/funding/routes/quotes.js +2 -2
  100. package/dist/apps/funding/routes/quotes.js.map +1 -1
  101. package/dist/apps/funding/routes/transfers.d.ts +33 -33
  102. package/dist/apps/management/App.d.ts +1433 -322
  103. package/dist/apps/management/App.d.ts.map +1 -1
  104. package/dist/apps/management/Billing.d.ts.map +1 -1
  105. package/dist/apps/management/Billing.js +19 -6
  106. package/dist/apps/management/Billing.js.map +1 -1
  107. package/dist/apps/management/routes/api-keys.d.ts +154 -94
  108. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  109. package/dist/apps/management/routes/api-keys.js +76 -30
  110. package/dist/apps/management/routes/api-keys.js.map +1 -1
  111. package/dist/apps/management/routes/billing.d.ts +103 -30
  112. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  113. package/dist/apps/management/routes/billing.js +91 -32
  114. package/dist/apps/management/routes/billing.js.map +1 -1
  115. package/dist/apps/management/routes/faucet.d.ts +12 -12
  116. package/dist/apps/management/routes/faucet.d.ts.map +1 -1
  117. package/dist/apps/management/routes/faucet.js +23 -12
  118. package/dist/apps/management/routes/faucet.js.map +1 -1
  119. package/dist/apps/management/routes/invitations.d.ts +46 -13
  120. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  121. package/dist/apps/management/routes/invitations.js +79 -29
  122. package/dist/apps/management/routes/invitations.js.map +1 -1
  123. package/dist/apps/management/routes/invite-links.d.ts +128 -83
  124. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  125. package/dist/apps/management/routes/invite-links.js +100 -41
  126. package/dist/apps/management/routes/invite-links.js.map +1 -1
  127. package/dist/apps/management/routes/me.d.ts +5 -5
  128. package/dist/apps/management/routes/me.d.ts.map +1 -1
  129. package/dist/apps/management/routes/me.js +14 -10
  130. package/dist/apps/management/routes/me.js.map +1 -1
  131. package/dist/apps/management/routes/members.d.ts +68 -47
  132. package/dist/apps/management/routes/members.d.ts.map +1 -1
  133. package/dist/apps/management/routes/members.js +37 -18
  134. package/dist/apps/management/routes/members.js.map +1 -1
  135. package/dist/apps/management/routes/orgs.d.ts +48 -8
  136. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  137. package/dist/apps/management/routes/orgs.js +48 -19
  138. package/dist/apps/management/routes/orgs.js.map +1 -1
  139. package/dist/apps/management/routes/projects.d.ts +130 -68
  140. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  141. package/dist/apps/management/routes/projects.js +72 -21
  142. package/dist/apps/management/routes/projects.js.map +1 -1
  143. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  144. package/dist/apps/management/routes/scopes.js +8 -5
  145. package/dist/apps/management/routes/scopes.js.map +1 -1
  146. package/dist/apps/management/routes/usage.d.ts +38 -38
  147. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  148. package/dist/apps/management/routes/usage.js +41 -31
  149. package/dist/apps/management/routes/usage.js.map +1 -1
  150. package/dist/apps/management/routes/verified-token-requests.d.ts +34 -6
  151. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
  152. package/dist/apps/management/routes/verified-token-requests.js +36 -17
  153. package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
  154. package/dist/apps/management/routes/webhooks.d.ts +1186 -197
  155. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  156. package/dist/apps/management/routes/webhooks.js +106 -38
  157. package/dist/apps/management/routes/webhooks.js.map +1 -1
  158. package/dist/apps/mpp/internal/Adapter.d.ts +1 -1
  159. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  160. package/dist/apps/mpp/internal/Adapter.js +12 -0
  161. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  162. package/dist/db/Db.d.ts +2 -0
  163. package/dist/db/Db.d.ts.map +1 -1
  164. package/dist/db/Db.js +61 -0
  165. package/dist/db/Db.js.map +1 -1
  166. package/dist/db/Schema.d.ts +30 -2
  167. package/dist/db/Schema.d.ts.map +1 -1
  168. package/dist/db/Schema.js +28 -3
  169. package/dist/db/Schema.js.map +1 -1
  170. package/dist/db/tables/earnVaults.d.ts +5 -1
  171. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  172. package/dist/db/tables/earnVaults.js +5 -0
  173. package/dist/db/tables/earnVaults.js.map +1 -1
  174. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
  175. package/dist/db/tables/webhookDeliveries.js +10 -0
  176. package/dist/db/tables/webhookDeliveries.js.map +1 -1
  177. package/dist/db/tables/webhookQueueCompletions.d.ts +15 -0
  178. package/dist/db/tables/webhookQueueCompletions.d.ts.map +1 -0
  179. package/dist/db/tables/webhookQueueCompletions.js +32 -0
  180. package/dist/db/tables/webhookQueueCompletions.js.map +1 -0
  181. package/dist/db/tables/webhookQueueEvents.d.ts +16 -20
  182. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  183. package/dist/db/tables/webhookQueueEvents.js +68 -43
  184. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  185. package/dist/db/tables/webhookSubscriptions.d.ts +47 -72
  186. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  187. package/dist/db/tables/webhookSubscriptions.js +92 -105
  188. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  189. package/dist/internal/Auth.d.ts +8 -1
  190. package/dist/internal/Auth.d.ts.map +1 -1
  191. package/dist/internal/Auth.js +13 -3
  192. package/dist/internal/Auth.js.map +1 -1
  193. package/dist/internal/Cache.d.ts.map +1 -1
  194. package/dist/internal/Cache.js +11 -7
  195. package/dist/internal/Cache.js.map +1 -1
  196. package/dist/internal/EarnVaults.d.ts +41 -2
  197. package/dist/internal/EarnVaults.d.ts.map +1 -1
  198. package/dist/internal/EarnVaults.js +167 -0
  199. package/dist/internal/EarnVaults.js.map +1 -1
  200. package/dist/internal/MetricSink.d.ts +35 -125
  201. package/dist/internal/MetricSink.d.ts.map +1 -1
  202. package/dist/internal/MetricSink.js +50 -121
  203. package/dist/internal/MetricSink.js.map +1 -1
  204. package/dist/internal/OpenApi.d.ts +26 -22
  205. package/dist/internal/OpenApi.d.ts.map +1 -1
  206. package/dist/internal/OpenApi.js +128 -39
  207. package/dist/internal/OpenApi.js.map +1 -1
  208. package/dist/internal/Response.d.ts +13 -8
  209. package/dist/internal/Response.d.ts.map +1 -1
  210. package/dist/internal/Response.js +16 -5
  211. package/dist/internal/Response.js.map +1 -1
  212. package/dist/internal/Schema.d.ts +8 -8
  213. package/dist/internal/Schema.d.ts.map +1 -1
  214. package/dist/internal/Schema.js +10 -9
  215. package/dist/internal/Schema.js.map +1 -1
  216. package/dist/internal/Store.d.ts +15 -6
  217. package/dist/internal/Store.d.ts.map +1 -1
  218. package/dist/internal/Store.js +45 -15
  219. package/dist/internal/Store.js.map +1 -1
  220. package/dist/internal/Tidx.d.ts +2 -0
  221. package/dist/internal/Tidx.d.ts.map +1 -1
  222. package/dist/internal/Tidx.js +16 -4
  223. package/dist/internal/Tidx.js.map +1 -1
  224. package/dist/internal/WebhookTransfer.d.ts +1 -55
  225. package/dist/internal/WebhookTransfer.d.ts.map +1 -1
  226. package/dist/internal/WebhookTransfer.js +1 -239
  227. package/dist/internal/WebhookTransfer.js.map +1 -1
  228. package/dist/internal/Webhooks.d.ts +112 -56
  229. package/dist/internal/Webhooks.d.ts.map +1 -1
  230. package/dist/internal/Webhooks.js +124 -93
  231. package/dist/internal/Webhooks.js.map +1 -1
  232. package/dist/internal/funding/Deposit.d.ts +2 -2
  233. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  234. package/dist/internal/funding/Deposit.js +9 -8
  235. package/dist/internal/funding/Deposit.js.map +1 -1
  236. package/dist/internal/funding/DepositAddress.d.ts +4 -4
  237. package/dist/internal/funding/DepositAddress.d.ts.map +1 -1
  238. package/dist/internal/funding/DepositAddress.js +9 -8
  239. package/dist/internal/funding/DepositAddress.js.map +1 -1
  240. package/dist/internal/funding/DepositWebhook.d.ts +25 -0
  241. package/dist/internal/funding/DepositWebhook.d.ts.map +1 -0
  242. package/dist/internal/funding/DepositWebhook.js +74 -0
  243. package/dist/internal/funding/DepositWebhook.js.map +1 -0
  244. package/dist/internal/funding/Provider.d.ts.map +1 -1
  245. package/dist/internal/funding/Provider.js +13 -12
  246. package/dist/internal/funding/Provider.js.map +1 -1
  247. package/dist/internal/funding/Reconciliation.d.ts +6 -0
  248. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  249. package/dist/internal/funding/Reconciliation.js +42 -10
  250. package/dist/internal/funding/Reconciliation.js.map +1 -1
  251. package/dist/internal/funding/index.d.ts +1 -0
  252. package/dist/internal/funding/index.d.ts.map +1 -1
  253. package/dist/internal/funding/index.js +1 -0
  254. package/dist/internal/funding/index.js.map +1 -1
  255. package/dist/internal/funding/providers/stargate.d.ts +19 -0
  256. package/dist/internal/funding/providers/stargate.d.ts.map +1 -0
  257. package/dist/internal/funding/providers/stargate.js +143 -0
  258. package/dist/internal/funding/providers/stargate.js.map +1 -0
  259. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
  260. package/dist/internal/webhookDestinations/slack.js +16 -0
  261. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  262. package/dist/providers/index.d.ts +7 -0
  263. package/dist/providers/index.d.ts.map +1 -1
  264. package/dist/providers/index.js +3 -0
  265. package/dist/providers/index.js.map +1 -1
  266. package/package.json +2 -2
  267. package/src/App.test.ts +48 -0
  268. package/src/App.ts +7 -2
  269. package/src/Assets.test.ts +18 -0
  270. package/src/Assets.ts +22 -0
  271. package/src/Client.test-d.ts +287 -17
  272. package/src/Webhooks.ts +1 -220
  273. package/src/admin/apps/earn-vaults.test.ts +143 -0
  274. package/src/admin/apps/earn-vaults.ts +83 -6
  275. package/src/admin/apps/organizations.ts +6 -2
  276. package/src/admin/ui/src/routes/api-keys.tsx +36 -0
  277. package/src/admin/ui.generated.ts +151 -189
  278. package/src/apps/data/App.test.ts +31 -0
  279. package/src/apps/data/App.ts +64 -10
  280. package/src/apps/data/ZoneSelection.test.ts +196 -0
  281. package/src/apps/data/ZoneSelection.ts +108 -0
  282. package/src/apps/data/routes/activities.test.ts +435 -12
  283. package/src/apps/data/routes/activities.ts +562 -125
  284. package/src/apps/data/routes/balances.ts +1 -1
  285. package/src/apps/data/routes/blocks.ts +1 -1
  286. package/src/apps/data/routes/earn.test.ts +183 -23
  287. package/src/apps/data/routes/earn.ts +225 -29
  288. package/src/apps/data/routes/earn.zone-access.test.ts +46 -0
  289. package/src/apps/data/routes/exchanges.test.ts +31 -1
  290. package/src/apps/data/routes/exchanges.ts +19 -15
  291. package/src/apps/data/routes/fee-amm.ts +18 -11
  292. package/src/apps/data/routes/receipts.ts +1 -1
  293. package/src/apps/data/routes/rpc.test.ts +75 -0
  294. package/src/apps/data/routes/rpc.ts +23 -9
  295. package/src/apps/data/routes/tokenlist.ts +21 -18
  296. package/src/apps/data/routes/tokens.test.ts +29 -0
  297. package/src/apps/data/routes/tokens.ts +38 -15
  298. package/src/apps/data/routes/transactions.ts +1 -1
  299. package/src/apps/data/routes/transfers.test.ts +3 -3
  300. package/src/apps/data/routes/transfers.ts +12 -9
  301. package/src/apps/data/routes/webhooks.test.ts +179 -1497
  302. package/src/apps/data/routes/webhooks.ts +156 -976
  303. package/src/apps/data/routes/zones.test.ts +19 -13
  304. package/src/apps/funding/routes/chains.test.ts +211 -7
  305. package/src/apps/funding/routes/chains.ts +19 -12
  306. package/src/apps/funding/routes/deposit-addresses.test.ts +394 -0
  307. package/src/apps/funding/routes/deposit-addresses.ts +84 -72
  308. package/src/apps/funding/routes/providers.ts +9 -5
  309. package/src/apps/funding/routes/quotes.test.ts +46 -0
  310. package/src/apps/funding/routes/quotes.ts +8 -5
  311. package/src/apps/funding/routes/transfers.test.ts +35 -32
  312. package/src/apps/management/Billing.test.ts +26 -0
  313. package/src/apps/management/Billing.ts +24 -7
  314. package/src/apps/management/routes/api-keys.test.ts +178 -0
  315. package/src/apps/management/routes/api-keys.ts +203 -144
  316. package/src/apps/management/routes/billing.test.ts +209 -0
  317. package/src/apps/management/routes/billing.ts +254 -177
  318. package/src/apps/management/routes/faucet.test.ts +39 -0
  319. package/src/apps/management/routes/faucet.ts +75 -41
  320. package/src/apps/management/routes/invitations.test.ts +216 -0
  321. package/src/apps/management/routes/invitations.ts +186 -109
  322. package/src/apps/management/routes/invite-links.test.ts +263 -1
  323. package/src/apps/management/routes/invite-links.ts +295 -214
  324. package/src/apps/management/routes/me.test.ts +49 -0
  325. package/src/apps/management/routes/me.ts +42 -32
  326. package/src/apps/management/routes/members.test.ts +124 -1
  327. package/src/apps/management/routes/members.ts +81 -51
  328. package/src/apps/management/routes/orgs.test.ts +176 -0
  329. package/src/apps/management/routes/orgs.ts +101 -59
  330. package/src/apps/management/routes/projects.test.ts +183 -0
  331. package/src/apps/management/routes/projects.ts +124 -60
  332. package/src/apps/management/routes/scopes.test.ts +44 -0
  333. package/src/apps/management/routes/scopes.ts +37 -28
  334. package/src/apps/management/routes/usage.test.ts +92 -0
  335. package/src/apps/management/routes/usage.ts +186 -151
  336. package/src/apps/management/routes/verified-token-requests.test.ts +114 -0
  337. package/src/apps/management/routes/verified-token-requests.ts +166 -133
  338. package/src/apps/management/routes/webhooks.test.ts +313 -1
  339. package/src/apps/management/routes/webhooks.ts +220 -71
  340. package/src/apps/mpp/internal/Adapter.ts +13 -1
  341. package/src/db/Db.test.ts +42 -5
  342. package/src/db/Db.ts +85 -0
  343. package/src/db/Schema.ts +41 -3
  344. package/src/db/tables/earnVaults.test.ts +22 -0
  345. package/src/db/tables/earnVaults.ts +11 -1
  346. package/src/db/tables/organizations.test.ts +5 -2
  347. package/src/db/tables/webhookDeliveries.ts +13 -0
  348. package/src/db/tables/webhookQueueCompletions.ts +55 -0
  349. package/src/db/tables/webhookQueueEvents.ts +97 -57
  350. package/src/db/tables/webhookSubscriptions.ts +134 -144
  351. package/src/internal/Auth.ts +23 -5
  352. package/src/internal/Cache.ts +14 -7
  353. package/src/internal/EarnVaults.capabilities.test.ts +33 -0
  354. package/src/internal/EarnVaults.test.ts +79 -0
  355. package/src/internal/EarnVaults.ts +277 -0
  356. package/src/internal/MetricSink.test.ts +41 -373
  357. package/src/internal/MetricSink.ts +92 -273
  358. package/src/internal/OpenApi.ts +165 -49
  359. package/src/internal/Response.test.ts +95 -0
  360. package/src/internal/Response.ts +40 -2
  361. package/src/internal/Schema.test.ts +34 -0
  362. package/src/internal/Schema.ts +20 -9
  363. package/src/internal/Store.test.ts +186 -0
  364. package/src/internal/Store.ts +57 -17
  365. package/src/internal/Tidx.test.ts +19 -0
  366. package/src/internal/Tidx.ts +16 -4
  367. package/src/internal/WebhookTransfer.ts +1 -351
  368. package/src/internal/Webhooks.test.ts +222 -145
  369. package/src/internal/Webhooks.ts +234 -135
  370. package/src/internal/funding/Deposit.ts +71 -64
  371. package/src/internal/funding/DepositAddress.ts +50 -43
  372. package/src/internal/funding/DepositWebhook.test.ts +131 -0
  373. package/src/internal/funding/DepositWebhook.ts +101 -0
  374. package/src/internal/funding/Provider.ts +164 -142
  375. package/src/internal/funding/Reconciliation.test.ts +14 -0
  376. package/src/internal/funding/Reconciliation.ts +161 -86
  377. package/src/internal/funding/index.test.ts +1 -0
  378. package/src/internal/funding/index.ts +1 -0
  379. package/src/internal/funding/providers/index.test.ts +185 -0
  380. package/src/internal/funding/providers/stargate.ts +184 -0
  381. package/src/internal/webhookDestinations/slack.ts +15 -0
  382. package/src/providers/index.test.ts +1 -0
  383. package/src/providers/index.ts +9 -0
  384. package/src/Webhooks.bench.ts +0 -714
  385. package/src/Webhooks.memory.bench.ts +0 -250
  386. package/src/Webhooks.test.ts +0 -146
@@ -19,12 +19,13 @@ import * as Ttl from '../../../internal/Ttl.js';
19
19
  import * as Value from '../../../internal/Value.js';
20
20
  import * as VerifiedTokens from '../../../internal/VerifiedTokens.js';
21
21
  import * as FxOracle from '../FxOracle.js';
22
+ import * as ZoneSelection from '../ZoneSelection.js';
22
23
  import * as Tokens from './tokens.js';
23
24
  import * as Transfers from './transfers.js';
24
25
  import * as Valuation from './valuation.js';
25
26
  /** Example transaction hash surfaced in OpenAPI docs. */
26
27
  const exampleHash = '0x4845ae2098724ab26a5d89370dce5124d044be6a5acc164afc348662de67d474';
27
- const tokenFields = ['token.logoUri', 'token.verified'];
28
+ const includeFields = ['token.logoUri', 'token.verified', 'zones'];
28
29
  // TIP-20 tokens live at deterministic `0x20c0…` addresses. Other contracts
29
30
  // can emit the same `Transfer` signature but do not expose TIP-20 metadata.
30
31
  const tip20AddressPrefix = '0x20c0';
@@ -130,6 +131,9 @@ export var schema;
130
131
  * transfer's `direction`/`memo`/`attribution`/`signer`) the resource lacks.
131
132
  */
132
133
  const base = {
134
+ chainId: z
135
+ .optional(Schema.ChainId)
136
+ .check(z.describe('Chain id containing this activity. Returned for multi-Zone requests.'), z.meta({ examples: [421700001] })),
133
137
  perspective: z
134
138
  .enum(['incoming', 'outgoing'])
135
139
  .check(z.describe('Your role in the transaction: `outgoing` when you sent or paid for it, `incoming` when it happened to you (someone else initiated it). For a `transfer`, `data.direction` is the finer-grained token-flow view.')),
@@ -820,9 +824,7 @@ export var schema;
820
824
  data: z
821
825
  .object({
822
826
  logoUri: z.string().check(z.describe('New logo URL for the token.'), z.meta({
823
- examples: [
824
- 'https://api.tempo.xyz/data/4217/icons/0x20c0000000000000000000008f5425160ebe5525.svg',
825
- ],
827
+ examples: [Tokens.tokenExample.logoUri],
826
828
  })),
827
829
  signer: Signer,
828
830
  updater: Schema.Address.check(z.describe('Address that changed the logo.')),
@@ -1261,6 +1263,9 @@ export var schema;
1261
1263
  /** A folded access-key group: consecutive same-signer items on one UTC day. */
1262
1264
  schema.Group = z
1263
1265
  .object({
1266
+ chainId: z
1267
+ .optional(Schema.ChainId)
1268
+ .check(z.describe('Chain id containing this activity group. Returned for multi-Zone requests.'), z.meta({ examples: [421700001] })),
1264
1269
  data: z
1265
1270
  .object({
1266
1271
  items: z.array(schema.Item).check(z.describe('Activity items included in this group.')),
@@ -1288,12 +1293,12 @@ export var schema;
1288
1293
  schema.Entry = z
1289
1294
  .union([...schema.items, schema.Group])
1290
1295
  .check(z.describe('Either one activity item, or a grouped set of access-key activity items.'));
1291
- /** Optional token fields that require sources beyond RPC metadata. */
1296
+ /** Optional activity resources and selection modes. */
1292
1297
  schema.Include = z
1293
- .enum(tokenFields)
1294
- .check(z.describe('Additional token fields to include in activity responses.'));
1295
- /** Parses comma-separated optional token fields. */
1296
- schema.includeQuery = Schema.includeQuery(schema.Include, 'Comma-separated token fields to include, such as `token.logoUri,token.verified`.');
1298
+ .enum(includeFields)
1299
+ .check(z.describe('Additional activity resources and selection modes to include.'));
1300
+ /** Parses comma-separated optional activity resources and selection modes. */
1301
+ schema.includeQuery = Schema.includeQuery(schema.Include, 'Comma-separated activity options, such as `zones,token.logoUri,token.verified`.');
1297
1302
  /** Schemas for the getAddressActivities operation. */
1298
1303
  let getAddressActivities;
1299
1304
  (function (getAddressActivities) {
@@ -1368,6 +1373,7 @@ export var schema;
1368
1373
  */
1369
1374
  getTransactionActivities.Response = z
1370
1375
  .object({
1376
+ chainId: Schema.ChainId.check(z.describe('Chain id containing the transaction.'), z.meta({ examples: [4217] })),
1371
1377
  data: z.array(schema.Item).check(z.describe('Activity items classified from the transaction.')),
1372
1378
  meta: z
1373
1379
  .optional(schema.Meta)
@@ -1599,7 +1605,7 @@ export function addresses(options = {}) {
1599
1605
  summary: 'List address activities',
1600
1606
  tags: ['Activities'],
1601
1607
  }), Cache.response({
1602
- cacheControl: Cache.policies.feed,
1608
+ cacheControl: Cache.policies.noStore,
1603
1609
  name: 'tempo-api:addresses:v1',
1604
1610
  key: (c) => Cache.urlKey(c, schema.getAddressActivities.Query),
1605
1611
  }), async (c) => {
@@ -1617,39 +1623,71 @@ export function addresses(options = {}) {
1617
1623
  });
1618
1624
  const { address } = c.req.valid('param');
1619
1625
  const query = c.req.valid('query');
1620
- // Cursor pages can carry current valuations and curated verification data.
1621
- if (query.cursor !== undefined)
1622
- Cache.setPolicy(c, Cache.policies.metadata);
1626
+ if (!query.include.includes('zones'))
1627
+ Cache.setPolicy(c, query.cursor === undefined ? Cache.policies.feed : Cache.policies.metadata);
1623
1628
  try {
1624
1629
  const chainId = query.chainId ?? c.get('chainId');
1625
- const provider = tidx({ chainId, tidx: c.get('getTidx')(chainId) });
1626
- const { items: unenrichedItems, nextCursor } = await Timing.time(c, 'address_activities', () => Store.memoize(() => list(provider, {
1627
- address: address,
1628
- cursor: query.cursor,
1629
- group: query.group,
1630
- limit: query.limit,
1631
- logs: query.logs,
1632
- store: c.get('store'),
1633
- }), {
1634
- key: `activities:v1:${chainId}:${address.toLowerCase()}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
1635
- store: c.get('store'),
1636
- ttl: Ttl.seconds(15),
1637
- }));
1638
- // Build immutable token and structured amount copies from RPC metadata.
1639
- const { items, rates } = await enrichTokens(c, {
1640
- chainId,
1641
- denomination: query['valuation.currency'],
1642
- include: query.include,
1643
- items: unenrichedItems,
1644
- oracle,
1630
+ const listed = await Timing.time(c, 'address_activities', async () => {
1631
+ if (!query.include.includes('zones')) {
1632
+ const result = await Store.memoize(() => list(tidx({ chainId, tidx: c.get('getTidx')(chainId) }), {
1633
+ address: address,
1634
+ cursor: query.cursor,
1635
+ group: query.group,
1636
+ limit: query.limit,
1637
+ logs: query.logs,
1638
+ store: c.get('store'),
1639
+ }), {
1640
+ key: `activities:v1:${chainId}:${address.toLowerCase()}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
1641
+ store: c.get('store'),
1642
+ ttl: Ttl.seconds(15),
1643
+ });
1644
+ return { chainId, kind: 'chain', ...result };
1645
+ }
1646
+ const zoneChainIds = c.get('zoneChainIds');
1647
+ if (!zoneChainIds)
1648
+ throw new Error('Inferred Zone selection was not resolved.');
1649
+ const result = await Store.memoize(() => listZones({
1650
+ address: address,
1651
+ cursor: query.cursor,
1652
+ group: query.group,
1653
+ limit: query.limit,
1654
+ logs: query.logs,
1655
+ providers: zoneChainIds.map((zoneChainId) => ({
1656
+ chainId: zoneChainId,
1657
+ provider: tidx({
1658
+ chainId: zoneChainId,
1659
+ tidx: c.get('getTidx')(zoneChainId),
1660
+ }),
1661
+ })),
1662
+ store: c.get('store'),
1663
+ }), {
1664
+ key: `activities:zones:v1:${zoneChainIds.join(',')}:${address.toLowerCase()}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
1665
+ store: c.get('store'),
1666
+ ttl: Ttl.seconds(15),
1667
+ });
1668
+ return { kind: 'zones', ...result };
1645
1669
  });
1670
+ const { items, rates } = listed.kind === 'zones'
1671
+ ? await enrichZoneTokens(c, {
1672
+ denomination: query['valuation.currency'],
1673
+ include: query.include,
1674
+ items: listed.items,
1675
+ oracle,
1676
+ })
1677
+ : await enrichTokens(c, {
1678
+ chainId: listed.chainId,
1679
+ denomination: query['valuation.currency'],
1680
+ include: query.include,
1681
+ items: listed.items,
1682
+ oracle,
1683
+ });
1646
1684
  // Fold consecutive access-key-signed items into `group` entries only
1647
1685
  // when requested; otherwise every item is returned at the root.
1648
1686
  const data = query.group ? groupByAccessKey(items) : items;
1649
1687
  return c.json(Response.validated(schema.getAddressActivities.Response, {
1650
1688
  data,
1651
1689
  ...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
1652
- nextCursor,
1690
+ nextCursor: listed.nextCursor,
1653
1691
  }), 200);
1654
1692
  }
1655
1693
  catch (cause) {
@@ -1686,6 +1724,10 @@ export function transactions(options = {}) {
1686
1724
  description: 'No mined transaction was found for that hash.',
1687
1725
  codes: ['transaction_not_found'],
1688
1726
  },
1727
+ 409: {
1728
+ description: 'More than one readable Zone contains that transaction hash.',
1729
+ codes: ['transaction_ambiguous'],
1730
+ },
1689
1731
  502: 'Tempo could not read activity or token data from an upstream service.',
1690
1732
  },
1691
1733
  success: {
@@ -1716,36 +1758,107 @@ export function transactions(options = {}) {
1716
1758
  });
1717
1759
  const { transactionHash } = c.req.valid('param');
1718
1760
  const query = c.req.valid('query');
1719
- const chainId = query.chainId ?? c.get('chainId');
1720
1761
  try {
1721
- const unenrichedItems = await Timing.time(c, 'transaction_activities', () => Store.memoize(() => getTransactionActivities({
1722
- chainId,
1723
- logs: query.logs,
1724
- store: c.get('store'),
1725
- tidx: c.get('getTidx')(chainId),
1726
- transactionHash,
1727
- }), {
1728
- key: `activities:v1:${chainId}:tx:${transactionHash.toLowerCase()}:${query.logs ?? false}`,
1729
- store: c.get('store'),
1730
- ttl: Ttl.seconds(15),
1731
- }));
1732
- if (unenrichedItems === null)
1762
+ const result = await Timing.time(c, 'transaction_activities', async () => {
1763
+ const selected = await (async () => {
1764
+ if (!query.include.includes('zones'))
1765
+ return {
1766
+ chainId: query.chainId ?? c.get('chainId'),
1767
+ kind: 'selected',
1768
+ receipt: null,
1769
+ };
1770
+ const zoneChainIds = c.get('zoneChainIds');
1771
+ if (!zoneChainIds)
1772
+ throw new Error('Inferred Zone selection was not resolved.');
1773
+ // Cache only positive resolution. Missing transactions must remain
1774
+ // visible as soon as their Zone indexer catches up.
1775
+ const match = await Store.memoize(async () => {
1776
+ const probes = await Promise.all(zoneChainIds.map(async (chainId) => {
1777
+ try {
1778
+ return {
1779
+ chainId,
1780
+ value: await getTransactionReceipt({
1781
+ chainId,
1782
+ tidx: c.get('getTidx')(chainId),
1783
+ transactionHash,
1784
+ }),
1785
+ };
1786
+ }
1787
+ catch (cause) {
1788
+ return { cause, chainId };
1789
+ }
1790
+ }));
1791
+ return ZoneSelection.uniqueMatch(probes);
1792
+ }, {
1793
+ key: `activities:zones:v1:${zoneChainIds.join(',')}:tx:${transactionHash.toLowerCase()}`,
1794
+ shouldCache: (match) => match.kind === 'selected',
1795
+ store: c.get('store'),
1796
+ ttl: Ttl.seconds(15),
1797
+ });
1798
+ if (match.kind === 'failed') {
1799
+ c.set('providerFailures', match.failures.map(({ cause, chainId }) => ({
1800
+ ...Tidx.providerFailure(cause),
1801
+ chainId,
1802
+ })));
1803
+ throw match.failures[0].cause;
1804
+ }
1805
+ if (match.kind !== 'selected')
1806
+ return match;
1807
+ return { chainId: match.chainId, kind: 'selected', receipt: match.value };
1808
+ })();
1809
+ if (selected.kind !== 'selected')
1810
+ return selected;
1811
+ const { chainId } = selected;
1812
+ const unenrichedItems = await Store.memoize(() => selected.receipt === null
1813
+ ? getTransactionActivities({
1814
+ chainId,
1815
+ logs: query.logs,
1816
+ store: c.get('store'),
1817
+ tidx: c.get('getTidx')(chainId),
1818
+ transactionHash,
1819
+ })
1820
+ : classifyTransactionActivities({
1821
+ chainId,
1822
+ logs: query.logs,
1823
+ receipt: selected.receipt,
1824
+ store: c.get('store'),
1825
+ tidx: c.get('getTidx')(chainId),
1826
+ transactionHash,
1827
+ }), {
1828
+ key: `activities:v1:${chainId}:tx:${transactionHash.toLowerCase()}:${query.logs ?? false}`,
1829
+ store: c.get('store'),
1830
+ ttl: Ttl.seconds(15),
1831
+ });
1832
+ return unenrichedItems === null
1833
+ ? { kind: 'not_found' }
1834
+ : { chainId, items: unenrichedItems, kind: 'found' };
1835
+ });
1836
+ if (result.kind === 'not_found')
1733
1837
  return Response.error(c, {
1734
1838
  code: 'transaction_not_found',
1735
1839
  message: 'Transaction not found',
1736
1840
  status: 404,
1737
1841
  });
1842
+ if (result.kind === 'ambiguous')
1843
+ return Response.error(c, {
1844
+ code: 'transaction_ambiguous',
1845
+ message: 'Transaction hash matched more than one readable Zone',
1846
+ status: 409,
1847
+ });
1738
1848
  // Mined activity can carry current valuations and verification data.
1739
- Cache.setPolicy(c, Cache.policies.metadata);
1849
+ if (!query.include.includes('zones'))
1850
+ Cache.setPolicy(c, Cache.policies.metadata);
1851
+ c.set('chainId', result.chainId);
1740
1852
  // Build immutable token and structured amount copies from RPC metadata.
1741
1853
  const { items, rates } = await enrichTokens(c, {
1742
- chainId,
1854
+ chainId: result.chainId,
1743
1855
  denomination: query['valuation.currency'],
1744
1856
  include: query.include,
1745
- items: unenrichedItems,
1857
+ items: result.items,
1746
1858
  oracle,
1747
1859
  });
1748
1860
  return c.json(Response.validated(schema.getTransactionActivities.Response, {
1861
+ chainId: result.chainId,
1749
1862
  data: items,
1750
1863
  ...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
1751
1864
  }), 200);
@@ -1768,7 +1881,13 @@ export function transactions(options = {}) {
1768
1881
  * Items carry stub tokens; the caller enriches them via {@link enrichTokens}.
1769
1882
  */
1770
1883
  export async function getTransactionActivities(options) {
1771
- const { chainId, logs = false, tidx: tidxClient } = options;
1884
+ const receipt = await getTransactionReceipt(options);
1885
+ if (!receipt)
1886
+ return null;
1887
+ return classifyTransactionActivities({ ...options, receipt });
1888
+ }
1889
+ async function getTransactionReceipt(options) {
1890
+ const { chainId, tidx: tidxClient } = options;
1772
1891
  const hash = options.transactionHash.toLowerCase();
1773
1892
  // The `receipts` table is indexed by `tx_hash`, so this point lookup needs no
1774
1893
  // block bound; it also yields the block number the `logs` lookup requires.
@@ -1781,9 +1900,17 @@ export async function getTransactionActivities(options) {
1781
1900
  const receipt = receiptResult.rows[0];
1782
1901
  if (!receipt)
1783
1902
  return null;
1784
- const blockNum = Number(Value.toNumber(receipt['block_num']));
1785
- const feePayer = lowerOrNull(receipt['fee_payer']);
1786
- const txSender = lowerOrNull(receipt['from']);
1903
+ return {
1904
+ blockNum: Number(Value.toNumber(receipt['block_num'])),
1905
+ feePayer: lowerOrNull(receipt['fee_payer']),
1906
+ txSender: lowerOrNull(receipt['from']),
1907
+ };
1908
+ }
1909
+ async function classifyTransactionActivities(options) {
1910
+ const { chainId, logs = false, receipt, tidx: tidxClient } = options;
1911
+ const hash = options.transactionHash.toLowerCase();
1912
+ const { blockNum, feePayer, txSender } = receipt;
1913
+ const fingerprintMap_promise = Mpp.fingerprintMap({ store: options.store }).catch(() => ({}));
1787
1914
  // `logs` is sorted by block position, so a bare `tx_hash =` scans to genesis;
1788
1915
  // pair it with the receipt's block number (see `embedReceipts` in receipts.ts).
1789
1916
  const logsResult = await tidxClient.fetch({
@@ -1812,7 +1939,7 @@ export async function getTransactionActivities(options) {
1812
1939
  return [];
1813
1940
  // Best-effort MPP service directory: a fetch failure yields an empty map, so
1814
1941
  // enrichment never blocks classification.
1815
- const fingerprintMap = await Mpp.fingerprintMap({ store: options.store }).catch(() => ({}));
1942
+ const fingerprintMap = await fingerprintMap_promise;
1816
1943
  // Anchor the viewer on the transaction sender: the sender initiated every
1817
1944
  // activity in the transaction, so `perspective` is `outgoing` and `signer`
1818
1945
  // resolves to `self`. Fall back to the zero address when the sender is absent.
@@ -1823,15 +1950,15 @@ export async function getTransactionActivities(options) {
1823
1950
  /**
1824
1951
  * Lists classified activity for an address by running the shared pipeline
1825
1952
  * (`groupByTx` → `classifyGroup` → `enrichItem`) over rows from a
1826
- * {@link Provider}. Returns enriched, chain-tagged items plus the next cursor;
1827
- * callers run {@link groupByAccessKey} over the result.
1953
+ * {@link Provider}. Returns classified items plus the next cursor; callers run
1954
+ * {@link groupByAccessKey} over the result.
1828
1955
  */
1829
1956
  export async function list(provider, options) {
1830
1957
  const { address, cursor, group = false, limit = 20, logs = false } = options;
1831
1958
  const viewer = address.toLowerCase();
1832
1959
  // Best-effort MPP service directory: a fetch failure yields an empty map, so
1833
1960
  // enrichment never blocks the feed.
1834
- const fingerprintMap = await Mpp.fingerprintMap({ store: options.store }).catch(() => ({}));
1961
+ const fingerprintMap_promise = Mpp.fingerprintMap({ store: options.store }).catch(() => ({}));
1835
1962
  let currentCursor = cursor;
1836
1963
  const allItems = [];
1837
1964
  let hasMore = false;
@@ -1846,6 +1973,7 @@ export async function list(provider, options) {
1846
1973
  const txGroups = grouped.slice(0, limit + 1);
1847
1974
  hasMore = txGroups.length > limit;
1848
1975
  const page = txGroups.slice(0, limit);
1976
+ const fingerprintMap = await fingerprintMap_promise;
1849
1977
  if (page.length === 0)
1850
1978
  break;
1851
1979
  allItems.push(...page.flatMap((txGroup) => classifyGroup(txGroup, viewer, fingerprintMap, logs).map(withTitle)));
@@ -1865,6 +1993,117 @@ export async function list(provider, options) {
1865
1993
  // public token references and structured amounts via {@link enrichTokens}.
1866
1994
  return { items: allItems, nextCursor };
1867
1995
  }
1996
+ const zoneCursorVersion = 1;
1997
+ /**
1998
+ * Lists address activity across multiple Zones in one stable timestamp-ordered
1999
+ * feed. Its opaque cursor retains each Zone provider's native continuation.
2000
+ */
2001
+ export async function listZones(options) {
2002
+ const { address, cursor, limit = 20, logs = false, providers, store } = options;
2003
+ const group = options.group ?? false;
2004
+ const orderedProviders = [...providers].sort((a, b) => a.chainId - b.chainId);
2005
+ const chainIds = orderedProviders.map(({ chainId }) => chainId);
2006
+ const cursors = decodeZoneCursor(cursor, chainIds);
2007
+ const viewer = address.toLowerCase();
2008
+ const fingerprintMap_promise = Mpp.fingerprintMap({ store }).catch(() => ({}));
2009
+ const states = orderedProviders.map(({ chainId, provider }) => ({
2010
+ chainId,
2011
+ exhausted: false,
2012
+ groups: [],
2013
+ provider,
2014
+ }));
2015
+ const allItems = [];
2016
+ let hasMore = false;
2017
+ for (let attempt = 0; attempt < 3; attempt++) {
2018
+ await Promise.all(states.map(async (state) => {
2019
+ if (state.exhausted || state.groups.length > 0)
2020
+ return;
2021
+ const { rows } = await state.provider.fetchRows({
2022
+ address: viewer,
2023
+ cursor: cursors.get(state.chainId),
2024
+ limit,
2025
+ });
2026
+ const groups = groupByTx(rows).slice(0, limit + 1);
2027
+ state.exhausted = groups.length <= limit;
2028
+ state.groups.push(...groups);
2029
+ }));
2030
+ const candidates = states
2031
+ .flatMap((state) => state.groups.map((txGroup) => ({ state, txGroup })))
2032
+ .sort((a, b) => {
2033
+ if (a.txGroup.blockTimestamp !== b.txGroup.blockTimestamp)
2034
+ return b.txGroup.blockTimestamp - a.txGroup.blockTimestamp;
2035
+ if (a.state.chainId !== b.state.chainId)
2036
+ return a.state.chainId - b.state.chainId;
2037
+ if (a.txGroup.blockNum !== b.txGroup.blockNum)
2038
+ return b.txGroup.blockNum - a.txGroup.blockNum;
2039
+ return b.txGroup.txIdx - a.txGroup.txIdx;
2040
+ });
2041
+ const page = candidates.slice(0, limit);
2042
+ const fingerprintMap = await fingerprintMap_promise;
2043
+ if (page.length === 0)
2044
+ break;
2045
+ for (const { state, txGroup } of page) {
2046
+ state.groups.splice(state.groups.indexOf(txGroup), 1);
2047
+ cursors.set(state.chainId, state.provider.cursorForGroup(txGroup));
2048
+ allItems.push(...classifyGroup(txGroup, viewer, fingerprintMap, logs).map((item) => ({
2049
+ ...withTitle(item),
2050
+ chainId: state.chainId,
2051
+ })));
2052
+ }
2053
+ hasMore = states.some((state) => !state.exhausted || state.groups.length > 0);
2054
+ const enough = group
2055
+ ? groupByAccessKeyItems(allItems).length >= minGroupEntries
2056
+ : allItems.length >= limit;
2057
+ if (enough || !hasMore)
2058
+ break;
2059
+ }
2060
+ // A consumed sentinel proves only that the provider may have more rows.
2061
+ // Probe drained buffers so `nextCursor` remains the end-of-list signal.
2062
+ await Promise.all(states.map(async (state) => {
2063
+ if (state.exhausted || state.groups.length > 0)
2064
+ return;
2065
+ const { rows } = await state.provider.fetchRows({
2066
+ address: viewer,
2067
+ cursor: cursors.get(state.chainId),
2068
+ limit: 1,
2069
+ });
2070
+ const group = groupByTx(rows)[0];
2071
+ if (group)
2072
+ state.groups.push(group);
2073
+ else
2074
+ state.exhausted = true;
2075
+ }));
2076
+ hasMore = states.some((state) => !state.exhausted || state.groups.length > 0);
2077
+ return {
2078
+ items: allItems,
2079
+ nextCursor: hasMore ? encodeZoneCursor(cursors, chainIds) : null,
2080
+ };
2081
+ }
2082
+ function decodeZoneCursor(cursor, chainIds) {
2083
+ const fields = ['int'];
2084
+ for (const _chainId of chainIds)
2085
+ fields.push('int', 'id');
2086
+ const decoded = cursor ? Cursor.decode(cursor, fields) : undefined;
2087
+ const cursors = new Map();
2088
+ if (!decoded || decoded[0] !== zoneCursorVersion)
2089
+ return cursors;
2090
+ for (let index = 0; index < chainIds.length; index++) {
2091
+ const chainId = chainIds[index];
2092
+ const offset = index * 2 + 1;
2093
+ if (decoded[offset] !== chainId)
2094
+ return new Map();
2095
+ const value = decoded[offset + 1];
2096
+ if (value !== 'head')
2097
+ cursors.set(chainId, value);
2098
+ }
2099
+ return cursors;
2100
+ }
2101
+ function encodeZoneCursor(cursors, chainIds) {
2102
+ return Cursor.encode([
2103
+ zoneCursorVersion,
2104
+ ...chainIds.flatMap((chainId) => [chainId, cursors.get(chainId) ?? 'head']),
2105
+ ]);
2106
+ }
1868
2107
  /**
1869
2108
  * Creates a TIDX-backed {@link Provider} that runs three sub-queries in
1870
2109
  * parallel and merges them:
@@ -2174,28 +2413,44 @@ function classifyGroup(group, viewer, fingerprintMap, includeLogs = false) {
2174
2413
  }
2175
2414
  /** Classifies a Q1 (log-bearing) group via `parseEventLogs`. */
2176
2415
  function classifyFromLogs(rows, ctx) {
2177
- const items = classifyFromLogsCore(rows, ctx);
2416
+ const decoded = decodeRows(rows);
2417
+ const items = (() => {
2418
+ try {
2419
+ return classifyFromLogsCore(rows, ctx, decoded);
2420
+ }
2421
+ catch {
2422
+ // Indexed logs can match a known signature without satisfying that event's expected shape.
2423
+ return [
2424
+ unknown(ctx.itemBase(Math.min(...rows.map((row) => row.logIdx))), {
2425
+ events: buildTxEvents(rows, decoded),
2426
+ signer: signerForRows(rows, { fallback: ctx.signer, viewer: ctx.viewer }),
2427
+ }),
2428
+ ];
2429
+ }
2430
+ })();
2178
2431
  // When the caller requested raw logs, attach the full per-transaction log set
2179
2432
  // (decoded when possible) to every classified item so no co-located log is
2180
2433
  // hidden behind the headline. `unknown` items already carry it.
2181
2434
  if (!ctx.includeLogs)
2182
2435
  return items;
2183
- const events = buildTxEvents(rows, decodeRows(rows));
2436
+ const events = buildTxEvents(rows, decoded);
2184
2437
  return items.map((item) => (item.type === 'unknown' ? item : { ...item, events }));
2185
2438
  }
2186
- /** Classifies a Q1 (log-bearing) group via `parseEventLogs`, picking one headline item. */
2187
- function classifyFromLogsCore(rows, ctx) {
2188
- const { blockNum, fingerprintMap, itemBase, viewer } = ctx;
2189
- // An access-key-signed tx emits AccessKeySpend at the accountKeychain; topic2
2190
- // is the access-key publicKey. Use it as the signer so successive access-key
2191
- // actions group together.
2192
- const accessKeySpendRow = rows.find((r) => r.selector === accessKeySpendSelector &&
2193
- Address.isEqual(r.logAddress, Addresses.accountKeychain));
2439
+ /** Resolves an access-key signer from raw rows, falling back to the transaction signer. */
2440
+ function signerForRows(rows, options) {
2441
+ const accessKeySpendRow = rows.find((row) => row.selector === accessKeySpendSelector &&
2442
+ Address.isEqual(row.logAddress, Addresses.accountKeychain));
2194
2443
  const accessKeySigner = accessKeySpendRow?.topic2
2195
2444
  ? `0x${accessKeySpendRow.topic2.slice(-40)}`.toLowerCase()
2196
2445
  : null;
2197
- const signer = accessKeySigner && !Address.isEqual(accessKeySigner, viewer) ? accessKeySigner : ctx.signer;
2198
- const events = decodeRows(rows);
2446
+ return accessKeySigner && !Address.isEqual(accessKeySigner, options.viewer)
2447
+ ? accessKeySigner
2448
+ : options.fallback;
2449
+ }
2450
+ /** Classifies a Q1 (log-bearing) group via `parseEventLogs`, picking one headline item. */
2451
+ function classifyFromLogsCore(rows, ctx, events = decodeRows(rows)) {
2452
+ const { blockNum, fingerprintMap, itemBase, viewer } = ctx;
2453
+ const signer = signerForRows(rows, { fallback: ctx.signer, viewer });
2199
2454
  const minLogIndex = Math.min(...rows.map((r) => r.logIdx));
2200
2455
  // Payment-channel settlement: a CloseRequested topic plus an optional refund
2201
2456
  // transfer back to the viewer.
@@ -2564,6 +2819,11 @@ function classifyFromLogsCore(rows, ctx) {
2564
2819
  }
2565
2820
  // Approval (excluding zone-outbox spenders).
2566
2821
  const approvalEvent = finalEvents.find((e) => e.eventName === 'Approval' &&
2822
+ // ERC-721 uses the same selector but indexes its token ID as topic3. In
2823
+ // non-strict mode viem otherwise decodes the missing ERC-20 amount as zero.
2824
+ rows.some((row) => row.logIdx === e.logIndex &&
2825
+ row.topic3 === null &&
2826
+ /^0x[0-9a-fA-F]{64}$/.test(row.data ?? '')) &&
2567
2827
  !Address.isEqual(e.args.spender, Addresses.zoneOutbox));
2568
2828
  if (approvalEvent) {
2569
2829
  const args = approvalEvent.args;
@@ -3433,21 +3693,28 @@ function unknown(base, data) {
3433
3693
  }
3434
3694
  /** Decodes a group's raw rows into `viem/tempo` events via `parseEventLogs` (non-strict). */
3435
3695
  function decodeRows(rows) {
3436
- const viemLogs = rows.map((r) => ({
3437
- address: r.logAddress,
3438
- blockHash: '0x0',
3439
- blockNumber: BigInt(r.blockNum),
3440
- data: (r.data ?? '0x'),
3441
- logIndex: r.logIdx,
3442
- removed: false,
3443
- topics: [r.selector, r.topic1, r.topic2, r.topic3].filter(Boolean),
3444
- transactionHash: r.txHash,
3445
- transactionIndex: r.txIdx,
3446
- }));
3447
- return parseEventLogs({
3448
- abi: [...Abis.abis, ...Abis.earnRouter, ...Abis.earnVault],
3449
- logs: viemLogs,
3450
- strict: false,
3696
+ return rows.flatMap((r) => {
3697
+ const log = {
3698
+ address: r.logAddress,
3699
+ blockHash: '0x0',
3700
+ blockNumber: BigInt(r.blockNum),
3701
+ data: (r.data ?? '0x'),
3702
+ logIndex: r.logIdx,
3703
+ removed: false,
3704
+ topics: [r.selector, r.topic1, r.topic2, r.topic3].filter(Boolean),
3705
+ transactionHash: r.txHash,
3706
+ transactionIndex: r.txIdx,
3707
+ };
3708
+ try {
3709
+ return parseEventLogs({
3710
+ abi: [...Abis.abis, ...Abis.earnRouter, ...Abis.earnVault],
3711
+ logs: [log],
3712
+ strict: false,
3713
+ });
3714
+ }
3715
+ catch {
3716
+ return [];
3717
+ }
3451
3718
  });
3452
3719
  }
3453
3720
  /**
@@ -3550,12 +3817,26 @@ async function enrichTokens(c, options) {
3550
3817
  collectTokens(item, addresses);
3551
3818
  const includeLogoUri = include.includes('token.logoUri');
3552
3819
  const includeVerified = include.includes('token.verified');
3553
- // Curated data is needed only for requested valuation or token fields.
3554
- const snapshot = addresses.size > 0 && (denomination !== undefined || includeLogoUri || includeVerified)
3555
- ? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
3820
+ const resolved_promise = addresses.size > 0
3821
+ ? Timing.time(c, 'tokens', () => Promise.all([...addresses].map(async (address) => {
3822
+ const [logoUri, metadata] = await Promise.all([
3823
+ includeLogoUri
3824
+ ? Tokens.getTokenLogo(c, { address, chainId }).catch(() => undefined)
3825
+ : undefined,
3826
+ getActivityTokenMetadata(c, { address, chainId }),
3827
+ ]);
3828
+ return { address: address.toLowerCase(), logoUri, metadata };
3829
+ })))
3556
3830
  : undefined;
3557
- const rates = denomination
3558
- ? await Valuation.ratesFor(c, {
3831
+ // Curated data is needed only for requested valuation or token fields.
3832
+ const snapshot_promise = addresses.size > 0 && (denomination !== undefined || includeLogoUri || includeVerified)
3833
+ ? VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
3834
+ : Promise.resolve(undefined);
3835
+ const rates_promise = (async () => {
3836
+ if (!denomination)
3837
+ return undefined;
3838
+ const snapshot = await snapshot_promise;
3839
+ return Valuation.ratesFor(c, {
3559
3840
  currencies: snapshot
3560
3841
  ? [...addresses].flatMap((address) => {
3561
3842
  const held = snapshot.byAddress.get(address)?.currency;
@@ -3564,37 +3845,63 @@ async function enrichTokens(c, options) {
3564
3845
  : [],
3565
3846
  denomination,
3566
3847
  oracle,
3567
- })
3568
- : undefined;
3569
- if (addresses.size === 0)
3570
- return { items: items, rates };
3571
- const resolved = await Timing.time(c, 'tokens', () => Promise.all([...addresses].map(async (address) => {
3572
- const [logoUri, metadata] = await Promise.all([
3573
- includeLogoUri
3574
- ? Tokens.getTokenLogo(c, { address, chainId }).catch(() => undefined)
3848
+ });
3849
+ })();
3850
+ if (!resolved_promise)
3851
+ return { items: items, rates: await rates_promise };
3852
+ const [resolved_raw, rates, snapshot] = await Promise.all([
3853
+ resolved_promise,
3854
+ rates_promise,
3855
+ snapshot_promise,
3856
+ ]);
3857
+ const resolved = resolved_raw.map(({ address, logoUri, metadata }) => [
3858
+ address,
3859
+ {
3860
+ currency: metadata.currency,
3861
+ decimals: metadata.decimals,
3862
+ logoUri: includeLogoUri
3863
+ ? (logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri)
3575
3864
  : undefined,
3576
- getActivityTokenMetadata(c, { address, chainId }),
3577
- ]);
3578
- return [
3579
- address.toLowerCase(),
3580
- {
3581
- currency: metadata.currency,
3582
- decimals: metadata.decimals,
3583
- logoUri: includeLogoUri
3584
- ? (logoUri ?? snapshot?.byAddress.get(address)?.logoUri ?? metadata.logoUri)
3585
- : undefined,
3586
- name: metadata.name,
3587
- symbol: metadata.symbol,
3588
- verified: includeVerified && snapshot ? snapshot.byAddress.has(address) : undefined,
3589
- },
3590
- ];
3591
- })));
3865
+ name: metadata.name,
3866
+ symbol: metadata.symbol,
3867
+ verified: includeVerified && snapshot ? snapshot.byAddress.has(address) : undefined,
3868
+ },
3869
+ ]);
3592
3870
  const byAddress = new Map(resolved);
3593
3871
  return {
3594
3872
  items: items.map((item) => enrichItem(item, byAddress, { denomination, rates, snapshot })),
3595
3873
  rates,
3596
3874
  };
3597
3875
  }
3876
+ /** Resolves token metadata on each item's source Zone without changing feed order. */
3877
+ async function enrichZoneTokens(c, options) {
3878
+ const byChain = new Map();
3879
+ for (const item of options.items) {
3880
+ const items = byChain.get(item.chainId) ?? [];
3881
+ items.push(item);
3882
+ byChain.set(item.chainId, items);
3883
+ }
3884
+ const results = await Promise.all([...byChain].map(async ([chainId, items]) => ({
3885
+ chainId,
3886
+ ...(await enrichTokens(c, {
3887
+ chainId,
3888
+ denomination: options.denomination,
3889
+ include: options.include,
3890
+ items,
3891
+ oracle: options.oracle,
3892
+ })),
3893
+ })));
3894
+ const buckets = new Map();
3895
+ for (const result of results)
3896
+ buckets.set(result.chainId, { index: 0, items: result.items });
3897
+ return {
3898
+ items: options.items.map((item) => {
3899
+ const bucket = buckets.get(item.chainId);
3900
+ return bucket.items[bucket.index++];
3901
+ }),
3902
+ rates: results.find((result) => result.rates !== undefined)?.rates,
3903
+ };
3904
+ }
3598
3905
  /** Returns an enriched copy of an item without mutating its cached token stubs. */
3599
3906
  function enrichItem(item, byAddress, valuation) {
3600
3907
  const source = item.data;
@@ -3652,6 +3959,7 @@ function groupByAccessKeyItems(items) {
3652
3959
  const itemSigner = signerOf(item);
3653
3960
  if (itemSigner !== 'self') {
3654
3961
  if (currentGroup &&
3962
+ currentGroup.items[0].chainId === item.chainId &&
3655
3963
  Address.isEqual(currentGroup.signer, itemSigner) &&
3656
3964
  sameCalendarDay(currentGroup.items[0].timestamp, item.timestamp)) {
3657
3965
  currentGroup.items.push(item);
@@ -3689,6 +3997,7 @@ function flushGroup(group) {
3689
3997
  const firstItem = group.items[0];
3690
3998
  const lastItem = group.items[group.items.length - 1];
3691
3999
  return {
4000
+ ...(firstItem.chainId === undefined ? {} : { chainId: firstItem.chainId }),
3692
4001
  data: { items: group.items, signer: group.signer },
3693
4002
  perspective: firstItem.perspective,
3694
4003
  id: `${firstItem.id}..${lastItem.id}:${group.items.length}`,