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
@@ -802,12 +802,10 @@ export namespace schema {
802
802
  z.meta({ examples: ['1000000'] }),
803
803
  ),
804
804
  quote: PairToken,
805
- timestamp: z.iso
806
- .datetime()
807
- .check(
808
- z.describe('Block timestamp when the pair was created.'),
809
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
810
- ),
805
+ timestamp: Schema.dateTime().check(
806
+ z.describe('Block timestamp when the pair was created.'),
807
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
808
+ ),
811
809
  transactionHash: Schema.Hash.check(
812
810
  z.describe('Transaction hash for the transaction that created the pair.'),
813
811
  ),
@@ -1004,12 +1002,10 @@ export namespace schema {
1004
1002
  ),
1005
1003
  destinationAmount: ValuedAmount,
1006
1004
  destinationToken: SwapSide,
1007
- filledAt: z.iso
1008
- .datetime()
1009
- .check(
1010
- z.describe('Block timestamp when the swap was filled onchain.'),
1011
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1012
- ),
1005
+ filledAt: Schema.dateTime().check(
1006
+ z.describe('Block timestamp when the swap was filled onchain.'),
1007
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1008
+ ),
1013
1009
  fills: z
1014
1010
  .array(Fill)
1015
1011
  .check(
@@ -1230,12 +1226,10 @@ export namespace schema {
1230
1226
  ),
1231
1227
  z.meta({ examples: ['1.00000'] }),
1232
1228
  ),
1233
- timestamp: z.iso
1234
- .datetime()
1235
- .check(
1236
- z.describe('ISO 8601 timestamp for the start of this candle bucket.'),
1237
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1238
- ),
1229
+ timestamp: Schema.dateTime().check(
1230
+ z.describe('ISO 8601 timestamp for the start of this candle bucket.'),
1231
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1232
+ ),
1239
1233
  volume: z
