tapimo 0.19.0 → 0.20.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 (494) hide show
  1. package/README.md +13 -5
  2. package/dist/ApiKey.d.ts +2 -2
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +2 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +85 -11
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +218 -56
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +12543 -13912
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +4 -5
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +12 -20
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +20 -36
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +871 -828
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +14 -26
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +93 -186
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +3 -5
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/audit-logs.d.ts +18 -18
  27. package/dist/admin/apps/audit-logs.js +1 -1
  28. package/dist/admin/apps/audit-logs.js.map +1 -1
  29. package/dist/admin/apps/earn-vaults.d.ts +27 -27
  30. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  31. package/dist/admin/apps/earn-vaults.js +11 -5
  32. package/dist/admin/apps/earn-vaults.js.map +1 -1
  33. package/dist/admin/apps/organizations.d.ts +17 -17
  34. package/dist/admin/apps/prop-amms.d.ts +4 -4
  35. package/dist/admin/apps/routes-support.js +1 -38
  36. package/dist/admin/apps/routes-support.js.map +1 -1
  37. package/dist/admin/apps/routes.d.ts +153 -153
  38. package/dist/admin/apps/sentinel.d.ts +4 -4
  39. package/dist/admin/apps/verified-tokens.d.ts +24 -24
  40. package/dist/admin/apps/zone-delegation-requests.d.ts +332 -0
  41. package/dist/admin/apps/zone-delegation-requests.d.ts.map +1 -0
  42. package/dist/admin/apps/zone-delegation-requests.js +200 -0
  43. package/dist/admin/apps/zone-delegation-requests.js.map +1 -0
  44. package/dist/admin/apps/zone-delegations.d.ts +512 -52
  45. package/dist/admin/apps/zone-delegations.d.ts.map +1 -1
  46. package/dist/admin/apps/zone-delegations.js +134 -44
  47. package/dist/admin/apps/zone-delegations.js.map +1 -1
  48. package/dist/admin/index.d.ts +1 -1
  49. package/dist/admin/index.d.ts.map +1 -1
  50. package/dist/admin/index.js +1 -1
  51. package/dist/admin/index.js.map +1 -1
  52. package/dist/admin/ui.generated.d.ts +1 -1
  53. package/dist/admin/ui.generated.d.ts.map +1 -1
  54. package/dist/admin/ui.generated.js +341 -397
  55. package/dist/admin/ui.generated.js.map +1 -1
  56. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  57. package/dist/analytics/tables/requestEvents.js +4 -2
  58. package/dist/analytics/tables/requestEvents.js.map +1 -1
  59. package/dist/apps/data/App.d.ts +11932 -13214
  60. package/dist/apps/data/App.d.ts.map +1 -1
  61. package/dist/apps/data/App.js +32 -13
  62. package/dist/apps/data/App.js.map +1 -1
  63. package/dist/apps/data/ZoneSelection.d.ts +1 -1
  64. package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
  65. package/dist/apps/data/ZoneSelection.js +2 -2
  66. package/dist/apps/data/ZoneSelection.js.map +1 -1
  67. package/dist/apps/data/routes/activities.d.ts +60 -27
  68. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  69. package/dist/apps/data/routes/activities.js +91 -16
  70. package/dist/apps/data/routes/activities.js.map +1 -1
  71. package/dist/apps/data/routes/addresses.d.ts +893 -875
  72. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  73. package/dist/apps/data/routes/balances.d.ts +36 -36
  74. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  75. package/dist/apps/data/routes/balances.js +3 -1
  76. package/dist/apps/data/routes/balances.js.map +1 -1
  77. package/dist/apps/data/routes/blocks.d.ts +40 -40
  78. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  79. package/dist/apps/data/routes/blocks.js +3 -7
  80. package/dist/apps/data/routes/blocks.js.map +1 -1
  81. package/dist/apps/data/routes/coingecko.d.ts +236 -236
  82. package/dist/apps/data/routes/earn-transactions.d.ts +14 -14
  83. package/dist/apps/data/routes/earn.d.ts +261 -1445
  84. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  85. package/dist/apps/data/routes/earn.js +64 -490
  86. package/dist/apps/data/routes/earn.js.map +1 -1
  87. package/dist/apps/data/routes/exchanges.d.ts +144 -144
  88. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  89. package/dist/apps/data/routes/exchanges.js +5 -15
  90. package/dist/apps/data/routes/exchanges.js.map +1 -1
  91. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  92. package/dist/apps/data/routes/fee-amm.js +3 -9
  93. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  94. package/dist/apps/data/routes/indexer.d.ts +13 -13
  95. package/dist/apps/data/routes/receipts.d.ts +53 -53
  96. package/dist/apps/data/routes/receipts.js +1 -1
  97. package/dist/apps/data/routes/receipts.js.map +1 -1
  98. package/dist/apps/data/routes/rpc.d.ts +52 -0
  99. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  100. package/dist/apps/data/routes/rpc.js +19 -18
  101. package/dist/apps/data/routes/rpc.js.map +1 -1
  102. package/dist/apps/data/routes/tokenlist.d.ts +14 -14
  103. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  104. package/dist/apps/data/routes/tokenlist.js +1 -3
  105. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  106. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  107. package/dist/apps/data/routes/tokens.js +7 -5
  108. package/dist/apps/data/routes/tokens.js.map +1 -1
  109. package/dist/apps/data/routes/transactions.d.ts +281 -281
  110. package/dist/apps/data/routes/transactions.js +3 -3
  111. package/dist/apps/data/routes/transactions.js.map +1 -1
  112. package/dist/apps/data/routes/transfers.d.ts +12 -12
  113. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  114. package/dist/apps/data/routes/transfers.js +1 -3
  115. package/dist/apps/data/routes/transfers.js.map +1 -1
  116. package/dist/apps/data/routes/valuation.d.ts +30 -30
  117. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  118. package/dist/apps/data/routes/valuation.js +1 -3
  119. package/dist/apps/data/routes/valuation.js.map +1 -1
  120. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  121. package/dist/apps/data/routes/webhooks.d.ts +102 -102
  122. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  123. package/dist/apps/data/routes/webhooks.js +9 -23
  124. package/dist/apps/data/routes/webhooks.js.map +1 -1
  125. package/dist/apps/data/routes/zone-deposits.d.ts +16 -16
  126. package/dist/apps/data/routes/zone-withdrawals.d.ts +31 -31
  127. package/dist/apps/data/routes/zones.d.ts +28 -28
  128. package/dist/apps/management/App.d.ts +18 -102
  129. package/dist/apps/management/App.d.ts.map +1 -1
  130. package/dist/apps/management/App.js +1 -1
  131. package/dist/apps/management/App.js.map +1 -1
  132. package/dist/apps/management/routes/api-keys.d.ts +253 -339
  133. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  134. package/dist/apps/management/routes/api-keys.js +25 -11
  135. package/dist/apps/management/routes/api-keys.js.map +1 -1
  136. package/dist/apps/management/routes/billing.d.ts +92 -92
  137. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  138. package/dist/apps/management/routes/billing.js +5 -13
  139. package/dist/apps/management/routes/billing.js.map +1 -1
  140. package/dist/apps/management/routes/cli.d.ts.map +1 -1
  141. package/dist/apps/management/routes/cli.js +3 -9
  142. package/dist/apps/management/routes/cli.js.map +1 -1
  143. package/dist/apps/management/routes/faucet.d.ts +16 -16
  144. package/dist/apps/management/routes/fee-payer-usage.d.ts +38 -38
  145. package/dist/apps/management/routes/fee-payer-usage.d.ts.map +1 -1
  146. package/dist/apps/management/routes/fee-payer-usage.js +2 -4
  147. package/dist/apps/management/routes/fee-payer-usage.js.map +1 -1
  148. package/dist/apps/management/routes/invitations.d.ts +52 -52
  149. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  150. package/dist/apps/management/routes/invitations.js +4 -12
  151. package/dist/apps/management/routes/invitations.js.map +1 -1
  152. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  153. package/dist/apps/management/routes/invite-links.js +6 -14
  154. package/dist/apps/management/routes/invite-links.js.map +1 -1
  155. package/dist/apps/management/routes/me.d.ts +6 -6
  156. package/dist/apps/management/routes/me.d.ts.map +1 -1
  157. package/dist/apps/management/routes/me.js +3 -7
  158. package/dist/apps/management/routes/me.js.map +1 -1
  159. package/dist/apps/management/routes/members.d.ts +84 -84
  160. package/dist/apps/management/routes/members.d.ts.map +1 -1
  161. package/dist/apps/management/routes/members.js +2 -4
  162. package/dist/apps/management/routes/members.js.map +1 -1
  163. package/dist/apps/management/routes/orgs.d.ts +44 -44
  164. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  165. package/dist/apps/management/routes/orgs.js +2 -6
  166. package/dist/apps/management/routes/orgs.js.map +1 -1
  167. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  168. package/dist/apps/management/routes/projects.js +2 -6
  169. package/dist/apps/management/routes/projects.js.map +1 -1
  170. package/dist/apps/management/routes/route-usage.d.ts +34 -34
  171. package/dist/apps/management/routes/route-usage.d.ts.map +1 -1
  172. package/dist/apps/management/routes/route-usage.js +2 -4
  173. package/dist/apps/management/routes/route-usage.js.map +1 -1
  174. package/dist/apps/management/routes/routes-access-requests.d.ts +120 -91
  175. package/dist/apps/management/routes/routes-access-requests.d.ts.map +1 -1
  176. package/dist/apps/management/routes/routes-access-requests.js +49 -9
  177. package/dist/apps/management/routes/routes-access-requests.js.map +1 -1
  178. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  179. package/dist/apps/management/routes/usage.js +8 -16
  180. package/dist/apps/management/routes/usage.js.map +1 -1
  181. package/dist/apps/management/routes/verified-token-requests.d.ts +39 -39
  182. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
  183. package/dist/apps/management/routes/verified-token-requests.js +3 -7
  184. package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
  185. package/dist/apps/management/routes/webhooks.d.ts +2089 -2089
  186. package/dist/apps/management/routes/zone-delegations.d.ts +14 -17
  187. package/dist/apps/management/routes/zone-delegations.d.ts.map +1 -1
  188. package/dist/apps/management/routes/zone-delegations.js +1 -6
  189. package/dist/apps/management/routes/zone-delegations.js.map +1 -1
  190. package/dist/apps/mpp/App.d.ts +44 -44
  191. package/dist/apps/mpp/App.js +3 -3
  192. package/dist/apps/mpp/App.js.map +1 -1
  193. package/dist/apps/mpp/internal/Adapter.js +1 -1
  194. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  195. package/dist/apps/mpp/internal/Error.d.ts.map +1 -1
  196. package/dist/apps/mpp/internal/Error.js +1 -0
  197. package/dist/apps/mpp/internal/Error.js.map +1 -1
  198. package/dist/apps/mpp/internal/Policy.d.ts +5 -1
  199. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  200. package/dist/apps/mpp/internal/Policy.js +35 -13
  201. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  202. package/dist/apps/relay/App.d.ts +2 -2
  203. package/dist/apps/relay/App.d.ts.map +1 -1
  204. package/dist/apps/relay/App.js +25 -16
  205. package/dist/apps/relay/App.js.map +1 -1
  206. package/dist/apps/routes/App.d.ts +311 -311
  207. package/dist/apps/routes/routes/deposit-addresses.d.ts +1099 -1099
  208. package/dist/apps/routes/routes/list.d.ts +74 -74
  209. package/dist/apps/routes/routes/transfers.d.ts +94 -94
  210. package/dist/cli/ApiKeys.d.ts +19 -26
  211. package/dist/cli/ApiKeys.d.ts.map +1 -1
  212. package/dist/db/Db.d.ts +3 -3
  213. package/dist/db/Db.d.ts.map +1 -1
  214. package/dist/db/Db.js +27 -0
  215. package/dist/db/Db.js.map +1 -1
  216. package/dist/db/Schema.d.ts +28 -62
  217. package/dist/db/Schema.d.ts.map +1 -1
  218. package/dist/db/Schema.js +18 -18
  219. package/dist/db/Schema.js.map +1 -1
  220. package/dist/db/tables/rewardRuns.d.ts +21 -0
  221. package/dist/db/tables/rewardRuns.d.ts.map +1 -1
  222. package/dist/db/tables/rewardRuns.js +19 -0
  223. package/dist/db/tables/rewardRuns.js.map +1 -1
  224. package/dist/db/tables/routesAccessRequests.d.ts +13 -0
  225. package/dist/db/tables/routesAccessRequests.d.ts.map +1 -1
  226. package/dist/db/tables/routesAccessRequests.js +12 -0
  227. package/dist/db/tables/routesAccessRequests.js.map +1 -1
  228. package/dist/db/tables/zoneDelegationRequests.d.ts +165 -0
  229. package/dist/db/tables/zoneDelegationRequests.d.ts.map +1 -0
  230. package/dist/db/tables/{zoneKeyRequests.js → zoneDelegationRequests.js} +43 -42
  231. package/dist/db/tables/zoneDelegationRequests.js.map +1 -0
  232. package/dist/db/tables/zoneDelegations.d.ts +11 -5
  233. package/dist/db/tables/zoneDelegations.d.ts.map +1 -1
  234. package/dist/db/tables/zoneDelegations.js +21 -3
  235. package/dist/db/tables/zoneDelegations.js.map +1 -1
  236. package/dist/handlers/internal/accounts.d.ts +7 -0
  237. package/dist/handlers/internal/accounts.d.ts.map +1 -0
  238. package/dist/handlers/internal/{multisig.js → accounts.js} +10 -10
  239. package/dist/handlers/internal/{multisig.js.map → accounts.js.map} +1 -1
  240. package/dist/handlers/internal/sponsorship.js +17 -17
  241. package/dist/handlers/internal/sponsorship.js.map +1 -1
  242. package/dist/handlers/relay.d.ts +6 -6
  243. package/dist/handlers/relay.d.ts.map +1 -1
  244. package/dist/handlers/relay.js +15 -15
  245. package/dist/handlers/relay.js.map +1 -1
  246. package/dist/internal/Auth.d.ts.map +1 -1
  247. package/dist/internal/Auth.js +4 -8
  248. package/dist/internal/Auth.js.map +1 -1
  249. package/dist/internal/EarnRates.d.ts.map +1 -1
  250. package/dist/internal/EarnRates.js +1 -3
  251. package/dist/internal/EarnRates.js.map +1 -1
  252. package/dist/internal/EarnVaults.js +2 -2
  253. package/dist/internal/Log.d.ts +2 -4
  254. package/dist/internal/Log.d.ts.map +1 -1
  255. package/dist/internal/Log.js +0 -3
  256. package/dist/internal/Log.js.map +1 -1
  257. package/dist/internal/Response.d.ts +1 -1
  258. package/dist/internal/Response.d.ts.map +1 -1
  259. package/dist/internal/Response.js +0 -3
  260. package/dist/internal/Response.js.map +1 -1
  261. package/dist/internal/Schema.d.ts +11 -0
  262. package/dist/internal/Schema.d.ts.map +1 -1
  263. package/dist/internal/Schema.js +24 -1
  264. package/dist/internal/Schema.js.map +1 -1
  265. package/dist/internal/ZoneAccess.d.ts +70 -35
  266. package/dist/internal/ZoneAccess.d.ts.map +1 -1
  267. package/dist/internal/ZoneAccess.js +312 -131
  268. package/dist/internal/ZoneAccess.js.map +1 -1
  269. package/dist/internal/ZoneDelegation.d.ts +7 -19
  270. package/dist/internal/ZoneDelegation.d.ts.map +1 -1
  271. package/dist/internal/ZoneDelegation.js +8 -29
  272. package/dist/internal/ZoneDelegation.js.map +1 -1
  273. package/dist/internal/{ZoneKeyApproval.d.ts → ZoneDelegationApproval.d.ts} +3 -5
  274. package/dist/internal/ZoneDelegationApproval.d.ts.map +1 -0
  275. package/dist/internal/ZoneDelegationApproval.js +16 -0
  276. package/dist/internal/ZoneDelegationApproval.js.map +1 -0
  277. package/dist/internal/ZoneKeyRewrite.d.ts +98 -0
  278. package/dist/internal/ZoneKeyRewrite.d.ts.map +1 -0
  279. package/dist/internal/ZoneKeyRewrite.js +151 -0
  280. package/dist/internal/ZoneKeyRewrite.js.map +1 -0
  281. package/dist/internal/rewards/Campaigns.d.ts +2 -0
  282. package/dist/internal/rewards/Campaigns.d.ts.map +1 -1
  283. package/dist/internal/rewards/Campaigns.js.map +1 -1
  284. package/dist/internal/rewards/Distributions.d.ts.map +1 -1
  285. package/dist/internal/rewards/Distributions.js +2 -6
  286. package/dist/internal/rewards/Distributions.js.map +1 -1
  287. package/dist/internal/rewards/Monitor.d.ts +4 -1
  288. package/dist/internal/rewards/Monitor.d.ts.map +1 -1
  289. package/dist/internal/rewards/Monitor.js +19 -2
  290. package/dist/internal/rewards/Monitor.js.map +1 -1
  291. package/dist/internal/rewards/Runner.d.ts.map +1 -1
  292. package/dist/internal/rewards/Runner.js +9 -1
  293. package/dist/internal/rewards/Runner.js.map +1 -1
  294. package/dist/internal/routes/Action.d.ts.map +1 -1
  295. package/dist/internal/routes/Action.js +2 -3
  296. package/dist/internal/routes/Action.js.map +1 -1
  297. package/dist/internal/routes/Deposit.d.ts.map +1 -1
  298. package/dist/internal/routes/Deposit.js +2 -6
  299. package/dist/internal/routes/Deposit.js.map +1 -1
  300. package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
  301. package/dist/internal/routes/DepositAddress.js +4 -10
  302. package/dist/internal/routes/DepositAddress.js.map +1 -1
  303. package/dist/internal/routes/Policy.d.ts.map +1 -1
  304. package/dist/internal/routes/Policy.js +2 -1
  305. package/dist/internal/routes/Policy.js.map +1 -1
  306. package/dist/internal/routes/Provider.js +8 -8
  307. package/dist/internal/routes/Provider.js.map +1 -1
  308. package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
  309. package/dist/internal/routes/Reconciliation.js +3 -2
  310. package/dist/internal/routes/Reconciliation.js.map +1 -1
  311. package/dist/internal/routes/Transfer.d.ts.map +1 -1
  312. package/dist/internal/routes/Transfer.js +4 -12
  313. package/dist/internal/routes/Transfer.js.map +1 -1
  314. package/dist/internal/routes/UniversalDepositAddress.d.ts.map +1 -1
  315. package/dist/internal/routes/UniversalDepositAddress.js +3 -6
  316. package/dist/internal/routes/UniversalDepositAddress.js.map +1 -1
  317. package/dist/internal/routes/providers/SquidOrder.d.ts.map +1 -1
  318. package/dist/internal/routes/providers/SquidOrder.js +3 -2
  319. package/dist/internal/routes/providers/SquidOrder.js.map +1 -1
  320. package/dist/internal/routes/providers/relay.d.ts.map +1 -1
  321. package/dist/internal/routes/providers/relay.js +4 -3
  322. package/dist/internal/routes/providers/relay.js.map +1 -1
  323. package/package.json +20 -5
  324. package/src/ApiKey.ts +2 -2
  325. package/src/ApiKeys.test.ts +284 -51
  326. package/src/ApiKeys.ts +297 -64
  327. package/src/App.ts +4 -5
  328. package/src/Client.test-d.ts +33 -126
  329. package/src/Scope.test.ts +26 -45
  330. package/src/Scope.ts +24 -37
  331. package/src/admin/App.test.ts +51 -4
  332. package/src/admin/App.ts +25 -33
  333. package/src/admin/Mcp.test.ts +2 -1
  334. package/src/admin/apps/api-keys.test.ts +90 -20
  335. package/src/admin/apps/api-keys.ts +5 -8
  336. package/src/admin/apps/audit-logs.ts +1 -1
  337. package/src/admin/apps/earn-vaults.test.ts +19 -19
  338. package/src/admin/apps/earn-vaults.ts +11 -5
  339. package/src/admin/apps/routes-support.test.ts +254 -3
  340. package/src/admin/apps/routes-support.ts +1 -44
  341. package/src/admin/apps/scopes.test.ts +3 -3
  342. package/src/admin/apps/zone-delegation-requests.test.ts +246 -0
  343. package/src/admin/apps/zone-delegation-requests.ts +240 -0
  344. package/src/admin/apps/zone-delegations.test.ts +218 -58
  345. package/src/admin/apps/zone-delegations.ts +146 -46
  346. package/src/admin/index.ts +1 -1
  347. package/src/admin/ui/src/components/ApiKeyForm.tsx +4 -3
  348. package/src/admin/ui/src/lib/config.ts +3 -3
  349. package/src/admin/ui/src/lib/query-client.ts +1 -1
  350. package/src/admin/ui/src/lib/review-queues.ts +10 -10
  351. package/src/admin/ui/src/lib/routes-setup.test.ts +1 -2
  352. package/src/admin/ui/src/lib/routes-setup.ts +3 -5
  353. package/src/admin/ui/src/lib/scopes.test.ts +3 -6
  354. package/src/admin/ui/src/lib/scopes.ts +2 -9
  355. package/src/admin/ui/src/lib/{zone-key-requests.ts → zone-delegation-requests.ts} +27 -31
  356. package/src/admin/ui/src/routeTree.gen.ts +17 -17
  357. package/src/admin/ui/src/routes/__root.tsx +1 -1
  358. package/src/admin/ui/src/routes/api-keys.tsx +2 -15
  359. package/src/admin/ui/src/routes/audit-logs.tsx +2 -2
  360. package/src/admin/ui/src/routes/index.tsx +11 -11
  361. package/src/admin/ui/src/routes/organizations.tsx +3 -1
  362. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +3 -1
  363. package/src/admin/ui/src/routes/organizations_.$orgId_.setup.tsx +1 -3
  364. package/src/admin/ui/src/routes/{zone-key-requests.tsx → zone-delegation-requests.tsx} +228 -172
  365. package/src/admin/ui/vite.config.ts +14 -1
  366. package/src/admin/ui.generated.ts +412 -583
  367. package/src/analytics/tables/requestEvents.test.ts +13 -3
  368. package/src/analytics/tables/requestEvents.ts +4 -3
  369. package/src/apps/data/App.test.ts +72 -35
  370. package/src/apps/data/App.ts +29 -13
  371. package/src/apps/data/ZoneSelection.test.ts +53 -70
  372. package/src/apps/data/ZoneSelection.ts +2 -2
  373. package/src/apps/data/routes/activities.test.ts +140 -6
  374. package/src/apps/data/routes/activities.ts +124 -18
  375. package/src/apps/data/routes/balances.ts +5 -1
  376. package/src/apps/data/routes/blocks.ts +9 -13
  377. package/src/apps/data/routes/earn-transactions.local.test.ts +6 -1
  378. package/src/apps/data/routes/earn-transactions.test.ts +7 -3
  379. package/src/apps/data/routes/earn.bench.ts +0 -14
  380. package/src/apps/data/routes/earn.discovery.test.ts +4 -39
  381. package/src/apps/data/routes/earn.local.test.ts +27 -34
  382. package/src/apps/data/routes/earn.test.ts +172 -490
  383. package/src/apps/data/routes/earn.ts +103 -652
  384. package/src/apps/data/routes/exchanges.ts +20 -30
  385. package/src/apps/data/routes/fee-amm.ts +12 -18
  386. package/src/apps/data/routes/indexer.test.ts +14 -12
  387. package/src/apps/data/routes/receipts.ts +1 -1
  388. package/src/apps/data/routes/rpc.test.ts +23 -18
  389. package/src/apps/data/routes/rpc.ts +21 -21
  390. package/src/apps/data/routes/rpc.zone.test.ts +60 -6
  391. package/src/apps/data/routes/tokenlist.ts +4 -6
  392. package/src/apps/data/routes/tokens.test.ts +20 -0
  393. package/src/apps/data/routes/tokens.ts +10 -5
  394. package/src/apps/data/routes/transactions.ts +3 -3
  395. package/src/apps/data/routes/transfers.ts +4 -6
  396. package/src/apps/data/routes/valuation.test.ts +2 -4
  397. package/src/apps/data/routes/valuation.ts +4 -6
  398. package/src/apps/data/routes/webhooks.test.ts +1 -5
  399. package/src/apps/data/routes/webhooks.ts +30 -44
  400. package/src/apps/data/routes/zones.test.ts +35 -19
  401. package/src/apps/management/App.ts +3 -1
  402. package/src/apps/management/routes/api-keys.test.ts +112 -22
  403. package/src/apps/management/routes/api-keys.ts +30 -15
  404. package/src/apps/management/routes/billing.ts +17 -25
  405. package/src/apps/management/routes/cli.ts +12 -18
  406. package/src/apps/management/routes/fee-payer-usage.ts +5 -4
  407. package/src/apps/management/routes/invitations.ts +16 -21
  408. package/src/apps/management/routes/invite-links.ts +18 -26
  409. package/src/apps/management/routes/me.ts +9 -13
  410. package/src/apps/management/routes/members.ts +5 -7
  411. package/src/apps/management/routes/orgs.ts +8 -12
  412. package/src/apps/management/routes/projects.ts +8 -12
  413. package/src/apps/management/routes/route-usage.ts +5 -4
  414. package/src/apps/management/routes/routes-access-requests.test.ts +64 -2
  415. package/src/apps/management/routes/routes-access-requests.ts +99 -15
  416. package/src/apps/management/routes/scopes.test.ts +3 -3
  417. package/src/apps/management/routes/usage.ts +20 -28
  418. package/src/apps/management/routes/verified-token-requests.ts +9 -13
  419. package/src/apps/management/routes/zone-delegations.test.ts +3 -5
  420. package/src/apps/management/routes/zone-delegations.ts +4 -9
  421. package/src/apps/mpp/App.ts +3 -3
  422. package/src/apps/mpp/Mpp.zone.test.ts +49 -18
  423. package/src/apps/mpp/internal/Adapter.ts +1 -1
  424. package/src/apps/mpp/internal/Error.test.ts +3 -0
  425. package/src/apps/mpp/internal/Error.ts +1 -0
  426. package/src/apps/mpp/internal/Policy.test.ts +9 -8
  427. package/src/apps/mpp/internal/Policy.ts +37 -14
  428. package/src/apps/relay/App.sandbox.test.ts +15 -14
  429. package/src/apps/relay/App.test.ts +120 -61
  430. package/src/apps/relay/App.ts +28 -18
  431. package/src/apps/relay/App.zone-billing.test.ts +9 -4
  432. package/src/apps/routes/App.test.ts +21 -22
  433. package/src/db/Db.ts +34 -3
  434. package/src/db/Schema.ts +26 -26
  435. package/src/db/tables/rewardRuns.ts +39 -0
  436. package/src/db/tables/routesAccessRequests.test.ts +65 -0
  437. package/src/db/tables/routesAccessRequests.ts +25 -0
  438. package/src/db/tables/{zoneKeyRequests.test.ts → zoneDelegationRequests.test.ts} +36 -77
  439. package/src/db/tables/{zoneKeyRequests.ts → zoneDelegationRequests.ts} +69 -52
  440. package/src/db/tables/zoneDelegations.test.ts +5 -6
  441. package/src/db/tables/zoneDelegations.ts +25 -8
  442. package/src/handlers/internal/{multisig.store.test.ts → accounts.store.test.ts} +16 -16
  443. package/src/handlers/internal/{multisig.test.ts → accounts.test.ts} +85 -82
  444. package/src/handlers/internal/{multisig.ts → accounts.ts} +9 -9
  445. package/src/handlers/internal/sponsorship.ts +20 -20
  446. package/src/handlers/relay.test.ts +48 -46
  447. package/src/handlers/relay.ts +26 -26
  448. package/src/internal/Auth.test.ts +6 -2
  449. package/src/internal/Auth.ts +4 -10
  450. package/src/internal/EarnRates.ts +4 -6
  451. package/src/internal/EarnVaults.ts +2 -2
  452. package/src/internal/Log.test-d.ts +1 -0
  453. package/src/internal/Log.test.ts +4 -6
  454. package/src/internal/Log.ts +2 -6
  455. package/src/internal/Response.ts +0 -3
  456. package/src/internal/Schema.test.ts +42 -0
  457. package/src/internal/Schema.ts +36 -1
  458. package/src/internal/ZoneAccess.test.ts +515 -312
  459. package/src/internal/ZoneAccess.ts +410 -158
  460. package/src/internal/ZoneDelegation.test.ts +1 -41
  461. package/src/internal/ZoneDelegation.ts +10 -48
  462. package/src/internal/ZoneDelegationApproval.test.ts +22 -0
  463. package/src/internal/{ZoneKeyApproval.ts → ZoneDelegationApproval.ts} +4 -11
  464. package/src/internal/ZoneKeyRewrite.ts +231 -0
  465. package/src/internal/rewards/Campaigns.ts +2 -0
  466. package/src/internal/rewards/Distributions.ts +8 -12
  467. package/src/internal/rewards/Monitor.test.ts +64 -0
  468. package/src/internal/rewards/Monitor.ts +27 -4
  469. package/src/internal/rewards/Runner.ts +9 -1
  470. package/src/internal/routes/Action.ts +5 -6
  471. package/src/internal/routes/Deposit.ts +8 -12
  472. package/src/internal/routes/DepositAddress.ts +13 -19
  473. package/src/internal/routes/Policy.ts +2 -1
  474. package/src/internal/routes/Provider.ts +8 -8
  475. package/src/internal/routes/Reconciliation.ts +3 -2
  476. package/src/internal/routes/Transfer.ts +16 -24
  477. package/src/internal/routes/UniversalDepositAddress.ts +9 -12
  478. package/src/internal/routes/providers/SquidOrder.ts +3 -2
  479. package/src/internal/routes/providers/relay.ts +4 -3
  480. package/dist/admin/apps/zone-key-requests.d.ts +0 -406
  481. package/dist/admin/apps/zone-key-requests.d.ts.map +0 -1
  482. package/dist/admin/apps/zone-key-requests.js +0 -183
  483. package/dist/admin/apps/zone-key-requests.js.map +0 -1
  484. package/dist/db/tables/zoneKeyRequests.d.ts +0 -289
  485. package/dist/db/tables/zoneKeyRequests.d.ts.map +0 -1
  486. package/dist/db/tables/zoneKeyRequests.js.map +0 -1
  487. package/dist/handlers/internal/multisig.d.ts +0 -7
  488. package/dist/handlers/internal/multisig.d.ts.map +0 -1
  489. package/dist/internal/ZoneKeyApproval.d.ts.map +0 -1
  490. package/dist/internal/ZoneKeyApproval.js +0 -21
  491. package/dist/internal/ZoneKeyApproval.js.map +0 -1
  492. package/src/admin/apps/zone-key-requests.test.ts +0 -272
  493. package/src/admin/apps/zone-key-requests.ts +0 -231
  494. package/src/internal/ZoneKeyApproval.test.ts +0 -46
