tapimo 0.7.1 → 0.7.2

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 (681) hide show
  1. package/dist/ApiKeys.d.ts +24 -7
  2. package/dist/ApiKeys.d.ts.map +1 -1
  3. package/dist/ApiKeys.js +17 -5
  4. package/dist/ApiKeys.js.map +1 -1
  5. package/dist/App.d.ts +12104 -7861
  6. package/dist/App.d.ts.map +1 -1
  7. package/dist/App.js +191 -128
  8. package/dist/App.js.map +1 -1
  9. package/dist/Assets.d.ts +10 -0
  10. package/dist/Assets.d.ts.map +1 -1
  11. package/dist/Assets.js +17 -4
  12. package/dist/Assets.js.map +1 -1
  13. package/dist/Scope.d.ts +19 -8
  14. package/dist/Scope.d.ts.map +1 -1
  15. package/dist/Scope.js +25 -9
  16. package/dist/Scope.js.map +1 -1
  17. package/dist/Webhooks.d.ts +1 -1
  18. package/dist/admin/App.d.ts +601 -20
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +12 -2
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +94 -11
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +141 -32
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +1069 -0
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -0
  28. package/dist/admin/apps/earn-vaults.js +409 -0
  29. package/dist/admin/apps/earn-vaults.js.map +1 -0
  30. package/dist/admin/apps/verified-tokens.d.ts +166 -166
  31. package/dist/admin/ui.generated.d.ts +1 -1
  32. package/dist/admin/ui.generated.d.ts.map +1 -1
  33. package/dist/admin/ui.generated.js +99 -43
  34. package/dist/admin/ui.generated.js.map +1 -1
  35. package/dist/analytics/Analytics.d.ts +2 -0
  36. package/dist/analytics/Analytics.d.ts.map +1 -1
  37. package/dist/analytics/Analytics.js +18 -2
  38. package/dist/analytics/Analytics.js.map +1 -1
  39. package/dist/analytics/tables/requestEvents.d.ts +22 -1
  40. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  41. package/dist/analytics/tables/requestEvents.js +59 -39
  42. package/dist/analytics/tables/requestEvents.js.map +1 -1
  43. package/dist/apps/Zones.d.ts +8335 -0
  44. package/dist/apps/Zones.d.ts.map +1 -0
  45. package/dist/apps/Zones.js +38 -0
  46. package/dist/apps/Zones.js.map +1 -0
  47. package/dist/apps/data/App.d.ts +12125 -7913
  48. package/dist/apps/data/App.d.ts.map +1 -1
  49. package/dist/apps/data/App.js +91 -19
  50. package/dist/apps/data/App.js.map +1 -1
  51. package/dist/apps/data/FxOracle.d.ts +1 -1
  52. package/dist/apps/data/FxOracle.d.ts.map +1 -1
  53. package/dist/apps/data/index.d.ts +0 -1
  54. package/dist/apps/data/index.d.ts.map +1 -1
  55. package/dist/apps/data/index.js +0 -1
  56. package/dist/apps/data/index.js.map +1 -1
  57. package/dist/apps/data/routes/activities.d.ts +32 -32
  58. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  59. package/dist/apps/data/routes/activities.js +130 -65
  60. package/dist/apps/data/routes/activities.js.map +1 -1
  61. package/dist/apps/data/routes/addresses.d.ts +312 -312
  62. package/dist/apps/data/routes/balances.d.ts +18 -18
  63. package/dist/apps/data/routes/balances.js +5 -5
  64. package/dist/apps/data/routes/balances.js.map +1 -1
  65. package/dist/apps/data/routes/coingecko.d.ts +176 -176
  66. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  67. package/dist/apps/data/routes/coingecko.js +62 -35
  68. package/dist/apps/data/routes/coingecko.js.map +1 -1
  69. package/dist/apps/data/routes/earn.d.ts +2144 -0
  70. package/dist/apps/data/routes/earn.d.ts.map +1 -0
  71. package/dist/apps/data/routes/earn.js +947 -0
  72. package/dist/apps/data/routes/earn.js.map +1 -0
  73. package/dist/apps/data/routes/exchanges.d.ts +1625 -718
  74. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  75. package/dist/apps/data/routes/exchanges.js +656 -193
  76. package/dist/apps/data/routes/exchanges.js.map +1 -1
  77. package/dist/apps/data/routes/fee-amm.d.ts +108 -108
  78. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  79. package/dist/apps/data/routes/fee-amm.js +59 -8
  80. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  81. package/dist/apps/data/routes/funding.d.ts +4092 -387
  82. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  83. package/dist/apps/data/routes/funding.js +1403 -256
  84. package/dist/apps/data/routes/funding.js.map +1 -1
  85. package/dist/apps/data/routes/indexer.d.ts +30 -30
  86. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  87. package/dist/apps/data/routes/indexer.js +19 -2
  88. package/dist/apps/data/routes/indexer.js.map +1 -1
  89. package/dist/apps/data/routes/receipts.d.ts +263 -263
  90. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  91. package/dist/apps/data/routes/receipts.js +11 -11
  92. package/dist/apps/data/routes/receipts.js.map +1 -1
  93. package/dist/apps/data/routes/rpc.d.ts +5 -5
  94. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  95. package/dist/apps/data/routes/rpc.js +211 -22
  96. package/dist/apps/data/routes/rpc.js.map +1 -1
  97. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  98. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  99. package/dist/apps/data/routes/tokenlist.js +39 -8
  100. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  101. package/dist/apps/data/routes/tokens.d.ts +114 -86
  102. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  103. package/dist/apps/data/routes/tokens.js +194 -91
  104. package/dist/apps/data/routes/tokens.js.map +1 -1
  105. package/dist/apps/data/routes/transactions.d.ts +53 -53
  106. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  107. package/dist/apps/data/routes/transactions.js +78 -39
  108. package/dist/apps/data/routes/transactions.js.map +1 -1
  109. package/dist/apps/data/routes/transfers.d.ts +76 -27
  110. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  111. package/dist/apps/data/routes/transfers.js +165 -67
  112. package/dist/apps/data/routes/transfers.js.map +1 -1
  113. package/dist/apps/data/routes/valuation.d.ts +42 -42
  114. package/dist/apps/data/routes/valuation.js +2 -2
  115. package/dist/apps/data/routes/valuation.js.map +1 -1
  116. package/dist/apps/data/routes/webhooks.d.ts +369 -367
  117. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  118. package/dist/apps/data/routes/webhooks.js +161 -59
  119. package/dist/apps/data/routes/webhooks.js.map +1 -1
  120. package/dist/apps/data/routes/zones.d.ts +281 -0
  121. package/dist/apps/data/routes/zones.d.ts.map +1 -0
  122. package/dist/apps/data/routes/zones.js +252 -0
  123. package/dist/apps/data/routes/zones.js.map +1 -0
  124. package/dist/apps/docs/reference.js +6 -5
  125. package/dist/apps/docs/reference.js.map +1 -1
  126. package/dist/apps/index.d.ts +2 -1
  127. package/dist/apps/index.d.ts.map +1 -1
  128. package/dist/apps/index.js +2 -1
  129. package/dist/apps/index.js.map +1 -1
  130. package/dist/apps/management/App.d.ts +670 -670
  131. package/dist/apps/management/Billing.d.ts +8 -0
  132. package/dist/apps/management/Billing.d.ts.map +1 -1
  133. package/dist/apps/management/Billing.js +12 -0
  134. package/dist/apps/management/Billing.js.map +1 -1
  135. package/dist/apps/management/Error.d.ts +12 -0
  136. package/dist/apps/management/Error.d.ts.map +1 -0
  137. package/dist/apps/management/Error.js +10 -0
  138. package/dist/apps/management/Error.js.map +1 -0
  139. package/dist/apps/management/routes/api-keys.d.ts +5 -5
  140. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  141. package/dist/apps/management/routes/api-keys.js +2 -8
  142. package/dist/apps/management/routes/api-keys.js.map +1 -1
  143. package/dist/apps/management/routes/billing.d.ts +119 -119
  144. package/dist/apps/management/routes/faucet.d.ts +2 -2
  145. package/dist/apps/management/routes/invitations.d.ts +62 -62
  146. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  147. package/dist/apps/management/routes/invitations.js +4 -10
  148. package/dist/apps/management/routes/invitations.js.map +1 -1
  149. package/dist/apps/management/routes/invite-links.d.ts +30 -30
  150. package/dist/apps/management/routes/me.d.ts +6 -6
  151. package/dist/apps/management/routes/members.d.ts +2 -2
  152. package/dist/apps/management/routes/orgs.d.ts +48 -48
  153. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  154. package/dist/apps/management/routes/orgs.js +2 -8
  155. package/dist/apps/management/routes/orgs.js.map +1 -1
  156. package/dist/apps/management/routes/projects.d.ts +9 -9
  157. package/dist/apps/management/routes/scopes.js +2 -2
  158. package/dist/apps/management/routes/scopes.js.map +1 -1
  159. package/dist/apps/management/routes/verified-token-requests.d.ts +36 -36
  160. package/dist/apps/management/routes/webhooks.d.ts +50 -50
  161. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  162. package/dist/apps/management/routes/webhooks.js +15 -3
  163. package/dist/apps/management/routes/webhooks.js.map +1 -1
  164. package/dist/apps/mpp/App.d.ts +55 -56
  165. package/dist/apps/mpp/App.d.ts.map +1 -1
  166. package/dist/apps/mpp/App.js +192 -27
  167. package/dist/apps/mpp/App.js.map +1 -1
  168. package/dist/apps/mpp/Mpp.d.ts +0 -20
  169. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  170. package/dist/apps/mpp/Mpp.js +0 -24
  171. package/dist/apps/mpp/Mpp.js.map +1 -1
  172. package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
  173. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
  174. package/dist/apps/mpp/internal/Adapter.js +66 -0
  175. package/dist/apps/mpp/internal/Adapter.js.map +1 -0
  176. package/dist/apps/mpp/internal/Error.d.ts +4 -0
  177. package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
  178. package/dist/apps/mpp/internal/Error.js +41 -0
  179. package/dist/apps/mpp/internal/Error.js.map +1 -0
  180. package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
  181. package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
  182. package/dist/apps/mpp/internal/Idempotency.js +28 -0
  183. package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
  184. package/dist/apps/mpp/internal/Policy.d.ts +46 -0
  185. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
  186. package/dist/apps/mpp/internal/Policy.js +57 -0
  187. package/dist/apps/mpp/internal/Policy.js.map +1 -0
  188. package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
  189. package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
  190. package/dist/apps/mpp/internal/ScreenManager.js +18 -0
  191. package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
  192. package/dist/apps/mpp/internal/Screening.d.ts +35 -0
  193. package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
  194. package/dist/apps/mpp/internal/Screening.js +20 -0
  195. package/dist/apps/mpp/internal/Screening.js.map +1 -0
  196. package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
  197. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
  198. package/dist/apps/mpp/internal/Sponsorship.js +103 -0
  199. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
  200. package/dist/apps/mpp/internal/Utils.d.ts +7 -0
  201. package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
  202. package/dist/apps/mpp/internal/Utils.js +24 -0
  203. package/dist/apps/mpp/internal/Utils.js.map +1 -0
  204. package/dist/apps/relay/App.js +183 -23
  205. package/dist/apps/relay/App.js.map +1 -1
  206. package/dist/apps/relay/Sponsorships.d.ts +4 -0
  207. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  208. package/dist/apps/relay/Sponsorships.js +15 -6
  209. package/dist/apps/relay/Sponsorships.js.map +1 -1
  210. package/dist/db/Db.d.ts +20 -0
  211. package/dist/db/Db.d.ts.map +1 -1
  212. package/dist/db/Db.js +342 -0
  213. package/dist/db/Db.js.map +1 -1
  214. package/dist/db/Schema.d.ts +921 -1
  215. package/dist/db/Schema.d.ts.map +1 -1
  216. package/dist/db/Schema.js +269 -1
  217. package/dist/db/Schema.js.map +1 -1
  218. package/dist/db/tables/earnVaults.d.ts +68 -0
  219. package/dist/db/tables/earnVaults.d.ts.map +1 -0
  220. package/dist/db/tables/earnVaults.js +72 -0
  221. package/dist/db/tables/earnVaults.js.map +1 -0
  222. package/dist/db/tables/fundingCatalog.d.ts +56 -0
  223. package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
  224. package/dist/db/tables/fundingCatalog.js +85 -0
  225. package/dist/db/tables/fundingCatalog.js.map +1 -0
  226. package/dist/db/tables/fundingDepositAddresses.d.ts +159 -0
  227. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
  228. package/dist/db/tables/fundingDepositAddresses.js +206 -0
  229. package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
  230. package/dist/db/tables/fundingDeposits.d.ts +115 -0
  231. package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
  232. package/dist/db/tables/fundingDeposits.js +100 -0
  233. package/dist/db/tables/fundingDeposits.js.map +1 -0
  234. package/dist/db/tables/fundingIdempotency.d.ts +91 -0
  235. package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
  236. package/dist/db/tables/fundingIdempotency.js +103 -0
  237. package/dist/db/tables/fundingIdempotency.js.map +1 -0
  238. package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
  239. package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
  240. package/dist/db/tables/fundingTransferEvents.js +18 -0
  241. package/dist/db/tables/fundingTransferEvents.js.map +1 -0
  242. package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
  243. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
  244. package/dist/db/tables/fundingTransferTransactions.js +27 -0
  245. package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
  246. package/dist/db/tables/fundingTransfers.d.ts +82 -0
  247. package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
  248. package/dist/db/tables/fundingTransfers.js +89 -0
  249. package/dist/db/tables/fundingTransfers.js.map +1 -0
  250. package/dist/db/tables/organizations.d.ts +8 -0
  251. package/dist/db/tables/organizations.d.ts.map +1 -1
  252. package/dist/db/tables/organizations.js +16 -0
  253. package/dist/db/tables/organizations.js.map +1 -1
  254. package/dist/db/tables/projects.d.ts +8 -0
  255. package/dist/db/tables/projects.d.ts.map +1 -1
  256. package/dist/db/tables/projects.js +16 -0
  257. package/dist/db/tables/projects.js.map +1 -1
  258. package/dist/db/tables/requestUsage.d.ts +13 -0
  259. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  260. package/dist/db/tables/requestUsage.js +16 -0
  261. package/dist/db/tables/requestUsage.js.map +1 -1
  262. package/dist/db/tables/sponsoredTransactions.d.ts +2 -2
  263. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  264. package/dist/db/tables/sponsoredTransactions.js +1 -1
  265. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  266. package/dist/db/tables/users.d.ts +8 -0
  267. package/dist/db/tables/users.d.ts.map +1 -1
  268. package/dist/db/tables/users.js +16 -0
  269. package/dist/db/tables/users.js.map +1 -1
  270. package/dist/db/tables/verifiedTokens.d.ts +14 -7
  271. package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
  272. package/dist/db/tables/verifiedTokens.js +9 -7
  273. package/dist/db/tables/verifiedTokens.js.map +1 -1
  274. package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
  275. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  276. package/dist/db/tables/webhookSubscriptions.js +24 -3
  277. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  278. package/dist/handlers/relay.js +108 -108
  279. package/dist/handlers/relay.js.map +1 -1
  280. package/dist/internal/Auth.d.ts +26 -0
  281. package/dist/internal/Auth.d.ts.map +1 -1
  282. package/dist/internal/Auth.js +35 -2
  283. package/dist/internal/Auth.js.map +1 -1
  284. package/dist/internal/Cache.d.ts.map +1 -1
  285. package/dist/internal/Cache.js +16 -10
  286. package/dist/internal/Cache.js.map +1 -1
  287. package/dist/internal/Cursor.js +1 -1
  288. package/dist/internal/Cursor.js.map +1 -1
  289. package/dist/internal/EarnRates.d.ts +89 -0
  290. package/dist/internal/EarnRates.d.ts.map +1 -0
  291. package/dist/internal/EarnRates.js +266 -0
  292. package/dist/internal/EarnRates.js.map +1 -0
  293. package/dist/internal/EarnVaults.d.ts +171 -0
  294. package/dist/internal/EarnVaults.d.ts.map +1 -0
  295. package/dist/internal/EarnVaults.js +547 -0
  296. package/dist/internal/EarnVaults.js.map +1 -0
  297. package/dist/internal/EdgeCache.d.ts +8 -1
  298. package/dist/internal/EdgeCache.d.ts.map +1 -1
  299. package/dist/internal/EdgeCache.js +33 -7
  300. package/dist/internal/EdgeCache.js.map +1 -1
  301. package/dist/internal/Id.d.ts +11 -0
  302. package/dist/internal/Id.d.ts.map +1 -1
  303. package/dist/internal/Id.js +13 -0
  304. package/dist/internal/Id.js.map +1 -1
  305. package/dist/internal/Idempotency.d.ts +83 -0
  306. package/dist/internal/Idempotency.d.ts.map +1 -0
  307. package/dist/internal/Idempotency.js +113 -0
  308. package/dist/internal/Idempotency.js.map +1 -0
  309. package/dist/internal/Log.d.ts +64 -9
  310. package/dist/internal/Log.d.ts.map +1 -1
  311. package/dist/internal/Log.js +29 -7
  312. package/dist/internal/Log.js.map +1 -1
  313. package/dist/internal/MetricSink.d.ts.map +1 -1
  314. package/dist/internal/MetricSink.js +47 -1
  315. package/dist/internal/MetricSink.js.map +1 -1
  316. package/dist/internal/OpenApi.d.ts +1 -1
  317. package/dist/internal/OpenApi.d.ts.map +1 -1
  318. package/dist/internal/OpenApi.js +3 -0
  319. package/dist/internal/OpenApi.js.map +1 -1
  320. package/dist/internal/Provider.d.ts +14 -0
  321. package/dist/internal/Provider.d.ts.map +1 -0
  322. package/dist/internal/Provider.js +5 -0
  323. package/dist/internal/Provider.js.map +1 -0
  324. package/dist/internal/Schema.d.ts +6 -1
  325. package/dist/internal/Schema.d.ts.map +1 -1
  326. package/dist/internal/Schema.js +20 -11
  327. package/dist/internal/Schema.js.map +1 -1
  328. package/dist/internal/Store.d.ts +6 -0
  329. package/dist/internal/Store.d.ts.map +1 -1
  330. package/dist/internal/Store.js +35 -0
  331. package/dist/internal/Store.js.map +1 -1
  332. package/dist/internal/Tidx.d.ts +43 -24
  333. package/dist/internal/Tidx.d.ts.map +1 -1
  334. package/dist/internal/Tidx.js +79 -11
  335. package/dist/internal/Tidx.js.map +1 -1
  336. package/dist/internal/Viem.d.ts +82 -65
  337. package/dist/internal/Viem.d.ts.map +1 -1
  338. package/dist/internal/Viem.js +83 -12
  339. package/dist/internal/Viem.js.map +1 -1
  340. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  341. package/dist/internal/WebhookDestination.js +34 -28
  342. package/dist/internal/WebhookDestination.js.map +1 -1
  343. package/dist/internal/Webhooks.d.ts +9 -0
  344. package/dist/internal/Webhooks.d.ts.map +1 -1
  345. package/dist/internal/Webhooks.js +15 -10
  346. package/dist/internal/Webhooks.js.map +1 -1
  347. package/dist/internal/exchange/Provider.d.ts +219 -0
  348. package/dist/internal/exchange/Provider.d.ts.map +1 -0
  349. package/dist/internal/exchange/Provider.js +117 -0
  350. package/dist/internal/exchange/Provider.js.map +1 -0
  351. package/dist/internal/exchange/index.d.ts +2 -0
  352. package/dist/internal/exchange/index.d.ts.map +1 -0
  353. package/dist/internal/exchange/index.js +2 -0
  354. package/dist/internal/exchange/index.js.map +1 -0
  355. package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
  356. package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
  357. package/dist/internal/exchange/providers/uniswap.js +553 -0
  358. package/dist/internal/exchange/providers/uniswap.js.map +1 -0
  359. package/dist/internal/funding/Action.d.ts +55 -0
  360. package/dist/internal/funding/Action.d.ts.map +1 -0
  361. package/dist/internal/funding/Action.js +74 -0
  362. package/dist/internal/funding/Action.js.map +1 -0
  363. package/dist/internal/funding/Catalog.d.ts +107 -0
  364. package/dist/internal/funding/Catalog.d.ts.map +1 -0
  365. package/dist/internal/funding/Catalog.js +270 -0
  366. package/dist/internal/funding/Catalog.js.map +1 -0
  367. package/dist/internal/funding/Chain.d.ts +76 -0
  368. package/dist/internal/funding/Chain.d.ts.map +1 -0
  369. package/dist/internal/funding/Chain.js +38 -0
  370. package/dist/internal/funding/Chain.js.map +1 -0
  371. package/dist/internal/funding/Deposit.d.ts +366 -0
  372. package/dist/internal/funding/Deposit.d.ts.map +1 -0
  373. package/dist/internal/funding/Deposit.js +286 -0
  374. package/dist/internal/funding/Deposit.js.map +1 -0
  375. package/dist/internal/funding/DepositAddress.d.ts +345 -0
  376. package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
  377. package/dist/internal/funding/DepositAddress.js +189 -0
  378. package/dist/internal/funding/DepositAddress.js.map +1 -0
  379. package/dist/internal/funding/Evidence.d.ts +52 -0
  380. package/dist/internal/funding/Evidence.d.ts.map +1 -0
  381. package/dist/internal/funding/Evidence.js +314 -0
  382. package/dist/internal/funding/Evidence.js.map +1 -0
  383. package/dist/internal/funding/Provider.d.ts +1186 -0
  384. package/dist/internal/funding/Provider.d.ts.map +1 -0
  385. package/dist/internal/funding/Provider.js +1081 -0
  386. package/dist/internal/funding/Provider.js.map +1 -0
  387. package/dist/internal/funding/Reconciliation.d.ts +113 -0
  388. package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
  389. package/dist/internal/funding/Reconciliation.js +676 -0
  390. package/dist/internal/funding/Reconciliation.js.map +1 -0
  391. package/dist/internal/funding/Route.d.ts +21 -0
  392. package/dist/internal/funding/Route.d.ts.map +1 -0
  393. package/dist/internal/funding/Route.js +5 -0
  394. package/dist/internal/funding/Route.js.map +1 -0
  395. package/dist/internal/funding/Subsidy.d.ts +113 -0
  396. package/dist/internal/funding/Subsidy.d.ts.map +1 -0
  397. package/dist/internal/funding/Subsidy.js +138 -0
  398. package/dist/internal/funding/Subsidy.js.map +1 -0
  399. package/dist/internal/funding/Token.d.ts +41 -0
  400. package/dist/internal/funding/Token.d.ts.map +1 -0
  401. package/dist/internal/funding/Token.js +22 -0
  402. package/dist/internal/funding/Token.js.map +1 -0
  403. package/dist/internal/funding/Transfer.d.ts +643 -0
  404. package/dist/internal/funding/Transfer.d.ts.map +1 -0
  405. package/dist/internal/funding/Transfer.js +332 -0
  406. package/dist/internal/funding/Transfer.js.map +1 -0
  407. package/dist/internal/funding/index.d.ts +13 -0
  408. package/dist/internal/funding/index.d.ts.map +1 -0
  409. package/dist/internal/funding/index.js +13 -0
  410. package/dist/internal/funding/index.js.map +1 -0
  411. package/dist/internal/funding/providers/across.d.ts +21 -0
  412. package/dist/internal/funding/providers/across.d.ts.map +1 -0
  413. package/dist/internal/funding/providers/across.js +117 -0
  414. package/dist/internal/funding/providers/across.js.map +1 -0
  415. package/dist/internal/funding/providers/relay.d.ts +46 -0
  416. package/dist/internal/funding/providers/relay.d.ts.map +1 -0
  417. package/dist/internal/funding/providers/relay.js +464 -0
  418. package/dist/internal/funding/providers/relay.js.map +1 -0
  419. package/dist/internal/funding/providers/rhino.d.ts +15 -0
  420. package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
  421. package/dist/internal/funding/providers/rhino.js +116 -0
  422. package/dist/internal/funding/providers/rhino.js.map +1 -0
  423. package/dist/internal/funding/providers/squid.d.ts +19 -0
  424. package/dist/internal/funding/providers/squid.d.ts.map +1 -0
  425. package/dist/internal/funding/providers/squid.js +120 -0
  426. package/dist/internal/funding/providers/squid.js.map +1 -0
  427. package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
  428. package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
  429. package/dist/internal/funding/providers/symbiosis.js +176 -0
  430. package/dist/internal/funding/providers/symbiosis.js.map +1 -0
  431. package/dist/internal/index.d.ts +5 -1
  432. package/dist/internal/index.d.ts.map +1 -1
  433. package/dist/internal/index.js +5 -1
  434. package/dist/internal/index.js.map +1 -1
  435. package/dist/internal/webhookDestinations/url.js +61 -57
  436. package/dist/internal/webhookDestinations/url.js.map +1 -1
  437. package/dist/providers/index.d.ts +43 -0
  438. package/dist/providers/index.d.ts.map +1 -0
  439. package/dist/providers/index.js +19 -0
  440. package/dist/providers/index.js.map +1 -0
  441. package/package.json +9 -4
  442. package/src/ApiKeys.test.ts +11 -7
  443. package/src/ApiKeys.ts +37 -9
  444. package/src/App.test.ts +85 -10
  445. package/src/App.ts +224 -137
  446. package/src/Assets.ts +29 -4
  447. package/src/Client.test-d.ts +650 -30
  448. package/src/Scope.test.ts +19 -0
  449. package/src/Scope.ts +28 -11
  450. package/src/Webhooks.test.ts +25 -0
  451. package/src/Webhooks.ts +1 -1
  452. package/src/admin/App.test.ts +9 -2
  453. package/src/admin/App.ts +32 -9
  454. package/src/admin/apps/api-keys.test.ts +167 -23
  455. package/src/admin/apps/api-keys.ts +166 -28
  456. package/src/admin/apps/earn-vaults.test.ts +338 -0
  457. package/src/admin/apps/earn-vaults.ts +572 -0
  458. package/src/admin/apps/scopes.test.ts +16 -1
  459. package/src/admin/ui/plugin.ts +2 -2
  460. package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
  461. package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
  462. package/src/admin/ui/src/components/Page.tsx +1 -1
  463. package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
  464. package/src/admin/ui/src/lib/api-keys.ts +37 -7
  465. package/src/admin/ui/src/lib/client.ts +1 -1
  466. package/src/admin/ui/src/lib/config.ts +1 -1
  467. package/src/admin/ui/src/lib/early-access.ts +8 -9
  468. package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
  469. package/src/admin/ui/src/lib/format.ts +13 -0
  470. package/src/admin/ui/src/lib/organizations.test.ts +14 -4
  471. package/src/admin/ui/src/lib/organizations.ts +7 -1
  472. package/src/admin/ui/src/lib/response.ts +22 -0
  473. package/src/admin/ui/src/lib/scopes.test.ts +19 -11
  474. package/src/admin/ui/src/lib/scopes.ts +28 -7
  475. package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
  476. package/src/admin/ui/src/routeTree.gen.ts +70 -7
  477. package/src/admin/ui/src/router.tsx +2 -2
  478. package/src/admin/ui/src/routes/__root.tsx +9 -8
  479. package/src/admin/ui/src/routes/api-keys.tsx +475 -64
  480. package/src/admin/ui/src/routes/early-access.tsx +5 -12
  481. package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
  482. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
  483. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
  484. package/src/admin/ui/src/routes/organizations.tsx +4 -7
  485. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
  486. package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
  487. package/src/admin/ui/vite.config.ts +4 -1
  488. package/src/admin/ui.generated.ts +113 -43
  489. package/src/analytics/Analytics.test.ts +69 -10
  490. package/src/analytics/Analytics.ts +20 -1
  491. package/src/analytics/tables/requestEvents.ts +79 -37
  492. package/src/apps/Zones.test.ts +33 -0
  493. package/src/apps/Zones.ts +40 -0
  494. package/src/apps/composition.test.ts +84 -1
  495. package/src/apps/data/App.test.ts +28 -11
  496. package/src/apps/data/App.ts +96 -33
  497. package/src/apps/data/FxOracle.ts +1 -1
  498. package/src/apps/data/index.ts +0 -1
  499. package/src/apps/data/routes/activities.test.ts +82 -6
  500. package/src/apps/data/routes/activities.ts +131 -71
  501. package/src/apps/data/routes/balances.test.ts +50 -37
  502. package/src/apps/data/routes/balances.ts +5 -5
  503. package/src/apps/data/routes/blocks.test.ts +2 -0
  504. package/src/apps/data/routes/coingecko.test.ts +22 -0
  505. package/src/apps/data/routes/coingecko.ts +84 -48
  506. package/src/apps/data/routes/earn.test.ts +1108 -0
  507. package/src/apps/data/routes/earn.ts +1391 -0
  508. package/src/apps/data/routes/exchanges.test.ts +82 -33
  509. package/src/apps/data/routes/exchanges.ts +842 -227
  510. package/src/apps/data/routes/fee-amm.test.ts +4 -6
  511. package/src/apps/data/routes/fee-amm.ts +69 -12
  512. package/src/apps/data/routes/funding.test.ts +2712 -221
  513. package/src/apps/data/routes/funding.ts +1604 -387
  514. package/src/apps/data/routes/indexer.test.ts +43 -34
  515. package/src/apps/data/routes/indexer.ts +19 -2
  516. package/src/apps/data/routes/receipts.test.ts +5 -3
  517. package/src/apps/data/routes/receipts.ts +13 -11
  518. package/src/apps/data/routes/rpc.test.ts +446 -28
  519. package/src/apps/data/routes/rpc.ts +243 -25
  520. package/src/apps/data/routes/tokenlist.ts +72 -19
  521. package/src/apps/data/routes/tokens.ts +258 -86
  522. package/src/apps/data/routes/transactions.test.ts +2 -0
  523. package/src/apps/data/routes/transactions.ts +77 -42
  524. package/src/apps/data/routes/transfers.test.ts +166 -4
  525. package/src/apps/data/routes/transfers.ts +216 -78
  526. package/src/apps/data/routes/valuation.test.ts +62 -9
  527. package/src/apps/data/routes/valuation.ts +2 -2
  528. package/src/apps/data/routes/webhooks.test.ts +386 -43
  529. package/src/apps/data/routes/webhooks.ts +172 -71
  530. package/src/apps/data/routes/zones.test.ts +473 -0
  531. package/src/apps/data/routes/zones.ts +338 -0
  532. package/src/apps/docs/reference.ts +8 -6
  533. package/src/apps/index.ts +2 -1
  534. package/src/apps/management/Billing.test.ts +29 -0
  535. package/src/apps/management/Billing.ts +23 -0
  536. package/src/apps/management/Error.ts +12 -0
  537. package/src/apps/management/routes/api-keys.test.ts +5 -3
  538. package/src/apps/management/routes/api-keys.ts +2 -9
  539. package/src/apps/management/routes/invitations.ts +4 -11
  540. package/src/apps/management/routes/orgs.ts +2 -9
  541. package/src/apps/management/routes/scopes.test.ts +7 -2
  542. package/src/apps/management/routes/scopes.ts +2 -2
  543. package/src/apps/management/routes/webhooks.test.ts +6 -1
  544. package/src/apps/management/routes/webhooks.ts +15 -3
  545. package/src/apps/mpp/App.ts +276 -29
  546. package/src/apps/mpp/Mpp.test.ts +631 -26
  547. package/src/apps/mpp/Mpp.ts +0 -42
  548. package/src/apps/mpp/internal/Adapter.ts +108 -3
  549. package/src/apps/mpp/internal/Error.test.ts +33 -0
  550. package/src/apps/mpp/internal/Error.ts +44 -6
  551. package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
  552. package/src/apps/mpp/internal/Idempotency.ts +59 -5
  553. package/src/apps/mpp/internal/Policy.test.ts +122 -0
  554. package/src/apps/mpp/internal/Policy.ts +98 -0
  555. package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
  556. package/src/apps/mpp/internal/ScreenManager.ts +41 -0
  557. package/src/apps/mpp/internal/Screening.ts +40 -3
  558. package/src/apps/mpp/internal/Sponsorship.ts +144 -0
  559. package/src/apps/mpp/internal/Utils.ts +30 -0
  560. package/src/apps/relay/App.test.ts +493 -62
  561. package/src/apps/relay/App.ts +233 -23
  562. package/src/apps/relay/Sponsorships.test.ts +49 -0
  563. package/src/apps/relay/Sponsorships.ts +18 -6
  564. package/src/db/Db.ts +439 -0
  565. package/src/db/Schema.ts +325 -2
  566. package/src/db/tables/earnVaults.test.ts +185 -0
  567. package/src/db/tables/earnVaults.ts +151 -0
  568. package/src/db/tables/fundingCatalog.test.ts +108 -0
  569. package/src/db/tables/fundingCatalog.ts +157 -0
  570. package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
  571. package/src/db/tables/fundingDepositAddresses.ts +376 -0
  572. package/src/db/tables/fundingDeposits.test.ts +261 -0
  573. package/src/db/tables/fundingDeposits.ts +229 -0
  574. package/src/db/tables/fundingIdempotency.test.ts +182 -0
  575. package/src/db/tables/fundingIdempotency.ts +180 -0
  576. package/src/db/tables/fundingTransferEvents.ts +28 -0
  577. package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
  578. package/src/db/tables/fundingTransferTransactions.ts +37 -0
  579. package/src/db/tables/fundingTransfers.test.ts +89 -0
  580. package/src/db/tables/fundingTransfers.ts +153 -0
  581. package/src/db/tables/organizations.ts +16 -0
  582. package/src/db/tables/projects.ts +16 -0
  583. package/src/db/tables/requestUsage.ts +23 -0
  584. package/src/db/tables/sponsoredTransactions.test.ts +11 -0
  585. package/src/db/tables/sponsoredTransactions.ts +3 -3
  586. package/src/db/tables/users.ts +16 -0
  587. package/src/db/tables/verifiedTokens.ts +19 -14
  588. package/src/db/tables/webhookSubscriptions.ts +58 -3
  589. package/src/handlers/relay.test.ts +2 -0
  590. package/src/handlers/relay.ts +95 -99
  591. package/src/internal/Auth.test.ts +48 -0
  592. package/src/internal/Auth.ts +61 -2
  593. package/src/internal/Cache.ts +13 -9
  594. package/src/internal/Cursor.test.ts +2 -2
  595. package/src/internal/Cursor.ts +1 -1
  596. package/src/internal/EarnRates.test.ts +125 -0
  597. package/src/internal/EarnRates.ts +409 -0
  598. package/src/internal/EarnVaults.test.ts +195 -0
  599. package/src/internal/EarnVaults.ts +876 -0
  600. package/src/internal/EdgeCache.test.ts +19 -0
  601. package/src/internal/EdgeCache.ts +35 -5
  602. package/src/internal/Id.ts +14 -0
  603. package/src/internal/Idempotency.test.ts +109 -0
  604. package/src/internal/Idempotency.ts +237 -0
  605. package/src/internal/Log.test-d.ts +41 -8
  606. package/src/internal/Log.test.ts +189 -8
  607. package/src/internal/Log.ts +124 -17
  608. package/src/internal/MetricSink.test.ts +244 -4
  609. package/src/internal/MetricSink.ts +51 -1
  610. package/src/internal/OpenApi.ts +3 -0
  611. package/src/internal/Provider.test.ts +17 -0
  612. package/src/internal/Provider.ts +17 -0
  613. package/src/internal/Schema.ts +27 -17
  614. package/src/internal/Store.test.ts +25 -0
  615. package/src/internal/Store.ts +46 -0
  616. package/src/internal/Tidx.local.test.ts +78 -3
  617. package/src/internal/Tidx.test.ts +212 -18
  618. package/src/internal/Tidx.ts +112 -32
  619. package/src/internal/VerifiedTokens.test.ts +15 -0
  620. package/src/internal/Viem.test.ts +170 -17
  621. package/src/internal/Viem.ts +111 -28
  622. package/src/internal/WebhookDestination.ts +25 -23
  623. package/src/internal/Webhooks.test.ts +59 -0
  624. package/src/internal/Webhooks.ts +34 -10
  625. package/src/internal/exchange/Provider.test.ts +216 -0
  626. package/src/internal/exchange/Provider.ts +326 -0
  627. package/src/internal/exchange/index.test.ts +6 -0
  628. package/src/internal/exchange/index.ts +1 -0
  629. package/src/internal/exchange/providers/uniswap.test.ts +122 -0
  630. package/src/internal/exchange/providers/uniswap.ts +682 -0
  631. package/src/internal/funding/Action.test.ts +138 -0
  632. package/src/internal/funding/Action.ts +117 -0
  633. package/src/internal/funding/Catalog.test.ts +311 -0
  634. package/src/internal/funding/Catalog.ts +347 -0
  635. package/src/internal/funding/Chain.test.ts +79 -0
  636. package/src/internal/funding/Chain.ts +120 -0
  637. package/src/internal/funding/Deposit.test.ts +26 -0
  638. package/src/internal/funding/Deposit.ts +453 -0
  639. package/src/internal/funding/DepositAddress.test.ts +18 -0
  640. package/src/internal/funding/DepositAddress.ts +312 -0
  641. package/src/internal/funding/Evidence.test.ts +297 -0
  642. package/src/internal/funding/Evidence.ts +430 -0
  643. package/src/internal/funding/Provider.test.ts +1328 -0
  644. package/src/internal/funding/Provider.ts +1796 -0
  645. package/src/internal/funding/Reconciliation.local.test.ts +504 -0
  646. package/src/internal/funding/Reconciliation.test.ts +2020 -0
  647. package/src/internal/funding/Reconciliation.ts +930 -0
  648. package/src/internal/funding/Route.test.ts +66 -0
  649. package/src/internal/funding/Route.ts +29 -0
  650. package/src/internal/funding/Subsidy.local.test.ts +152 -0
  651. package/src/internal/funding/Subsidy.test.ts +75 -0
  652. package/src/internal/funding/Subsidy.ts +260 -0
  653. package/src/internal/funding/Token.test.ts +47 -0
  654. package/src/internal/funding/Token.ts +59 -0
  655. package/src/internal/funding/Transfer.test.ts +369 -0
  656. package/src/internal/funding/Transfer.ts +522 -0
  657. package/src/internal/funding/index.test.ts +20 -0
  658. package/src/internal/funding/index.ts +12 -0
  659. package/src/internal/funding/providers/across.ts +149 -0
  660. package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
  661. package/src/internal/funding/providers/relay.test.ts +474 -0
  662. package/src/internal/funding/providers/relay.ts +559 -0
  663. package/src/internal/funding/providers/rhino.ts +139 -0
  664. package/src/internal/funding/providers/squid.ts +151 -0
  665. package/src/internal/funding/providers/symbiosis.ts +221 -0
  666. package/src/internal/index.test.ts +5 -1
  667. package/src/internal/index.ts +5 -1
  668. package/src/internal/webhookDestinations/url.ts +49 -45
  669. package/src/providers/index.test.ts +14 -0
  670. package/src/providers/index.ts +54 -0
  671. package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
  672. package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
  673. package/dist/apps/data/FundingQuoteProviders.js +0 -775
  674. package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
  675. package/dist/internal/FundingQuotes.d.ts +0 -864
  676. package/dist/internal/FundingQuotes.d.ts.map +0 -1
  677. package/dist/internal/FundingQuotes.js +0 -672
  678. package/dist/internal/FundingQuotes.js.map +0 -1
  679. package/src/apps/data/FundingQuoteProviders.ts +0 -1043
  680. package/src/internal/FundingQuotes.test.ts +0 -456
  681. package/src/internal/FundingQuotes.ts +0 -944
