tapimo 0.10.2 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (386) hide show
  1. package/dist/App.d.ts +4896 -2166
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +2 -2
  4. package/dist/App.js.map +1 -1
  5. package/dist/Assets.d.ts +15 -0
  6. package/dist/Assets.d.ts.map +1 -1
  7. package/dist/Assets.js +7 -0
  8. package/dist/Assets.js.map +1 -1
  9. package/dist/Webhooks.d.ts +0 -75
  10. package/dist/Webhooks.d.ts.map +1 -1
  11. package/dist/Webhooks.js +1 -143
  12. package/dist/Webhooks.js.map +1 -1
  13. package/dist/admin/App.d.ts +127 -78
  14. package/dist/admin/App.d.ts.map +1 -1
  15. package/dist/admin/apps/earn-vaults.d.ts +115 -1
  16. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  17. package/dist/admin/apps/earn-vaults.js +59 -6
  18. package/dist/admin/apps/earn-vaults.js.map +1 -1
  19. package/dist/admin/apps/organizations.d.ts +3 -3
  20. package/dist/admin/apps/organizations.d.ts.map +1 -1
  21. package/dist/admin/apps/organizations.js +4 -2
  22. package/dist/admin/apps/organizations.js.map +1 -1
  23. package/dist/admin/apps/verified-tokens.d.ts +83 -83
  24. package/dist/admin/ui.generated.d.ts +1 -1
  25. package/dist/admin/ui.generated.d.ts.map +1 -1
  26. package/dist/admin/ui.generated.js +151 -151
  27. package/dist/admin/ui.generated.js.map +1 -1
  28. package/dist/apps/data/App.d.ts +5924 -4310
  29. package/dist/apps/data/App.d.ts.map +1 -1
  30. package/dist/apps/data/App.js +61 -9
  31. package/dist/apps/data/App.js.map +1 -1
  32. package/dist/apps/data/ZoneSelection.d.ts +62 -0
  33. package/dist/apps/data/ZoneSelection.d.ts.map +1 -0
  34. package/dist/apps/data/ZoneSelection.js +44 -0
  35. package/dist/apps/data/ZoneSelection.js.map +1 -0
  36. package/dist/apps/data/routes/activities.d.ts +2368 -5
  37. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  38. package/dist/apps/data/routes/activities.js +423 -114
  39. package/dist/apps/data/routes/activities.js.map +1 -1
  40. package/dist/apps/data/routes/addresses.d.ts +131 -0
  41. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  42. package/dist/apps/data/routes/balances.d.ts +25 -25
  43. package/dist/apps/data/routes/balances.js +1 -1
  44. package/dist/apps/data/routes/balances.js.map +1 -1
  45. package/dist/apps/data/routes/blocks.d.ts +1 -1
  46. package/dist/apps/data/routes/blocks.js +1 -1
  47. package/dist/apps/data/routes/blocks.js.map +1 -1
  48. package/dist/apps/data/routes/earn.d.ts +135 -10
  49. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  50. package/dist/apps/data/routes/earn.js +157 -25
  51. package/dist/apps/data/routes/earn.js.map +1 -1
  52. package/dist/apps/data/routes/exchanges.d.ts +829 -123
  53. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  54. package/dist/apps/data/routes/exchanges.js +16 -13
  55. package/dist/apps/data/routes/exchanges.js.map +1 -1
  56. package/dist/apps/data/routes/fee-amm.d.ts +26 -26
  57. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  58. package/dist/apps/data/routes/fee-amm.js +9 -11
  59. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  60. package/dist/apps/data/routes/receipts.d.ts +54 -54
  61. package/dist/apps/data/routes/receipts.js +1 -1
  62. package/dist/apps/data/routes/receipts.js.map +1 -1
  63. package/dist/apps/data/routes/rpc.js +24 -10
  64. package/dist/apps/data/routes/rpc.js.map +1 -1
  65. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  66. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  67. package/dist/apps/data/routes/tokenlist.js +16 -15
  68. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  69. package/dist/apps/data/routes/tokens.d.ts +17 -3
  70. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  71. package/dist/apps/data/routes/tokens.js +34 -15
  72. package/dist/apps/data/routes/tokens.js.map +1 -1
  73. package/dist/apps/data/routes/transactions.d.ts +1 -1
  74. package/dist/apps/data/routes/transactions.js +1 -1
  75. package/dist/apps/data/routes/transactions.js.map +1 -1
  76. package/dist/apps/data/routes/transfers.d.ts +13 -13
  77. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  78. package/dist/apps/data/routes/transfers.js +7 -9
  79. package/dist/apps/data/routes/transfers.js.map +1 -1
  80. package/dist/apps/data/routes/valuation.d.ts +21 -21
  81. package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
  82. package/dist/apps/data/routes/webhooks.d.ts +1011 -151
  83. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  84. package/dist/apps/data/routes/webhooks.js +126 -739
  85. package/dist/apps/data/routes/webhooks.js.map +1 -1
  86. package/dist/apps/data/routes/zones.d.ts +15 -15
  87. package/dist/apps/funding/App.d.ts +27 -27
  88. package/dist/apps/funding/routes/chains.d.ts.map +1 -1
  89. package/dist/apps/funding/routes/chains.js +5 -4
  90. package/dist/apps/funding/routes/chains.js.map +1 -1
  91. package/dist/apps/funding/routes/deposit-addresses.d.ts +18 -18
  92. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  93. package/dist/apps/funding/routes/deposit-addresses.js +8 -8
  94. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  95. package/dist/apps/funding/routes/providers.d.ts.map +1 -1
  96. package/dist/apps/funding/routes/providers.js +3 -2
  97. package/dist/apps/funding/routes/providers.js.map +1 -1
  98. package/dist/apps/funding/routes/quotes.d.ts.map +1 -1
  99. package/dist/apps/funding/routes/quotes.js +2 -2
  100. package/dist/apps/funding/routes/quotes.js.map +1 -1
  101. package/dist/apps/funding/routes/transfers.d.ts +33 -33
  102. package/dist/apps/management/App.d.ts +1433 -322
  103. package/dist/apps/management/App.d.ts.map +1 -1
  104. package/dist/apps/management/Billing.d.ts.map +1 -1
  105. package/dist/apps/management/Billing.js +19 -6
  106. package/dist/apps/management/Billing.js.map +1 -1
  107. package/dist/apps/management/routes/api-keys.d.ts +154 -94
  108. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  109. package/dist/apps/management/routes/api-keys.js +76 -30
  110. package/dist/apps/management/routes/api-keys.js.map +1 -1
  111. package/dist/apps/management/routes/billing.d.ts +103 -30
  112. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  113. package/dist/apps/management/routes/billing.js +91 -32
  114. package/dist/apps/management/routes/billing.js.map +1 -1
  115. package/dist/apps/management/routes/faucet.d.ts +12 -12
  116. package/dist/apps/management/routes/faucet.d.ts.map +1 -1
  117. package/dist/apps/management/routes/faucet.js +23 -12
  118. package/dist/apps/management/routes/faucet.js.map +1 -1
  119. package/dist/apps/management/routes/invitations.d.ts +46 -13
  120. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  121. package/dist/apps/management/routes/invitations.js +79 -29
  122. package/dist/apps/management/routes/invitations.js.map +1 -1
  123. package/dist/apps/management/routes/invite-links.d.ts +128 -83
  124. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  125. package/dist/apps/management/routes/invite-links.js +100 -41
  126. package/dist/apps/management/routes/invite-links.js.map +1 -1
  127. package/dist/apps/management/routes/me.d.ts +5 -5
  128. package/dist/apps/management/routes/me.d.ts.map +1 -1
  129. package/dist/apps/management/routes/me.js +14 -10
  130. package/dist/apps/management/routes/me.js.map +1 -1
  131. package/dist/apps/management/routes/members.d.ts +68 -47
  132. package/dist/apps/management/routes/members.d.ts.map +1 -1
  133. package/dist/apps/management/routes/members.js +37 -18
  134. package/dist/apps/management/routes/members.js.map +1 -1
  135. package/dist/apps/management/routes/orgs.d.ts +48 -8
  136. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  137. package/dist/apps/management/routes/orgs.js +48 -19
  138. package/dist/apps/management/routes/orgs.js.map +1 -1
  139. package/dist/apps/management/routes/projects.d.ts +130 -68
  140. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  141. package/dist/apps/management/routes/projects.js +72 -21
  142. package/dist/apps/management/routes/projects.js.map +1 -1
  143. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  144. package/dist/apps/management/routes/scopes.js +8 -5
  145. package/dist/apps/management/routes/scopes.js.map +1 -1
  146. package/dist/apps/management/routes/usage.d.ts +38 -38
  147. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  148. package/dist/apps/management/routes/usage.js +41 -31
  149. package/dist/apps/management/routes/usage.js.map +1 -1
  150. package/dist/apps/management/routes/verified-token-requests.d.ts +34 -6
  151. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -1
  152. package/dist/apps/management/routes/verified-token-requests.js +36 -17
  153. package/dist/apps/management/routes/verified-token-requests.js.map +1 -1
  154. package/dist/apps/management/routes/webhooks.d.ts +1186 -197
  155. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  156. package/dist/apps/management/routes/webhooks.js +106 -38
  157. package/dist/apps/management/routes/webhooks.js.map +1 -1
  158. package/dist/apps/mpp/internal/Adapter.d.ts +1 -1
  159. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  160. package/dist/apps/mpp/internal/Adapter.js +12 -0
  161. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  162. package/dist/db/Db.d.ts +2 -0
  163. package/dist/db/Db.d.ts.map +1 -1
  164. package/dist/db/Db.js +61 -0
  165. package/dist/db/Db.js.map +1 -1
  166. package/dist/db/Schema.d.ts +30 -2
  167. package/dist/db/Schema.d.ts.map +1 -1
  168. package/dist/db/Schema.js +28 -3
  169. package/dist/db/Schema.js.map +1 -1
  170. package/dist/db/tables/earnVaults.d.ts +5 -1
  171. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  172. package/dist/db/tables/earnVaults.js +5 -0
  173. package/dist/db/tables/earnVaults.js.map +1 -1
  174. package/dist/db/tables/webhookDeliveries.d.ts.map +1 -1
  175. package/dist/db/tables/webhookDeliveries.js +10 -0
  176. package/dist/db/tables/webhookDeliveries.js.map +1 -1
  177. package/dist/db/tables/webhookQueueCompletions.d.ts +15 -0
  178. package/dist/db/tables/webhookQueueCompletions.d.ts.map +1 -0
  179. package/dist/db/tables/webhookQueueCompletions.js +32 -0
  180. package/dist/db/tables/webhookQueueCompletions.js.map +1 -0
  181. package/dist/db/tables/webhookQueueEvents.d.ts +16 -20
  182. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  183. package/dist/db/tables/webhookQueueEvents.js +68 -43
  184. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  185. package/dist/db/tables/webhookSubscriptions.d.ts +47 -72
  186. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  187. package/dist/db/tables/webhookSubscriptions.js +92 -105
  188. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  189. package/dist/internal/Auth.d.ts +8 -1
  190. package/dist/internal/Auth.d.ts.map +1 -1
  191. package/dist/internal/Auth.js +13 -3
  192. package/dist/internal/Auth.js.map +1 -1
  193. package/dist/internal/Cache.d.ts.map +1 -1
  194. package/dist/internal/Cache.js +11 -7
  195. package/dist/internal/Cache.js.map +1 -1
  196. package/dist/internal/EarnVaults.d.ts +41 -2
  197. package/dist/internal/EarnVaults.d.ts.map +1 -1
  198. package/dist/internal/EarnVaults.js +167 -0
  199. package/dist/internal/EarnVaults.js.map +1 -1
  200. package/dist/internal/MetricSink.d.ts +35 -125
  201. package/dist/internal/MetricSink.d.ts.map +1 -1
  202. package/dist/internal/MetricSink.js +50 -121
  203. package/dist/internal/MetricSink.js.map +1 -1
  204. package/dist/internal/OpenApi.d.ts +26 -22
  205. package/dist/internal/OpenApi.d.ts.map +1 -1
  206. package/dist/internal/OpenApi.js +128 -39
  207. package/dist/internal/OpenApi.js.map +1 -1
  208. package/dist/internal/Response.d.ts +13 -8
  209. package/dist/internal/Response.d.ts.map +1 -1
  210. package/dist/internal/Response.js +16 -5
  211. package/dist/internal/Response.js.map +1 -1
  212. package/dist/internal/Schema.d.ts +8 -8
  213. package/dist/internal/Schema.d.ts.map +1 -1
  214. package/dist/internal/Schema.js +10 -9
  215. package/dist/internal/Schema.js.map +1 -1
  216. package/dist/internal/Store.d.ts +15 -6
  217. package/dist/internal/Store.d.ts.map +1 -1
  218. package/dist/internal/Store.js +45 -15
  219. package/dist/internal/Store.js.map +1 -1
  220. package/dist/internal/Tidx.d.ts +2 -0
  221. package/dist/internal/Tidx.d.ts.map +1 -1
  222. package/dist/internal/Tidx.js +16 -4
  223. package/dist/internal/Tidx.js.map +1 -1
  224. package/dist/internal/WebhookTransfer.d.ts +1 -55
  225. package/dist/internal/WebhookTransfer.d.ts.map +1 -1
  226. package/dist/internal/WebhookTransfer.js +1 -239
  227. package/dist/internal/WebhookTransfer.js.map +1 -1
  228. package/dist/internal/Webhooks.d.ts +112 -56
  229. package/dist/internal/Webhooks.d.ts.map +1 -1
  230. package/dist/internal/Webhooks.js +124 -93
  231. package/dist/internal/Webhooks.js.map +1 -1
  232. package/dist/internal/funding/Deposit.d.ts +2 -2
  233. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  234. package/dist/internal/funding/Deposit.js +9 -8
  235. package/dist/internal/funding/Deposit.js.map +1 -1
  236. package/dist/internal/funding/DepositAddress.d.ts +4 -4
  237. package/dist/internal/funding/DepositAddress.d.ts.map +1 -1
  238. package/dist/internal/funding/DepositAddress.js +9 -8
  239. package/dist/internal/funding/DepositAddress.js.map +1 -1
  240. package/dist/internal/funding/DepositWebhook.d.ts +25 -0
  241. package/dist/internal/funding/DepositWebhook.d.ts.map +1 -0
  242. package/dist/internal/funding/DepositWebhook.js +74 -0
  243. package/dist/internal/funding/DepositWebhook.js.map +1 -0
  244. package/dist/internal/funding/Provider.d.ts.map +1 -1
  245. package/dist/internal/funding/Provider.js +13 -12
  246. package/dist/internal/funding/Provider.js.map +1 -1
  247. package/dist/internal/funding/Reconciliation.d.ts +6 -0
  248. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  249. package/dist/internal/funding/Reconciliation.js +42 -10
  250. package/dist/internal/funding/Reconciliation.js.map +1 -1
  251. package/dist/internal/funding/index.d.ts +1 -0
  252. package/dist/internal/funding/index.d.ts.map +1 -1
  253. package/dist/internal/funding/index.js +1 -0
  254. package/dist/internal/funding/index.js.map +1 -1
  255. package/dist/internal/funding/providers/stargate.d.ts +19 -0
  256. package/dist/internal/funding/providers/stargate.d.ts.map +1 -0
  257. package/dist/internal/funding/providers/stargate.js +143 -0
  258. package/dist/internal/funding/providers/stargate.js.map +1 -0
  259. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
  260. package/dist/internal/webhookDestinations/slack.js +16 -0
  261. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  262. package/dist/providers/index.d.ts +7 -0
  263. package/dist/providers/index.d.ts.map +1 -1
  264. package/dist/providers/index.js +3 -0
  265. package/dist/providers/index.js.map +1 -1
  266. package/package.json +2 -2
  267. package/src/App.test.ts +48 -0
  268. package/src/App.ts +7 -2
  269. package/src/Assets.test.ts +18 -0
  270. package/src/Assets.ts +22 -0
  271. package/src/Client.test-d.ts +287 -17
  272. package/src/Webhooks.ts +1 -220
  273. package/src/admin/apps/earn-vaults.test.ts +143 -0
  274. package/src/admin/apps/earn-vaults.ts +83 -6
  275. package/src/admin/apps/organizations.ts +6 -2
  276. package/src/admin/ui/src/routes/api-keys.tsx +36 -0
  277. package/src/admin/ui.generated.ts +151 -189
  278. package/src/apps/data/App.test.ts +31 -0
  279. package/src/apps/data/App.ts +64 -10
  280. package/src/apps/data/ZoneSelection.test.ts +196 -0
  281. package/src/apps/data/ZoneSelection.ts +108 -0
  282. package/src/apps/data/routes/activities.test.ts +435 -12
  283. package/src/apps/data/routes/activities.ts +562 -125
  284. package/src/apps/data/routes/balances.ts +1 -1
  285. package/src/apps/data/routes/blocks.ts +1 -1
  286. package/src/apps/data/routes/earn.test.ts +183 -23
  287. package/src/apps/data/routes/earn.ts +225 -29
  288. package/src/apps/data/routes/earn.zone-access.test.ts +46 -0
  289. package/src/apps/data/routes/exchanges.test.ts +31 -1
  290. package/src/apps/data/routes/exchanges.ts +19 -15
  291. package/src/apps/data/routes/fee-amm.ts +18 -11
  292. package/src/apps/data/routes/receipts.ts +1 -1
  293. package/src/apps/data/routes/rpc.test.ts +75 -0
  294. package/src/apps/data/routes/rpc.ts +23 -9
  295. package/src/apps/data/routes/tokenlist.ts +21 -18
  296. package/src/apps/data/routes/tokens.test.ts +29 -0
  297. package/src/apps/data/routes/tokens.ts +38 -15
  298. package/src/apps/data/routes/transactions.ts +1 -1
  299. package/src/apps/data/routes/transfers.test.ts +3 -3
  300. package/src/apps/data/routes/transfers.ts +12 -9
  301. package/src/apps/data/routes/webhooks.test.ts +179 -1497
  302. package/src/apps/data/routes/webhooks.ts +156 -976
  303. package/src/apps/data/routes/zones.test.ts +19 -13
  304. package/src/apps/funding/routes/chains.test.ts +211 -7
  305. package/src/apps/funding/routes/chains.ts +19 -12
  306. package/src/apps/funding/routes/deposit-addresses.test.ts +394 -0
  307. package/src/apps/funding/routes/deposit-addresses.ts +84 -72
  308. package/src/apps/funding/routes/providers.ts +9 -5
  309. package/src/apps/funding/routes/quotes.test.ts +46 -0
  310. package/src/apps/funding/routes/quotes.ts +8 -5
  311. package/src/apps/funding/routes/transfers.test.ts +35 -32
  312. package/src/apps/management/Billing.test.ts +26 -0
  313. package/src/apps/management/Billing.ts +24 -7
  314. package/src/apps/management/routes/api-keys.test.ts +178 -0
  315. package/src/apps/management/routes/api-keys.ts +203 -144
  316. package/src/apps/management/routes/billing.test.ts +209 -0
  317. package/src/apps/management/routes/billing.ts +254 -177
  318. package/src/apps/management/routes/faucet.test.ts +39 -0
  319. package/src/apps/management/routes/faucet.ts +75 -41
  320. package/src/apps/management/routes/invitations.test.ts +216 -0
  321. package/src/apps/management/routes/invitations.ts +186 -109
  322. package/src/apps/management/routes/invite-links.test.ts +263 -1
  323. package/src/apps/management/routes/invite-links.ts +295 -214
  324. package/src/apps/management/routes/me.test.ts +49 -0
  325. package/src/apps/management/routes/me.ts +42 -32
  326. package/src/apps/management/routes/members.test.ts +124 -1
  327. package/src/apps/management/routes/members.ts +81 -51
  328. package/src/apps/management/routes/orgs.test.ts +176 -0
  329. package/src/apps/management/routes/orgs.ts +101 -59
  330. package/src/apps/management/routes/projects.test.ts +183 -0
  331. package/src/apps/management/routes/projects.ts +124 -60
  332. package/src/apps/management/routes/scopes.test.ts +44 -0
  333. package/src/apps/management/routes/scopes.ts +37 -28
  334. package/src/apps/management/routes/usage.test.ts +92 -0
  335. package/src/apps/management/routes/usage.ts +186 -151
  336. package/src/apps/management/routes/verified-token-requests.test.ts +114 -0
  337. package/src/apps/management/routes/verified-token-requests.ts +166 -133
  338. package/src/apps/management/routes/webhooks.test.ts +313 -1
  339. package/src/apps/management/routes/webhooks.ts +220 -71
  340. package/src/apps/mpp/internal/Adapter.ts +13 -1
  341. package/src/db/Db.test.ts +42 -5
  342. package/src/db/Db.ts +85 -0
  343. package/src/db/Schema.ts +41 -3
  344. package/src/db/tables/earnVaults.test.ts +22 -0
  345. package/src/db/tables/earnVaults.ts +11 -1
  346. package/src/db/tables/organizations.test.ts +5 -2
  347. package/src/db/tables/webhookDeliveries.ts +13 -0
  348. package/src/db/tables/webhookQueueCompletions.ts +55 -0
  349. package/src/db/tables/webhookQueueEvents.ts +97 -57
  350. package/src/db/tables/webhookSubscriptions.ts +134 -144
  351. package/src/internal/Auth.ts +23 -5
  352. package/src/internal/Cache.ts +14 -7
  353. package/src/internal/EarnVaults.capabilities.test.ts +33 -0
  354. package/src/internal/EarnVaults.test.ts +79 -0
  355. package/src/internal/EarnVaults.ts +277 -0
  356. package/src/internal/MetricSink.test.ts +41 -373
  357. package/src/internal/MetricSink.ts +92 -273
  358. package/src/internal/OpenApi.ts +165 -49
  359. package/src/internal/Response.test.ts +95 -0
  360. package/src/internal/Response.ts +40 -2
  361. package/src/internal/Schema.test.ts +34 -0
  362. package/src/internal/Schema.ts +20 -9
  363. package/src/internal/Store.test.ts +186 -0
  364. package/src/internal/Store.ts +57 -17
  365. package/src/internal/Tidx.test.ts +19 -0
  366. package/src/internal/Tidx.ts +16 -4
  367. package/src/internal/WebhookTransfer.ts +1 -351
  368. package/src/internal/Webhooks.test.ts +222 -145
  369. package/src/internal/Webhooks.ts +234 -135
  370. package/src/internal/funding/Deposit.ts +71 -64
  371. package/src/internal/funding/DepositAddress.ts +50 -43
  372. package/src/internal/funding/DepositWebhook.test.ts +131 -0
  373. package/src/internal/funding/DepositWebhook.ts +101 -0
  374. package/src/internal/funding/Provider.ts +164 -142
  375. package/src/internal/funding/Reconciliation.test.ts +14 -0
  376. package/src/internal/funding/Reconciliation.ts +161 -86
  377. package/src/internal/funding/index.test.ts +1 -0
  378. package/src/internal/funding/index.ts +1 -0
  379. package/src/internal/funding/providers/index.test.ts +185 -0
  380. package/src/internal/funding/providers/stargate.ts +184 -0
  381. package/src/internal/webhookDestinations/slack.ts +15 -0
  382. package/src/providers/index.test.ts +1 -0
  383. package/src/providers/index.ts +9 -0
  384. package/src/Webhooks.bench.ts +0 -714
  385. package/src/Webhooks.memory.bench.ts +0 -250
  386. package/src/Webhooks.test.ts +0 -146