@@ -215,6 +215,28 @@ describe('GET /addresses/:address/activities', () => {
215
215
  ).toBe(false)
216
216
  })
217
217
 
218
+ test('normalizes timestamp bounds to UTC and rejects an inverted window', () => {
219
+ expect(
220
+ Activities.schema.getAddressActivities.Query.parse({
221
+ 'timestamp.from': '2026-10-22T10:00:00+02:00',
222
+ 'timestamp.to': '2026-10-23T00:00:00Z',
223
+ }),
224
+ ).toMatchObject({
225
+ 'timestamp.from': '2026-10-22T08:00:00.000Z',
226
+ 'timestamp.to': '2026-10-23T00:00:00.000Z',
227
+ })
228
+ expect(
229
+ Activities.schema.getAddressActivities.Query.safeParse({ 'timestamp.from': '1761091200' })
230
+ .success,
231
+ ).toBe(false)
232
+ expect(
233
+ Activities.schema.getAddressActivities.Query.safeParse({
234
+ 'timestamp.from': '2026-10-23T00:00:00Z',
235
+ 'timestamp.to': '2026-10-22T00:00:00Z',
236
+ }).success,
237
+ ).toBe(false)
238
+ })
239
+
218
240
  test('validates valuation amount filters', () => {
219
241
  expect(
220
242
  Activities.schema.getAddressActivities.Query.parse({
@@ -292,6 +314,35 @@ describe('GET /addresses/:address/activities', () => {
292
314
  ).toBe(true)
293
315
  })
294
316
 
317
+ test('filters activities by inclusive block timestamp window', async () => {
318
+ const unfiltered = await activities(accounts.creator, { limit: '5' })
319
+ const pivot = unfiltered.data.at(-1)
320
+ expect(pivot).toBeDefined()
321
+ if (!pivot) return
322
+
323
+ const windowed = await activities(accounts.creator, {
324
+ 'timestamp.from': pivot.timestamp,
325
+ 'timestamp.to': pivot.timestamp,
326
+ })
327
+ expect(windowed.data.length).toBeGreaterThan(0)
328
+ expect(windowed.data.every((entry) => entry.timestamp === pivot.timestamp)).toBe(true)
329
+ expect(windowed.data.some((entry) => entry.id === pivot.id)).toBe(true)
330
+ expect(windowed.nextCursor).toBeNull()
331
+
332
+ // Nothing lands between whole seconds, and nothing predates the chain.
333
+ const seconds = Date.parse(pivot.timestamp)
334
+ const between = await activities(accounts.creator, {
335
+ 'timestamp.from': new Date(seconds + 500).toISOString(),
336
+ 'timestamp.to': new Date(seconds + 999).toISOString(),
337
+ })
338
+ expect(between.data).toEqual([])
339
+ const before = await activities(accounts.creator, {
340
+ 'timestamp.to': '1970-01-01T00:00:00Z',
341
+ })
342
+ expect(before.data).toEqual([])
343
+ expect(before.nextCursor).toBeNull()
344
+ })
345
+
295
346
  test.skipIf(runtime.mode !== 'localnet')(
296
347
  'filters and paginates indexed transfers by inclusive raw amount',
297
348
  async () => {
@@ -1113,14 +1164,15 @@ describe('GET /transactions/:transactionHash/activities', () => {
1113
1164
  to: Tempo.accounts[1].address,
1114
1165
  token: Addresses.pathUsd,
1115
1166
  })
1116
- const zoneReader = {
1117
- ...TestApp.key,
1118
- id: 'key_inferred_zone',
1119
- scopes: [...TestApp.key.scopes, `zone:${runtime.zone.chainId}:read`],
1120
- token: 'secret_inferred_zone',
1121
- } satisfies TestApp.kvStore.Key
1167
+ const zoneReader = TestApp.zoneReader(
1168
+ { ...TestApp.key, id: 'key_inferred_zone', token: 'secret_inferred_zone' },
1169
+ [runtime.zone.chainId],
1170
+ )
1171
+ const zoneDb = TestApp.database()
1172
+ await TestApp.delegateZone(zoneDb, { chainIds: [runtime.zone.chainId] })
1122
1173
  const client = TestApp.client({
1123
1174
  auth: { keys: [zoneReader] },
1175
+ db: zoneDb,
1124
1176
  zones: [zone],
1125
1177
  })
1126
1178
  let response = await client.v1.transactions[':transactionHash'].activities.$get(
@@ -1668,6 +1720,88 @@ describe('Activities.list classification', () => {
1668
1720
  expect(queries.filter((query) => query.includes('FROM Transfer')).length).toBeGreaterThan(0)
1669
1721
  })
1670
1722
 
1723
+ test('resolves timestamp bounds to a block range on every candidate query', async () => {
1724
+ const queries: string[] = []
1725
+ const tidx = {
1726
+ fetch: async ({ query }: { query: string }) => {
1727
+ queries.push(query.replace(/\s+/g, ' ').trim())
1728
+ if (query.includes('FROM blocks'))
1729
+ return { rows: [{ num: query.includes('timestamp >=') ? 900 : 1000 }] }
1730
+ // Reject the materialized scan so the decoded fallback is bounded too.
1731
+ if (query.includes('WITH transfer_candidates'))
1732
+ throw new core_Tidx.FetchRequestError(
1733
+ 'ClickHouse query failed: Code: 60. DB::Exception: Unknown table expression identifier token_transfers (UNKNOWN_TABLE)',
1734
+ new Response(null, { status: 422 }),
1735
+ )
1736
+ return { rows: [] }
1737
+ },
1738
+ } as unknown as Parameters<typeof Activities.tidx>[0]['tidx']
1739
+ const provider = Activities.tidx({ chainId: 4217, tidx })
1740
+
1741
+ const { rows } = await provider.fetchRows({
1742
+ address: viewer,
1743
+ cursor: Cursor.encode([101, 5]),
1744
+ filter: {
1745
+ timestamp: { from: '2026-10-22T08:00:00.000Z', to: '2026-10-23T00:00:00.000Z' },
1746
+ },
1747
+ limit: 2,
1748
+ })
1749
+
1750
+ expect(rows).toEqual([])
1751
+ expect(queries.map((query) => query.match(/WHERE .*?(?= ORDER BY| LIMIT)/g)))
1752
+ .toMatchInlineSnapshot(`
1753
+ [
1754
+ [
1755
+ "WHERE timestamp >= '2026-10-22T08:00:00.000Z'",
1756
+ ],
1757
+ [
1758
+ "WHERE timestamp <= '2026-10-23T00:00:00.000Z'",
1759
+ ],
1760
+ [
1761
+ "WHERE "from" = '0x1111111111111111111111111111111111111111' AND block_num >= 900 AND block_num <= 1000 AND block_num <= 101 AND (block_num < 101 OR idx < 5)",
1762
+ "WHERE fee_payer = '0x1111111111111111111111111111111111111111' AND block_num >= 900 AND block_num <= 1000 AND block_num <= 101 AND (block_num < 101 OR tx_idx < 5)",
1763
+ ],
1764
+ [
1765
+ "WHERE "to" = '0x1111111111111111111111111111111111111111' AND "from" != '0x1111111111111111111111111111111111111111' AND block_num >= 900 AND block_num <= 1000 AND (block_num < 101 OR (block_num = 101 AND tx_idx < 5))",
1766
+ "WHERE "from" = '0x1111111111111111111111111111111111111111' AND "to" != '0x1111111111111111111111111111111111111111' AND block_num >= 900 AND block_num <= 1000 AND (block_num < 101 OR (block_num = 101 AND tx_idx < 5))",
1767
+ ],
1768
+ [
1769
+ "WHERE "to" = '0x1111111111111111111111111111111111111111' AND "from" != '0x1111111111111111111111111111111111111111' AND block_num = 101 AND tx_idx < 5 AND block_num >= 900 AND block_num <= 1000",
1770
+ ],
1771
+ [
1772
+ "WHERE "from" = '0x1111111111111111111111111111111111111111' AND "to" != '0x1111111111111111111111111111111111111111' AND block_num = 101 AND tx_idx < 5 AND block_num >= 900 AND block_num <= 1000",
1773
+ ],
1774
+ [
1775
+ "WHERE "to" = '0x1111111111111111111111111111111111111111' AND "from" != '0x1111111111111111111111111111111111111111' AND block_num < 101 AND block_num >= 900 AND block_num <= 1000",
1776
+ ],
1777
+ [
1778
+ "WHERE "from" = '0x1111111111111111111111111111111111111111' AND "to" != '0x1111111111111111111111111111111111111111' AND block_num < 101 AND block_num >= 900 AND block_num <= 1000",
1779
+ ],
1780
+ ]
1781
+ `)
1782
+ })
1783
+
1784
+ test('skips candidate queries when no block falls inside the timestamp window', async () => {
1785
+ const queries: string[] = []
1786
+ const tidx = {
1787
+ fetch: async ({ query }: { query: string }) => {
1788
+ queries.push(query.replace(/\s+/g, ' ').trim())
1789
+ return { rows: [] }
1790
+ },
1791
+ } as unknown as Parameters<typeof Activities.tidx>[0]['tidx']
1792
+ const provider = Activities.tidx({ chainId: 4217, tidx })
1793
+
1794
+ const { rows } = await provider.fetchRows({
1795
+ address: viewer,
1796
+ filter: { timestamp: { from: '2999-01-01T00:00:00.000Z' } },
1797
+ limit: 2,
1798
+ })
1799
+
1800
+ expect(rows).toEqual([])
1801
+ expect(queries.every((query) => query.includes('FROM blocks'))).toBe(true)
1802
+ expect(queries).toHaveLength(1)
1803
+ })
1804
+
1671
1805
  test('skips hydration when no candidates match', async () => {
1672
1806
  const queries: string[] = []
1673
1807
  const tidx = {
@@ -151,8 +151,7 @@ export namespace schema {
151
151
  ),
152
152
  sourceAmount: SourceAmount,
153
153
  sourceToken: Token.check(z.describe('Token that moved in the transfer.')),
154
- timestamp: z
155
- .iso.datetime()
154
+ timestamp: Schema.dateTime()
156
155
  .check(z.describe('Block timestamp for the transfer.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })), // prettier-ignore
157
156
  transactionHash: Schema.Hash.check(
158
157
  z.describe('Transaction hash that contains this transfer.'),
@@ -252,8 +251,7 @@ export namespace schema {
252
251
  z.describe('Log index for this activity within the block.'),
253
252
  z.meta({ examples: [3] }),
254
253
  ),
255
- timestamp: z
256
- .iso.datetime()
254
+ timestamp: Schema.dateTime()
257
255
  .check(z.describe('Block timestamp as an ISO 8601 string.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })), // prettier-ignore
258
256
  title: z
259
257
  .string()
@@ -1554,8 +1552,7 @@ export namespace schema {
1554
1552
  ],
1555
1553
  }),
1556
1554
  ),
1557
- timestamp: z
1558
- .iso.datetime()
1555
+ timestamp: Schema.dateTime()
1559
1556
  .check(z.describe('Timestamp of the first item in the group, as an ISO 8601 string.'), z.meta({ examples: ['2024-01-01T00:00:00Z'] })), // prettier-ignore
1560
1557
  title: z
1561
1558
  .literal('Group')
@@ -1662,6 +1659,8 @@ export namespace schema {
1662
1659
  sender: z
1663
1660
  .optional(Schema.Address)
1664
1661
  .check(z.describe('Only include activities sent from this sender address.')),
1662
+ 'timestamp.from': Schema.timestampBound('activities', 'from'),
1663
+ 'timestamp.to': Schema.timestampBound('activities', 'to'),
1665
1664
  token: z
1666
1665
  .optional(Schema.TokenAddress)
1667
1666
  .check(
@@ -1715,6 +1714,16 @@ export namespace schema {
1715
1714
  path: ['valuation.amount.from'],
1716
1715
  },
1717
1716
  ),
1717
+ z.refine(
1718
+ (query) =>
1719
+ query['timestamp.from'] === undefined ||
1720
+ query['timestamp.to'] === undefined ||
1721
+ query['timestamp.from'] <= query['timestamp.to'],
1722
+ {
1723
+ error: '`timestamp.from` must be less than or equal to `timestamp.to`.',
1724
+ path: ['timestamp.from'],
1725
+ },
1726
+ ),
1718
1727
  z.describe(
1719
1728
  'Query parameters for the address activity request. This feed uses cursor pagination only because activity classification can fold a variable number of rows into each entry, so positional `page` pagination would not be stable.',
1720
1729
  ),
@@ -2323,8 +2332,30 @@ type QueryFilter<item extends UnenrichedItem = UnenrichedItem> = {
2323
2332
  refine?: ((items: readonly item[]) => Promise<item[]> | item[]) | undefined
2324
2333
  }
2325
2334
 
2326
- /** Sound predicates an activity provider can apply before classification. */
2327
- export type CandidateFilter = ActivityFilter
2335
+ /** Inclusive ISO-8601 bounds on a transaction's block timestamp. */
2336
+ export type TimestampBounds = {
2337
+ /** Earliest block timestamp to include. */
2338
+ from?: string | undefined
2339
+ /** Latest block timestamp to include. */
2340
+ to?: string | undefined
2341
+ }
2342
+
2343
+ /** Inclusive block-number range a timestamp window resolves to. */
2344
+ type BlockRange = {
2345
+ /** Lowest block number to include. */
2346
+ from?: number | undefined
2347
+ /** Highest block number to include. */
2348
+ to?: number | undefined
2349
+ }
2350
+
2351
+ /**
2352
+ * Sound predicates an activity provider can apply before classification.
2353
+ * Timestamp bounds are exact: every row of a transaction shares its block.
2354
+ */
2355
+ export type CandidateFilter = ActivityFilter & {
2356
+ /** Block timestamp window; the provider resolves it to a block range before querying. */
2357
+ timestamp?: TimestampBounds | undefined
2358
+ }
2328
2359
 
2329
2360
  /** Internal group of rows that share a transaction hash. */
2330
2361
  type TxGroup = {
@@ -2440,9 +2471,21 @@ export function addresses(options: addresses.Options = {}) {
2440
2471
  ...(query.sender ? { sender: query.sender } : {}),
2441
2472
  ...(query.token ? { token: query.token } : {}),
2442
2473
  }
2443
- const candidate = Object.keys(activityFilter).length > 0 ? activityFilter : undefined
2474
+ const filterByActivity = Object.keys(activityFilter).length > 0
2475
+ const timestampBounds = {
2476
+ ...(query['timestamp.from'] !== undefined ? { from: query['timestamp.from'] } : {}),
2477
+ ...(query['timestamp.to'] !== undefined ? { to: query['timestamp.to'] } : {}),
2478
+ }
2479
+ const filterByTimestamp = Object.keys(timestampBounds).length > 0
2480
+ const candidate: CandidateFilter | undefined =
2481
+ filterByActivity || filterByTimestamp
2482
+ ? {
2483
+ ...activityFilter,
2484
+ ...(filterByTimestamp ? { timestamp: timestampBounds } : {}),
2485
+ }
2486
+ : undefined
2444
2487
  const types = new Set(query.type)
2445
- const refine = types.size > 0 || candidate ? <item extends UnenrichedItem>(items: readonly item[]) => filterActivities({ filter: activityFilter, items: items.filter((item) => types.size === 0 || types.has(item.type)) }) : undefined // prettier-ignore
2488
+ const refine = types.size > 0 || filterByActivity ? <item extends UnenrichedItem>(items: readonly item[]) => filterActivities({ filter: activityFilter, items: items.filter((item) => types.size === 0 || types.has(item.type)) }) : undefined // prettier-ignore
2446
2489
  const listed = await Timing.time(c, 'address_activities', async () => {
2447
2490
  if (!query.include.includes('zones')) {
2448
2491
  const result = await Store.memoize(
@@ -2490,7 +2533,7 @@ export function addresses(options: addresses.Options = {}) {
2490
2533
  },
2491
2534
  ),
2492
2535
  {
2493
- key: `activities:v5:${chainId}:${address.toLowerCase()}:${query.type.join(',')}:${query['amount.from'] ?? ''}:${query['amount.to'] ?? ''}:${query.recipient ?? ''}:${query.sender ?? ''}:${query.token ?? ''}:${query['valuation.amount.from'] ?? ''}:${query['valuation.amount.to'] ?? ''}:${query['valuation.currency'] ?? ''}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
2536
+ key: `activities:v6:${chainId}:${address.toLowerCase()}:${query.type.join(',')}:${query['amount.from'] ?? ''}:${query['amount.to'] ?? ''}:${query.recipient ?? ''}:${query.sender ?? ''}:${query.token ?? ''}:${query['timestamp.from'] ?? ''}:${query['timestamp.to'] ?? ''}:${query['valuation.amount.from'] ?? ''}:${query['valuation.amount.to'] ?? ''}:${query['valuation.currency'] ?? ''}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
2494
2537
  store: c.get('store'),
2495
2538
  ttl: Ttl.seconds(15),
2496
2539
  },
@@ -2545,7 +2588,7 @@ export function addresses(options: addresses.Options = {}) {
2545
2588
  time: (name, fn) => Timing.sum(c, name, fn),
2546
2589
  }),
2547
2590
  {
2548
- key: `activities:zones:v6:${chainIds.join(',')}:${address.toLowerCase()}:${query.type.join(',')}:${query['amount.from'] ?? ''}:${query['amount.to'] ?? ''}:${query.recipient ?? ''}:${query.sender ?? ''}:${query.token ?? ''}:${query['valuation.amount.from'] ?? ''}:${query['valuation.amount.to'] ?? ''}:${query['valuation.currency'] ?? ''}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
2591
+ key: `activities:zones:v7:${chainIds.join(',')}:${address.toLowerCase()}:${query.type.join(',')}:${query['amount.from'] ?? ''}:${query['amount.to'] ?? ''}:${query.recipient ?? ''}:${query.sender ?? ''}:${query.token ?? ''}:${query['timestamp.from'] ?? ''}:${query['timestamp.to'] ?? ''}:${query['valuation.amount.from'] ?? ''}:${query['valuation.amount.to'] ?? ''}:${query['valuation.currency'] ?? ''}:${query.group ?? false}:${query.logs ?? false}:${query.cursor ?? 'head'}:${query.limit}`,
2549
2592
  store: c.get('store'),
2550
2593
  ttl: Ttl.seconds(15),
2551
2594
  },
@@ -2975,6 +3018,7 @@ type AddressActivityTimingName =
2975
3018
  | 'address_activity_mpp'
2976
3019
  | 'address_activity_outbound'
2977
3020
  | 'address_activity_transfers'
3021
+ | 'address_activity_window'
2978
3022
 
2979
3023
  type AddressActivityTime = <value>(
2980
3024
  name: AddressActivityTimingName,
@@ -3292,13 +3336,61 @@ export function tidx(deps: tidx.Deps): Provider {
3292
3336
  return { blockNum: decoded[0] as number, txIdx: decoded[1] as number }
3293
3337
  }
3294
3338
 
3339
+ /**
3340
+ * Resolves a timestamp window to the indexed blocks it spans, so every candidate
3341
+ * scan can stop at a `block_num` floor. `null` means no indexed block falls inside it.
3342
+ */
3343
+ async function queryBlockRange(bounds: TimestampBounds): Promise<BlockRange | null> {
3344
+ const blockNumber = (result: { rows: Record<string, unknown>[] }) =>
3345
+ Value.toNumber(result.rows[0]?.['num'])
3346
+ const [from, to] = await time('address_activity_window', () =>
3347
+ Promise.all([
3348
+ bounds.from === undefined
3349
+ ? undefined
3350
+ : fetch({
3351
+ chainId,
3352
+ query: `
3353
+ SELECT num
3354
+ FROM blocks
3355
+ WHERE timestamp >= '${bounds.from}'
3356
+ ORDER BY num ASC
3357
+ LIMIT 1
3358
+ ` as string,
3359
+ }).then(blockNumber),
3360
+ bounds.to === undefined
3361
+ ? undefined
3362
+ : fetch({
3363
+ chainId,
3364
+ query: `
3365
+ SELECT num
3366
+ FROM blocks
3367
+ WHERE timestamp <= '${bounds.to}'
3368
+ ORDER BY num DESC
3369
+ LIMIT 1
3370
+ ` as string,
3371
+ }).then(blockNumber),
3372
+ ]),
3373
+ )
3374
+ if (bounds.from !== undefined && from === undefined) return null
3375
+ if (bounds.to !== undefined && to === undefined) return null
3376
+ if (from !== undefined && to !== undefined && from > to) return null
3377
+ return {
3378
+ ...(from !== undefined ? { from } : {}),
3379
+ ...(to !== undefined ? { to } : {}),
3380
+ }
3381
+ }
3382
+
3295
3383
  /** Q1 selects bounded outbound transactions, then reads their logs. */
3296
3384
  async function queryOutbound(options: {
3297
3385
  address: Address.Address
3298
3386
  cursor: { blockNum: number; txIdx: number } | undefined
3299
3387
  limit: number
3388
+ range: BlockRange | undefined
3300
3389
  }): Promise<Row[]> {
3301
- const { address, cursor, limit } = options
3390
+ const { address, cursor, limit, range } = options
3391
+ const window = blockRangePredicates(range)
3392
+ .map((predicate) => `AND ${predicate}`)
3393
+ .join(' ')
3302
3394
  const receiptKeyset = cursor
3303
3395
  ? `AND block_num <= ${cursor.blockNum} AND (block_num < ${cursor.blockNum} OR tx_idx < ${cursor.txIdx})`
3304
3396
  : ''
@@ -3315,13 +3407,13 @@ export function tidx(deps: tidx.Deps): Provider {
3315
3407
  WITH outbound_candidates AS (
3316
3408
  (SELECT hash AS tx_hash, block_num, block_timestamp, idx AS tx_idx, "from", fee_payer
3317
3409
  FROM txs
3318
- WHERE "from" = '${address}' ${txKeyset}
3410
+ WHERE "from" = '${address}' ${window} ${txKeyset}
3319
3411
  ORDER BY block_num DESC, idx DESC
3320
3412
  LIMIT ${queryLimit})
3321
3413
  UNION
3322
3414
  (SELECT tx_hash, block_num, block_timestamp, tx_idx, "from", fee_payer
3323
3415
  FROM receipts
3324
- WHERE fee_payer = '${address}' ${receiptKeyset}
3416
+ WHERE fee_payer = '${address}' ${window} ${receiptKeyset}
3325
3417
  ORDER BY block_num DESC, tx_idx DESC
3326
3418
  LIMIT ${queryLimit})
3327
3419
  )
@@ -3415,8 +3507,9 @@ export function tidx(deps: tidx.Deps): Provider {
3415
3507
  cursor: { blockNum: number; txIdx: number } | undefined
3416
3508
  filter: CandidateFilter | undefined
3417
3509
  limit: number
3510
+ range: BlockRange | undefined
3418
3511
  }): Promise<Row[]> {
3419
- const { address, cursor, filter, limit } = options
3512
+ const { address, cursor, filter, limit, range } = options
3420
3513
  const keyset = cursor
3421
3514
  ? `AND (block_num < ${cursor.blockNum} OR (block_num = ${cursor.blockNum} AND tx_idx < ${cursor.txIdx}))`
3422
3515
  : ''
@@ -3428,6 +3521,7 @@ export function tidx(deps: tidx.Deps): Provider {
3428
3521
  const materializedPredicate = [
3429
3522
  ...participantPredicates,
3430
3523
  ...(filter?.token !== undefined ? [`token = '${filter.token}'`] : []),
3524
+ ...blockRangePredicates(range),
3431
3525
  ...(amount?.from !== undefined
3432
3526
  ? amount.from > maxTokenAmount
3433
3527
  ? ['0']
@@ -3442,6 +3536,7 @@ export function tidx(deps: tidx.Deps): Provider {
3442
3536
  const decodedPredicate = [
3443
3537
  ...participantPredicates,
3444
3538
  ...(filter?.token !== undefined ? [`address = '${filter.token}'`] : []),
3539
+ ...blockRangePredicates(range),
3445
3540
  ...(amount?.from !== undefined
3446
3541
  ? amount.from > maxTokenAmount
3447
3542
  ? ['0']
@@ -3680,9 +3775,11 @@ export function tidx(deps: tidx.Deps): Provider {
3680
3775
  },
3681
3776
  async fetchRows({ address, cursor, filter, limit }) {
3682
3777
  const parsed = cursor ? parseCursor(cursor) : undefined
3778
+ const range = filter?.timestamp ? await queryBlockRange(filter.timestamp) : undefined
3779
+ if (range === null) return { rows: [] }
3683
3780
  const [q1, q2] = await Promise.all([
3684
- queryOutbound({ address, cursor: parsed, limit }),
3685
- queryTransfers({ address, cursor: parsed, filter, limit }),
3781
+ queryOutbound({ address, cursor: parsed, limit, range }),
3782
+ queryTransfers({ address, cursor: parsed, filter, limit, range }),
3686
3783
  ])
3687
3784
  return { rows: mergeAndSort(q1, q2, []) }
3688
3785
  },
@@ -3703,6 +3800,15 @@ export declare namespace tidx {
3703
3800
  }
3704
3801
  }
3705
3802
 
3803
+ /** Builds inclusive `block_num` predicates for a candidate query. */
3804
+ function blockRangePredicates(range: BlockRange | undefined): string[] {
3805
+ if (!range) return []
3806
+ return [
3807
+ ...(range.from !== undefined ? [`block_num >= ${range.from}`] : []),
3808
+ ...(range.to !== undefined ? [`block_num <= ${range.to}`] : []),
3809
+ ]
3810
+ }
3811
+
3706
3812
  /**
3707
3813
  * Merges three sub-query results into one `(blockNum desc, txIdx desc)` stream.
3708
3814
  * Q2/Q3 rows whose hash already appears in Q1 are dropped (Q1 rows are richer),
@@ -281,7 +281,11 @@ export namespace schema {
281
281
  'valuation.currency': getAddressBalances.Query.shape['valuation.currency'],
282
282
  verified: getAddressBalances.Query.shape.verified,
283
283
  })
284
- .check(z.describe('Query parameters for listing token balances across accounts.'))
284
+ .check(
285
+ // Preserve the published parameter shape; the transform still enforces the existing address-count validation.
286
+ z.meta({ required: [] }),
287
+ z.describe('Query parameters for listing token balances across accounts.'),
288
+ )
285
289
 
286
290
  /** Balances held by one requested address. */
287
291
  export const AddressBalances = OpenApi.component(
@@ -25,7 +25,7 @@ const blockTags = ['latest', 'finalized'] as const
25
25
  * route's param schema (validation + OpenAPI `date-time` format) and
26
26
  * {@link parseBlockIdentifier} (runtime dispatch) so the two cannot drift.
27
27
  */
28
- const blockTimestamp = z.iso.datetime({ offset: true })
28
+ const blockTimestamp = Schema.dateTime({ offset: true })
29
29
 
30
30
  /** Zod schemas owned by the block handlers. */
31
31
  export namespace schema {
@@ -194,12 +194,10 @@ export namespace schema {
194
194
  z.describe('Size of the block in bytes.'),
195
195
  z.meta({ examples: [1024] }),
196
196
  ),
197
- timestamp: z.iso
198
- .datetime()
199
- .check(
200
- z.describe('Block timestamp formatted as ISO 8601.'),
201
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
202
- ),
197
+ timestamp: Schema.dateTime().check(
198
+ z.describe('Block timestamp formatted as ISO 8601.'),
199
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
200
+ ),
203
201
  transactionCount: z
204
202
  .number()
205
203
  .check(
@@ -242,12 +240,10 @@ export namespace schema {
242
240
  z.describe('The block height, starting from genesis block 0.'),
243
241
  z.meta({ examples: [23456789] }),
244
242
  ),
245
- timestamp: z.iso
246
- .datetime()
247
- .check(
248
- z.describe('Block timestamp formatted as ISO 8601.'),
249
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
250
- ),
243
+ timestamp: Schema.dateTime().check(
244
+ z.describe('Block timestamp formatted as ISO 8601.'),
245
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
246
+ ),
251
247
  transactionCount: z
252
248
  .number()
253
249
  .check(
@@ -52,7 +52,9 @@ const privateClient = createClient({
52
52
  chain,
53
53
  transport: zoneHttp(runtime.zone.publicZoneUrl, { store }),
54
54
  })
55
- const key = { ...TestApp.key, scopes: ['data:read', `zone:${runtime.zone.chainId}:read`] }
55
+ const key = TestApp.zoneReader({ ...TestApp.key, scopes: ['data:read'] }, [runtime.zone.chainId])
56
+ /** Holds the key's organization delegation for the Zone. */
57
+ const db = TestApp.database()
56
58
  let stack: Awaited<ReturnType<typeof EarnLocal.deploy>>
57
59
  let zone: Awaited<ReturnType<typeof EarnLocal.getZone>>
58
60
  let app: ReturnType<typeof TestApp.create>
@@ -64,8 +66,10 @@ beforeAll(async () => {
64
66
  zone = await EarnLocal.getZone({ client: parent, zoneId })
65
67
  await EarnLocal.enableZoneTokens({ client: administrator, portal: zone.portal, stack })
66
68
  await Actions.zone.signAuthorizationToken(privateClient, { store, zoneId })
69
+ await TestApp.delegateZone(db, { chainIds: [runtime.zone.chainId] })
67
70
  app = TestApp.create({
68
71
  auth: { keys: [key] },
72
+ db,
69
73
  zones: [
70
74
  TestApp.zone({
71
75
  chainId: runtime.zone.chainId,
@@ -159,6 +163,7 @@ describe('GET /v1/earn/transactions/:senderTag', () => {
159
163
  let unavailable = true
160
164
  const degraded = TestApp.create({
161
165
  auth: { keys: [key] },
166
+ db,
162
167
  logger: (entry) => {
163
168
  entries.push(entry)
164
169
  },
@@ -15,11 +15,14 @@ const query = new URLSearchParams({
15
15
  chainId: String(runtime.zone.chainId),
16
16
  })
17
17
  const endpoint = `/v1/earn/transactions/0x${'11'.repeat(32)}?${query}`
18
- const reader = { ...TestApp.key, scopes: ['data:read', `zone:${runtime.zone.chainId}:read`] }
18
+ const reader = TestApp.zoneReader({ ...TestApp.key, scopes: ['data:read'] }, [runtime.zone.chainId])
19
+ /** Holds the reader's organization delegation for the Zone. */
20
+ const db = TestApp.database()
21
+ await TestApp.delegateZone(db, { chainIds: [runtime.zone.chainId] })
19
22
  const headers = { 'tempo-api-key': reader.token }
20
23
 
21
24
  describe('GET /v1/earn/transactions/:senderTag', () => {
22
- test('requires a matching Zone scope', async () => {
25
+ test('requires a delegated Zone tag', async () => {
23
26
  const response = await TestApp.create({ zones, auth: { keys: [TestApp.key] } }).request(
24
27
  endpoint,
25
28
  {
@@ -31,7 +34,7 @@ describe('GET /v1/earn/transactions/:senderTag', () => {
31
34
  })
32
35
 
33
36
  test('validates the sender tag, action id, and chain id', async () => {
34
- const app = TestApp.create({ zones, auth: { keys: [reader] } })
37
+ const app = TestApp.create({ zones, auth: { keys: [reader] }, db })
35
38
  for (const field of ['actionId', 'chainId']) {
36
39
  const invalid = new URLSearchParams(query)
37
40
  invalid.delete(field)
@@ -51,6 +54,7 @@ describe('GET /v1/earn/transactions/:senderTag', () => {
51
54
  const app = TestApp.create({
52
55
  zones,
53
56
  auth: { keys: [reader] },
57
+ db,
54
58
  logger: (entry) => {
55
59
  entries.push(entry)
56
60
  },
@@ -28,20 +28,6 @@ const vaultQueries = [
28
28
  'include=zone',
29
29
  ] as const
30
30
 
31
- const collectionQueries = ['capability=deposit', ...vaultQueries] as const
32
-
33
- QueryBench.bench({
34
- name: 'getEarnVaults',
35
- path: '/v1/earn/vaults',
36
- queries: collectionQueries,
37
- })
38
-
39
- QueryBench.bench({
40
- name: 'getVerifiedEarnVaults',
41
- path: '/v1/earn/vaults/verified',
42
- queries: collectionQueries,
43
- })
44
-
45
31
  QueryBench.bench({
46
32
  name: 'getEarnAddressPositions',
47
33
  path: {
@@ -18,7 +18,6 @@ import {
18
18
  import * as TestApp from '../../../../test/App.js'
19
19
  import * as TestEarn from '../../../../test/Earn.js'
20
20
  import * as Runtime from '../../../../test/runtime.js'
21
- import * as Cursor from '../../../internal/Cursor.js'
22
21
  import * as Earn from './earn.js'
23
22
 
24
23
  const abi = parseAbi([
@@ -27,7 +26,6 @@ const abi = parseAbi([
27
26
  const share = '0x20c00000000000000000000075d0f7d57b571b8a'
28
27
  const asset = '0x20c0000000000000000000000000000000000001'
29
28
  const factory = '0xb4944264260a6412351d64653f65d2c27d9cb038'
30
- const foreignFactory = '0x5b972d2490d06e436982fab77612fd9987f097d0'
31
29
  const attacker = '0x1111111111111111111111111111111111111111'
32
30
 
33
31
  let url: string
@@ -156,36 +154,6 @@ repair_derived_on_startup = false
156
154
  expect(BigInt(result.data[0]!.shareAmount.amount)).toBeGreaterThan(0n)
157
155
  })
158
156
 
159
- test.each([attacker, foreignFactory] as const)(
160
- 'rejects deployment logs from %s before filtering and pagination',
161
- async (address) => {
162
- await insert({
163
- address,
164
- asset: zeroAddress,
165
- blockNumber: 101,
166
- vault: TestEarn.activeEarningsVaultAddress,
167
- })
168
- await insert({ address, blockNumber: 102, vault: TestEarn.vaultAddress })
169
- const cursor = Cursor.encode([101, 0])
170
- const response = await app.request(
171
- `/v1/earn/vaults?chainId=42431&asset=${asset}&cursor=${encodeURIComponent(cursor)}&limit=5`,
172
- )
173
- expect(response.status, await response.clone().text()).toBe(200)
174
- const result = await TestApp.json(response, Earn.schema.getEarnVaults.Response)
175
- expect({ ids: result.data.map((vault) => vault.id), nextCursor: result.nextCursor }).toEqual({
176
- ids: [TestEarn.activeEarningsVaultAddress],
177
- nextCursor: null,
178
- })
179
- const unfiltered = await app.request('/v1/earn/vaults?chainId=42431&limit=5')
180
- expect(unfiltered.status).toBe(200)
181
- const page = await TestApp.json(unfiltered, Earn.schema.getEarnVaults.Response)
182
- expect({ ids: page.data.map((vault) => vault.id), nextCursor: page.nextCursor }).toEqual({
183
- ids: [TestEarn.activeEarningsVaultAddress],
184
- nextCursor: null,
185
- })
186
- },
187
- )
188
-
189
157
  test('returns no indexed discoveries on an unconfigured chain', async () => {
190
158
  const app = TestApp.create({
191
159
  auth: false,
@@ -194,14 +162,11 @@ repair_derived_on_startup = false
194
162
  supportedChainIds: [1337],
195
163
  tidx: { baseUrl: 'http://127.0.0.1:1' },
196
164
  })
197
- for (const path of [
198
- '/v1/earn/vaults',
165
+ const response = await app.request(
199
166
  `/v1/earn/addresses/${TestEarn.activeEarningsAddress}/positions`,
200
- ]) {
201
- const response = await app.request(path)
202
- expect(response.status, await response.clone().text()).toBe(200)
203
- expect(await response.json()).toEqual({ data: [], nextCursor: null })
204
- }
167
+ )
168
+ expect(response.status, await response.clone().text()).toBe(200)
169
+ expect(await response.json()).toEqual({ data: [], nextCursor: null })
205
170
  })
206
171
  })
207
172