@@ -0,0 +1,1391 @@
1
+ import { type Context, Hono } from 'hono'
2
+ import { Value as core_Value } from 'ox'
3
+ import {
4
+ type Chain,
5
+ ContractFunctionExecutionError,
6
+ ContractFunctionRevertedError,
7
+ ContractFunctionZeroDataError,
8
+ } from 'viem'
9
+ import * as z from 'zod/mini'
10
+
11
+ import type * as App from '../../../App.js'
12
+ import * as Db from '../../../db/Db.js'
13
+ import * as core_EarnVaults from '../../../db/tables/earnVaults.js'
14
+ import * as Auth from '../../../internal/Auth.js'
15
+ import * as Cache from '../../../internal/Cache.js'
16
+ import * as Cursor from '../../../internal/Cursor.js'
17
+ import * as EarnRates from '../../../internal/EarnRates.js'
18
+ import * as EarnVaults from '../../../internal/EarnVaults.js'
19
+ import * as OpenApi from '../../../internal/OpenApi.js'
20
+ import * as Response from '../../../internal/Response.js'
21
+ import * as Schema from '../../../internal/Schema.js'
22
+ import * as Store from '../../../internal/Store.js'
23
+ import * as Timing from '../../../internal/Timing.js'
24
+ import * as Ttl from '../../../internal/Ttl.js'
25
+ import * as Value from '../../../internal/Value.js'
26
+ import * as VerifiedTokens from '../../../internal/VerifiedTokens.js'
27
+ import * as FxOracle from '../FxOracle.js'
28
+ import * as Tokens from './tokens.js'
29
+ import * as Valuation from './valuation.js'
30
+
31
+ const deployedSignature =
32
+ 'event EarnStackDeployed(address indexed earnVault,address indexed earnShare,address indexed earnFees,address engine,address asset,address owner,bytes32 deploymentId,address emergencyGuardian,address asyncJanitor,uint8 migrationMode,bytes32 earnShareSalt,bytes32 controlConfigHash,bytes32 feeConfigHash,bytes32 earnFeesSalt)'
33
+
34
+ const maxScannedDeployments = 250
35
+ const scanLimit = 50
36
+
37
+ /** Vault TVL is reported in USD only; the API exposes no denomination parameter. */
38
+ const tvlDenomination = 'USD'
39
+
40
+ /** `Valuation.valuationFor` floors to 6 dp, so 6 is the precision a valued amount carries. */
41
+ const tvlDecimals = 6
42
+
43
+ /** Returns the smallest useful live-discovery batch. */
44
+ export function discoveryBatchLimit(options: discoveryBatchLimit.Options): number {
45
+ const needed = options.limit + 1 - options.matches
46
+ return Math.min(options.filtered ? needed * 2 : needed, options.remaining, scanLimit)
47
+ }
48
+
49
+ export declare namespace discoveryBatchLimit {
50
+ /** Inputs controlling one discovery batch. */
51
+ type Options = {
52
+ /** Whether filters can reject resolved candidates. */
53
+ filtered: boolean
54
+ /** Requested response page size. */
55
+ limit: number
56
+ /** Compatible matches already collected. */
57
+ matches: number
58
+ /** Candidates remaining within the scan bound. */
59
+ remaining: number
60
+ }
61
+ }
62
+
63
+ /** Zod schemas owned by the public Earn-vault resource. */
64
+ export namespace schema {
65
+ const capability = z
66
+ .enum([
67
+ 'asyncRedeem',
68
+ 'boundedRedeem',
69
+ 'deposit',
70
+ 'exactWithdraw',
71
+ 'inKindDeposit',
72
+ 'privateRouting',
73
+ 'redeem',
74
+ 'routerSwaps',
75
+ ])
76
+ .check(z.describe('Vault capability required by the request.'))
77
+
78
+ const engineType = z
79
+ .enum(['erc4626', 'veda'])
80
+ .check(z.describe('Inferred vault engine type.'), z.meta({ examples: ['erc4626'] }))
81
+
82
+ const engine = Schema.describe(
83
+ z.strictObject({
84
+ address: Schema.Address.check(
85
+ z.describe('Current vault engine contract address.'),
86
+ z.meta({ examples: ['0xd85fc943333a6cd7c0e3391acd54fc4e572f0baf'] }),
87
+ ),
88
+ type: z
89
+ .nullable(engineType)
90
+ .check(z.describe('Inferred engine type, or null when it is unknown.')),
91
+ venue: z
92
+ .nullable(
93
+ Schema.Address.check(
94
+ z.describe('Yield venue contract bound to the engine.'),
95
+ z.meta({ examples: ['0xa8b4f0e69cd4b0e56b676343f02acd8c3b355322'] }),
96
+ ),
97
+ )
98
+ .check(z.describe('Yield venue, or null when the engine does not expose one.')),
99
+ }),
100
+ 'Current vault engine.',
101
+ )
102
+
103
+ const include = z
104
+ .enum(['access', 'apy', 'capabilities', 'token.logoUri', 'tvl', 'zone'])
105
+ .check(z.describe('Optional vault fields to embed via `include`.'))
106
+
107
+ const includeQuery = Schema.includeQuery(
108
+ include,
109
+ 'Comma-separated vault fields to include, such as `apy,tvl`.',
110
+ )
111
+
112
+ // `apy` and `tvl` need indexer and FX access, so surfaces lacking either
113
+ // select from this reduced set instead.
114
+ const baseInclude = z
115
+ .enum(['access', 'capabilities', 'token.logoUri', 'zone'])
116
+ .check(z.describe('Optional vault fields to embed via `include`.'))
117
+
118
+ const baseIncludeQuery = Schema.includeQuery(
119
+ baseInclude,
120
+ 'Comma-separated vault fields to include, such as `access,zone`.',
121
+ )
122
+
123
+ const zone = z
124
+ .strictObject({
125
+ chainId: Schema.ChainId.check(
126
+ z.describe('Private Zone chain id.'),
127
+ z.meta({ examples: [421700001] }),
128
+ ),
129
+ inputTokens: z
130
+ .array(Schema.Address)
131
+ .check(
132
+ z.describe('Tokens accepted by private deposits.'),
133
+ z.meta({ examples: [['0x20c000000000000000000000ff04042ee92fd449']] }),
134
+ ),
135
+ name: z.string().check(z.describe('Private Zone name.'), z.meta({ examples: ['zone-e'] })),
136
+ outputTokens: z
137
+ .array(Schema.Address)
138
+ .check(
139
+ z.describe('Tokens supported by private redemptions.'),
140
+ z.meta({ examples: [['0x20c000000000000000000000ff04042ee92fd449']] }),
141
+ ),
142
+ })
143
+ .check(z.describe('Private Zone route configured for a verified vault.'))
144
+
145
+ const value = z.strictObject({
146
+ amount: Schema.DecimalString.check(
147
+ z.describe('Value in base units at `decimals` precision.'),
148
+ z.meta({ examples: ['125288750000'] }),
149
+ ),
150
+ currency: z
151
+ .string()
152
+ .check(z.describe('Display currency of this value.'), z.meta({ examples: ['USD'] })),
153
+ decimals: z
154
+ .number()
155
+ .check(
156
+ z.int(),
157
+ z.nonnegative(),
158
+ z.describe('Decimal places used to convert `amount` into `formatted`.'),
159
+ z.meta({ examples: [6] }),
160
+ ),
161
+ formatted: z
162
+ .string()
163
+ .check(
164
+ z.regex(/^\d+(\.\d+)?$/),
165
+ z.describe('Value rendered in whole units.'),
166
+ z.meta({ examples: ['125288.75'] }),
167
+ ),
168
+ })
169
+
170
+ const vault = z.strictObject({
171
+ access: z
172
+ .optional(EarnVaults.schema.Discovery.shape.access)
173
+ .check(z.describe('Vault share-token access, when requested.')),
174
+ apy: z
175
+ .optional(z.nullable(EarnRates.schema.Apy))
176
+ .check(
177
+ z.describe(
178
+ 'Annualized share-price growth over the selected window, when requested via `include=apy` or by selecting `apy.window`. Null when the rate could not be measured: the vault predates the window, a boundary or historical quote is unavailable, the engine changed inside the window, or the growth is too extreme to annualize as a ratio.',
179
+ ),
180
+ ),
181
+ assetToken: Tokens.schema.Token.check(z.describe('Asset accepted by the vault.')),
182
+ capabilities: z
183
+ .optional(EarnVaults.schema.Discovery.shape.capabilities)
184
+ .check(z.describe('Vault capabilities, when requested.')),
185
+ description: z
186
+ .nullable(z.string())
187
+ .check(
188
+ z.describe('Curated vault description, or null when the vault is not verified.'),
189
+ z.meta({ examples: ['Bridge test PATHUSD deposited into Tempo Earn.'] }),
190
+ ),
191
+ engine,
192
+ id: Schema.Address.check(
193
+ z.describe('Stable vault id, equal to the lowercase vault address.'),
194
+ z.meta({ examples: ['0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a'] }),
195
+ ),
196
+ instantLiquidity: EarnVaults.schema.Discovery.shape.instantLiquidity.check(
197
+ z.describe(
198
+ 'Assets the venue would release right now, capped at the vault backing, in asset base units. Null when the engine interface cannot report a reliable number.',
199
+ ),
200
+ ),
201
+ label: z
202
+ .string()
203
+ .check(z.describe('Vault display label.'), z.meta({ examples: ['btPATHUSD Earn'] })),
204
+ sharePrice: z
205
+ .nullable(value)
206
+ .check(
207
+ z.describe(
208
+ 'Assets returned for one whole Earn share, in the asset display currency, or null when the engine cannot quote an exit.',
209
+ ),
210
+ ),
211
+ shareToken: Tokens.schema.Token.check(z.describe('Token representing vault shares.')),
212
+ slug: z
213
+ .nullable(z.string())
214
+ .check(
215
+ z.describe('Curated URL slug, or null when the vault is not verified.'),
216
+ z.meta({ examples: ['btpathusd-earn-h8k2m4n6'] }),
217
+ ),
218
+ state: EarnVaults.schema.Discovery.shape.state,
219
+ tvl: z
220
+ .optional(z.nullable(value))
221
+ .check(
222
+ z.describe(
223
+ 'Total assets valued in USD, when requested via `include=tvl`, or null when the asset has no priced display currency.',
224
+ ),
225
+ ),
226
+ vaultAddress: Schema.Address.check(
227
+ z.describe('Earn vault contract address.'),
228
+ z.meta({ examples: ['0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a'] }),
229
+ ),
230
+ verified: z
231
+ .boolean()
232
+ .check(
233
+ z.describe('Whether this vault is in the curated Earn registry.'),
234
+ z.meta({ examples: [true] }),
235
+ ),
236
+ zone: z
237
+ .optional(z.nullable(zone))
238
+ .check(z.describe('Curated private Zone route, when requested, or null when absent.')),
239
+ })
240
+
241
+ /** One compatible Earn vault resolved from current chain state. */
242
+ export const Vault = Schema.describe(vault, 'A compatible Earn vault resolved from chain state.')
243
+
244
+ /** One registry-curated Earn vault. */
245
+ export const VerifiedVault = Schema.describe(
246
+ z.extend(vault, {
247
+ engine: z.extend(engine, { type: engineType }),
248
+ slug: z
249
+ .string()
250
+ .check(
251
+ z.describe('Stable curated vault slug.'),
252
+ z.meta({ examples: ['btpathusd-earn-h8k2m4n6'] }),
253
+ ),
254
+ verified: z
255
+ .literal(true)
256
+ .check(
257
+ z.describe('This vault is in the curated Earn registry.'),
258
+ z.meta({ examples: [true] }),
259
+ ),
260
+ }),
261
+ 'A registry-curated Earn vault resolved from chain state.',
262
+ )
263
+
264
+ const position = z.strictObject({
265
+ account: Schema.Address.check(
266
+ z.describe('Account whose Earn position was read.'),
267
+ z.meta({ examples: ['0xbe058e1c4df8a4366a387bf595b284246a93039e'] }),
268
+ ),
269
+ assetAllowance: Schema.DecimalString.check(
270
+ z.describe('Assets the vault may spend from this account, in asset base units.'),
271
+ z.meta({ examples: ['0'] }),
272
+ ),
273
+ assetBalance: Schema.DecimalString.check(
274
+ z.describe('Assets this account currently holds, in asset base units.'),
275
+ z.meta({ examples: ['250000000'] }),
276
+ ),
277
+ assetToken: Schema.tokenAddress('0x20c000000000000000000000b9537d11c60e8b50').check(
278
+ z.describe('TIP-20 asset token accepted by the vault.'),
279
+ ),
280
+ id: Schema.Address.check(
281
+ z.describe('Stable resource ID for this vault position, equal to the account address.'),
282
+ z.meta({ examples: ['0xbe058e1c4df8a4366a387bf595b284246a93039e'] }),
283
+ ),
284
+ shareAllowance: Schema.DecimalString.check(
285
+ z.describe('Earn shares the vault may spend from this account, in share base units.'),
286
+ z.meta({ examples: ['0'] }),
287
+ ),
288
+ shareBalance: Schema.DecimalString.check(
289
+ z.describe('Earn shares this account currently holds, in share base units.'),
290
+ z.meta({ examples: ['99500000'] }),
291
+ ),
292
+ shareToken: Schema.tokenAddress('0x20c000000000000000000000300e14ab91a10769').check(
293
+ z.describe('TIP-20 token representing Earn shares.'),
294
+ ),
295
+ value: Schema.DecimalString.check(
296
+ z.describe(
297
+ 'Current asset value of this account’s Earn shares, including fees, in asset base units.',
298
+ ),
299
+ z.meta({ examples: ['100000000'] }),
300
+ ),
301
+ })
302
+
303
+ const meta = z
304
+ .object({
305
+ valuation: z
306
+ .optional(Valuation.schema.Pricing)
307
+ .check(
308
+ z.describe(
309
+ 'Rate provenance for valued fields. Present when `include=tvl` consulted conversion rates; absent when TVL was not requested, every value was identity-valued, or rates were unavailable.',
310
+ ),
311
+ ),
312
+ })
313
+ .check(z.describe('Rate provenance for valued fields.'))
314
+
315
+ const collectionFilters = z.strictObject({
316
+ asset: z
317
+ .optional(Schema.Address)
318
+ .check(z.describe('Only include vaults accepting this asset address.')),
319
+ capability: Schema.includeQuery(
320
+ capability,
321
+ 'Comma-separated capabilities that every returned vault must support.',
322
+ ),
323
+ chainId: Schema.ChainIdQuery,
324
+ cursor: Schema.Cursor,
325
+ 'engine.type': z
326
+ .optional(engineType)
327
+ .check(z.describe('Only include vaults with this inferred engine type.')),
328
+ include: includeQuery,
329
+ limit: Schema.Limit,
330
+ })
331
+
332
+ const collectionQuery = z
333
+ .extend(collectionFilters, { 'apy.window': EarnRates.schema.Window })
334
+ .check(z.describe('Query parameters for listing Earn vaults.'))
335
+
336
+ const vaultSelector = z.strictObject({
337
+ chainId: Schema.ChainIdQuery,
338
+ include: includeQuery,
339
+ })
340
+
341
+ /** Schemas for the getEarnVaults operation. */
342
+ export namespace getEarnVaults {
343
+ /** Query parameters for all compatible deployed Earn vaults. */
344
+ export const Query = collectionQuery
345
+
346
+ /** Paginated list of compatible deployed Earn vaults. */
347
+ export const Response = z
348
+ .strictObject({
349
+ data: z
350
+ .array(Vault)
351
+ .check(z.describe('Compatible deployed Earn vaults in deployment order.')),
352
+ meta: z.optional(meta),
353
+ nextCursor: Schema.NextCursor,
354
+ })
355
+ .check(z.describe('A page of compatible deployed Earn vaults.'))
356
+ }
357
+
358
+ /** Schemas for the getVerifiedEarnVaults operation. */
359
+ export namespace getVerifiedEarnVaults {
360
+ /** Collection query without rates or valuation, for surfaces that cannot measure them. */
361
+ export const BaseQuery = Schema.describe(
362
+ z.extend(collectionFilters, { include: baseIncludeQuery }),
363
+ 'Query parameters for listing Earn vaults.',
364
+ )
365
+
366
+ /** Query parameters for registry-curated Earn vaults. */
367
+ export const Query = collectionQuery
368
+
369
+ /** Paginated list of registry-curated Earn vaults. */
370
+ export const Response = z
371
+ .strictObject({
372
+ data: z
373
+ .array(VerifiedVault)
374
+ .check(z.describe('Registry-curated Earn vaults ordered by vault address.')),
375
+ meta: z.optional(meta),
376
+ nextCursor: Schema.NextCursor,
377
+ })
378
+ .check(z.describe('A page of registry-curated Earn vaults.'))
379
+ }
380
+
381
+ /** Schemas for the getEarnVault operation. */
382
+ export namespace getEarnVault {
383
+ /** Path parameters identifying one Earn vault. */
384
+ export const Params = z
385
+ .strictObject({
386
+ vaultId: Schema.Address.check(z.describe('Earn vault contract address.')),
387
+ })
388
+ .check(z.describe('Path parameters identifying one Earn vault.'))
389
+
390
+ /** Detail query without rates or valuation, for surfaces that cannot measure them. */
391
+ export const BaseQuery = Schema.describe(
392
+ z.extend(vaultSelector, { include: baseIncludeQuery }),
393
+ 'Query parameters selecting one Earn vault.',
394
+ )
395
+
396
+ /** Query parameters selecting the chain containing the vault. */
397
+ export const Query = z
398
+ .extend(vaultSelector, { 'apy.window': EarnRates.schema.Window })
399
+ .check(z.describe('Query parameters selecting one Earn vault.'))
400
+
401
+ /** One compatible Earn vault resolved directly from current chain state. */
402
+ export const Response = Schema.describe(
403
+ z.extend(vault, { meta: z.optional(meta) }),
404
+ 'A compatible Earn vault resolved from chain state, with rate provenance for its valued fields.',
405
+ )
406
+ }
407
+
408
+ /** Schemas for the getEarnVaultPosition operation. */
409
+ export namespace getEarnVaultPosition {
410
+ /** Path parameters identifying the Earn vault and account. */
411
+ export const Params = z
412
+ .strictObject({
413
+ address: Schema.Address.check(z.describe('Account whose Earn position to read.')),
414
+ vaultId: Schema.address('0xdb48b00fb28d9a8db881fcd671c3fb1bf8c486b6').check(
415
+ z.describe('Earn vault contract address.'),
416
+ ),
417
+ })
418
+ .check(z.describe('Path parameters identifying an Earn vault position.'))
419
+
420
+ /** Query parameters selecting the chain containing the vault. */
421
+ export const Query = z
422
+ .strictObject({ chainId: Schema.ChainIdQuery })
423
+ .check(z.describe('Query parameters selecting an Earn vault position.'))
424
+
425
+ /** Current asset and Earn-share state for one account in one vault. */
426
+ export const Response = Schema.describe(
427
+ position,
428
+ 'Current asset and Earn-share balances, allowances, and asset value for an account in one Earn vault.',
429
+ )
430
+ }
431
+ }
432
+
433
+ /** Creates the public Earn-vault handlers. */
434
+ export function earn(options: earn.Options = {}) {
435
+ const oracle = options.fx?.oracle ?? FxOracle.ecb()
436
+ return new Hono<App.Environment>()
437
+ .get(
438
+ '/v1/earn/vaults',
439
+ Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
440
+ OpenApi.validate('query', schema.getEarnVaults.Query, {
441
+ code: 'query_invalid',
442
+ message: 'Invalid query parameters',
443
+ }),
444
+ OpenApi.describeRoute({
445
+ description:
446
+ 'Lists compatible Earn vaults discovered from deployment events and resolved from current chain state.',
447
+ operationId: 'getEarnVaults',
448
+ responses: OpenApi.responses({
449
+ errors: { 502: 'Could not read Earn deployment or vault data.' },
450
+ success: {
451
+ description: 'A page of compatible deployed Earn vaults.',
452
+ schema: schema.getEarnVaults.Response,
453
+ },
454
+ }),
455
+ summary: 'List Earn vaults',
456
+ tags: ['Earn'],
457
+ }),
458
+ // Live state and rate enrichment are embedded, so every vault read caches
459
+ // as current-state rather than slow-changing metadata.
460
+ Cache.response<App.Environment>({
461
+ cacheControl: Cache.policies.state,
462
+ key: (c) => Cache.urlKey(c, schema.getEarnVaults.Query),
463
+ name: 'tempo-api:earn-vaults:v2',
464
+ }),
465
+ async (c) => {
466
+ if (Auth.narrowAccess) return Auth.paidAccessError(c)
467
+ if (OpenApi.narrowValidation)
468
+ return OpenApi.validationError(c, {
469
+ code: 'query_invalid',
470
+ message: 'Invalid query parameters',
471
+ })
472
+
473
+ const query = c.req.valid('query')
474
+ try {
475
+ const chainId = query.chainId ?? c.get('chainId')
476
+ const data = await listVaults(c, { ...query, chainId, oracle })
477
+ return c.json(Response.validated(schema.getEarnVaults.Response, data), 200)
478
+ } catch (cause) {
479
+ return Response.upstream(c, cause)
480
+ }
481
+ },
482
+ )
483
+ .get(
484
+ '/v1/earn/vaults/verified',
485
+ Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
486
+ OpenApi.validate('query', schema.getVerifiedEarnVaults.Query, {
487
+ code: 'query_invalid',
488
+ message: 'Invalid query parameters',
489
+ }),
490
+ OpenApi.describeRoute({
491
+ description:
492
+ 'Lists registry-curated Earn vaults after resolving their current onchain configuration.',
493
+ operationId: 'getVerifiedEarnVaults',
494
+ responses: OpenApi.responses({
495
+ errors: { 502: 'Could not read curated Earn registry or vault data.' },
496
+ success: {
497
+ description: 'A page of registry-curated Earn vaults.',
498
+ schema: schema.getVerifiedEarnVaults.Response,
499
+ },
500
+ }),
501
+ summary: 'List verified vaults',
502
+ tags: ['Earn'],
503
+ }),
504
+ Cache.response<App.Environment>({
505
+ cacheControl: Cache.policies.state,
506
+ key: (c) => Cache.urlKey(c, schema.getVerifiedEarnVaults.Query),
507
+ name: 'tempo-api:earn-vaults:v2',
508
+ }),
509
+ async (c) => {
510
+ if (Auth.narrowAccess) return Auth.paidAccessError(c)
511
+ if (OpenApi.narrowValidation)
512
+ return OpenApi.validationError(c, {
513
+ code: 'query_invalid',
514
+ message: 'Invalid query parameters',
515
+ })
516
+
517
+ const query = c.req.valid('query')
518
+ try {
519
+ const chainId = query.chainId ?? c.get('chainId')
520
+ const data = await listVerifiedVaults(c, { ...query, chainId, oracle })
521
+ return c.json(Response.validated(schema.getVerifiedEarnVaults.Response, data), 200)
522
+ } catch (cause) {
523
+ return Response.upstream(c, cause)
524
+ }
525
+ },
526
+ )
527
+ .get(
528
+ '/v1/earn/vaults/:vaultId/positions/:address',
529
+ Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
530
+ OpenApi.validate('param', schema.getEarnVaultPosition.Params, {
531
+ code: 'position_invalid',
532
+ message: 'Invalid vault position',
533
+ }),
534
+ OpenApi.validate('query', schema.getEarnVaultPosition.Query, {
535
+ code: 'query_invalid',
536
+ message: 'Invalid query parameters',
537
+ }),
538
+ OpenApi.describeRoute({
539
+ description:
540
+ 'Gets an account’s asset and Earn-share balances, allowances, and current asset value for one Earn vault.',
541
+ operationId: 'getEarnVaultPosition',
542
+ responses: OpenApi.responses({
543
+ errors: {
544
+ 400: {
545
+ codes: [
546
+ 'chain_id_invalid',
547
+ 'chain_id_unsupported',
548
+ 'position_invalid',
549
+ 'query_invalid',
550
+ ],
551
+ },
552
+ 404: {
553
+ codes: ['earn_vault_not_found'],
554
+ description: 'No compatible Earn vault was found at the supplied vault address.',
555
+ },
556
+ 502: 'Could not read the Earn vault position.',
557
+ },
558
+ success: {
559
+ description: 'Current Earn position for one account in one vault.',
560
+ schema: schema.getEarnVaultPosition.Response,
561
+ },
562
+ }),
563
+ summary: 'Get vault position',
564
+ tags: ['Earn'],
565
+ }),
566
+ Cache.response<App.Environment>({
567
+ cacheControl: Cache.policies.state,
568
+ key: (c) => Cache.urlKey(c, schema.getEarnVaultPosition.Query),
569
+ name: 'tempo-api:earn-vault-positions:v1',
570
+ }),
571
+ async (c) => {
572
+ if (Auth.narrowAccess) return Auth.paidAccessError(c)
573
+ if (OpenApi.narrowValidation)
574
+ return Response.error(c, {
575
+ code: 'chain_id_invalid',
576
+ message: 'Invalid chain id',
577
+ status: 400,
578
+ })
579
+ if (OpenApi.narrowValidation)
580
+ return Response.error(c, {
581
+ code: 'chain_id_unsupported',
582
+ message: 'Unsupported chain id',
583
+ status: 400,
584
+ })
585
+ if (OpenApi.narrowValidation)
586
+ return OpenApi.validationError(c, {
587
+ code: 'position_invalid',
588
+ message: 'Invalid request parameters',
589
+ })
590
+ if (OpenApi.narrowValidation)
591
+ return OpenApi.validationError(c, {
592
+ code: 'query_invalid',
593
+ message: 'Invalid query parameters',
594
+ })
595
+
596
+ const { address, vaultId } = c.req.valid('param')
597
+ const query = c.req.valid('query')
598
+ const chainId = query.chainId ?? c.get('chainId')
599
+ try {
600
+ const position = await c
601
+ .get('getClient')(chainId)
602
+ .earn.getPosition({ account: address, vault: vaultId })
603
+ return c.json(
604
+ Response.validated(schema.getEarnVaultPosition.Response, {
605
+ account: address,
606
+ assetAllowance: position.assetAllowance.toString(),
607
+ assetBalance: position.assetBalance.toString(),
608
+ assetToken: position.assetToken,
609
+ id: address,
610
+ shareAllowance: position.shareAllowance.toString(),
611
+ shareBalance: position.shareBalance.toString(),
612
+ shareToken: position.shareToken,
613
+ value: position.value.toString(),
614
+ }),
615
+ 200,
616
+ )
617
+ } catch (cause) {
618
+ try {
619
+ await resolveVaultDiscovery(c, { chainId, include: [], vaultAddress: vaultId })
620
+ } catch (vaultCause) {
621
+ if (isIncompatible(vaultCause))
622
+ return Response.error(c, {
623
+ code: 'earn_vault_not_found',
624
+ message: 'Earn vault not found',
625
+ status: 404,
626
+ })
627
+ }
628
+ return Response.upstream(c, cause)
629
+ }
630
+ },
631
+ )
632
+ .get(
633
+ '/v1/earn/vaults/:vaultId',
634
+ Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
635
+ OpenApi.validate('param', schema.getEarnVault.Params, {
636
+ code: 'vault_id_invalid',
637
+ message: 'Invalid vault id',
638
+ }),
639
+ OpenApi.validate('query', schema.getEarnVault.Query, {
640
+ code: 'query_invalid',
641
+ message: 'Invalid query parameters',
642
+ }),
643
+ OpenApi.describeRoute({
644
+ description:
645
+ 'Resolves any compatible Earn vault directly from current chain state and enriches it when curated.',
646
+ operationId: 'getEarnVault',
647
+ responses: OpenApi.responses({
648
+ errors: {
649
+ 404: {
650
+ codes: ['earn_vault_not_found'],
651
+ description: 'No compatible Earn vault was found at this address.',
652
+ },
653
+ 502: 'Could not read Earn vault data.',
654
+ },
655
+ success: {
656
+ description: 'One compatible Earn vault.',
657
+ schema: schema.getEarnVault.Response,
658
+ },
659
+ }),
660
+ summary: 'Get Earn vault',
661
+ tags: ['Earn'],
662
+ }),
663
+ Cache.response<App.Environment>({
664
+ cacheControl: Cache.policies.state,
665
+ key: (c) => Cache.urlKey(c, schema.getEarnVault.Query),
666
+ name: 'tempo-api:earn-vaults:v2',
667
+ }),
668
+ async (c) => {
669
+ if (Auth.narrowAccess) return Auth.paidAccessError(c)
670
+ if (OpenApi.narrowValidation)
671
+ return OpenApi.validationError(c, {
672
+ code: 'vault_id_invalid',
673
+ message: 'Invalid request parameters',
674
+ })
675
+ if (OpenApi.narrowValidation)
676
+ return OpenApi.validationError(c, {
677
+ code: 'query_invalid',
678
+ message: 'Invalid request parameters',
679
+ })
680
+
681
+ const { vaultId } = c.req.valid('param')
682
+ const query = c.req.valid('query')
683
+ try {
684
+ const chainId = query.chainId ?? c.get('chainId')
685
+ const data = await getVault(c, {
686
+ 'apy.window': query['apy.window'],
687
+ chainId,
688
+ include: query.include,
689
+ oracle,
690
+ vaultAddress: vaultId,
691
+ })
692
+ return c.json(Response.validated(schema.getEarnVault.Response, data), 200)
693
+ } catch (cause) {
694
+ if (cause instanceof NotFoundError)
695
+ return Response.error(c, {
696
+ code: 'earn_vault_not_found',
697
+ message: 'Earn vault not found',
698
+ status: 404,
699
+ })
700
+ return Response.upstream(c, cause)
701
+ }
702
+ },
703
+ )
704
+ }
705
+
706
+ export declare namespace earn {
707
+ /** Options for the public Earn-vault handlers. */
708
+ type Options = {
709
+ /** FX configuration backing TVL valuation. */
710
+ fx?: Valuation.addresses.Fx | undefined
711
+ }
712
+ }
713
+
714
+ /** Lists compatible deployed Earn vaults. */
715
+ export async function listVaults(c: Context<App.Environment>, options: listVaults.Options) {
716
+ const db = Db.get(c.get('dbCached'))
717
+ const [records, snapshot] = await Promise.all([
718
+ core_EarnVaults.list(db, { chainId: options.chainId }),
719
+ VerifiedTokens.snapshot(c, options.chainId),
720
+ ])
721
+ const registry = new Map(records.map((record) => [record.vaultAddress.toLowerCase(), record]))
722
+ const decoded = options.cursor ? Cursor.decode(options.cursor, ['int', 'int']) : undefined
723
+ let position = decoded
724
+ ? ([Number(decoded[0]), Number(decoded[1])] as listVaults.Position)
725
+ : undefined
726
+ let hasMore = false
727
+ let scanned = 0
728
+ const matches: listVaults.Match[] = []
729
+
730
+ while (matches.length <= options.limit && scanned < maxScannedDeployments) {
731
+ const page = await queryDeployments(c, {
732
+ asset: options.asset,
733
+ chainId: options.chainId,
734
+ cursor: position,
735
+ limit: discoveryBatchLimit({
736
+ filtered: options.capability.length > 0 || options['engine.type'] !== undefined,
737
+ limit: options.limit,
738
+ matches: matches.length,
739
+ remaining: maxScannedDeployments - scanned,
740
+ }),
741
+ })
742
+ hasMore = page.hasMore
743
+ if (page.items.length === 0) {
744
+ hasMore = false
745
+ break
746
+ }
747
+ scanned += page.items.length
748
+
749
+ const discovered = await Promise.all(
750
+ page.items.map(async (item) => {
751
+ const record = registry.get(item.vaultAddress.toLowerCase())
752
+ try {
753
+ const discovery = await resolveVaultDiscovery(c, {
754
+ chainId: options.chainId,
755
+ include: discoveryInclude(options),
756
+ vaultAddress: item.vaultAddress,
757
+ })
758
+ return { discovery, position: item.position, record }
759
+ } catch (cause) {
760
+ if (!record && isIncompatible(cause)) return undefined
761
+ throw cause
762
+ }
763
+ }),
764
+ )
765
+ for (const match of discovered) {
766
+ if (!match || !matchesVaultFilters(match.discovery, options)) continue
767
+ matches.push(match)
768
+ }
769
+
770
+ position = page.items.at(-1)!.position
771
+ if (!hasMore) break
772
+ }
773
+
774
+ const page = matches.slice(0, options.limit)
775
+ const discoveries = page.map(({ discovery }) => discovery)
776
+ const include = vaultInclude(options)
777
+ const [apy, rates, tokens] = await Promise.all([
778
+ resolvePageApy(c, {
779
+ chainId: options.chainId,
780
+ discoveries,
781
+ include,
782
+ window: options['apy.window'],
783
+ }),
784
+ resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
785
+ resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
786
+ ])
787
+ const data = page.map((match) =>
788
+ resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
789
+ )
790
+ const last = matches[options.limit - 1]
791
+ const nextPosition =
792
+ matches.length > options.limit ? last?.position : hasMore ? position : undefined
793
+ return {
794
+ data,
795
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
796
+ nextCursor: nextPosition ? Cursor.encode(nextPosition) : null,
797
+ }
798
+ }
799
+
800
+ export declare namespace listVaults {
801
+ /** One compatible deployment found while scanning TIDX. */
802
+ type Match = {
803
+ discovery: EarnVaults.Discovery
804
+ position: Position
805
+ record?: RegistryRecord | undefined
806
+ }
807
+
808
+ /** Options for listing compatible Earn vaults. */
809
+ type Options = z.output<typeof schema.getEarnVaults.Query> & {
810
+ chainId: z.output<typeof Schema.ChainId>
811
+ /** FX rate oracle backing TVL valuation. */
812
+ oracle: FxOracle.Oracle
813
+ }
814
+
815
+ /** TIDX deployment cursor position. */
816
+ type Position = [number, number]
817
+ }
818
+
819
+ /** Lists registry-curated Earn vaults. */
820
+ export async function listVerifiedVaults(
821
+ c: Context<App.Environment>,
822
+ options: listVerifiedVaults.Options,
823
+ ) {
824
+ const db = Db.get(c.get('dbCached'))
825
+ const [records, snapshot] = await Promise.all([
826
+ core_EarnVaults.list(db, { chainId: options.chainId }),
827
+ VerifiedTokens.snapshot(c, options.chainId),
828
+ ])
829
+ const decoded = options.cursor ? Cursor.decode(options.cursor, ['address']) : undefined
830
+ const cursor = decoded?.[0]?.toString().toLowerCase()
831
+ const candidates = records.filter(
832
+ (record) => !cursor || record.vaultAddress.toLowerCase() > cursor,
833
+ )
834
+ const matches: listVerifiedVaults.Match[] = []
835
+
836
+ let offset = 0
837
+ while (offset < candidates.length && matches.length <= options.limit) {
838
+ const batchSize = discoveryBatchLimit({
839
+ filtered: options.capability.length > 0 || options['engine.type'] !== undefined,
840
+ limit: options.limit,
841
+ matches: matches.length,
842
+ remaining: candidates.length - offset,
843
+ })
844
+ const batch = candidates.slice(offset, offset + batchSize)
845
+ offset += batch.length
846
+ const discovered = await Promise.all(
847
+ batch.map(async (record) => ({
848
+ discovery: await resolveVaultDiscovery(c, {
849
+ chainId: options.chainId,
850
+ include: discoveryInclude(options),
851
+ vaultAddress: Schema.Address.parse(record.vaultAddress.toLowerCase()),
852
+ }),
853
+ record,
854
+ })),
855
+ )
856
+ for (const match of discovered) {
857
+ if (!matchesVaultFilters(match.discovery, options)) continue
858
+ matches.push(match)
859
+ }
860
+ }
861
+
862
+ const page = matches.slice(0, options.limit)
863
+ const discoveries = page.map(({ discovery }) => discovery)
864
+ const include = vaultInclude(options)
865
+ const [apy, rates, tokens] = await Promise.all([
866
+ resolvePageApy(c, {
867
+ chainId: options.chainId,
868
+ discoveries,
869
+ include,
870
+ window: options['apy.window'],
871
+ }),
872
+ resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
873
+ resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
874
+ ])
875
+ const data = page.map((match) =>
876
+ Response.validated(
877
+ schema.VerifiedVault,
878
+ resolveVault(c, { ...match, apy, include, rates, snapshot, tokens }),
879
+ ),
880
+ )
881
+ const last = matches[options.limit - 1]
882
+ return {
883
+ data,
884
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
885
+ nextCursor:
886
+ matches.length > options.limit && last ? Cursor.encode([last.record.vaultAddress]) : null,
887
+ }
888
+ }
889
+
890
+ export declare namespace listVerifiedVaults {
891
+ /** One verified vault and its current onchain state. */
892
+ type Match = {
893
+ discovery: EarnVaults.Discovery
894
+ record: RegistryRecord
895
+ }
896
+
897
+ /** Options for listing verified Earn vaults. */
898
+ type Options = z.output<typeof schema.getVerifiedEarnVaults.Query> & {
899
+ chainId: z.output<typeof Schema.ChainId>
900
+ /** FX rate oracle backing TVL valuation. */
901
+ oracle: FxOracle.Oracle
902
+ }
903
+ }
904
+
905
+ /** Gets one compatible Earn vault. */
906
+ export async function getVault(c: Context<App.Environment>, options: getVault.Options) {
907
+ const db = Db.get(c.get('dbCached'))
908
+ const [record, snapshot] = await Promise.all([
909
+ core_EarnVaults.get(db, {
910
+ chainId: options.chainId,
911
+ vaultAddress: options.vaultAddress,
912
+ }),
913
+ VerifiedTokens.snapshot(c, options.chainId),
914
+ ])
915
+ try {
916
+ const discovery = await resolveVaultDiscovery(c, {
917
+ chainId: options.chainId,
918
+ include: discoveryInclude({ capability: [], include: options.include }),
919
+ vaultAddress: options.vaultAddress,
920
+ })
921
+ const discoveries = [discovery]
922
+ const include = vaultInclude(options)
923
+ const [apy, rates, tokens] = await Promise.all([
924
+ resolvePageApy(c, {
925
+ chainId: options.chainId,
926
+ discoveries,
927
+ include,
928
+ window: options['apy.window'],
929
+ }),
930
+ resolvePageRates(c, { discoveries, include, oracle: options.oracle, snapshot }),
931
+ resolvePageTokens(c, { chainId: options.chainId, discoveries, include, snapshot }),
932
+ ])
933
+ return {
934
+ ...resolveVault(c, {
935
+ apy,
936
+ discovery,
937
+ include,
938
+ rates,
939
+ record,
940
+ snapshot,
941
+ tokens,
942
+ }),
943
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, options.oracle) } } : {}),
944
+ }
945
+ } catch (cause) {
946
+ if (cause instanceof EarnVaults.NotFoundError || (!record && isIncompatible(cause)))
947
+ throw new NotFoundError()
948
+ throw cause
949
+ }
950
+ }
951
+
952
+ export declare namespace getVault {
953
+ /** Options for getting one Earn vault. */
954
+ type Options = {
955
+ /** Canonical rate window the vault's APY covers. */
956
+ 'apy.window': z.output<typeof schema.getEarnVault.Query>['apy.window']
957
+ chainId: z.output<typeof Schema.ChainId>
958
+ include: z.output<typeof schema.getEarnVault.Query>['include']
959
+ /** FX rate oracle backing TVL valuation. */
960
+ oracle: FxOracle.Oracle
961
+ vaultAddress: z.output<typeof Schema.Address>
962
+ }
963
+ }
964
+
965
+ // Selecting a rate window is a request for the rate it measures, mirroring how
966
+ // a capability filter promotes `capabilities`.
967
+ function vaultInclude(options: vaultInclude.Options) {
968
+ const { include } = options
969
+ if (options['apy.window'] === undefined || include.includes('apy')) return include
970
+ return [...include, 'apy' as const]
971
+ }
972
+
973
+ declare namespace vaultInclude {
974
+ type Options = Pick<z.output<typeof schema.getEarnVault.Query>, 'apy.window' | 'include'>
975
+ }
976
+
977
+ function discoveryInclude(
978
+ options: discoveryInclude.Options,
979
+ ): readonly EarnVaults.resolve.Include[] {
980
+ const includeCapabilities =
981
+ options.include.includes('capabilities') ||
982
+ options.include.includes('zone') ||
983
+ options.capability.length > 0
984
+ return [
985
+ ...(options.include.includes('access') ? (['access'] as const) : []),
986
+ ...(includeCapabilities ? (['capabilities'] as const) : []),
987
+ ]
988
+ }
989
+
990
+ declare namespace discoveryInclude {
991
+ type Options = Pick<z.output<typeof schema.getEarnVaults.Query>, 'capability' | 'include'>
992
+ }
993
+
994
+ async function resolveVaultDiscovery(
995
+ c: Context<App.Environment>,
996
+ options: resolveVaultDiscovery.Options,
997
+ ) {
998
+ return Store.memoize(
999
+ () =>
1000
+ Timing.time(c, 'earn_vault_discovery', () =>
1001
+ EarnVaults.resolve({
1002
+ getClient: c.get('getClient'),
1003
+ include: options.include,
1004
+ input: {
1005
+ chainId: options.chainId,
1006
+ vaultAddress: options.vaultAddress,
1007
+ },
1008
+ zones: [...c.get('zones').values()],
1009
+ }),
1010
+ ),
1011
+ {
1012
+ key: `earn-vault:v3:${options.chainId}:${options.vaultAddress.toLowerCase()}:include:${options.include.join(',') || 'base'}`,
1013
+ store: c.get('store'),
1014
+ // Matches the routes' `state` policy `max-age` so the two cache layers do
1015
+ // not compound staleness on live vault state.
1016
+ ttl: Ttl.seconds(30),
1017
+ },
1018
+ )
1019
+ }
1020
+
1021
+ declare namespace resolveVaultDiscovery {
1022
+ type Options = {
1023
+ chainId: z.output<typeof Schema.ChainId>
1024
+ include: readonly EarnVaults.resolve.Include[]
1025
+ vaultAddress: z.output<typeof Schema.Address>
1026
+ }
1027
+ }
1028
+
1029
+ // Measuring a rate costs indexer boundary queries plus historical quotes against
1030
+ // an archive node, so an unrequested rate reaches neither.
1031
+ function resolvePageApy(c: Context<App.Environment>, options: resolvePageApy.Options) {
1032
+ if (!options.include.includes('apy')) return undefined
1033
+ return Timing.time(c, 'earn_apy', () =>
1034
+ EarnRates.resolve({
1035
+ chainId: options.chainId,
1036
+ getClient: c.get('getClient'),
1037
+ getTidx: c.get('getTidx'),
1038
+ store: c.get('store'),
1039
+ vaults: options.discoveries.map(({ vaultAddress }) => vaultAddress),
1040
+ window: options.window,
1041
+ }),
1042
+ )
1043
+ }
1044
+
1045
+ declare namespace resolvePageApy {
1046
+ type Options = {
1047
+ chainId: z.output<typeof Schema.ChainId>
1048
+ discoveries: readonly EarnVaults.Discovery[]
1049
+ include: z.output<typeof schema.getEarnVault.Query>['include']
1050
+ window: z.output<typeof schema.getEarnVault.Query>['apy.window']
1051
+ }
1052
+ }
1053
+
1054
+ // The TVL denomination is a fixed constant, not caller input, so a rate set
1055
+ // lacking it leaves `tvl` unpriced instead of failing the whole vault read.
1056
+ function resolvePageRates(c: Context<App.Environment>, options: resolvePageRates.Options) {
1057
+ // Valuing total assets is the only reason this read consults the oracle.
1058
+ if (!options.include.includes('tvl')) return undefined
1059
+ return Valuation.ratesFor(c, {
1060
+ currencies: options.discoveries.flatMap((discovery) => {
1061
+ const currency = options.snapshot.byAddress.get(discovery.assetToken.address)?.currency
1062
+ return currency === undefined ? [] : [currency]
1063
+ }),
1064
+ denomination: tvlDenomination,
1065
+ oracle: options.oracle,
1066
+ }).catch((cause) => {
1067
+ if (cause instanceof Valuation.UnsupportedDenominationError) return undefined
1068
+ throw cause
1069
+ })
1070
+ }
1071
+
1072
+ declare namespace resolvePageRates {
1073
+ type Options = {
1074
+ discoveries: readonly EarnVaults.Discovery[]
1075
+ include: z.output<typeof schema.getEarnVault.Query>['include']
1076
+ oracle: FxOracle.Oracle
1077
+ snapshot: VerifiedTokens.Snapshot
1078
+ }
1079
+ }
1080
+
1081
+ async function resolvePageTokens(c: Context<App.Environment>, options: resolvePageTokens.Options) {
1082
+ const metadata = new Map(
1083
+ options.discoveries.flatMap(({ assetToken, shareToken }) => [
1084
+ [Schema.Address.parse(assetToken.address.toLowerCase()), assetToken] as const,
1085
+ [Schema.Address.parse(shareToken.address.toLowerCase()), shareToken] as const,
1086
+ ]),
1087
+ )
1088
+ return Tokens.resolveTokens(c, {
1089
+ addresses: [...metadata.keys()],
1090
+ chainId: options.chainId,
1091
+ include: [
1092
+ 'token.verified',
1093
+ ...(options.include.includes('token.logoUri') ? (['token.logoUri'] as const) : []),
1094
+ ],
1095
+ metadata,
1096
+ snapshot: options.snapshot,
1097
+ })
1098
+ }
1099
+
1100
+ declare namespace resolvePageTokens {
1101
+ type Options = {
1102
+ chainId: z.output<typeof Schema.ChainId>
1103
+ discoveries: readonly EarnVaults.Discovery[]
1104
+ include: z.output<typeof schema.getEarnVault.Query>['include']
1105
+ snapshot: VerifiedTokens.Snapshot
1106
+ }
1107
+ }
1108
+
1109
+ function resolveVault(c: Context<App.Environment>, options: resolveVault.Options) {
1110
+ const { discovery, record } = options
1111
+ const valued = options.include.includes('tvl')
1112
+ ? Valuation.valuationFor({
1113
+ amount: BigInt(discovery.state.totalAssets),
1114
+ denomination: tvlDenomination,
1115
+ rates: options.rates,
1116
+ token: options.snapshot.byAddress.get(discovery.assetToken.address),
1117
+ })
1118
+ : undefined
1119
+ return serializeVault({
1120
+ apy: options.apy?.get(discovery.vaultAddress) ?? null,
1121
+ assetToken: getToken(options.tokens, discovery.assetToken.address),
1122
+ discovery,
1123
+ include: options.include,
1124
+ record,
1125
+ shareToken: getToken(options.tokens, discovery.shareToken.address),
1126
+ tvl: valued
1127
+ ? {
1128
+ amount: core_Value.from(valued.amount, tvlDecimals).toString(),
1129
+ currency: valued.currency,
1130
+ decimals: tvlDecimals,
1131
+ formatted: valued.amount,
1132
+ }
1133
+ : null,
1134
+ zones: [...c.get('zones').values()],
1135
+ })
1136
+ }
1137
+
1138
+ declare namespace resolveVault {
1139
+ type Options = {
1140
+ apy: ReadonlyMap<string, EarnRates.Apy | null> | undefined
1141
+ discovery: EarnVaults.Discovery
1142
+ include: z.output<typeof schema.getEarnVault.Query>['include']
1143
+ rates: Awaited<ReturnType<typeof Valuation.ratesFor>>
1144
+ record?: RegistryRecord | undefined
1145
+ snapshot: VerifiedTokens.Snapshot
1146
+ tokens: Tokens.resolveTokens.ReturnType
1147
+ }
1148
+ }
1149
+
1150
+ /** Serializes resolved onchain and curated fields into the shared vault contract. */
1151
+ export function serializeVault(options: serializeVault.Options): z.output<typeof schema.Vault> {
1152
+ const { discovery, record } = options
1153
+ if (options.include.includes('access') && !discovery.access)
1154
+ throw new Error('Earn vault access was not resolved.')
1155
+ if (options.include.includes('capabilities') && !discovery.capabilities)
1156
+ throw new Error('Earn vault capabilities were not resolved.')
1157
+ const vaultAddress = Schema.Address.parse(discovery.vaultAddress.toLowerCase())
1158
+ return Response.validated(schema.Vault, {
1159
+ ...(options.include.includes('access') ? { access: discovery.access } : {}),
1160
+ ...(options.include.includes('apy') ? { apy: options.apy } : {}),
1161
+ assetToken: options.assetToken,
1162
+ ...(options.include.includes('capabilities') ? { capabilities: discovery.capabilities } : {}),
1163
+ description: record?.description ?? null,
1164
+ engine: {
1165
+ address: discovery.engine.address.toLowerCase(),
1166
+ type: discovery.engine.type,
1167
+ venue: discovery.engine.venue?.toLowerCase() ?? null,
1168
+ },
1169
+ id: vaultAddress,
1170
+ instantLiquidity: discovery.instantLiquidity,
1171
+ label: record?.label ?? options.shareToken.name,
1172
+ sharePrice:
1173
+ discovery.sharePrice === null
1174
+ ? null
1175
+ : {
1176
+ amount: discovery.sharePrice,
1177
+ currency: options.assetToken.currency,
1178
+ decimals: options.assetToken.decimals,
1179
+ formatted: core_Value.format(BigInt(discovery.sharePrice), options.assetToken.decimals),
1180
+ },
1181
+ shareToken: options.shareToken,
1182
+ slug: record?.slug ?? null,
1183
+ state: discovery.state,
1184
+ ...(options.include.includes('tvl') ? { tvl: options.tvl } : {}),
1185
+ vaultAddress,
1186
+ verified: record !== undefined,
1187
+ ...(options.include.includes('zone')
1188
+ ? { zone: record ? resolveZone({ discovery, record, zones: options.zones }) : null }
1189
+ : {}),
1190
+ })
1191
+ }
1192
+
1193
+ export declare namespace serializeVault {
1194
+ /** Values used to serialize one resolved Earn vault. */
1195
+ type Options = {
1196
+ /** Measured rate, or null when unavailable; omitted unless `include` carries `apy`. */
1197
+ apy: EarnRates.Apy | null
1198
+ /** Resolved asset token. */
1199
+ assetToken: z.output<typeof Tokens.schema.Token>
1200
+ /** Live onchain vault state. */
1201
+ discovery: EarnVaults.Discovery
1202
+ /** Optional vault fields selected by the request. */
1203
+ include: z.output<typeof schema.getEarnVault.Query>['include']
1204
+ /** Curated registry row, when verified. */
1205
+ record?: core_EarnVaults.Record | undefined
1206
+ /** Resolved share token. */
1207
+ shareToken: z.output<typeof Tokens.schema.Token>
1208
+ /** USD value of the assets, or null when unpriced; omitted unless `include` carries `tvl`. */
1209
+ tvl: z.output<typeof schema.Vault>['tvl']
1210
+ /** Private Zones available to the vault. */
1211
+ zones: readonly Chain[]
1212
+ }
1213
+ }
1214
+
1215
+ function resolveZone(options: resolveZone.Options): z.output<typeof schema.Vault.shape.zone> {
1216
+ if (!options.discovery.capabilities?.privateRouting) return null
1217
+ const hasInputs = options.record.privateInputTokens.length > 0
1218
+ const hasOutputs = options.record.privateOutputTokens.length > 0
1219
+ if (!hasInputs && !hasOutputs) return null
1220
+ if (hasInputs !== hasOutputs)
1221
+ throw new Error('Private input and output tokens must both be configured.')
1222
+
1223
+ const configured = options.zones.filter((zone) => zone.sourceId === options.record.chainId)
1224
+ if (configured.length !== 1)
1225
+ throw new Error(`Expected one Earn Zone for chain ${options.record.chainId}.`)
1226
+ const zone = configured[0]!
1227
+ return {
1228
+ chainId: zone.id,
1229
+ inputTokens: options.record.privateInputTokens.map((token) =>
1230
+ Schema.Address.parse(token.toLowerCase()),
1231
+ ),
1232
+ name: zone.name,
1233
+ outputTokens: options.record.privateOutputTokens.map((token) =>
1234
+ Schema.Address.parse(token.toLowerCase()),
1235
+ ),
1236
+ }
1237
+ }
1238
+
1239
+ declare namespace resolveZone {
1240
+ type Options = {
1241
+ discovery: EarnVaults.Discovery
1242
+ record: RegistryRecord
1243
+ zones: readonly Chain[]
1244
+ }
1245
+ }
1246
+
1247
+ function getToken(
1248
+ tokens: Tokens.resolveTokens.ReturnType,
1249
+ address: z.output<typeof Schema.Address>,
1250
+ ): z.output<typeof Tokens.schema.Token> {
1251
+ const token = tokens.get(Schema.Address.parse(address.toLowerCase()))
1252
+ if (!token) throw new Error(`Token metadata was not resolved for ${address}.`)
1253
+ return Response.validated(Tokens.schema.Token, token)
1254
+ }
1255
+
1256
+ async function queryDeployments(
1257
+ c: Context<App.Environment>,
1258
+ options: queryDeployments.Options,
1259
+ ): Promise<queryDeployments.Result> {
1260
+ const filters = ['deployment_rank = 1']
1261
+ if (options.asset) filters.push(`lower(asset) = '${options.asset.toLowerCase()}'`)
1262
+ if (options.cursor)
1263
+ filters.push(
1264
+ Cursor.keyset([
1265
+ {
1266
+ literal: Cursor.literal(options.cursor[0], 'int'),
1267
+ name: 'block_num',
1268
+ order: 'desc',
1269
+ },
1270
+ {
1271
+ literal: Cursor.literal(options.cursor[1], 'int'),
1272
+ name: 'log_idx',
1273
+ order: 'desc',
1274
+ },
1275
+ ]),
1276
+ )
1277
+
1278
+ // ClickHouse supports ordering and windowing over decoded event CTEs.
1279
+ const result = await c
1280
+ .get('getTidx')(options.chainId)
1281
+ .fetch({
1282
+ chainId: options.chainId,
1283
+ engine: 'clickhouse',
1284
+ query: `
1285
+ SELECT "earnVault", asset, block_num, log_idx
1286
+ FROM (
1287
+ SELECT
1288
+ "earnVault",
1289
+ asset,
1290
+ block_num,
1291
+ log_idx,
1292
+ row_number() OVER (
1293
+ PARTITION BY lower("earnVault")
1294
+ ORDER BY block_num DESC, log_idx DESC
1295
+ ) AS deployment_rank
1296
+ FROM EarnStackDeployed
1297
+ )
1298
+ WHERE ${filters.join(' AND ')}
1299
+ ORDER BY block_num DESC, log_idx DESC
1300
+ LIMIT ${options.limit + 1}
1301
+ ` as string,
1302
+ signatures: [deployedSignature],
1303
+ })
1304
+
1305
+ const rows: readonly Record<string, unknown>[] = result.rows
1306
+ const items = rows.slice(0, options.limit).map((row) => {
1307
+ const vaultAddress = Schema.Address.safeParse(Value.toText(row['earnVault']))
1308
+ const asset = Schema.Address.safeParse(Value.toText(row['asset']))
1309
+ const blockNumber = Value.toNumber(row['block_num'])
1310
+ const logIndex = Value.toNumber(row['log_idx'])
1311
+ if (
1312
+ !vaultAddress.success ||
1313
+ !asset.success ||
1314
+ blockNumber === undefined ||
1315
+ logIndex === undefined
1316
+ )
1317
+ throw new Error('TIDX returned an invalid Earn deployment row.')
1318
+ return {
1319
+ asset: asset.data,
1320
+ position: [blockNumber, logIndex] as queryDeployments.Position,
1321
+ vaultAddress: vaultAddress.data,
1322
+ }
1323
+ })
1324
+ return { hasMore: rows.length > options.limit, items }
1325
+ }
1326
+
1327
+ declare namespace queryDeployments {
1328
+ type Item = {
1329
+ asset: z.output<typeof Schema.Address>
1330
+ position: Position
1331
+ vaultAddress: z.output<typeof Schema.Address>
1332
+ }
1333
+
1334
+ type Options = {
1335
+ asset?: z.output<typeof Schema.Address> | undefined
1336
+ chainId: z.output<typeof Schema.ChainId>
1337
+ cursor?: Position | undefined
1338
+ limit: number
1339
+ }
1340
+
1341
+ type Position = [number, number]
1342
+
1343
+ type Result = {
1344
+ hasMore: boolean
1345
+ items: readonly Item[]
1346
+ }
1347
+ }
1348
+
1349
+ /** Tests live vault state against the shared collection filters. */
1350
+ export function matchesVaultFilters(
1351
+ discovery: EarnVaults.Discovery,
1352
+ options: matchesVaultFilters.Options,
1353
+ ): boolean {
1354
+ if (options.asset && discovery.assetToken.address.toLowerCase() !== options.asset.toLowerCase())
1355
+ return false
1356
+ const capabilities = discovery.capabilities
1357
+ if (options.capability.length > 0 && !capabilities)
1358
+ throw new Error('Earn vault capabilities were not resolved.')
1359
+ if (capabilities && !options.capability.every((name) => capabilities[name])) return false
1360
+ if (options['engine.type'] && discovery.engine.type !== options['engine.type']) return false
1361
+ return true
1362
+ }
1363
+
1364
+ export declare namespace matchesVaultFilters {
1365
+ /** Filters shared by the all-vault and verified-vault collections. */
1366
+ type Options = Pick<
1367
+ z.output<typeof schema.getEarnVaults.Query>,
1368
+ 'asset' | 'capability' | 'engine.type'
1369
+ >
1370
+ }
1371
+
1372
+ /** Returns whether a failed read proves the address is not a compatible Earn vault. */
1373
+ export function isIncompatible(cause: unknown) {
1374
+ if (cause instanceof EarnVaults.NotFoundError) return true
1375
+ if (cause instanceof EarnVaults.VerificationError) return cause.result.status === 'mismatch'
1376
+ if (!(cause instanceof ContractFunctionExecutionError)) return false
1377
+ return Boolean(
1378
+ cause.walk(
1379
+ (error) =>
1380
+ error instanceof ContractFunctionRevertedError ||
1381
+ error instanceof ContractFunctionZeroDataError,
1382
+ ),
1383
+ )
1384
+ }
1385
+
1386
+ type RegistryRecord = Awaited<ReturnType<typeof core_EarnVaults.list>>[number]
1387
+
1388
+ /** Thrown when no compatible Earn vault exists at the requested address. */
1389
+ export class NotFoundError extends Error {
1390
+ override name = 'Earn.NotFoundError'
1391
+ }