@@ -11,6 +11,7 @@ import {
11
11
  import * as z from 'zod/mini'
12
12
 
13
13
  import type * as App from '../../../App.js'
14
+ import * as Scope from '../../../Scope.js'
14
15
  import * as Db from '../../../db/Db.js'
15
16
  import * as core_EarnVaults from '../../../db/tables/earnVaults.js'
16
17
  import * as Auth from '../../../internal/Auth.js'
@@ -90,6 +91,22 @@ export declare namespace discoveryBatchLimit {
90
91
  }
91
92
  }
92
93
 
94
+ /** Returns whether API-key scopes grant read access to one private Zone. */
95
+ export function hasZoneAccess(options: hasZoneAccess.Options): boolean {
96
+ const scopes = options.scopes ?? []
97
+ return scopes.includes(Scope.wildcard) || scopes.includes(`zone:${options.chainId}:read`)
98
+ }
99
+
100
+ export declare namespace hasZoneAccess {
101
+ /** Inputs selecting one Zone against an optional API-key scope set. */
102
+ type Options = {
103
+ /** Private Zone chain id. */
104
+ chainId: number
105
+ /** API-key scopes, absent for every other principal. */
106
+ scopes?: readonly string[] | undefined
107
+ }
108
+ }
109
+
93
110
  /** Zod schemas owned by the public Earn-vault resource. */