1240
1234
  .object({
1241
1235
  base: Schema.DecimalString.check(
@@ -1544,12 +1538,10 @@ export namespace schema {
1544
1538
  orderId: Schema.DecimalString.check(
1545
1539
  z.describe('On-chain order id, returned as a decimal string.'),
1546
1540
  ),
1547
- placedAt: z.iso
1548
- .datetime()
1549
- .check(
1550
- z.describe('Block timestamp when the order was placed.'),
1551
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1552
- ),
1541
+ placedAt: Schema.dateTime().check(
1542
+ z.describe('Block timestamp when the order was placed.'),
1543
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1544
+ ),
1553
1545
  price: z
1554
1546
  .string()
1555
1547
  .check(
@@ -1681,12 +1673,10 @@ export namespace schema {
1681
1673
  z.describe('Block number where the fill was included.'),
1682
1674
  z.meta({ examples: [23456789] }),
1683
1675
  ),
1684
- filledAt: z.iso
1685
- .datetime()
1686
- .check(
1687
- z.describe('Block timestamp when the fill landed onchain.'),
1688
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1689
- ),
1676
+ filledAt: Schema.dateTime().check(
1677
+ z.describe('Block timestamp when the fill landed onchain.'),
1678
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
1679
+ ),
1690
1680
  id: z.string().check(
1691
1681
  z.describe('Stable API id built from the lowercase transaction hash and log index.'),
1692
1682
  z.meta({
@@ -154,21 +154,17 @@ export namespace schema {
154
154
  export const Pool = OpenApi.component(
155
155
  z
156
156
  .object({
157
- createdAt: z.iso
158
- .datetime()
159
- .check(
160
- z.describe('Timestamp when liquidity was first minted into this pool.'),
161
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
162
- ),
157
+ createdAt: Schema.dateTime().check(
158
+ z.describe('Timestamp when liquidity was first minted into this pool.'),
159
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
160
+ ),
163
161
  id: Schema.Hash.check(
164
162
  z.describe('Stable resource id for the pool; this is the same value as `poolId`.'),
165
163
  ),
166
- lastMintAt: z.iso
167
- .datetime()
168
- .check(
169
- z.describe('Timestamp when liquidity was most recently minted into this pool.'),
170
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
171
- ),
164
+ lastMintAt: Schema.dateTime().check(
165
+ z.describe('Timestamp when liquidity was most recently minted into this pool.'),
166
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
167
+ ),
172
168
  mintCount: z
173
169
  .number()
174
170
  .check(
@@ -283,12 +279,10 @@ export namespace schema {
283
279
  'Address that received the minted liquidity. Only present on current-signature mints.',
284
280
  ),
285
281
  ),
286
- timestamp: z.iso
287
- .datetime()
288
- .check(
289
- z.describe('Block timestamp when the mint occurred.'),
290
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
291
- ),
282
+ timestamp: Schema.dateTime().check(
283
+ z.describe('Block timestamp when the mint occurred.'),
284
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
285
+ ),
292
286
  transactionHash: Schema.Hash.check(
293
287
  z.describe('Hash of the transaction that emitted this mint.'),
294
288
  ),
@@ -451,12 +451,12 @@ describe('GET /indexer/query', () => {
451
451
 
452
452
  test('routes Zone queries to the Zone TIDX with its basic auth', async () => {
453
453
  const zone = runtime.zone.chainId
454
- const zoneReader = {
455
- id: 'key_zone_indexer',
456
- orgId: 'org_test',
457
- scopes: ['data:read', 'indexer:query', `zone:${zone}:read`],
458
- token: 'secret_zone_indexer',
459
- } satisfies TestApp.kvStore.Key
454
+ const zoneReader = TestApp.zoneReader(
455
+ { id: 'key_zone_indexer', orgId: 'org_test', scopes: ['data:read', 'indexer:query'], token: 'secret_zone_indexer' }, // prettier-ignore
456
+ [zone],
457
+ )
458
+ const db = TestApp.database()
459
+ await TestApp.delegateZone(db, { chainIds: [zone] })
460
460
  const fetch = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
461
461
  new Response(JSON.stringify({ columns: [], ok: true, row_count: 0, rows: [] }), {
462
462
  headers: { 'content-type': 'application/json' },
@@ -465,6 +465,7 @@ describe('GET /indexer/query', () => {
465
465
  try {
466
466
  const client = TestApp.client({
467
467
  auth: { keys: [zoneReader] },
468
+ db,
468
469
  tidx: { auth: JSON.stringify({ [zone]: 'zone:secret' }) },
469
470
  zones: [
470
471
  TestApp.zone({
@@ -496,12 +497,12 @@ describe('GET /indexer/query', () => {
496
497
 
497
498
  test('routes Zone queries to the Zone TIDX with its bearer auth', async () => {
498
499
  const zone = runtime.zone.chainId
499
- const zoneReader = {
500
- id: 'key_zone_bearer_indexer',
501
- orgId: 'org_test',
502
- scopes: ['data:read', 'indexer:query', `zone:${zone}:read`],
503
- token: 'secret_zone_bearer_indexer',
504
- } satisfies TestApp.kvStore.Key
500
+ const zoneReader = TestApp.zoneReader(
501
+ { id: 'key_zone_bearer_indexer', orgId: 'org_test', scopes: ['data:read', 'indexer:query'], token: 'secret_zone_bearer_indexer' }, // prettier-ignore
502
+ [zone],
503
+ )
504
+ const db = TestApp.database()
505
+ await TestApp.delegateZone(db, { chainIds: [zone] })
505
506
  const fetch = vi.spyOn(globalThis, 'fetch').mockResolvedValue(
506
507
  new Response(JSON.stringify({ columns: [], ok: true, row_count: 0, rows: [] }), {
507
508
  headers: { 'content-type': 'application/json' },
@@ -510,6 +511,7 @@ describe('GET /indexer/query', () => {
510
511
  try {
511
512
  const client = TestApp.client({
512
513
  auth: { keys: [zoneReader] },
514
+ db,
513
515
  tidx: { auth: 'zone-secret', baseUrl: 'https://zone.tidx.test' },
514
516
  zones: [TestApp.zone({ chainId: zone, rpcUrl: runtime.zone.publicZoneUrl })],
515
517
  })
@@ -312,7 +312,7 @@ export namespace schema {
312
312
  z.meta({ examples: ['success'] }),
313
313
  ),
314
314
  timestamp: z
315
- .nullable(z.iso.datetime())
315
+ .nullable(Schema.dateTime())
316
316
  .check(
317
317
  z.describe('The block timestamp as ISO 8601, or `null` when it is unavailable.'),
318
318
  z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
@@ -82,18 +82,22 @@ const zoneOptions = TestApp.zone({
82
82
  chainId: zone,
83
83
  rpcUrl: runtime.zone.internalRpcUrl,
84
84
  })
85
- const zoneReader = {
86
- id: 'key_zone_reader',
87
- orgId: 'org_test',
88
- scopes: ['data:read', `zone:${zone}:read`],
89
- token: 'secret_zone_reader',
90
- } satisfies TestApp.kvStore.Key
91
- const zoneReaderOtherWriter = {
92
- id: 'key_zone_reader_other_writer',
93
- orgId: 'org_test',
94
- scopes: ['data:read', `zone:${zone}:read`, `zone:${zone + 1}:write`],
95
- token: 'secret_zone_reader_other_writer',
96
- } satisfies TestApp.kvStore.Key
85
+ const zoneReader = TestApp.zoneReader(
86
+ { id: 'key_zone_reader', orgId: 'org_test', scopes: ['data:read'], token: 'secret_zone_reader' },
87
+ [zone],
88
+ )
89
+ const zoneReaderOtherWriter = TestApp.zoneReader(
90
+ {
91
+ id: 'key_zone_reader_other_writer',
92
+ orgId: 'org_test',
93
+ scopes: ['data:read', `zone:${zone + 1}:write`],
94
+ token: 'secret_zone_reader_other_writer',
95
+ },
96
+ [zone],
97
+ )
98
+ /** Holds the readers' organization delegation for the Zone. */
99
+ const zoneDb = TestApp.database()
100
+ await TestApp.delegateZone(zoneDb, { chainIds: [zone] })
97
101
  const zoneWriter = {
98
102
  id: 'key_zone_writer',
99
103
  orgId: 'org_test',
@@ -1092,7 +1096,7 @@ describe('POST /rpc', () => {
1092
1096
 
1093
1097
  expect(response.status).toBe(403)
1094
1098
  expect(body.error.code).toBe('api_key_forbidden')
1095
- expect(body.error.message).toContain(`zone:${zone}:read`)
1099
+ expect(body.error.message).toContain('`zone:read`')
1096
1100
  // Refused before any upstream round-trip.
1097
1101
  expect(fetch.calls).toHaveLength(0)
1098
1102
  } finally {
@@ -1101,7 +1105,7 @@ describe('POST /rpc', () => {
1101
1105
  })
1102
1106
 
1103
1107
  test('routes Zone-scoped reads to the internal RPC', async () => {
1104
- const app = TestApp.create({ auth: { keys: [zoneReader] }, zones: [zoneOptions] })
1108
+ const app = TestApp.create({ auth: { keys: [zoneReader] }, db: zoneDb, zones: [zoneOptions] })
1105
1109
  const response = await app.fetch(
1106
1110
  new Request(`http://tempo-api.test/rpc/${zone}`, {
1107
1111
  body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: 'eth_chainId' }),
@@ -1115,7 +1119,7 @@ describe('POST /rpc', () => {
1115
1119
  })
1116
1120
 
1117
1121
  test('allows Zone-scoped eth_fillTransaction calls', async () => {
1118
- const app = TestApp.create({ auth: { keys: [zoneReader] }, zones: [zoneOptions] })
1122
+ const app = TestApp.create({ auth: { keys: [zoneReader] }, db: zoneDb, zones: [zoneOptions] })
1119
1123
  const response = await app.fetch(
1120
1124
  new Request(`http://tempo-api.test/rpc/${zone}`, {
1121
1125
  body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: 'eth_fillTransaction' }),
@@ -1140,6 +1144,7 @@ describe('POST /rpc', () => {
1140
1144
  try {
1141
1145
  const app = TestApp.create({
1142
1146
  auth: { keys: [zoneReader] },
1147
+ db: zoneDb,
1143
1148
  rpc: ({ chainId }) => (chainId === zone ? { auth: 'rpc:secret', url: server.url } : {}),
1144
1149
  zones: [zoneOptions],
1145
1150
  })
@@ -1165,7 +1170,7 @@ describe('POST /rpc', () => {
1165
1170
  })
1166
1171
 
1167
1172
  test('blocks caller-authenticated Zone methods for Zone read scopes', async () => {
1168
- const app = TestApp.create({ auth: { keys: [zoneReader] }, zones: [zoneOptions] })
1173
+ const app = TestApp.create({ auth: { keys: [zoneReader] }, db: zoneDb, zones: [zoneOptions] })
1169
1174
  const response = await app.fetch(
1170
1175
  new Request(`http://tempo-api.test/rpc/${zone}`, {
1171
1176
  body: JSON.stringify({
@@ -1184,7 +1189,7 @@ describe('POST /rpc', () => {
1184
1189
 
1185
1190
  test('rejects writes without the matching Zone write scope', async () => {
1186
1191
  for (const key of [zoneReader, zoneReaderOtherWriter]) {
1187
- const app = TestApp.create({ auth: { keys: [key] }, zones: [zoneOptions] })
1192
+ const app = TestApp.create({ auth: { keys: [key] }, db: zoneDb, zones: [zoneOptions] })
1188
1193
  const response = await app.fetch(
1189
1194
  new Request(`http://tempo-api.test/rpc/${zone}`, {
1190
1195
  body: JSON.stringify({ id: 1, jsonrpc: '2.0', method: 'eth_sendRawTransaction' }),
@@ -1313,7 +1318,7 @@ describe('POST /rpc', () => {
1313
1318
  })
1314
1319
 
1315
1320
  test('rejects a Zone-scoped batch containing a write', async () => {
1316
- const app = TestApp.create({ auth: { keys: [zoneReader] }, zones: [zoneOptions] })
1321
+ const app = TestApp.create({ auth: { keys: [zoneReader] }, db: zoneDb, zones: [zoneOptions] })
1317
1322
  const response = await app.fetch(
1318
1323
  new Request(`http://tempo-api.test/rpc/${zone}`, {
1319
1324
  body: JSON.stringify([
@@ -320,33 +320,33 @@ async function handleRpc(c: Context<App.Environment>) {
320
320
  }
321
321
  if (zone) {
322
322
  const requests = Array.isArray(body) ? body : [body]
323
- const check = (verb: ZoneAccess.Verb) =>
324
- ZoneAccess.check(c, { chainId, verb, zoneToken: Boolean(zoneToken) }).allowed
323
+ // Account-scoped methods need the token itself, so the token is the grant.
324
+ const reads = (request: unknown) =>
325
+ isZoneReadMethod(request) || (Boolean(zoneToken) && isZoneTokenMethod(request))
326
+ const classified = requests.every((request) => reads(request) || isZoneWriteMethod(request))
327
+ const options_access = { accounts: zoneAccounts(requests), chainId, zoneToken: Boolean(zoneToken) } // prettier-ignore
328
+ // Tokenless reads reach the internal node, which trusts a caller-supplied `from`;
329
+ // write scopes authorize broadcasts only, never those reads. Reads are decided
330
+ // once for the batch's accounts; a broadcast anywhere makes the record a write.
331
+ const read =
332
+ requests.some(reads) || !requests.some(isZoneWriteMethod)
333
+ ? await ZoneAccess.authorize(c, { ...options_access, verb: 'read' })
334
+ : undefined
335
+ const write = requests.some(isZoneWriteMethod)
336
+ ? await ZoneAccess.authorize(c, { ...options_access, verb: 'write' })
337
+ : undefined
325
338
  const allowed =
326
- requests.length > 0 &&
327
- requests.every(
328
- (request) =>
329
- // Tokenless reads reach the internal node, which trusts a caller-supplied `from`;
330
- // write scopes authorize broadcasts only, never those reads.
331
- (isZoneReadMethod(request) && check('read')) ||
332
- (isZoneWriteMethod(request) && check('write')) ||
333
- // Account-scoped methods need the token itself, so the token is the grant.
334
- (Boolean(zoneToken) && isZoneTokenMethod(request) && check('read')),
335
- )
336
- // One record per request: the strictest operation the batch performs,
337
- // denied when any method fails the allowlist.
338
- ZoneAccess.authorize(c, {
339
- accounts: zoneAccounts(requests),
340
- chainId,
341
- verb: requests.some(isZoneWriteMethod) ? 'write' : 'read',
342
- zoneToken: Boolean(zoneToken),
343
- })
339
+ requests.length > 0 && classified && (read?.allowed ?? true) && (write?.allowed ?? true)
344
340
  if (!allowed) {
345
341
  ZoneAccess.deny(c)
342
+ // A failed delegation read is retriable, unlike a missing grant.
343
+ for (const result of [read, write])
344
+ if (result && !result.allowed && result.error.status === 503)
345
+ return Response.error(c, result.error)
346
346
  return Response.error(c, {
347
347
  code: 'api_key_forbidden',
348
348
  message:
349
- 'Zone RPC permits read-only methods and signed transaction broadcasts. Reads require a matching Zone read scope or a Zone token; broadcasts require a matching Zone write scope or a Zone token; account-scoped methods require a Zone token.',
349
+ 'Zone RPC permits read-only methods and signed transaction broadcasts. Reads require a delegated `zone:read` key tagged for the Zone or a Zone token; broadcasts require a matching Zone write scope or a Zone token; account-scoped methods require a Zone token.',
350
350
  status: 403,
351
351
  })
352
352
  }
@@ -233,14 +233,20 @@ describe('POST /rpc Zone authorization', () => {
233
233
  const server = await Relay.createServer(listener)
234
234
  const internal = await Relay.createServer(listener)
235
235
  try {
236
- const key = {
237
- ...TestApp.key,
238
- id: 'key_zone_reader',
239
- scopes: ['data:read', `zone:${chainId}:read`],
240
- token: 'secret_zone_reader',
241
- }
236
+ const key = TestApp.zoneReader(
237
+ {
238
+ ...TestApp.key,
239
+ id: 'key_zone_reader',
240
+ scopes: ['data:read'],
241
+ token: 'secret_zone_reader',
242
+ },
243
+ [chainId],
244
+ )
245
+ const db = TestApp.database()
246
+ await TestApp.delegateZone(db, { chainIds: [chainId] })
242
247
  const app = TestApp.create({
243
248
  auth: { keys: [key, TestApp.key] },
249
+ db,
244
250
  rpc: {
245
251
  auth: 'internal:secret',
246
252
  publicZoneUrl: { [chainId]: `${server.url}/public` },
@@ -308,6 +314,54 @@ describe('POST /rpc Zone authorization', () => {
308
314
  }
309
315
  })
310
316
 
317
+ test('broadcasts through the generic write scope only to tagged Zones, and never reads', async () => {
318
+ const calls: string[] = []
319
+ const server = await Relay.createServer(
320
+ RequestListener.fromFetchHandler(async (request) => {
321
+ calls.push((JSON.parse(await request.text()) as { method: string }).method)
322
+ return Response.json({ id: 1, jsonrpc: '2.0', result: null })
323
+ }),
324
+ )
325
+ try {
326
+ const tagged = { ...TestApp.key, id: 'key_tagged', scopes: ['data:read', 'zone:write'], token: 'secret_tagged', zoneTags: [chainId] } // prettier-ignore
327
+ const elsewhere = { ...tagged, id: 'key_elsewhere', token: 'secret_elsewhere', zoneTags: [chainId + 1] } // prettier-ignore
328
+ const untagged = { ...TestApp.key, id: 'key_untagged', scopes: ['data:read', 'zone:write'], token: 'secret_untagged' } // prettier-ignore
329
+ const db = TestApp.database()
330
+ await TestApp.delegateZone(db, { chainIds: [chainId] })
331
+ const app = TestApp.create({
332
+ auth: { keys: [tagged, elsewhere, untagged] },
333
+ db,
334
+ rpc: { url: server.url },
335
+ zones: [TestApp.zone({ chainId, rpcUrl: server.url })],
336
+ })
337
+ const send = (token: string, method: string) =>
338
+ app.fetch(
339
+ new Request(`http://tempo-api.test/rpc/${chainId}`, {
340
+ body: JSON.stringify({ id: 1, jsonrpc: '2.0', method, params: [] }),
341
+ headers: { 'tempo-api-key': token },
342
+ method: 'POST',
343
+ }),
344
+ )
345
+ expect((await send(tagged.token, 'eth_sendRawTransaction')).status).toBe(200)
346
+ const refused = await Promise.all([
347
+ send(tagged.token, 'eth_chainId'),
348
+ send(elsewhere.token, 'eth_sendRawTransaction'),
349
+ send(untagged.token, 'eth_sendRawTransaction'),
350
+ ])
351
+ expect(refused.map((response) => response.status)).toEqual([403, 403, 403])
352
+ const { requestId: _requestId, ...error } = (await refused[2].json()).error
353
+ expect(error).toMatchInlineSnapshot(`
354
+ {
355
+ "code": "api_key_forbidden",
356
+ "message": "Chain ID 421700001 is a Zone. Use an API key granting \`zone:read\` and tagged for Zone 421700001, issued to an organization delegated that Zone (or \`zone:write\` with a tag for Zone 421700001 for broadcasts), or pass a Zone token via \`X-Authorization-Token\`.",
357
+ }
358
+ `)
359
+ expect(calls).toEqual(['eth_sendRawTransaction'])
360
+ } finally {
361
+ await server.closeAsync()
362
+ }
363
+ })
364
+
311
365
  test('does not fall back when a public URL map only contains a legacy Zone alias', async () => {
312
366
  const calls: string[] = []
313
367
  const server = await Relay.createServer(
@@ -114,12 +114,10 @@ export namespace schema {
114
114
  z.describe('The human-readable name of this token list.'),
115
115
  z.meta({ examples: ['Tempo Verified Tokens'] }),
116
116
  ),
117
- timestamp: z.iso
118
- .datetime()
119
- .check(
120
- z.describe('The ISO 8601 timestamp when this token list was last updated.'),
121
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
122
- ),
117
+ timestamp: Schema.dateTime().check(
118
+ z.describe('The ISO 8601 timestamp when this token list was last updated.'),
119
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
120
+ ),
123
121
  version: z
124
122
  .union([Version])
125
123
  .check(
@@ -1100,6 +1100,26 @@ describe('GET /tokens?addresses=', () => {
1100
1100
  })
1101
1101
 
1102
1102
  describe('GET /tokens/:token', () => {
1103
+ test('returns the 404 envelope for an unknown token', async () => {
1104
+ const client = app()
1105
+ const response = await client.v1.tokens[':token'].$get(
1106
+ { param: { token: '0x20c00000000000000000000000000000000000ff' }, query: {} },
1107
+ TestApp.auth,
1108
+ )
1109
+ const body = await TestApp.json(response, Schema.ErrorResponse)
1110
+ const { requestId: _, ...stable } = body
1111
+
1112
+ expect(response.status).toMatchInlineSnapshot(`404`)
1113
+ expect(stable).toMatchInlineSnapshot(`
1114
+ {
1115
+ "error": {
1116
+ "code": "token_not_found",
1117
+ "message": "Token not found",
1118
+ },
1119
+ }
1120
+ `)
1121
+ })
1122
+
1103
1123
  test('returns token metadata for a small token', async () => {
1104
1124
  const client = app()
1105
1125
  const response = await client.v1.tokens[':token'].$get(
@@ -1,7 +1,7 @@
1
1
  import { Hono, type Context, type TypedResponse } from 'hono'
2
2
  import type { JSONParsed } from 'hono/utils/types'
3
3
  import { AbiEvent, AbiParameters, Hash } from 'ox'
4
- import { type Address, ContractFunctionExecutionError } from 'viem'
4
+ import { type Address, BaseError, ContractFunctionExecutionError } from 'viem'
5
5
  import { Abis, Addresses } from 'viem/tempo'
6
6
  import * as z from 'zod/mini'
7
7
 
@@ -134,7 +134,7 @@ export namespace schema {
134
134
  z.meta({ examples: [tokenExample.currency] }),
135
135
  ),
136
136
  createdAt: z
137
- .optional(z.iso.datetime())
137
+ .optional(Schema.dateTime())
138
138
  .check(
139
139
  z.describe(
140
140
  'Token creation timestamp, present when requested via `include=createdAt` ' +
@@ -212,7 +212,7 @@ export namespace schema {
212
212
  z.meta({ examples: [12345] }),
213
213
  ),
214
214
  firstAt: z
215
- .nullable(z.iso.datetime())
215
+ .nullable(Schema.dateTime())
216
216
  .check(
217
217
  z.describe(
218
218
  'The time of this token’s first `Transfer` event, or `null` if no transfers exist.',
@@ -220,7 +220,7 @@ export namespace schema {
220
220
  z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
221
221
  ),
222
222
  lastAt: z
223
- .nullable(z.iso.datetime())
223
+ .nullable(Schema.dateTime())
224
224
  .check(
225
225
  z.describe(
226
226
  'The time of this token’s most recent `Transfer` event, or `null` if no transfers exist.',
@@ -2591,7 +2591,12 @@ declare namespace getTokens {
2591
2591
 
2592
2592
  /** Matches metadata-read failures for addresses that are not TIP-20 tokens. */
2593
2593
  export function isTokenNotFound(cause: unknown) {
2594
- if (cause instanceof ContractFunctionExecutionError) return true
2594
+ // Tempo actions rethrow decoded reverts as `TempoExecutionError`, keeping the contract error as a cause.
2595
+ if (
2596
+ cause instanceof BaseError &&
2597
+ cause.walk((error) => error instanceof ContractFunctionExecutionError)
2598
+ )
2599
+ return true
2595
2600
  if (cause instanceof Error && cause.message.includes('invalid tip20 address')) return true
2596
2601
  return false
2597
2602
  }
@@ -450,7 +450,7 @@ export namespace schema {
450
450
  z.describe('The address that submitted or authorized the transaction.'),
451
451
  ),
452
452
  timestamp: z
453
- .nullable(z.iso.datetime())
453
+ .nullable(Schema.dateTime())
454
454
  .check(
455
455
  z.describe(
456
456
  'The block timestamp as ISO 8601, or `null` while the transaction is pending.',
@@ -465,13 +465,13 @@ export namespace schema {
465
465
  ),
466
466
  type: TransactionType,
467
467
  validAfter: z
468
- .nullish(z.iso.datetime())
468
+ .nullish(Schema.dateTime())
469
469
  .check(
470
470
  z.describe('Earliest ISO 8601 time when this Tempo transaction may be included.'),
471
471
  z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
472
472
  ),
473
473
  validBefore: z
474
- .nullish(z.iso.datetime())
474
+ .nullish(Schema.dateTime())
475
475
  .check(
476
476
  z.describe('Latest ISO 8601 time when this Tempo transaction may be included.'),
477
477
  z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
@@ -284,12 +284,10 @@ export namespace schema {
284
284
  sender: Schema.Address.check(z.describe('The account address that sent the tokens.')),
285
285
  sourceAmount: valuedTokenAmount,
286
286
  sourceToken: transferToken.check(z.describe('The token that moved.')),
287
- timestamp: z.iso
288
- .datetime()
289
- .check(
290
- z.describe('The block timestamp when this transfer was recorded.'),
291
- z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
292
- ),
287
+ timestamp: Schema.dateTime().check(
288
+ z.describe('The block timestamp when this transfer was recorded.'),
289
+ z.meta({ examples: ['2024-01-01T00:00:00Z'] }),
290
+ ),
293
291
  transactionHash: Schema.Hash.check(
294
292
  z.describe('The hash of the transaction that emitted this transfer event.'),
295
293
  ),
@@ -255,10 +255,8 @@ describe('GET /addresses/:address/valuation', () => {
255
255
  // Zone TIP-20 `balanceOf` reverts unless the `eth_call` caller is the queried account.
256
256
  const zoneDb = TestApp.database()
257
257
  await TestApp.verifiedSeed(zoneDb, runtime.zone.chainId, { tokens: usdTokens })
258
- const key = {
259
- ...TestApp.key,
260
- scopes: ['data:read', `zone:${runtime.zone.chainId}:read`],
261
- } satisfies TestApp.kvStore.Key
258
+ await TestApp.delegateZone(zoneDb, { chainIds: [runtime.zone.chainId] })
259
+ const key = TestApp.zoneReader({ ...TestApp.key, scopes: ['data:read'] }, [runtime.zone.chainId]) // prettier-ignore
262
260
  const client = app({
263
261
  auth: { keys: [key] },
264
262
  db: zoneDb,
@@ -57,12 +57,10 @@ export namespace schema {
57
57
  export const Pricing = OpenApi.component(
58
58
  z
59
59
  .object({
60
- asOf: z.iso
61
- .datetime()
62
- .check(
63
- z.describe('Publication date of the rate set as an ISO 8601 timestamp.'),
64
- z.meta({ examples: ['2026-07-20T00:00:00.000Z'] }),
65
- ),
60
+ asOf: Schema.dateTime().check(
61
+ z.describe('Publication date of the rate set as an ISO 8601 timestamp.'),
62
+ z.meta({ examples: ['2026-07-20T00:00:00.000Z'] }),
63
+ ),
66
64
  basis: z
67
65
  .literal('nominal')
68
66
  .check(
@@ -366,11 +366,7 @@ describe('access matrix', () => {
366
366
 
367
367
  test('rejects a sandbox key selecting a mainnet Zone', async () => {
368
368
  const zone = 421_700_001
369
- const sandbox = {
370
- ...writer,
371
- environment: 'sandbox',
372
- scopes: [...writer.scopes, `zone:${zone}:read`],
373
- } satisfies TestApp.kvStore.Key
369
+ const sandbox = TestApp.zoneReader({ ...writer, environment: 'sandbox' }, [zone])
374
370
  const app = TestApp.create({
375
371
  auth: { keys: [sandbox] },
376
372
  webhook: { supportedChainIds: [4217, 42431, zone] },