94
111
  export namespace schema {
95
112
  const capability = z
@@ -131,7 +148,7 @@ export namespace schema {
131
148
  )
132
149
 
133
150
  const include = z
134
- .enum(['access', 'apy', 'capabilities', 'token.logoUri', 'tvl', 'zone'])
151
+ .enum(['access', 'apy', 'capabilities', 'token.logoUri', 'tvl', 'zone', 'zones'])
135
152
  .check(z.describe('Optional vault fields to embed via `include`.'))
136
153
 
137
154
  const includeQuery = Schema.includeQuery(
@@ -142,7 +159,7 @@ export namespace schema {
142
159
  // `apy` and `tvl` need indexer and FX access, so surfaces lacking either
143
160
  // select from this reduced set instead.
144
161
  const baseInclude = z
145
- .enum(['access', 'capabilities', 'token.logoUri', 'zone'])
162
+ .enum(['access', 'capabilities', 'token.logoUri', 'zone', 'zones'])
146
163
  .check(z.describe('Optional vault fields to embed via `include`.'))
147
164
 
148
165
  const baseIncludeQuery = Schema.includeQuery(
@@ -174,6 +191,42 @@ export namespace schema {
174
191
  })
175
192
  .check(z.describe('Private Zone route configured for a verified vault.'))
176
193
 
194
+ const zoneRoute = z
195
+ .strictObject({
196
+ chainId: Schema.ChainId.check(
197
+ z.describe('Private Zone chain id.'),
198
+ z.meta({ examples: [1424310001] }),
199
+ ),
200
+ deploymentBlock: z
201
+ .number()
202
+ .check(
203
+ z.int(),
204
+ z.nonnegative(),
205
+ z.describe('Parent-chain block that deployed the Earn router.'),
206
+ z.meta({ examples: [31039238] }),
207
+ ),
208
+ earnRouter: Schema.Address.check(
209
+ z.describe('Parent-chain router for this Zone and Earn vault.'),
210
+ z.meta({ examples: ['0x9144086a79dea966d8bf1b52125ebed8919fc45c'] }),
211
+ ),
212
+ inputTokens: z
213
+ .array(Schema.Address)
214
+ .check(
215
+ z.describe('Tokens accepted by private deposits.'),
216
+ z.meta({ examples: [['0x20c000000000000000000000ff04042ee92fd449']] }),
217
+ ),
218
+ name: z
219
+ .string()
220
+ .check(z.describe('Private Zone name.'), z.meta({ examples: ['zone-moderato-internal'] })),
221
+ outputTokens: z
222
+ .array(Schema.Address)
223
+ .check(
224
+ z.describe('Tokens returned by private redemptions.'),
225
+ z.meta({ examples: [['0x20c000000000000000000000ff04042ee92fd449']] }),
226
+ ),
227
+ })
228
+ .check(z.describe('Verified Earn route through one private Zone.'))
229
+
177
230
  const value = z.strictObject({
178
231
  amount: Schema.DecimalString.check(
179
232
  z.describe('Value in base units at `decimals` precision.'),
@@ -268,6 +321,23 @@ export namespace schema {
268
321
  zone: z
269
322
  .optional(z.nullable(zone))
270
323
  .check(z.describe('Curated private Zone route, when requested, or null when absent.')),
324
+ zones: z.optional(z.array(zoneRoute)).check(
325
+ z.describe('Curated private Zone routes, when requested.'),
326
+ z.meta({
327
+ examples: [
328
+ [
329
+ {
330
+ chainId: 1424310001,
331
+ deploymentBlock: 31039238,
332
+ earnRouter: '0x9144086a79dea966d8bf1b52125ebed8919fc45c',
333
+ inputTokens: ['0x20c000000000000000000000ff04042ee92fd449'],
334
+ name: 'zone-moderato-internal',
335
+ outputTokens: ['0x20c000000000000000000000ff04042ee92fd449'],
336
+ },
337
+ ],
338
+ ],
339
+ }),
340
+ ),
271
341
  })
272
342
 
273
343
  /** One compatible Earn vault resolved from current chain state. */
@@ -736,8 +806,8 @@ export function earn(options: earn.Options = {}) {
736
806
  // as current-state rather than slow-changing metadata.
737
807
  Cache.response<App.Environment>({
738
808
  cacheControl: Cache.policies.state,
739
- key: (c) => Cache.urlKey(c, schema.getEarnVaults.Query),
740
- name: 'tempo-api:earn-vaults:v2',
809
+ key: (c) => vaultCacheKey(c, schema.getEarnVaults.Query),
810
+ name: 'tempo-api:earn-vaults:v3',
741
811
  }),
742
812
  async (c) => {
743
813
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
@@ -780,8 +850,8 @@ export function earn(options: earn.Options = {}) {
780
850
  }),
781
851
  Cache.response<App.Environment>({
782
852
  cacheControl: Cache.policies.state,
783
- key: (c) => Cache.urlKey(c, schema.getVerifiedEarnVaults.Query),
784
- name: 'tempo-api:earn-vaults:v2',
853
+ key: (c) => vaultCacheKey(c, schema.getVerifiedEarnVaults.Query),
854
+ name: 'tempo-api:earn-vaults:v3',
785
855
  }),
786
856
  async (c) => {
787
857
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
@@ -1114,8 +1184,8 @@ export function earn(options: earn.Options = {}) {
1114
1184
  }),
1115
1185
  Cache.response<App.Environment>({
1116
1186
  cacheControl: Cache.policies.state,
1117
- key: (c) => Cache.urlKey(c, schema.getEarnVault.Query),
1118
- name: 'tempo-api:earn-vaults:v2',
1187
+ key: (c) => vaultCacheKey(c, schema.getEarnVault.Query),
1188
+ name: 'tempo-api:earn-vaults:v3',
1119
1189
  }),
1120
1190
  async (c) => {
1121
1191
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
@@ -2080,12 +2150,18 @@ export async function listVaults(c: Context<App.Environment>, options: listVault
2080
2150
  page.items.map(async (item) => {
2081
2151
  const record = registry.get(item.vaultAddress.toLowerCase())
2082
2152
  try {
2083
- const discovery = await resolveVaultDiscovery(c, {
2153
+ const discovered = await resolveVaultDiscovery(c, {
2084
2154
  chainId: options.chainId,
2085
2155
  include: discoveryInclude(options),
2086
2156
  vaultAddress: item.vaultAddress,
2087
2157
  })
2088
- return { discovery, position: item.position, record }
2158
+ const { discovery, zoneRoutes } = await resolveVaultRoutes(c, {
2159
+ capability: options.capability,
2160
+ discovery: discovered,
2161
+ include,
2162
+ record,
2163
+ })
2164
+ return { discovery, position: item.position, record, zoneRoutes }
2089
2165
  } catch (cause) {
2090
2166
  if (!record && isIncompatible(cause)) return undefined
2091
2167
  throw cause
@@ -2132,8 +2208,8 @@ export async function listVaults(c: Context<App.Environment>, options: listVault
2132
2208
  ])
2133
2209
  for (const [vault, apy] of missingApy ?? []) apyByVault.set(vault, apy)
2134
2210
  const apy = include.includes('apy') ? apyByVault : undefined
2135
- const data = page.map((match) =>
2136
- resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
2211
+ const data = await Promise.all(
2212
+ page.map((match) => resolveVault(c, { ...match, apy, include, rates, snapshot, tokens })),
2137
2213
  )
2138
2214
  const last = matches[options.limit - 1]
2139
2215
  const nextPosition =
@@ -2151,6 +2227,7 @@ export declare namespace listVaults {
2151
2227
  discovery: EarnVaults.Discovery
2152
2228
  position: Position
2153
2229
  record?: RegistryRecord | undefined
2230
+ zoneRoutes: readonly EarnVaults.ResolvedZoneRoute[]
2154
2231
  }
2155
2232
 
2156
2233
  /** Options for listing compatible Earn vaults. */
@@ -2179,6 +2256,7 @@ export async function listVerifiedVaults(
2179
2256
  const candidates = records.filter(
2180
2257
  (record) => !cursor || record.vaultAddress.toLowerCase() > cursor,
2181
2258
  )
2259
+ const include = vaultInclude(options)
2182
2260
  const matches: listVerifiedVaults.Match[] = []
2183
2261
 
2184
2262
  let offset = 0
@@ -2192,14 +2270,20 @@ export async function listVerifiedVaults(
2192
2270
  const batch = candidates.slice(offset, offset + batchSize)
2193
2271
  offset += batch.length
2194
2272
  const discovered = await Promise.all(
2195
- batch.map(async (record) => ({
2196
- discovery: await resolveVaultDiscovery(c, {
2273
+ batch.map(async (record) => {
2274
+ const discovered = await resolveVaultDiscovery(c, {
2197
2275
  chainId: options.chainId,
2198
2276
  include: discoveryInclude(options),
2199
2277
  vaultAddress: Schema.Address.parse(record.vaultAddress.toLowerCase()),
2200
- }),
2201
- record,
2202
- })),
2278
+ })
2279
+ const { discovery, zoneRoutes } = await resolveVaultRoutes(c, {
2280
+ capability: options.capability,
2281
+ discovery: discovered,
2282
+ include,
2283
+ record,
2284
+ })
2285
+ return { discovery, record, zoneRoutes }
2286
+ }),
2203
2287
  )
2204
2288
  for (const match of discovered) {
2205
2289
  if (!matchesVaultFilters(match.discovery, options)) continue
@@ -2209,7 +2293,6 @@ export async function listVerifiedVaults(
2209
2293
 
2210
2294
  const page = matches.slice(0, options.limit)
2211
2295
  const discoveries = page.map(({ discovery }) => discovery)
2212
- const include = vaultInclude(options)
2213
2296
  const [apy, rates, tokens] = await Promise.all([
2214
2297
  resolvePageApy(c, {
2215
2298
  chainId: options.chainId,
@@ -2220,10 +2303,12 @@ export async function listVerifiedVaults(
2220
2303
  resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
2221
2304
  resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
2222
2305
  ])
2223
- const data = page.map((match) =>
2224
- Response.validated(
2225
- schema.VerifiedVault,
2226
- resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
2306
+ const data = await Promise.all(
2307
+ page.map(async (match) =>
2308
+ Response.validated(
2309
+ schema.VerifiedVault,
2310
+ await resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
2311
+ ),
2227
2312
  ),
2228
2313
  )
2229
2314
  const last = matches[options.limit - 1]
@@ -2240,6 +2325,7 @@ export declare namespace listVerifiedVaults {
2240
2325
  type Match = {
2241
2326
  discovery: EarnVaults.Discovery
2242
2327
  record: RegistryRecord
2328
+ zoneRoutes: readonly EarnVaults.ResolvedZoneRoute[]
2243
2329
  }
2244
2330
 
2245
2331
  /** Options for listing verified Earn vaults. */
@@ -2525,13 +2611,19 @@ export async function getVault(c: Context<App.Environment>, options: getVault.Op
2525
2611
  VerifiedTokens.snapshot(c, options.chainId),
2526
2612
  ])
2527
2613
  try {
2528
- const discovery = await resolveVaultDiscovery(c, {
2614
+ const discovered = await resolveVaultDiscovery(c, {
2529
2615
  chainId: options.chainId,
2530
2616
  include: discoveryInclude({ capability: [], include: options.include }),
2531
2617
  vaultAddress: options.vaultAddress,
2532
2618
  })
2533
- const discoveries = [discovery]
2534
2619
  const include = vaultInclude(options)
2620
+ const { discovery, zoneRoutes } = await resolveVaultRoutes(c, {
2621
+ capability: [],
2622
+ discovery: discovered,
2623
+ include,
2624
+ record,
2625
+ })
2626
+ const discoveries = [discovery]
2535
2627
  const [apy, rates, tokens] = await Promise.all([
2536
2628
  resolvePageApy(c, {
2537
2629
  chainId: options.chainId,
@@ -2543,7 +2635,7 @@ export async function getVault(c: Context<App.Environment>, options: getVault.Op
2543
2635
  resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
2544
2636
  ])
2545
2637
  return {
2546
- ...resolveVault(c, {
2638
+ ...(await resolveVault(c, {
2547
2639
  apy,
2548
2640
  discovery,
2549
2641
  include,
@@ -2551,7 +2643,8 @@ export async function getVault(c: Context<App.Environment>, options: getVault.Op
2551
2643
  record,
2552
2644
  snapshot,
2553
2645
  tokens,
2554
- }),
2646
+ zoneRoutes,
2647
+ })),
2555
2648
  ...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
2556
2649
  }
2557
2650
  } catch (cause) {
@@ -2586,6 +2679,24 @@ declare namespace vaultInclude {
2586
2679
  type Options = Pick<z.output<typeof schema.getEarnVault.Query>, 'apy.window' | 'include'>
2587
2680
  }
2588
2681
 
2682
+ /** Builds an Earn-vault cache key partitioned by Zone-visible API keys. */
2683
+ export function vaultCacheKey<const query extends z.ZodMiniType>(
2684
+ c: Context<App.Environment>,
2685
+ query: query,
2686
+ ): string {
2687
+ const key = Cache.urlKey(c, query)
2688
+ const url = new URL(key)
2689
+ const includesRoutes = url.searchParams
2690
+ .getAll('include')
2691
+ .some((include) => include === 'zone' || include === 'zones')
2692
+ if (!includesRoutes) return key
2693
+
2694
+ const principal = Auth.getPrincipal(c)
2695
+ if (principal?.type !== 'api_key') return key
2696
+ url.searchParams.set('principal', `${principal.type}:${principal.id}`)
2697
+ return url.toString()
2698
+ }
2699
+
2589
2700
  function discoveryInclude(
2590
2701
  options: discoveryInclude.Options,
2591
2702
  ): readonly EarnVaults.resolve.Include[] {
@@ -2638,6 +2749,60 @@ declare namespace resolveVaultDiscovery {
2638
2749
  }
2639
2750
  }
2640
2751
 
2752
+ async function resolveVaultRoutes(
2753
+ c: Context<App.Environment>,
2754
+ options: resolveVaultRoutes.Options,
2755
+ ): Promise<resolveVaultRoutes.Result> {
2756
+ const { discovery, record } = options
2757
+ if (!record || record.zones.length === 0) return { discovery, zoneRoutes: [] }
2758
+
2759
+ const principal = Auth.getPrincipal(c)
2760
+ const scopes = principal?.type === 'api_key' ? principal.apiKey.scopes : undefined
2761
+ const includesRoutes = options.include.includes('zone') || options.include.includes('zones')
2762
+ const needsCapabilities =
2763
+ options.include.includes('capabilities') ||
2764
+ options.capability.includes('privateRouting') ||
2765
+ options.capability.includes('routerSwaps')
2766
+ const visibleRoutes = record.zones.filter((route) =>
2767
+ hasZoneAccess({ chainId: route.chainId, scopes }),
2768
+ )
2769
+ // Capabilities describe the vault; API-key scopes limit only the route metadata.
2770
+ const routes = needsCapabilities ? record.zones : includesRoutes ? visibleRoutes : []
2771
+ if (routes.length === 0) return { discovery, zoneRoutes: [] }
2772
+
2773
+ const resolved = await EarnVaults.resolveZoneRoutes({
2774
+ discovery,
2775
+ getClient: c.get('getClient'),
2776
+ routes,
2777
+ zones: [...c.get('zones').values()],
2778
+ })
2779
+ const capabilities = discovery.capabilities
2780
+ if (needsCapabilities && !capabilities)
2781
+ throw new Error('Earn vault capabilities were not resolved.')
2782
+ return {
2783
+ discovery: capabilities
2784
+ ? { ...discovery, capabilities: EarnVaults.addZoneRouteCapabilities(capabilities) }
2785
+ : discovery,
2786
+ zoneRoutes: includesRoutes
2787
+ ? resolved.filter((route) => hasZoneAccess({ chainId: route.chainId, scopes }))
2788
+ : [],
2789
+ }
2790
+ }
2791
+
2792
+ declare namespace resolveVaultRoutes {
2793
+ type Options = {
2794
+ capability: z.output<typeof schema.getEarnVaults.Query>['capability']
2795
+ discovery: EarnVaults.Discovery
2796
+ include: z.output<typeof schema.getEarnVault.Query>['include']
2797
+ record?: RegistryRecord | undefined
2798
+ }
2799
+
2800
+ type Result = {
2801
+ discovery: EarnVaults.Discovery
2802
+ zoneRoutes: readonly EarnVaults.ResolvedZoneRoute[]
2803
+ }
2804
+ }
2805
+
2641
2806
  // Measuring a rate costs indexer boundary queries plus historical quotes against
2642
2807
  // an archive node, so an unrequested rate reaches neither.
2643
2808
  function resolvePageApy(c: Context<App.Environment>, options: resolvePageApy.Options) {
@@ -2718,8 +2883,13 @@ declare namespace resolvePageTokens {
2718
2883
  }
2719
2884
  }
2720
2885
 
2721
- function resolveVault(c: Context<App.Environment>, options: resolveVault.Options) {
2886
+ async function resolveVault(c: Context<App.Environment>, options: resolveVault.Options) {
2722
2887
  const { discovery, record } = options
2888
+ const principal = Auth.getPrincipal(c)
2889
+ const scopes = principal?.type === 'api_key' ? principal.apiKey.scopes : undefined
2890
+ const zones = [...c.get('zones').values()].filter((zone) =>
2891
+ hasZoneAccess({ chainId: zone.id, scopes }),
2892
+ )
2723
2893
  const valued = options.include.includes('tvl')
2724
2894
  ? Valuation.valuationFor({
2725
2895
  amount: BigInt(discovery.state.totalAssets),
@@ -2743,7 +2913,8 @@ function resolveVault(c: Context<App.Environment>, options: resolveVault.Options
2743
2913
  formatted: valued.amount,
2744
2914
  }
2745
2915
  : null,
2746
- zones: [...c.get('zones').values()],
2916
+ zoneRoutes: options.zoneRoutes,
2917
+ zones,
2747
2918
  })
2748
2919
  }
2749
2920
 
@@ -2756,6 +2927,7 @@ declare namespace resolveVault {
2756
2927
  record?: RegistryRecord | undefined
2757
2928
  snapshot: VerifiedTokens.Snapshot
2758
2929
  tokens: Tokens.resolveTokens.ReturnType
2930
+ zoneRoutes: readonly EarnVaults.ResolvedZoneRoute[]
2759
2931
  }
2760
2932
  }
2761
2933
 
@@ -2797,8 +2969,18 @@ export function serializeVault(options: serializeVault.Options): z.output<typeof
2797
2969
  vaultAddress,
2798
2970
  verified: record !== undefined,
2799
2971
  ...(options.include.includes('zone')
2800
- ? { zone: record ? resolveZone({ discovery, record, zones: options.zones }) : null }
2972
+ ? {
2973
+ zone: record
2974
+ ? resolveZone({
2975
+ discovery,
2976
+ record,
2977
+ zoneRoutes: options.zoneRoutes,
2978
+ zones: options.zones,
2979
+ })
2980
+ : null,
2981
+ }
2801
2982
  : {}),
2983
+ ...(options.include.includes('zones') ? { zones: record ? options.zoneRoutes : [] } : {}),
2802
2984
  })
2803
2985
  }
2804
2986
 
@@ -2819,12 +3001,24 @@ export declare namespace serializeVault {
2819
3001
  shareToken: z.output<typeof Tokens.schema.Token>
2820
3002
  /** USD value of the assets, or null when unpriced; omitted unless `include` carries `tvl`. */
2821
3003
  tvl: z.output<typeof schema.Vault>['tvl']
3004
+ /** Verified Zone routes with immutable router bindings. */
3005
+ zoneRoutes: readonly EarnVaults.ResolvedZoneRoute[]
2822
3006
  /** Private Zones available to the vault. */
2823
3007
  zones: readonly Chain[]
2824
3008
  }
2825
3009
  }
2826
3010
 
2827
3011
  function resolveZone(options: resolveZone.Options): z.output<typeof schema.Vault.shape.zone> {
3012
+ if (options.record.zones.length > 0) {
3013
+ if (options.zoneRoutes.length !== 1) return null
3014
+ const route = options.zoneRoutes[0]!
3015
+ return {
3016
+ chainId: route.chainId,
3017
+ inputTokens: [...route.inputTokens],
3018
+ name: route.name,
3019
+ outputTokens: [...route.outputTokens],
3020
+ }
3021
+ }
2828
3022
  if (!options.discovery.capabilities?.privateRouting) return null
2829
3023
  const hasInputs = options.record.privateInputTokens.length > 0
2830
3024
  const hasOutputs = options.record.privateOutputTokens.length > 0
@@ -2833,6 +3027,7 @@ function resolveZone(options: resolveZone.Options): z.output<typeof schema.Vault
2833
3027
  throw new Error('Private input and output tokens must both be configured.')
2834
3028
 
2835
3029
  const configured = options.zones.filter((zone) => zone.sourceId === options.record.chainId)
3030
+ if (configured.length === 0) return null
2836
3031
  if (configured.length !== 1)
2837
3032
  throw new Error(`Expected one Earn Zone for chain ${options.record.chainId}.`)
2838
3033
  const zone = configured[0]!
@@ -2852,6 +3047,7 @@ declare namespace resolveZone {
2852
3047
  type Options = {
2853
3048
  discovery: EarnVaults.Discovery
2854
3049
  record: RegistryRecord
3050
+ zoneRoutes: readonly EarnVaults.ResolvedZoneRoute[]
2855
3051
  zones: readonly Chain[]
2856
3052
  }
2857
3053
  }
@@ -0,0 +1,46 @@
1
+ import { Hono } from 'hono'
2
+
3
+ import * as Earn from './earn.js'
4
+
5
+ describe('hasZoneAccess', () => {
6
+ test('matches every Zone granted by read or wildcard scopes', () => {
7
+ const scopes = ['data:read', 'zone:1424310001:read', 'zone:1424310003:write']
8
+ const visible = [1424310001, 1424310002, 1424310003].filter((chainId) =>
9
+ Earn.hasZoneAccess({ chainId, scopes }),
10
+ )
11
+
12
+ expect(visible).toStrictEqual([1424310001])
13
+ expect(Earn.hasZoneAccess({ chainId: 1424310002, scopes: ['*'] })).toBe(true)
14
+ expect(Earn.hasZoneAccess({ chainId: 1424310003, scopes })).toBe(false)
15
+ expect(Earn.hasZoneAccess({ chainId: 1424310001 })).toBe(false)
16
+ })
17
+ })
18
+
19
+ describe('vaultCacheKey', () => {
20
+ test('partitions Zone projections by API key after query credentials are stripped', async () => {
21
+ const app = new Hono()
22
+ app.use('*', async (c, next) => {
23
+ c.set('chainId' as never, 42_431 as never)
24
+ const principal = c.req.header('x-principal')
25
+ if (principal) c.set('principal' as never, { id: principal, type: 'api_key' } as never)
26
+ await next()
27
+ })
28
+ app.get('/', (c) => {
29
+ return c.text(Earn.vaultCacheKey(c as never, Earn.schema.getEarnVault.Query))
30
+ })
31
+
32
+ const [first, second, public_, unscoped] = await Promise.all([
33
+ app.request('/?include=zones', { headers: { 'x-principal': 'key_1' } }),
34
+ app.request('/?include=zones', { headers: { 'x-principal': 'key_2' } }),
35
+ app.request('/?include=zones'),
36
+ app.request('/', { headers: { 'x-principal': 'key_1' } }),
37
+ ])
38
+
39
+ expect([
40
+ new URL(await first.text()).searchParams.get('principal'),
41
+ new URL(await second.text()).searchParams.get('principal'),
42
+ new URL(await public_.text()).searchParams.get('principal'),
43
+ new URL(await unscoped.text()).searchParams.get('principal'),
44
+ ]).toStrictEqual(['api_key:key_1', 'api_key:key_2', null, null])
45
+ })
46
+ })
@@ -845,7 +845,37 @@ describe('GET /exchange/swaps', () => {
845
845
  }, 60000)
846
846
  })
847
847
 
848
- describe('POST /exchange/quotes', () => {
848
+ describe('POST and QUERY /exchange/quotes', () => {
849
+ test('POST and QUERY accept the same body and return equivalent quote errors', async () => {
850
+ const client = TestApp.client()
851
+ const destinationToken = Schema.TokenAddress.parse(Addresses.pathUsd)
852
+ const request = {
853
+ json: {
854
+ account: Relay.accounts[1]!.address,
855
+ amount: (2n ** 128n).toString(),
856
+ destinationToken,
857
+ mode: 'exactSource' as const,
858
+ slippageBps: 50,
859
+ sourceToken: '0x20c0000000000000000000008f5425160ebe5525' as const,
860
+ },
861
+ query: {},
862
+ }
863
+ const [post, query] = await Promise.all([
864
+ client.v1.exchange.quotes.$post(request, TestApp.auth),
865
+ client.v1.exchange.quotes.$query(request, TestApp.auth),
866
+ ])
867
+
868
+ expect([post.status, query.status]).toEqual([404, 404])
869
+ expect([post.headers.get('cache-control'), query.headers.get('cache-control')]).toEqual([
870
+ 'no-store',
871
+ 'no-store',
872
+ ])
873
+ expect([await post.json(), await query.json()]).toMatchObject([
874
+ { error: { code: 'quote_not_available' } },
875
+ { error: { code: 'quote_not_available' } },
876
+ ])
877
+ })
878
+
849
879
  test('validates denominations without verification data', async () => {
850
880
  const db = () =>
851
881
  Db.postgres({ connectionString: 'postgresql://postgres:postgres@127.0.0.1:1/none' })
@@ -191,17 +191,17 @@ export namespace schema {
191
191
  */
192
192
  export const PairToken = Schema.describe(
193
193
  z.object({
194
- address: Schema.TokenAddress.check(
194
+ address: Schema.tokenAddress(Tokens.tokenExample.address).check(
195
195
  z.describe(
196
196
  'TIP-20 token contract address — the `0x`-prefixed 20-byte identifier for this token.',
197
197
  ),
198
- z.meta({ examples: ['0x20c0000000000000000000008f5425160ebe5525'] }),
198
+ z.meta({ examples: [Tokens.tokenExample.address] }),
199
199
  ),
200
200
  currency: z
201
201
  .optional(z.string())
202
202
  .check(
203
203
  z.describe('Human-readable currency code for the token, when known.'),
204
- z.meta({ examples: ['USD'] }),
204
+ z.meta({ examples: [Tokens.tokenExample.currency] }),
205
205
  ),
206
206
  decimals: z
207
207
  .optional(z.number().check(z.int(), z.nonnegative()))
@@ -209,27 +209,25 @@ export namespace schema {
209
209
  z.describe(
210
210
  'Number of decimal places the token uses; stablecoins on Tempo typically use 6.',
211
211
  ),
212
- z.meta({ examples: [6] }),
212
+ z.meta({ examples: [Tokens.tokenExample.decimals] }),
213
213
  ),
214
214
  logoUri: z.optional(z.string()).check(
215
- z.describe('URL for the token logo SVG, when one is available.'),
215
+ z.describe('URL for the token logo image, when one is available.'),
216
216
  z.meta({
217
- examples: [
218
- 'https://api.tempo.xyz/data/4217/icons/0x20c0000000000000000000008f5425160ebe5525.svg',
219
- ],
217
+ examples: [Tokens.tokenExample.logoUri],
220
218
  }),
221
219
  ),
222
220
  name: z
223
221
  .optional(z.string())
224
222
  .check(
225
223
  z.describe('Human-readable token name, such as `USD Coin`.'),
226
- z.meta({ examples: ['USD Coin'] }),
224
+ z.meta({ examples: [Tokens.tokenExample.name] }),
227
225
  ),
228
226
  symbol: z
229
227
  .optional(z.string())
230
228
  .check(
231
229
  z.describe('Short token ticker symbol, such as `USDC`.'),
232
- z.meta({ examples: ['USDC'] }),
230
+ z.meta({ examples: [Tokens.tokenExample.symbol] }),
233
231
  ),
234
232
  verified: z
235
233
  .optional(z.boolean())
@@ -1719,9 +1717,15 @@ export namespace schema {
1719
1717
  export function exchanges(options: exchanges.Options = {}) {
1720
1718
  const oracle = options.fx?.oracle ?? FxOracle.ecb()
1721
1719
  return new Hono<App.Environment>()
1722
- .post(
1720
+ .on(
1721
+ ['POST', 'QUERY'],
1723
1722
  '/v1/exchange/quotes',
1724
- Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
1723
+ Auth.policy({
1724
+ apiKey: { scopes: ['data:read'] },
1725
+ inheritOverridesFrom: 'POST',
1726
+ mpp: true,
1727
+ public: true,
1728
+ }),
1725
1729
  OpenApi.validate('query', schema.createQuote.Query, {
1726
1730
  code: 'query_invalid',
1727
1731
  message: 'Invalid query parameters',
@@ -2411,7 +2415,7 @@ export function exchanges(options: exchanges.Options = {}) {
2411
2415
  200,
2412
2416
  )
2413
2417
  } catch (cause) {
2414
- return Response.upstream(c, cause)
2418
+ return Response.upstream(c, cause, { page: options.page })
2415
2419
  }
2416
2420
  },
2417
2421
  )
@@ -2633,7 +2637,7 @@ export function exchanges(options: exchanges.Options = {}) {
2633
2637
  200,
2634
2638
  )
2635
2639
  } catch (cause) {
2636
- return Response.upstream(c, cause)
2640
+ return Response.upstream(c, cause, { page: options.page })
2637
2641
  }
2638
2642
  },
2639
2643
  )
@@ -2831,7 +2835,7 @@ export function exchanges(options: exchanges.Options = {}) {
2831
2835
  200,
2832
2836
  )
2833
2837
  } catch (cause) {
2834
- return Response.upstream(c, cause)
2838
+ return Response.upstream(c, cause, { page: options.page })
2835
2839
  }
2836
2840
  },
2837
2841
  )