tapimo 0.14.0 → 0.15.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 (1141) hide show
  1. package/README.md +7 -4
  2. package/dist/ApiKey.js +1 -1
  3. package/dist/ApiKey.js.map +1 -1
  4. package/dist/ApiKeys.d.ts +95 -14
  5. package/dist/ApiKeys.d.ts.map +1 -1
  6. package/dist/ApiKeys.js +360 -49
  7. package/dist/ApiKeys.js.map +1 -1
  8. package/dist/App.d.ts +12457 -10365
  9. package/dist/App.d.ts.map +1 -1
  10. package/dist/App.js +300 -22
  11. package/dist/App.js.map +1 -1
  12. package/dist/Assets.d.ts.map +1 -1
  13. package/dist/Assets.js +2 -1
  14. package/dist/Assets.js.map +1 -1
  15. package/dist/Handler.d.ts +0 -1
  16. package/dist/Handler.d.ts.map +1 -1
  17. package/dist/Handler.js +0 -1
  18. package/dist/Handler.js.map +1 -1
  19. package/dist/Scope.d.ts +13 -5
  20. package/dist/Scope.d.ts.map +1 -1
  21. package/dist/Scope.js +16 -5
  22. package/dist/Scope.js.map +1 -1
  23. package/dist/Webhooks.js +1 -1
  24. package/dist/Webhooks.js.map +1 -1
  25. package/dist/admin/App.d.ts +3057 -549
  26. package/dist/admin/App.d.ts.map +1 -1
  27. package/dist/admin/App.js +26 -5
  28. package/dist/admin/App.js.map +1 -1
  29. package/dist/admin/apps/api-keys.d.ts +159 -7
  30. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  31. package/dist/admin/apps/api-keys.js +95 -43
  32. package/dist/admin/apps/api-keys.js.map +1 -1
  33. package/dist/admin/apps/earn-vaults.d.ts +1398 -0
  34. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  35. package/dist/admin/apps/earn-vaults.js +463 -7
  36. package/dist/admin/apps/earn-vaults.js.map +1 -1
  37. package/dist/admin/apps/organizations.d.ts +267 -15
  38. package/dist/admin/apps/organizations.d.ts.map +1 -1
  39. package/dist/admin/apps/organizations.js +241 -25
  40. package/dist/admin/apps/organizations.js.map +1 -1
  41. package/dist/admin/apps/routes-support.d.ts +95 -0
  42. package/dist/admin/apps/routes-support.d.ts.map +1 -0
  43. package/dist/admin/apps/routes-support.js +151 -0
  44. package/dist/admin/apps/routes-support.js.map +1 -0
  45. package/dist/admin/apps/routes.d.ts +2764 -0
  46. package/dist/admin/apps/routes.d.ts.map +1 -0
  47. package/dist/admin/apps/routes.js +728 -0
  48. package/dist/admin/apps/routes.js.map +1 -0
  49. package/dist/admin/apps/subsidies.d.ts +501 -0
  50. package/dist/admin/apps/subsidies.d.ts.map +1 -0
  51. package/dist/admin/apps/subsidies.js +384 -0
  52. package/dist/admin/apps/subsidies.js.map +1 -0
  53. package/dist/admin/apps/verified-tokens.d.ts +88 -88
  54. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  55. package/dist/admin/apps/verified-tokens.js +3 -3
  56. package/dist/admin/apps/verified-tokens.js.map +1 -1
  57. package/dist/admin/ui.generated.d.ts +1 -1
  58. package/dist/admin/ui.generated.d.ts.map +1 -1
  59. package/dist/admin/ui.generated.js +129 -69
  60. package/dist/admin/ui.generated.js.map +1 -1
  61. package/dist/analytics/Analytics.d.ts +5 -2
  62. package/dist/analytics/Analytics.d.ts.map +1 -1
  63. package/dist/analytics/Analytics.js +31 -1
  64. package/dist/analytics/Analytics.js.map +1 -1
  65. package/dist/analytics/tables/requestEvents.d.ts +2 -1
  66. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  67. package/dist/analytics/tables/requestEvents.js +10 -1
  68. package/dist/analytics/tables/requestEvents.js.map +1 -1
  69. package/dist/analytics/tables/routesLifecycleIntervals.d.ts +72 -0
  70. package/dist/analytics/tables/routesLifecycleIntervals.d.ts.map +1 -0
  71. package/dist/analytics/tables/routesLifecycleIntervals.js +56 -0
  72. package/dist/analytics/tables/routesLifecycleIntervals.js.map +1 -0
  73. package/dist/apps/Zones.d.ts +21 -12526
  74. package/dist/apps/Zones.d.ts.map +1 -1
  75. package/dist/apps/Zones.js +37 -5
  76. package/dist/apps/Zones.js.map +1 -1
  77. package/dist/apps/data/App.d.ts +3971 -2595
  78. package/dist/apps/data/App.d.ts.map +1 -1
  79. package/dist/apps/data/App.js +76 -21
  80. package/dist/apps/data/App.js.map +1 -1
  81. package/dist/apps/data/routes/activities.d.ts +364 -34
  82. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  83. package/dist/apps/data/routes/activities.js +495 -190
  84. package/dist/apps/data/routes/activities.js.map +1 -1
  85. package/dist/apps/data/routes/addresses.d.ts +72 -0
  86. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  87. package/dist/apps/data/routes/blocks.d.ts +37 -37
  88. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  89. package/dist/apps/data/routes/coingecko.js +47 -21
  90. package/dist/apps/data/routes/coingecko.js.map +1 -1
  91. package/dist/apps/data/routes/earn.d.ts +1450 -337
  92. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  93. package/dist/apps/data/routes/earn.js +1226 -144
  94. package/dist/apps/data/routes/earn.js.map +1 -1
  95. package/dist/apps/data/routes/fee-amm.d.ts +5 -0
  96. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  97. package/dist/apps/data/routes/fee-amm.js +31 -19
  98. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  99. package/dist/apps/data/routes/indexer.d.ts +125 -0
  100. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  101. package/dist/apps/data/routes/indexer.js +83 -27
  102. package/dist/apps/data/routes/indexer.js.map +1 -1
  103. package/dist/apps/data/routes/rpc.d.ts +507 -33
  104. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  105. package/dist/apps/data/routes/rpc.js +266 -156
  106. package/dist/apps/data/routes/rpc.js.map +1 -1
  107. package/dist/apps/data/routes/tokenlist.d.ts +47 -15
  108. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  109. package/dist/apps/data/routes/tokenlist.js +68 -11
  110. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  111. package/dist/apps/data/routes/tokens.d.ts +2 -0
  112. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  113. package/dist/apps/data/routes/tokens.js +26 -14
  114. package/dist/apps/data/routes/tokens.js.map +1 -1
  115. package/dist/apps/data/routes/transfers.d.ts +28 -12
  116. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  117. package/dist/apps/data/routes/transfers.js +9 -7
  118. package/dist/apps/data/routes/transfers.js.map +1 -1
  119. package/dist/apps/data/routes/valuation.d.ts +30 -30
  120. package/dist/apps/data/routes/verified-tokens.d.ts +9 -9
  121. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  122. package/dist/apps/data/routes/verified-tokens.js +64 -20
  123. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  124. package/dist/apps/data/routes/webhooks.d.ts +613 -176
  125. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  126. package/dist/apps/data/routes/webhooks.js +291 -195
  127. package/dist/apps/data/routes/webhooks.js.map +1 -1
  128. package/dist/apps/data/routes/zones.d.ts.map +1 -1
  129. package/dist/apps/data/routes/zones.js +20 -12
  130. package/dist/apps/data/routes/zones.js.map +1 -1
  131. package/dist/apps/docs/reference.js +2 -2
  132. package/dist/apps/docs/reference.js.map +1 -1
  133. package/dist/apps/index.d.ts +1 -1
  134. package/dist/apps/index.d.ts.map +1 -1
  135. package/dist/apps/index.js +1 -1
  136. package/dist/apps/index.js.map +1 -1
  137. package/dist/apps/management/App.d.ts +3763 -3385
  138. package/dist/apps/management/App.d.ts.map +1 -1
  139. package/dist/apps/management/App.js +5 -14
  140. package/dist/apps/management/App.js.map +1 -1
  141. package/dist/apps/management/Billing.d.ts +48 -7
  142. package/dist/apps/management/Billing.d.ts.map +1 -1
  143. package/dist/apps/management/Billing.js +204 -25
  144. package/dist/apps/management/Billing.js.map +1 -1
  145. package/dist/apps/management/routes/api-keys.d.ts +106 -4
  146. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  147. package/dist/apps/management/routes/api-keys.js +43 -15
  148. package/dist/apps/management/routes/api-keys.js.map +1 -1
  149. package/dist/apps/management/routes/billing.d.ts +290 -4
  150. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  151. package/dist/apps/management/routes/billing.js +274 -49
  152. package/dist/apps/management/routes/billing.js.map +1 -1
  153. package/dist/apps/management/routes/faucet.d.ts +6 -6
  154. package/dist/apps/management/routes/faucet.js +1 -1
  155. package/dist/apps/management/routes/faucet.js.map +1 -1
  156. package/dist/apps/management/routes/invitations.d.ts +77 -2
  157. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  158. package/dist/apps/management/routes/invitations.js +117 -13
  159. package/dist/apps/management/routes/invitations.js.map +1 -1
  160. package/dist/apps/management/routes/invite-links.d.ts +4 -4
  161. package/dist/apps/management/routes/me.d.ts.map +1 -1
  162. package/dist/apps/management/routes/me.js +6 -2
  163. package/dist/apps/management/routes/me.js.map +1 -1
  164. package/dist/apps/management/routes/members.d.ts +30 -30
  165. package/dist/apps/management/routes/orgs.d.ts +18 -2
  166. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  167. package/dist/apps/management/routes/orgs.js +52 -12
  168. package/dist/apps/management/routes/orgs.js.map +1 -1
  169. package/dist/apps/management/routes/projects.d.ts +4 -4
  170. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  171. package/dist/apps/management/routes/projects.js +6 -1
  172. package/dist/apps/management/routes/projects.js.map +1 -1
  173. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  174. package/dist/apps/management/routes/scopes.js +4 -1
  175. package/dist/apps/management/routes/scopes.js.map +1 -1
  176. package/dist/apps/management/routes/usage.d.ts +24 -24
  177. package/dist/apps/management/routes/usage.js +21 -4
  178. package/dist/apps/management/routes/usage.js.map +1 -1
  179. package/dist/apps/management/routes/verified-token-requests.d.ts +2 -2
  180. package/dist/apps/management/routes/webhooks.d.ts +280 -214
  181. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  182. package/dist/apps/management/routes/webhooks.js +58 -12
  183. package/dist/apps/management/routes/webhooks.js.map +1 -1
  184. package/dist/apps/mcp.d.ts +1 -1
  185. package/dist/apps/mcp.js +7 -7
  186. package/dist/apps/mcp.js.map +1 -1
  187. package/dist/apps/mpp/App.d.ts.map +1 -1
  188. package/dist/apps/mpp/App.js +35 -7
  189. package/dist/apps/mpp/App.js.map +1 -1
  190. package/dist/apps/mpp/internal/Adapter.d.ts +2 -0
  191. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  192. package/dist/apps/mpp/internal/Adapter.js +30 -1
  193. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  194. package/dist/apps/mpp/internal/Policy.d.ts +22 -4
  195. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  196. package/dist/apps/mpp/internal/Policy.js +24 -6
  197. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  198. package/dist/apps/mpp/internal/Sponsorship.d.ts +3 -0
  199. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  200. package/dist/apps/mpp/internal/Sponsorship.js +6 -3
  201. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  202. package/dist/apps/relay/App.d.ts +2 -0
  203. package/dist/apps/relay/App.d.ts.map +1 -1
  204. package/dist/apps/relay/App.js +134 -75
  205. package/dist/apps/relay/App.js.map +1 -1
  206. package/dist/apps/relay/Sponsorships.d.ts +5 -3
  207. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  208. package/dist/apps/relay/Sponsorships.js +209 -28
  209. package/dist/apps/relay/Sponsorships.js.map +1 -1
  210. package/dist/apps/{funding → routes}/Access.d.ts +4 -4
  211. package/dist/apps/routes/Access.d.ts.map +1 -0
  212. package/dist/apps/{funding → routes}/Access.js +4 -4
  213. package/dist/apps/routes/Access.js.map +1 -0
  214. package/dist/apps/{funding → routes}/App.d.ts +418 -124
  215. package/dist/apps/{funding → routes}/App.d.ts.map +1 -1
  216. package/dist/apps/{funding → routes}/App.js +16 -16
  217. package/dist/apps/routes/App.js.map +1 -0
  218. package/dist/apps/routes/Inventory.d.ts.map +1 -0
  219. package/dist/apps/{funding → routes}/Inventory.js +2 -2
  220. package/dist/apps/routes/Inventory.js.map +1 -0
  221. package/dist/apps/routes/index.d.ts +2 -0
  222. package/dist/apps/routes/index.d.ts.map +1 -0
  223. package/dist/apps/routes/index.js +2 -0
  224. package/dist/apps/routes/index.js.map +1 -0
  225. package/dist/apps/{funding → routes}/routes/chains.d.ts +7 -7
  226. package/dist/apps/routes/routes/chains.d.ts.map +1 -0
  227. package/dist/apps/{funding → routes}/routes/chains.js +25 -25
  228. package/dist/apps/routes/routes/chains.js.map +1 -0
  229. package/dist/apps/{funding → routes}/routes/deposit-addresses.d.ts +107 -43
  230. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -0
  231. package/dist/apps/{funding → routes}/routes/deposit-addresses.js +497 -222
  232. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -0
  233. package/dist/apps/{funding → routes}/routes/providers.d.ts +8 -8
  234. package/dist/apps/routes/routes/providers.d.ts.map +1 -0
  235. package/dist/apps/routes/routes/providers.js +57 -0
  236. package/dist/apps/routes/routes/providers.js.map +1 -0
  237. package/dist/apps/{funding → routes}/routes/quotes.d.ts +19 -16
  238. package/dist/apps/routes/routes/quotes.d.ts.map +1 -0
  239. package/dist/apps/{funding → routes}/routes/quotes.js +55 -38
  240. package/dist/apps/routes/routes/quotes.js.map +1 -0
  241. package/dist/apps/{funding → routes}/routes/transfers.d.ts +379 -74
  242. package/dist/apps/routes/routes/transfers.d.ts.map +1 -0
  243. package/dist/apps/routes/routes/transfers.js +1140 -0
  244. package/dist/apps/routes/routes/transfers.js.map +1 -0
  245. package/dist/cli/Cli.d.ts +30 -0
  246. package/dist/cli/Cli.d.ts.map +1 -1
  247. package/dist/cli/commands/admin.d.ts +36 -0
  248. package/dist/cli/commands/admin.d.ts.map +1 -1
  249. package/dist/cli/commands/admin.js +273 -0
  250. package/dist/cli/commands/admin.js.map +1 -1
  251. package/dist/cloudflare.d.ts +16 -14
  252. package/dist/cloudflare.d.ts.map +1 -1
  253. package/dist/cloudflare.js +26 -21
  254. package/dist/cloudflare.js.map +1 -1
  255. package/dist/db/Db.d.ts +63 -21
  256. package/dist/db/Db.d.ts.map +1 -1
  257. package/dist/db/Db.js +1030 -15
  258. package/dist/db/Db.js.map +1 -1
  259. package/dist/db/Schema.d.ts +780 -133
  260. package/dist/db/Schema.d.ts.map +1 -1
  261. package/dist/db/Schema.js +575 -162
  262. package/dist/db/Schema.js.map +1 -1
  263. package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts +4 -0
  264. package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts.map +1 -0
  265. package/dist/db/tables/apiKeyAdmissionBootstraps.js +2 -0
  266. package/dist/db/tables/apiKeyAdmissionBootstraps.js.map +1 -0
  267. package/dist/db/tables/apiKeyAdmissions.d.ts +73 -0
  268. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -0
  269. package/dist/db/tables/apiKeyAdmissions.js +142 -0
  270. package/dist/db/tables/apiKeyAdmissions.js.map +1 -0
  271. package/dist/db/tables/apiKeyOwnerAdmissions.d.ts +4 -0
  272. package/dist/db/tables/apiKeyOwnerAdmissions.d.ts.map +1 -0
  273. package/dist/db/tables/apiKeyOwnerAdmissions.js +2 -0
  274. package/dist/db/tables/apiKeyOwnerAdmissions.js.map +1 -0
  275. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +20 -0
  276. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -0
  277. package/dist/db/tables/apiKeyOwnerTombstones.js +57 -0
  278. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -0
  279. package/dist/db/tables/apiKeyRevocations.d.ts +21 -0
  280. package/dist/db/tables/apiKeyRevocations.d.ts.map +1 -0
  281. package/dist/db/tables/apiKeyRevocations.js +98 -0
  282. package/dist/db/tables/apiKeyRevocations.js.map +1 -0
  283. package/dist/db/tables/authAccounts.d.ts +47 -0
  284. package/dist/db/tables/authAccounts.d.ts.map +1 -0
  285. package/dist/db/tables/authAccounts.js +72 -0
  286. package/dist/db/tables/authAccounts.js.map +1 -0
  287. package/dist/db/tables/authSessions.d.ts +12 -0
  288. package/dist/db/tables/authSessions.d.ts.map +1 -0
  289. package/dist/db/tables/authSessions.js +2 -0
  290. package/dist/db/tables/authSessions.js.map +1 -0
  291. package/dist/db/tables/authVerifications.d.ts +12 -0
  292. package/dist/db/tables/authVerifications.d.ts.map +1 -0
  293. package/dist/db/tables/authVerifications.js +2 -0
  294. package/dist/db/tables/authVerifications.js.map +1 -0
  295. package/dist/db/tables/invitations.d.ts +17 -1
  296. package/dist/db/tables/invitations.d.ts.map +1 -1
  297. package/dist/db/tables/invitations.js +123 -43
  298. package/dist/db/tables/invitations.js.map +1 -1
  299. package/dist/db/tables/memberships.d.ts +8 -0
  300. package/dist/db/tables/memberships.d.ts.map +1 -1
  301. package/dist/db/tables/memberships.js +51 -2
  302. package/dist/db/tables/memberships.js.map +1 -1
  303. package/dist/db/tables/organizations.d.ts +32 -10
  304. package/dist/db/tables/organizations.d.ts.map +1 -1
  305. package/dist/db/tables/organizations.js +110 -49
  306. package/dist/db/tables/organizations.js.map +1 -1
  307. package/dist/db/tables/projects.d.ts +2 -0
  308. package/dist/db/tables/projects.d.ts.map +1 -1
  309. package/dist/db/tables/projects.js +12 -3
  310. package/dist/db/tables/projects.js.map +1 -1
  311. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  312. package/dist/db/tables/requestUsage.js.map +1 -1
  313. package/dist/db/tables/rewardAccounts.d.ts +86 -0
  314. package/dist/db/tables/rewardAccounts.d.ts.map +1 -0
  315. package/dist/db/tables/rewardAccounts.js +88 -0
  316. package/dist/db/tables/rewardAccounts.js.map +1 -0
  317. package/dist/db/tables/rewardCampaignDistributors.d.ts +36 -0
  318. package/dist/db/tables/rewardCampaignDistributors.d.ts.map +1 -0
  319. package/dist/db/tables/rewardCampaignDistributors.js +30 -0
  320. package/dist/db/tables/rewardCampaignDistributors.js.map +1 -0
  321. package/dist/db/tables/rewardCampaigns.d.ts +171 -0
  322. package/dist/db/tables/rewardCampaigns.d.ts.map +1 -0
  323. package/dist/db/tables/rewardCampaigns.js +392 -0
  324. package/dist/db/tables/rewardCampaigns.js.map +1 -0
  325. package/dist/db/tables/rewardCredits.d.ts +53 -0
  326. package/dist/db/tables/rewardCredits.d.ts.map +1 -0
  327. package/dist/db/tables/rewardCredits.js +63 -0
  328. package/dist/db/tables/rewardCredits.js.map +1 -0
  329. package/dist/db/tables/rewardEligibilityAssociations.d.ts +61 -0
  330. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -0
  331. package/dist/db/tables/rewardEligibilityAssociations.js +103 -0
  332. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -0
  333. package/dist/db/tables/rewardRuns.d.ts +188 -0
  334. package/dist/db/tables/rewardRuns.d.ts.map +1 -0
  335. package/dist/db/tables/rewardRuns.js +278 -0
  336. package/dist/db/tables/rewardRuns.js.map +1 -0
  337. package/dist/db/tables/rewardTransactionAttempts.d.ts +100 -0
  338. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -0
  339. package/dist/db/tables/rewardTransactionAttempts.js +163 -0
  340. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -0
  341. package/dist/db/tables/routesCatalog.d.ts +58 -0
  342. package/dist/db/tables/routesCatalog.d.ts.map +1 -0
  343. package/dist/db/tables/{fundingCatalog.js → routesCatalog.js} +19 -19
  344. package/dist/db/tables/routesCatalog.js.map +1 -0
  345. package/dist/db/tables/routesDepositAddresses.d.ts +476 -0
  346. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -0
  347. package/dist/db/tables/routesDepositAddresses.js +587 -0
  348. package/dist/db/tables/routesDepositAddresses.js.map +1 -0
  349. package/dist/db/tables/{fundingDepositRequestObservations.d.ts → routesDepositRequestObservations.d.ts} +6 -6
  350. package/dist/db/tables/routesDepositRequestObservations.d.ts.map +1 -0
  351. package/dist/db/tables/{fundingDepositRequestObservations.js → routesDepositRequestObservations.js} +6 -6
  352. package/dist/db/tables/routesDepositRequestObservations.js.map +1 -0
  353. package/dist/db/tables/{fundingDeposits.d.ts → routesDeposits.d.ts} +210 -22
  354. package/dist/db/tables/routesDeposits.d.ts.map +1 -0
  355. package/dist/db/tables/routesDeposits.js +576 -0
  356. package/dist/db/tables/routesDeposits.js.map +1 -0
  357. package/dist/db/tables/routesIdempotency.d.ts +166 -0
  358. package/dist/db/tables/routesIdempotency.d.ts.map +1 -0
  359. package/dist/db/tables/routesIdempotency.js +330 -0
  360. package/dist/db/tables/routesIdempotency.js.map +1 -0
  361. package/dist/db/tables/routesSubsidies.d.ts +27 -0
  362. package/dist/db/tables/routesSubsidies.d.ts.map +1 -0
  363. package/dist/db/tables/routesSubsidies.js +45 -0
  364. package/dist/db/tables/routesSubsidies.js.map +1 -0
  365. package/dist/db/tables/{fundingTransferEvents.d.ts → routesTransferEvents.d.ts} +3 -3
  366. package/dist/db/tables/routesTransferEvents.d.ts.map +1 -0
  367. package/dist/db/tables/{fundingTransferEvents.js → routesTransferEvents.js} +3 -3
  368. package/dist/db/tables/routesTransferEvents.js.map +1 -0
  369. package/dist/db/tables/routesTransferSubsidies.d.ts +19 -0
  370. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -0
  371. package/dist/db/tables/routesTransferSubsidies.js +17 -0
  372. package/dist/db/tables/routesTransferSubsidies.js.map +1 -0
  373. package/dist/db/tables/routesTransferSubsidyNonces.d.ts +51 -0
  374. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -0
  375. package/dist/db/tables/routesTransferSubsidyNonces.js +82 -0
  376. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -0
  377. package/dist/db/tables/routesTransferTransactions.d.ts +77 -0
  378. package/dist/db/tables/routesTransferTransactions.d.ts.map +1 -0
  379. package/dist/db/tables/{fundingTransferTransactions.js → routesTransferTransactions.js} +31 -13
  380. package/dist/db/tables/routesTransferTransactions.js.map +1 -0
  381. package/dist/db/tables/routesTransfers.d.ts +319 -0
  382. package/dist/db/tables/routesTransfers.d.ts.map +1 -0
  383. package/dist/db/tables/routesTransfers.js +372 -0
  384. package/dist/db/tables/routesTransfers.js.map +1 -0
  385. package/dist/db/tables/sponsoredTransactions.d.ts +75 -20
  386. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  387. package/dist/db/tables/sponsoredTransactions.js +124 -54
  388. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  389. package/dist/db/tables/sponsorshipAttributions.d.ts +69 -0
  390. package/dist/db/tables/sponsorshipAttributions.d.ts.map +1 -0
  391. package/dist/db/tables/sponsorshipAttributions.js +77 -0
  392. package/dist/db/tables/sponsorshipAttributions.js.map +1 -0
  393. package/dist/db/tables/sponsorshipReconciliationCursors.d.ts +22 -0
  394. package/dist/db/tables/sponsorshipReconciliationCursors.d.ts.map +1 -0
  395. package/dist/db/tables/sponsorshipReconciliationCursors.js +45 -0
  396. package/dist/db/tables/sponsorshipReconciliationCursors.js.map +1 -0
  397. package/dist/db/tables/stripeCustomers.d.ts +11 -0
  398. package/dist/db/tables/stripeCustomers.d.ts.map +1 -1
  399. package/dist/db/tables/stripeCustomers.js +13 -0
  400. package/dist/db/tables/stripeCustomers.js.map +1 -1
  401. package/dist/db/tables/users.d.ts +17 -1
  402. package/dist/db/tables/users.d.ts.map +1 -1
  403. package/dist/db/tables/users.js +47 -2
  404. package/dist/db/tables/users.js.map +1 -1
  405. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  406. package/dist/db/tables/webhookQueueEvents.js +5 -1
  407. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  408. package/dist/db/tables/webhookSubscriptions.d.ts +19 -11
  409. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  410. package/dist/db/tables/webhookSubscriptions.js +45 -13
  411. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  412. package/dist/handlers/internal/executionError.d.ts +2 -2
  413. package/dist/handlers/internal/executionError.d.ts.map +1 -1
  414. package/dist/handlers/internal/executionError.js +1 -2
  415. package/dist/handlers/internal/executionError.js.map +1 -1
  416. package/dist/handlers/internal/multisig.d.ts +4 -232
  417. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  418. package/dist/handlers/internal/multisig.js +11 -537
  419. package/dist/handlers/internal/multisig.js.map +1 -1
  420. package/dist/handlers/internal/sponsorship.d.ts +19 -8
  421. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  422. package/dist/handlers/internal/sponsorship.js +13 -9
  423. package/dist/handlers/internal/sponsorship.js.map +1 -1
  424. package/dist/handlers/relay.d.ts +9 -12
  425. package/dist/handlers/relay.d.ts.map +1 -1
  426. package/dist/handlers/relay.js +81 -85
  427. package/dist/handlers/relay.js.map +1 -1
  428. package/dist/index.d.ts +0 -17
  429. package/dist/index.d.ts.map +1 -1
  430. package/dist/index.js +0 -17
  431. package/dist/index.js.map +1 -1
  432. package/dist/internal/AssetResponse.d.ts +12 -0
  433. package/dist/internal/AssetResponse.d.ts.map +1 -0
  434. package/dist/internal/AssetResponse.js +21 -0
  435. package/dist/internal/AssetResponse.js.map +1 -0
  436. package/dist/internal/Auth.d.ts +48 -12
  437. package/dist/internal/Auth.d.ts.map +1 -1
  438. package/dist/internal/Auth.js +603 -175
  439. package/dist/internal/Auth.js.map +1 -1
  440. package/dist/internal/BetterAuth.d.ts +1488 -0
  441. package/dist/internal/BetterAuth.d.ts.map +1 -0
  442. package/dist/internal/BetterAuth.js +253 -0
  443. package/dist/internal/BetterAuth.js.map +1 -0
  444. package/dist/internal/Cache.d.ts +2 -0
  445. package/dist/internal/Cache.d.ts.map +1 -1
  446. package/dist/internal/Cache.js +2 -0
  447. package/dist/internal/Cache.js.map +1 -1
  448. package/dist/internal/EarnRates.d.ts +26 -3
  449. package/dist/internal/EarnRates.d.ts.map +1 -1
  450. package/dist/internal/EarnRates.js +84 -19
  451. package/dist/internal/EarnRates.js.map +1 -1
  452. package/dist/internal/EarnSharePrices.d.ts +120 -0
  453. package/dist/internal/EarnSharePrices.d.ts.map +1 -0
  454. package/dist/internal/EarnSharePrices.js +179 -0
  455. package/dist/internal/EarnSharePrices.js.map +1 -0
  456. package/dist/internal/EarnVaults.d.ts +4 -0
  457. package/dist/internal/EarnVaults.d.ts.map +1 -1
  458. package/dist/internal/EarnVaults.js +27 -10
  459. package/dist/internal/EarnVaults.js.map +1 -1
  460. package/dist/internal/Email.d.ts +37 -0
  461. package/dist/internal/Email.d.ts.map +1 -0
  462. package/dist/internal/Email.js +16 -0
  463. package/dist/internal/Email.js.map +1 -0
  464. package/dist/internal/Log.d.ts +32 -28
  465. package/dist/internal/Log.d.ts.map +1 -1
  466. package/dist/internal/Log.js +18 -11
  467. package/dist/internal/Log.js.map +1 -1
  468. package/dist/internal/MetricSink.d.ts +3 -0
  469. package/dist/internal/MetricSink.d.ts.map +1 -1
  470. package/dist/internal/MetricSink.js +67 -8
  471. package/dist/internal/MetricSink.js.map +1 -1
  472. package/dist/internal/Mpp.d.ts.map +1 -1
  473. package/dist/internal/Mpp.js +20 -25
  474. package/dist/internal/Mpp.js.map +1 -1
  475. package/dist/internal/OpenApi.d.ts +26 -3
  476. package/dist/internal/OpenApi.d.ts.map +1 -1
  477. package/dist/internal/OpenApi.js +25 -10
  478. package/dist/internal/OpenApi.js.map +1 -1
  479. package/dist/internal/Provider.d.ts +1 -1
  480. package/dist/internal/Provider.d.ts.map +1 -1
  481. package/dist/internal/RateLimit.d.ts.map +1 -1
  482. package/dist/internal/RateLimit.js +13 -1
  483. package/dist/internal/RateLimit.js.map +1 -1
  484. package/dist/internal/Store.d.ts +16 -0
  485. package/dist/internal/Store.d.ts.map +1 -1
  486. package/dist/internal/Store.js +59 -8
  487. package/dist/internal/Store.js.map +1 -1
  488. package/dist/internal/Tidx.d.ts +9 -2
  489. package/dist/internal/Tidx.d.ts.map +1 -1
  490. package/dist/internal/Tidx.js +78 -11
  491. package/dist/internal/Tidx.js.map +1 -1
  492. package/dist/internal/Timing.d.ts +26 -0
  493. package/dist/internal/Timing.d.ts.map +1 -1
  494. package/dist/internal/Timing.js +63 -5
  495. package/dist/internal/Timing.js.map +1 -1
  496. package/dist/internal/VercelOidc.d.ts +94 -0
  497. package/dist/internal/VercelOidc.d.ts.map +1 -0
  498. package/dist/internal/VercelOidc.js +128 -0
  499. package/dist/internal/VercelOidc.js.map +1 -0
  500. package/dist/internal/VerifiedTokens.d.ts +2 -8
  501. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  502. package/dist/internal/VerifiedTokens.js +24 -24
  503. package/dist/internal/VerifiedTokens.js.map +1 -1
  504. package/dist/internal/Viem.d.ts +30 -2067
  505. package/dist/internal/Viem.d.ts.map +1 -1
  506. package/dist/internal/Viem.js +167 -17
  507. package/dist/internal/Viem.js.map +1 -1
  508. package/dist/internal/Webhooks.d.ts +12 -4
  509. package/dist/internal/Webhooks.d.ts.map +1 -1
  510. package/dist/internal/Webhooks.js +9 -3
  511. package/dist/internal/Webhooks.js.map +1 -1
  512. package/dist/internal/ZoneRpc.d.ts +7 -0
  513. package/dist/internal/ZoneRpc.d.ts.map +1 -0
  514. package/dist/internal/ZoneRpc.js +49 -0
  515. package/dist/internal/ZoneRpc.js.map +1 -0
  516. package/dist/internal/index.d.ts +3 -1
  517. package/dist/internal/index.d.ts.map +1 -1
  518. package/dist/internal/index.js +3 -1
  519. package/dist/internal/index.js.map +1 -1
  520. package/dist/internal/rewards/Audit.d.ts +88 -0
  521. package/dist/internal/rewards/Audit.d.ts.map +1 -0
  522. package/dist/internal/rewards/Audit.js +134 -0
  523. package/dist/internal/rewards/Audit.js.map +1 -0
  524. package/dist/internal/rewards/Campaigns.d.ts +572 -0
  525. package/dist/internal/rewards/Campaigns.d.ts.map +1 -0
  526. package/dist/internal/rewards/Campaigns.js +531 -0
  527. package/dist/internal/rewards/Campaigns.js.map +1 -0
  528. package/dist/internal/rewards/Credits.d.ts +76 -0
  529. package/dist/internal/rewards/Credits.d.ts.map +1 -0
  530. package/dist/internal/rewards/Credits.js +95 -0
  531. package/dist/internal/rewards/Credits.js.map +1 -0
  532. package/dist/internal/rewards/Events.d.ts +100 -0
  533. package/dist/internal/rewards/Events.d.ts.map +1 -0
  534. package/dist/internal/rewards/Events.js +340 -0
  535. package/dist/internal/rewards/Events.js.map +1 -0
  536. package/dist/internal/rewards/Projection.d.ts +237 -0
  537. package/dist/internal/rewards/Projection.d.ts.map +1 -0
  538. package/dist/internal/rewards/Projection.js +616 -0
  539. package/dist/internal/rewards/Projection.js.map +1 -0
  540. package/dist/internal/rewards/Rates.d.ts +44 -0
  541. package/dist/internal/rewards/Rates.d.ts.map +1 -0
  542. package/dist/internal/rewards/Rates.js +60 -0
  543. package/dist/internal/rewards/Rates.js.map +1 -0
  544. package/dist/internal/rewards/Read.d.ts +158 -0
  545. package/dist/internal/rewards/Read.d.ts.map +1 -0
  546. package/dist/internal/rewards/Read.js +292 -0
  547. package/dist/internal/rewards/Read.js.map +1 -0
  548. package/dist/internal/rewards/Runner.d.ts +164 -0
  549. package/dist/internal/rewards/Runner.d.ts.map +1 -0
  550. package/dist/internal/rewards/Runner.js +1778 -0
  551. package/dist/internal/rewards/Runner.js.map +1 -0
  552. package/dist/internal/rewards/Signer.d.ts +224 -0
  553. package/dist/internal/rewards/Signer.d.ts.map +1 -0
  554. package/dist/internal/rewards/Signer.js +135 -0
  555. package/dist/internal/rewards/Signer.js.map +1 -0
  556. package/dist/internal/rewards/index.d.ts +15 -0
  557. package/dist/internal/rewards/index.d.ts.map +1 -0
  558. package/dist/internal/rewards/index.js +15 -0
  559. package/dist/internal/rewards/index.js.map +1 -0
  560. package/dist/internal/{funding → routes}/Action.d.ts +12 -1
  561. package/dist/internal/routes/Action.d.ts.map +1 -0
  562. package/dist/internal/{funding → routes}/Action.js +17 -9
  563. package/dist/internal/routes/Action.js.map +1 -0
  564. package/dist/internal/{funding → routes}/Catalog.d.ts +20 -20
  565. package/dist/internal/routes/Catalog.d.ts.map +1 -0
  566. package/dist/internal/{funding → routes}/Catalog.js +29 -29
  567. package/dist/internal/routes/Catalog.js.map +1 -0
  568. package/dist/internal/{funding → routes}/Chain.d.ts +10 -10
  569. package/dist/internal/routes/Chain.d.ts.map +1 -0
  570. package/dist/internal/{funding → routes}/Chain.js +3 -3
  571. package/dist/internal/routes/Chain.js.map +1 -0
  572. package/dist/internal/{funding → routes}/Deposit.d.ts +45 -23
  573. package/dist/internal/routes/Deposit.d.ts.map +1 -0
  574. package/dist/internal/{funding → routes}/Deposit.js +60 -27
  575. package/dist/internal/routes/Deposit.js.map +1 -0
  576. package/dist/internal/{funding → routes}/DepositAddress.d.ts +56 -27
  577. package/dist/internal/routes/DepositAddress.d.ts.map +1 -0
  578. package/dist/internal/{funding → routes}/DepositAddress.js +95 -33
  579. package/dist/internal/routes/DepositAddress.js.map +1 -0
  580. package/dist/internal/{funding → routes}/DepositWebhook.d.ts +4 -4
  581. package/dist/internal/routes/DepositWebhook.d.ts.map +1 -0
  582. package/dist/internal/{funding → routes}/DepositWebhook.js +4 -4
  583. package/dist/internal/routes/DepositWebhook.js.map +1 -0
  584. package/dist/internal/routes/Economics.d.ts +25 -0
  585. package/dist/internal/routes/Economics.d.ts.map +1 -0
  586. package/dist/internal/routes/Economics.js +28 -0
  587. package/dist/internal/routes/Economics.js.map +1 -0
  588. package/dist/internal/{funding → routes}/Evidence.d.ts +3 -3
  589. package/dist/internal/routes/Evidence.d.ts.map +1 -0
  590. package/dist/internal/{funding → routes}/Evidence.js +7 -7
  591. package/dist/internal/routes/Evidence.js.map +1 -0
  592. package/dist/internal/routes/Observability.d.ts +154 -0
  593. package/dist/internal/routes/Observability.d.ts.map +1 -0
  594. package/dist/internal/routes/Observability.js +389 -0
  595. package/dist/internal/routes/Observability.js.map +1 -0
  596. package/dist/internal/{funding → routes}/Provider.d.ts +311 -105
  597. package/dist/internal/routes/Provider.d.ts.map +1 -0
  598. package/dist/internal/{funding → routes}/Provider.js +229 -98
  599. package/dist/internal/routes/Provider.js.map +1 -0
  600. package/dist/internal/{funding → routes}/Reconciliation.d.ts +11 -6
  601. package/dist/internal/routes/Reconciliation.d.ts.map +1 -0
  602. package/dist/internal/{funding → routes}/Reconciliation.js +408 -158
  603. package/dist/internal/routes/Reconciliation.js.map +1 -0
  604. package/dist/internal/routes/Route.d.ts +21 -0
  605. package/dist/internal/routes/Route.d.ts.map +1 -0
  606. package/dist/internal/{funding → routes}/Route.js +1 -1
  607. package/dist/internal/routes/Route.js.map +1 -0
  608. package/dist/internal/{funding → routes}/SourceObservation.d.ts +6 -6
  609. package/dist/internal/routes/SourceObservation.d.ts.map +1 -0
  610. package/dist/internal/{funding → routes}/SourceObservation.js +8 -8
  611. package/dist/internal/routes/SourceObservation.js.map +1 -0
  612. package/dist/internal/{funding → routes}/Subsidy.d.ts +48 -3
  613. package/dist/internal/routes/Subsidy.d.ts.map +1 -0
  614. package/dist/internal/{funding → routes}/Subsidy.js +43 -3
  615. package/dist/internal/routes/Subsidy.js.map +1 -0
  616. package/dist/internal/{funding → routes}/Token.d.ts +4 -4
  617. package/dist/internal/routes/Token.d.ts.map +1 -0
  618. package/dist/internal/{funding → routes}/Token.js +3 -3
  619. package/dist/internal/routes/Token.js.map +1 -0
  620. package/dist/internal/{funding → routes}/Transfer.d.ts +241 -46
  621. package/dist/internal/routes/Transfer.d.ts.map +1 -0
  622. package/dist/internal/routes/Transfer.js +728 -0
  623. package/dist/internal/routes/Transfer.js.map +1 -0
  624. package/dist/internal/{funding → routes}/TransferReconciliation.d.ts +13 -10
  625. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -0
  626. package/dist/internal/routes/TransferReconciliation.js +422 -0
  627. package/dist/internal/routes/TransferReconciliation.js.map +1 -0
  628. package/dist/internal/routes/TransferSubsidy.d.ts +201 -0
  629. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -0
  630. package/dist/internal/routes/TransferSubsidy.js +256 -0
  631. package/dist/internal/routes/TransferSubsidy.js.map +1 -0
  632. package/dist/internal/{funding → routes}/TransferWebhook.d.ts +5 -5
  633. package/dist/internal/routes/TransferWebhook.d.ts.map +1 -0
  634. package/dist/internal/{funding → routes}/TransferWebhook.js +3 -3
  635. package/dist/internal/routes/TransferWebhook.js.map +1 -0
  636. package/dist/internal/{funding → routes}/index.d.ts +2 -0
  637. package/dist/internal/routes/index.d.ts.map +1 -0
  638. package/dist/internal/{funding → routes}/index.js +2 -0
  639. package/dist/internal/routes/index.js.map +1 -0
  640. package/dist/internal/{funding → routes}/providers/across.d.ts +4 -4
  641. package/dist/internal/routes/providers/across.d.ts.map +1 -0
  642. package/dist/internal/{funding → routes}/providers/across.js +13 -13
  643. package/dist/internal/routes/providers/across.js.map +1 -0
  644. package/dist/internal/{funding → routes}/providers/relay.d.ts +21 -12
  645. package/dist/internal/routes/providers/relay.d.ts.map +1 -0
  646. package/dist/internal/{funding → routes}/providers/relay.js +194 -110
  647. package/dist/internal/routes/providers/relay.js.map +1 -0
  648. package/dist/internal/{funding → routes}/providers/rhino.d.ts +4 -4
  649. package/dist/internal/routes/providers/rhino.d.ts.map +1 -0
  650. package/dist/internal/{funding → routes}/providers/rhino.js +10 -10
  651. package/dist/internal/routes/providers/rhino.js.map +1 -0
  652. package/dist/internal/{funding → routes}/providers/squid.d.ts +4 -4
  653. package/dist/internal/routes/providers/squid.d.ts.map +1 -0
  654. package/dist/internal/{funding → routes}/providers/squid.js +14 -14
  655. package/dist/internal/routes/providers/squid.js.map +1 -0
  656. package/dist/internal/{funding → routes}/providers/stargate.d.ts +46 -18
  657. package/dist/internal/routes/providers/stargate.d.ts.map +1 -0
  658. package/dist/internal/routes/providers/stargate.js +898 -0
  659. package/dist/internal/routes/providers/stargate.js.map +1 -0
  660. package/dist/internal/{funding → routes}/providers/symbiosis.d.ts +4 -4
  661. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -0
  662. package/dist/internal/{funding → routes}/providers/symbiosis.js +30 -20
  663. package/dist/internal/routes/providers/symbiosis.js.map +1 -0
  664. package/dist/internal/webhookDestinations/slack.js +12 -12
  665. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  666. package/dist/providers/index.d.ts +12 -12
  667. package/dist/providers/index.d.ts.map +1 -1
  668. package/dist/providers/index.js +12 -12
  669. package/dist/providers/index.js.map +1 -1
  670. package/dist/server.d.ts +19 -0
  671. package/dist/server.d.ts.map +1 -0
  672. package/dist/server.js +19 -0
  673. package/dist/server.js.map +1 -0
  674. package/package.json +15 -4
  675. package/src/ApiKey.ts +1 -1
  676. package/src/ApiKeys.test.ts +1033 -3
  677. package/src/ApiKeys.ts +489 -48
  678. package/src/App.test-d.ts +1 -1
  679. package/src/App.test.ts +216 -25
  680. package/src/App.ts +334 -31
  681. package/src/Assets.test.ts +2 -2
  682. package/src/Assets.ts +3 -1
  683. package/src/Auth.test-d.ts +1 -1
  684. package/src/Client.test-d.ts +539 -110
  685. package/src/Handler.ts +0 -1
  686. package/src/OpenApi.contract.test.ts +195 -0
  687. package/src/Scope.ts +17 -5
  688. package/src/Webhooks.ts +1 -1
  689. package/src/admin/App.test.ts +30 -2
  690. package/src/admin/App.ts +42 -6
  691. package/src/admin/apps/api-keys.test.ts +267 -5
  692. package/src/admin/apps/api-keys.ts +100 -50
  693. package/src/admin/apps/earn-vaults.test.ts +158 -0
  694. package/src/admin/apps/earn-vaults.ts +679 -6
  695. package/src/admin/apps/organizations.test.ts +306 -17
  696. package/src/admin/apps/organizations.ts +299 -24
  697. package/src/admin/apps/routes-support.test.ts +200 -0
  698. package/src/admin/apps/routes-support.ts +201 -0
  699. package/src/admin/apps/routes.test.ts +450 -0
  700. package/src/admin/apps/routes.ts +896 -0
  701. package/src/admin/apps/scopes.test.ts +15 -5
  702. package/src/admin/apps/subsidies.test.ts +306 -0
  703. package/src/admin/apps/subsidies.ts +457 -0
  704. package/src/admin/apps/verified-tokens.test.ts +8 -3
  705. package/src/admin/apps/verified-tokens.ts +3 -3
  706. package/src/admin/ui/plugin.ts +1 -2
  707. package/src/admin/ui/src/components/RewardCampaignForm.tsx +1009 -0
  708. package/src/admin/ui/src/lib/config.ts +11 -2
  709. package/src/admin/ui/src/lib/earn-vaults.ts +2 -2
  710. package/src/admin/ui/src/lib/organizations.test.ts +83 -50
  711. package/src/admin/ui/src/lib/organizations.ts +106 -25
  712. package/src/admin/ui/src/lib/query-client.ts +1 -1
  713. package/src/admin/ui/src/lib/reward-campaigns.ts +136 -0
  714. package/src/admin/ui/src/lib/routes.test.ts +88 -0
  715. package/src/admin/ui/src/lib/routes.ts +304 -0
  716. package/src/admin/ui/src/lib/subsidies.ts +75 -0
  717. package/src/admin/ui/src/routeTree.gen.ts +63 -0
  718. package/src/admin/ui/src/routes/__root.tsx +12 -1
  719. package/src/admin/ui/src/routes/api-keys.tsx +196 -84
  720. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +105 -70
  721. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +239 -23
  722. package/src/admin/ui/src/routes/routes.tsx +1615 -0
  723. package/src/admin/ui/src/routes/routes_.support.tsx +248 -0
  724. package/src/admin/ui/src/routes/subsidies.tsx +799 -0
  725. package/src/admin/ui.generated.ts +144 -69
  726. package/src/analytics/Analytics.test.ts +108 -18
  727. package/src/analytics/Analytics.ts +38 -6
  728. package/src/analytics/tables/requestEvents.test.ts +100 -0
  729. package/src/analytics/tables/requestEvents.ts +10 -1
  730. package/src/analytics/tables/routesLifecycleIntervals.ts +140 -0
  731. package/src/apps/Zones.test.ts +15 -0
  732. package/src/apps/Zones.ts +52 -5
  733. package/src/apps/composition.test.ts +68 -60
  734. package/src/apps/data/App.test.ts +154 -2
  735. package/src/apps/data/App.ts +88 -28
  736. package/src/apps/data/routes/activities.test.ts +419 -7
  737. package/src/apps/data/routes/activities.ts +683 -216
  738. package/src/apps/data/routes/balances.test.ts +2 -2
  739. package/src/apps/data/routes/blocks.test.ts +46 -1
  740. package/src/apps/data/routes/coingecko.test.ts +419 -1
  741. package/src/apps/data/routes/coingecko.ts +309 -253
  742. package/src/apps/data/routes/earn.discovery.test.ts +274 -0
  743. package/src/apps/data/routes/earn.test.ts +1294 -17
  744. package/src/apps/data/routes/earn.ts +1838 -321
  745. package/src/apps/data/routes/exchanges.test.ts +12 -15
  746. package/src/apps/data/routes/fee-amm.test.ts +224 -0
  747. package/src/apps/data/routes/fee-amm.ts +191 -160
  748. package/src/apps/data/routes/indexer.test.ts +389 -0
  749. package/src/apps/data/routes/indexer.ts +165 -69
  750. package/src/apps/data/routes/receipts.test.ts +1 -1
  751. package/src/apps/data/routes/rpc.test.ts +352 -8
  752. package/src/apps/data/routes/rpc.ts +407 -219
  753. package/src/apps/data/routes/rpc.zone.test.ts +340 -0
  754. package/src/apps/data/routes/tokenlist.test.ts +285 -0
  755. package/src/apps/data/routes/tokenlist.ts +173 -88
  756. package/src/apps/data/routes/tokens.test.ts +93 -3
  757. package/src/apps/data/routes/tokens.ts +39 -23
  758. package/src/apps/data/routes/transactions.test.ts +1 -1
  759. package/src/apps/data/routes/transfers.test.ts +56 -24
  760. package/src/apps/data/routes/transfers.ts +19 -8
  761. package/src/apps/data/routes/valuation.test.ts +1 -1
  762. package/src/apps/data/routes/verified-tokens.test.ts +345 -0
  763. package/src/apps/data/routes/verified-tokens.ts +99 -29
  764. package/src/apps/data/routes/webhooks.test.ts +645 -83
  765. package/src/apps/data/routes/webhooks.ts +1089 -857
  766. package/src/apps/data/routes/zones.test.ts +148 -71
  767. package/src/apps/data/routes/zones.ts +71 -55
  768. package/src/apps/docs/reference.ts +2 -2
  769. package/src/apps/index.ts +1 -1
  770. package/src/apps/management/App.ts +9 -51
  771. package/src/apps/management/Billing.test.ts +375 -14
  772. package/src/apps/management/Billing.ts +265 -29
  773. package/src/apps/management/routes/api-keys.test.ts +269 -7
  774. package/src/apps/management/routes/api-keys.ts +61 -20
  775. package/src/apps/management/routes/billing.test.ts +477 -15
  776. package/src/apps/management/routes/billing.ts +377 -50
  777. package/src/apps/management/routes/faucet.test.ts +1 -1
  778. package/src/apps/management/routes/faucet.ts +1 -1
  779. package/src/apps/management/routes/invitations.test.ts +270 -3
  780. package/src/apps/management/routes/invitations.ts +185 -15
  781. package/src/apps/management/routes/invoicePreview.test.ts +549 -0
  782. package/src/apps/management/routes/me.test.ts +246 -5
  783. package/src/apps/management/routes/me.ts +7 -2
  784. package/src/apps/management/routes/members.test.ts +108 -0
  785. package/src/apps/management/routes/orgs.test.ts +191 -3
  786. package/src/apps/management/routes/orgs.ts +58 -11
  787. package/src/apps/management/routes/projects.test.ts +33 -3
  788. package/src/apps/management/routes/projects.ts +6 -1
  789. package/src/apps/management/routes/scopes.test.ts +30 -2
  790. package/src/apps/management/routes/scopes.ts +4 -1
  791. package/src/apps/management/routes/usage.test.ts +32 -0
  792. package/src/apps/management/routes/usage.ts +22 -4
  793. package/src/apps/management/routes/webhooks.test.ts +49 -26
  794. package/src/apps/management/routes/webhooks.ts +78 -22
  795. package/src/apps/mcp.test.ts +6 -6
  796. package/src/apps/mcp.ts +7 -7
  797. package/src/apps/mpp/App.ts +37 -7
  798. package/src/apps/mpp/Mpp.test.ts +49 -8
  799. package/src/apps/mpp/Mpp.zone.test.ts +219 -0
  800. package/src/apps/mpp/internal/Adapter.ts +34 -0
  801. package/src/apps/mpp/internal/Policy.test.ts +86 -31
  802. package/src/apps/mpp/internal/Policy.ts +49 -7
  803. package/src/apps/mpp/internal/Sponsorship.test.ts +207 -0
  804. package/src/apps/mpp/internal/Sponsorship.ts +9 -3
  805. package/src/apps/relay/App.test.ts +839 -64
  806. package/src/apps/relay/App.ts +148 -81
  807. package/src/apps/relay/App.zone-billing.test.ts +257 -0
  808. package/src/apps/relay/Sponsorships.test.ts +67 -4
  809. package/src/apps/relay/Sponsorships.ts +233 -32
  810. package/src/apps/relay/Sponsorships.zone.test.ts +102 -0
  811. package/src/apps/{funding → routes}/Access.ts +6 -6
  812. package/src/apps/routes/App.test.ts +165 -0
  813. package/src/apps/routes/App.ts +96 -0
  814. package/src/apps/{funding → routes}/Inventory.ts +2 -2
  815. package/src/apps/routes/index.ts +1 -0
  816. package/src/apps/{funding → routes}/routes/chains.test.ts +66 -66
  817. package/src/apps/{funding → routes}/routes/chains.ts +23 -23
  818. package/src/apps/{funding → routes}/routes/deposit-addresses.test.ts +1358 -458
  819. package/src/apps/{funding → routes}/routes/deposit-addresses.ts +566 -246
  820. package/src/apps/{funding → routes}/routes/providers.test.ts +27 -33
  821. package/src/apps/{funding → routes}/routes/providers.ts +23 -23
  822. package/src/apps/{funding → routes}/routes/quotes.test.ts +298 -41
  823. package/src/apps/{funding → routes}/routes/quotes.ts +57 -40
  824. package/src/apps/{funding → routes}/routes/transfers.test.ts +1100 -353
  825. package/src/apps/routes/routes/transfers.ts +1332 -0
  826. package/src/cli/Cli.test.ts +1 -1
  827. package/src/cli/commands/admin.test.ts +748 -1
  828. package/src/cli/commands/admin.ts +278 -0
  829. package/src/cloudflare.ts +52 -47
  830. package/src/db/Db.test.ts +245 -2
  831. package/src/db/Db.ts +1476 -34
  832. package/src/db/Schema.ts +729 -228
  833. package/src/db/tables/apiKeyAdmissionBootstraps.ts +4 -0
  834. package/src/db/tables/apiKeyAdmissions.ts +218 -0
  835. package/src/db/tables/apiKeyOwnerAdmissions.ts +4 -0
  836. package/src/db/tables/apiKeyOwnerTombstones.ts +81 -0
  837. package/src/db/tables/apiKeyRevocations.test.ts +74 -0
  838. package/src/db/tables/apiKeyRevocations.ts +121 -0
  839. package/src/db/tables/authAccounts.ts +105 -0
  840. package/src/db/tables/authSessions.ts +13 -0
  841. package/src/db/tables/authVerifications.ts +13 -0
  842. package/src/db/tables/invitations.ts +142 -45
  843. package/src/db/tables/memberships.ts +79 -3
  844. package/src/db/tables/organizations.test.ts +690 -13
  845. package/src/db/tables/organizations.ts +139 -55
  846. package/src/db/tables/projects.test.ts +16 -0
  847. package/src/db/tables/projects.ts +13 -3
  848. package/src/db/tables/requestUsage.ts +4 -1
  849. package/src/db/tables/rewardAccounts.ts +178 -0
  850. package/src/db/tables/rewardCampaignDistributors.ts +68 -0
  851. package/src/db/tables/rewardCampaigns.test.ts +1388 -0
  852. package/src/db/tables/rewardCampaigns.ts +647 -0
  853. package/src/db/tables/rewardCredits.ts +110 -0
  854. package/src/db/tables/rewardEligibilityAssociations.test.ts +271 -0
  855. package/src/db/tables/rewardEligibilityAssociations.ts +184 -0
  856. package/src/db/tables/rewardRuns.ts +514 -0
  857. package/src/db/tables/rewardTransactionAttempts.ts +272 -0
  858. package/src/db/tables/routesCatalog.test.ts +185 -0
  859. package/src/db/tables/routesCatalog.ts +163 -0
  860. package/src/db/tables/routesDepositAddresses.test.ts +1048 -0
  861. package/src/db/tables/routesDepositAddresses.ts +1008 -0
  862. package/src/db/tables/{fundingDepositRequestObservations.test.ts → routesDepositRequestObservations.test.ts} +13 -14
  863. package/src/db/tables/{fundingDepositRequestObservations.ts → routesDepositRequestObservations.ts} +10 -10
  864. package/src/db/tables/{fundingDeposits.test.ts → routesDeposits.test.ts} +316 -46
  865. package/src/db/tables/routesDeposits.ts +1062 -0
  866. package/src/db/tables/routesIdempotency.test.ts +796 -0
  867. package/src/db/tables/routesIdempotency.ts +496 -0
  868. package/src/db/tables/routesSubsidies.test.ts +120 -0
  869. package/src/db/tables/routesSubsidies.ts +71 -0
  870. package/src/db/tables/{fundingTransferEvents.ts → routesTransferEvents.ts} +4 -4
  871. package/src/db/tables/routesTransferSubsidies.ts +38 -0
  872. package/src/db/tables/routesTransferSubsidyNonces.ts +124 -0
  873. package/src/db/tables/routesTransferTransactions.test.ts +195 -0
  874. package/src/db/tables/{fundingTransferTransactions.ts → routesTransferTransactions.ts} +63 -18
  875. package/src/db/tables/routesTransfers.test.ts +338 -0
  876. package/src/db/tables/routesTransfers.ts +662 -0
  877. package/src/db/tables/sponsoredTransactions.test.ts +269 -45
  878. package/src/db/tables/sponsoredTransactions.ts +225 -65
  879. package/src/db/tables/sponsorshipAttributions.test.ts +160 -0
  880. package/src/db/tables/sponsorshipAttributions.ts +168 -0
  881. package/src/db/tables/sponsorshipReconciliationCursors.test.ts +115 -0
  882. package/src/db/tables/sponsorshipReconciliationCursors.ts +67 -0
  883. package/src/db/tables/stripeCustomers.test.ts +85 -0
  884. package/src/db/tables/stripeCustomers.ts +24 -0
  885. package/src/db/tables/users.test.ts +129 -0
  886. package/src/db/tables/users.ts +49 -3
  887. package/src/db/tables/webhookQueueEvents.ts +8 -1
  888. package/src/db/tables/webhookSubscriptions.ts +95 -20
  889. package/src/handlers/internal/executionError.ts +3 -4
  890. package/src/handlers/internal/multisig.ts +13 -816
  891. package/src/handlers/internal/sponsorship.ts +26 -10
  892. package/src/handlers/relay.test-d.ts +9 -1
  893. package/src/handlers/relay.test.ts +823 -3
  894. package/src/handlers/relay.ts +127 -107
  895. package/src/index.test-d.ts +7 -0
  896. package/src/index.ts +0 -17
  897. package/src/internal/AssetResponse.ts +26 -0
  898. package/src/internal/Auth.test.ts +1564 -9
  899. package/src/internal/Auth.ts +833 -239
  900. package/src/internal/BetterAuth.test.ts +242 -0
  901. package/src/internal/BetterAuth.ts +349 -0
  902. package/src/internal/Cache.ts +2 -0
  903. package/src/internal/EarnRates.test.ts +17 -0
  904. package/src/internal/EarnRates.ts +124 -31
  905. package/src/internal/EarnSharePrices.test.ts +182 -0
  906. package/src/internal/EarnSharePrices.ts +313 -0
  907. package/src/internal/EarnVaults.test.ts +21 -0
  908. package/src/internal/EarnVaults.ts +33 -11
  909. package/src/internal/Email.ts +54 -0
  910. package/src/internal/Idempotency.test.ts +2 -2
  911. package/src/internal/Log.test-d.ts +8 -7
  912. package/src/internal/Log.test.ts +114 -16
  913. package/src/internal/Log.ts +53 -40
  914. package/src/internal/MetricSink.test.ts +313 -26
  915. package/src/internal/MetricSink.ts +73 -8
  916. package/src/internal/Mpp.test.ts +31 -0
  917. package/src/internal/Mpp.ts +21 -24
  918. package/src/internal/OpenApi.ts +45 -12
  919. package/src/internal/Provider.test.ts +1 -1
  920. package/src/internal/Provider.ts +1 -1
  921. package/src/internal/RateLimit.test.ts +21 -3
  922. package/src/internal/RateLimit.ts +12 -1
  923. package/src/internal/Store.test-d.ts +1 -1
  924. package/src/internal/Store.test.ts +151 -8
  925. package/src/internal/Store.ts +76 -9
  926. package/src/internal/Tidx.test.ts +59 -8
  927. package/src/internal/Tidx.ts +86 -14
  928. package/src/internal/Timing.test.ts +77 -0
  929. package/src/internal/Timing.ts +83 -6
  930. package/src/internal/VercelOidc.test.ts +188 -0
  931. package/src/internal/VercelOidc.ts +193 -0
  932. package/src/internal/VerifiedTokens.test.ts +60 -6
  933. package/src/internal/VerifiedTokens.ts +21 -24
  934. package/src/internal/Viem.batch.test.ts +80 -0
  935. package/src/internal/Viem.test.ts +201 -2
  936. package/src/internal/Viem.ts +221 -25
  937. package/src/internal/Webhooks.test.ts +85 -6
  938. package/src/internal/Webhooks.ts +22 -4
  939. package/src/internal/ZoneRpc.ts +50 -0
  940. package/src/internal/exchange/Provider.test.ts +2 -2
  941. package/src/internal/index.test.ts +3 -1
  942. package/src/internal/index.ts +3 -1
  943. package/src/internal/rewards/Audit.ts +231 -0
  944. package/src/internal/rewards/Campaigns.test.ts +1234 -0
  945. package/src/internal/rewards/Campaigns.ts +1205 -0
  946. package/src/internal/rewards/Credits.ts +165 -0
  947. package/src/internal/rewards/Events.local.test.ts +113 -0
  948. package/src/internal/rewards/Events.test.ts +152 -0
  949. package/src/internal/rewards/Events.ts +468 -0
  950. package/src/internal/rewards/Projection.test.ts +681 -0
  951. package/src/internal/rewards/Projection.ts +987 -0
  952. package/src/internal/rewards/Rates.test.ts +171 -0
  953. package/src/internal/rewards/Rates.ts +110 -0
  954. package/src/internal/rewards/Read.test.ts +501 -0
  955. package/src/internal/rewards/Read.ts +476 -0
  956. package/src/internal/rewards/Runner.checkpoint.test.ts +80 -0
  957. package/src/internal/rewards/Runner.states.test.ts +188 -0
  958. package/src/internal/rewards/Runner.test.ts +90 -0
  959. package/src/internal/rewards/Runner.ts +2229 -0
  960. package/src/internal/rewards/Signer.test.ts +79 -0
  961. package/src/internal/rewards/Signer.ts +180 -0
  962. package/src/internal/rewards/index.ts +14 -0
  963. package/src/internal/{funding → routes}/Action.test.ts +63 -14
  964. package/src/internal/{funding → routes}/Action.ts +35 -8
  965. package/src/internal/{funding → routes}/Catalog.test.ts +3 -3
  966. package/src/internal/{funding → routes}/Catalog.ts +39 -39
  967. package/src/internal/{funding → routes}/Chain.test.ts +1 -1
  968. package/src/internal/{funding → routes}/Chain.ts +11 -11
  969. package/src/internal/{funding → routes}/Deposit.test.ts +1 -1
  970. package/src/internal/{funding → routes}/Deposit.ts +93 -45
  971. package/src/internal/{funding → routes}/DepositAddress.test.ts +11 -3
  972. package/src/internal/{funding → routes}/DepositAddress.ts +132 -53
  973. package/src/internal/{funding → routes}/DepositWebhook.test.ts +61 -18
  974. package/src/internal/{funding → routes}/DepositWebhook.ts +9 -9
  975. package/src/internal/routes/Economics.test.ts +42 -0
  976. package/src/internal/routes/Economics.ts +47 -0
  977. package/src/internal/{funding → routes}/Evidence.test.ts +6 -6
  978. package/src/internal/{funding → routes}/Evidence.ts +9 -9
  979. package/src/internal/routes/Observability.test.ts +636 -0
  980. package/src/internal/routes/Observability.ts +668 -0
  981. package/src/internal/{funding → routes}/Provider.test.ts +489 -153
  982. package/src/internal/{funding → routes}/Provider.ts +489 -186
  983. package/src/internal/{funding → routes}/Reconciliation.local.test.ts +84 -12
  984. package/src/internal/{funding → routes}/Reconciliation.test.ts +1213 -279
  985. package/src/internal/{funding → routes}/Reconciliation.ts +501 -203
  986. package/src/internal/routes/Reconciliation.unattributed.test.ts +250 -0
  987. package/src/internal/{funding → routes}/Route.ts +7 -7
  988. package/src/internal/{funding → routes}/SourceObservation.test.ts +13 -14
  989. package/src/internal/{funding → routes}/SourceObservation.ts +13 -13
  990. package/src/internal/{funding → routes}/Subsidy.local.test.ts +7 -7
  991. package/src/internal/routes/Subsidy.test.ts +169 -0
  992. package/src/internal/{funding → routes}/Subsidy.ts +86 -6
  993. package/src/internal/{funding → routes}/Token.test.ts +1 -1
  994. package/src/internal/{funding → routes}/Token.ts +5 -5
  995. package/src/internal/routes/Transfer.test.ts +1199 -0
  996. package/src/internal/routes/Transfer.ts +1206 -0
  997. package/src/internal/routes/TransferReconciliation.test.ts +731 -0
  998. package/src/internal/routes/TransferReconciliation.ts +527 -0
  999. package/src/internal/routes/TransferSubsidy.test.ts +172 -0
  1000. package/src/internal/routes/TransferSubsidy.ts +447 -0
  1001. package/src/internal/{funding → routes}/TransferWebhook.test.ts +13 -13
  1002. package/src/internal/{funding → routes}/TransferWebhook.ts +7 -7
  1003. package/src/internal/{funding → routes}/index.test.ts +5 -3
  1004. package/src/internal/{funding → routes}/index.ts +2 -0
  1005. package/src/internal/{funding → routes}/providers/across.ts +16 -16
  1006. package/src/internal/{funding → routes}/providers/index.test.ts +157 -44
  1007. package/src/internal/{funding → routes}/providers/relay.test.ts +165 -32
  1008. package/src/internal/{funding → routes}/providers/relay.ts +228 -121
  1009. package/src/internal/{funding → routes}/providers/rhino.ts +16 -16
  1010. package/src/internal/{funding → routes}/providers/squid.ts +17 -17
  1011. package/src/internal/routes/providers/stargate.test.ts +728 -0
  1012. package/src/internal/routes/providers/stargate.ts +1276 -0
  1013. package/src/internal/{funding → routes}/providers/symbiosis.ts +64 -24
  1014. package/src/internal/webhookDestinations/slack.ts +10 -10
  1015. package/src/providers/index.ts +13 -13
  1016. package/src/server.ts +18 -0
  1017. package/dist/apps/funding/Access.d.ts.map +0 -1
  1018. package/dist/apps/funding/Access.js.map +0 -1
  1019. package/dist/apps/funding/App.js.map +0 -1
  1020. package/dist/apps/funding/Inventory.d.ts.map +0 -1
  1021. package/dist/apps/funding/Inventory.js.map +0 -1
  1022. package/dist/apps/funding/ProviderAttempts.d.ts +0 -5
  1023. package/dist/apps/funding/ProviderAttempts.d.ts.map +0 -1
  1024. package/dist/apps/funding/ProviderAttempts.js +0 -24
  1025. package/dist/apps/funding/ProviderAttempts.js.map +0 -1
  1026. package/dist/apps/funding/index.d.ts +0 -2
  1027. package/dist/apps/funding/index.d.ts.map +0 -1
  1028. package/dist/apps/funding/index.js +0 -2
  1029. package/dist/apps/funding/index.js.map +0 -1
  1030. package/dist/apps/funding/routes/chains.d.ts.map +0 -1
  1031. package/dist/apps/funding/routes/chains.js.map +0 -1
  1032. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +0 -1
  1033. package/dist/apps/funding/routes/deposit-addresses.js.map +0 -1
  1034. package/dist/apps/funding/routes/providers.d.ts.map +0 -1
  1035. package/dist/apps/funding/routes/providers.js +0 -57
  1036. package/dist/apps/funding/routes/providers.js.map +0 -1
  1037. package/dist/apps/funding/routes/quotes.d.ts.map +0 -1
  1038. package/dist/apps/funding/routes/quotes.js.map +0 -1
  1039. package/dist/apps/funding/routes/transfers.d.ts.map +0 -1
  1040. package/dist/apps/funding/routes/transfers.js +0 -828
  1041. package/dist/apps/funding/routes/transfers.js.map +0 -1
  1042. package/dist/db/tables/fundingCatalog.d.ts +0 -58
  1043. package/dist/db/tables/fundingCatalog.d.ts.map +0 -1
  1044. package/dist/db/tables/fundingCatalog.js.map +0 -1
  1045. package/dist/db/tables/fundingDepositAddresses.d.ts +0 -192
  1046. package/dist/db/tables/fundingDepositAddresses.d.ts.map +0 -1
  1047. package/dist/db/tables/fundingDepositAddresses.js +0 -235
  1048. package/dist/db/tables/fundingDepositAddresses.js.map +0 -1
  1049. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +0 -1
  1050. package/dist/db/tables/fundingDepositRequestObservations.js.map +0 -1
  1051. package/dist/db/tables/fundingDeposits.d.ts.map +0 -1
  1052. package/dist/db/tables/fundingDeposits.js +0 -295
  1053. package/dist/db/tables/fundingDeposits.js.map +0 -1
  1054. package/dist/db/tables/fundingIdempotency.d.ts +0 -91
  1055. package/dist/db/tables/fundingIdempotency.d.ts.map +0 -1
  1056. package/dist/db/tables/fundingIdempotency.js +0 -103
  1057. package/dist/db/tables/fundingIdempotency.js.map +0 -1
  1058. package/dist/db/tables/fundingTransferEvents.d.ts.map +0 -1
  1059. package/dist/db/tables/fundingTransferEvents.js.map +0 -1
  1060. package/dist/db/tables/fundingTransferTransactions.d.ts +0 -53
  1061. package/dist/db/tables/fundingTransferTransactions.d.ts.map +0 -1
  1062. package/dist/db/tables/fundingTransferTransactions.js.map +0 -1
  1063. package/dist/db/tables/fundingTransfers.d.ts +0 -99
  1064. package/dist/db/tables/fundingTransfers.d.ts.map +0 -1
  1065. package/dist/db/tables/fundingTransfers.js +0 -110
  1066. package/dist/db/tables/fundingTransfers.js.map +0 -1
  1067. package/dist/internal/funding/Action.d.ts.map +0 -1
  1068. package/dist/internal/funding/Action.js.map +0 -1
  1069. package/dist/internal/funding/Catalog.d.ts.map +0 -1
  1070. package/dist/internal/funding/Catalog.js.map +0 -1
  1071. package/dist/internal/funding/Chain.d.ts.map +0 -1
  1072. package/dist/internal/funding/Chain.js.map +0 -1
  1073. package/dist/internal/funding/Deposit.d.ts.map +0 -1
  1074. package/dist/internal/funding/Deposit.js.map +0 -1
  1075. package/dist/internal/funding/DepositAddress.d.ts.map +0 -1
  1076. package/dist/internal/funding/DepositAddress.js.map +0 -1
  1077. package/dist/internal/funding/DepositWebhook.d.ts.map +0 -1
  1078. package/dist/internal/funding/DepositWebhook.js.map +0 -1
  1079. package/dist/internal/funding/Evidence.d.ts.map +0 -1
  1080. package/dist/internal/funding/Evidence.js.map +0 -1
  1081. package/dist/internal/funding/Provider.d.ts.map +0 -1
  1082. package/dist/internal/funding/Provider.js.map +0 -1
  1083. package/dist/internal/funding/Reconciliation.d.ts.map +0 -1
  1084. package/dist/internal/funding/Reconciliation.js.map +0 -1
  1085. package/dist/internal/funding/Route.d.ts +0 -21
  1086. package/dist/internal/funding/Route.d.ts.map +0 -1
  1087. package/dist/internal/funding/Route.js.map +0 -1
  1088. package/dist/internal/funding/SourceObservation.d.ts.map +0 -1
  1089. package/dist/internal/funding/SourceObservation.js.map +0 -1
  1090. package/dist/internal/funding/Subsidy.d.ts.map +0 -1
  1091. package/dist/internal/funding/Subsidy.js.map +0 -1
  1092. package/dist/internal/funding/Token.d.ts.map +0 -1
  1093. package/dist/internal/funding/Token.js.map +0 -1
  1094. package/dist/internal/funding/Transfer.d.ts.map +0 -1
  1095. package/dist/internal/funding/Transfer.js +0 -462
  1096. package/dist/internal/funding/Transfer.js.map +0 -1
  1097. package/dist/internal/funding/TransferReconciliation.d.ts.map +0 -1
  1098. package/dist/internal/funding/TransferReconciliation.js +0 -192
  1099. package/dist/internal/funding/TransferReconciliation.js.map +0 -1
  1100. package/dist/internal/funding/TransferWebhook.d.ts.map +0 -1
  1101. package/dist/internal/funding/TransferWebhook.js.map +0 -1
  1102. package/dist/internal/funding/index.d.ts.map +0 -1
  1103. package/dist/internal/funding/index.js.map +0 -1
  1104. package/dist/internal/funding/providers/across.d.ts.map +0 -1
  1105. package/dist/internal/funding/providers/across.js.map +0 -1
  1106. package/dist/internal/funding/providers/relay.d.ts.map +0 -1
  1107. package/dist/internal/funding/providers/relay.js.map +0 -1
  1108. package/dist/internal/funding/providers/rhino.d.ts.map +0 -1
  1109. package/dist/internal/funding/providers/rhino.js.map +0 -1
  1110. package/dist/internal/funding/providers/squid.d.ts.map +0 -1
  1111. package/dist/internal/funding/providers/squid.js.map +0 -1
  1112. package/dist/internal/funding/providers/stargate.d.ts.map +0 -1
  1113. package/dist/internal/funding/providers/stargate.js +0 -579
  1114. package/dist/internal/funding/providers/stargate.js.map +0 -1
  1115. package/dist/internal/funding/providers/symbiosis.d.ts.map +0 -1
  1116. package/dist/internal/funding/providers/symbiosis.js.map +0 -1
  1117. package/src/apps/funding/App.test.ts +0 -78
  1118. package/src/apps/funding/App.ts +0 -88
  1119. package/src/apps/funding/ProviderAttempts.ts +0 -26
  1120. package/src/apps/funding/index.ts +0 -1
  1121. package/src/apps/funding/routes/transfers.ts +0 -987
  1122. package/src/db/tables/fundingCatalog.test.ts +0 -122
  1123. package/src/db/tables/fundingCatalog.ts +0 -163
  1124. package/src/db/tables/fundingDepositAddresses.test.ts +0 -608
  1125. package/src/db/tables/fundingDepositAddresses.ts +0 -443
  1126. package/src/db/tables/fundingDeposits.ts +0 -572
  1127. package/src/db/tables/fundingIdempotency.test.ts +0 -182
  1128. package/src/db/tables/fundingIdempotency.ts +0 -180
  1129. package/src/db/tables/fundingTransferTransactions.test.ts +0 -112
  1130. package/src/db/tables/fundingTransfers.test.ts +0 -115
  1131. package/src/db/tables/fundingTransfers.ts +0 -189
  1132. package/src/handlers/internal/multisig.test.ts +0 -818
  1133. package/src/internal/funding/Subsidy.test.ts +0 -75
  1134. package/src/internal/funding/Transfer.test.ts +0 -524
  1135. package/src/internal/funding/Transfer.ts +0 -762
  1136. package/src/internal/funding/TransferReconciliation.test.ts +0 -147
  1137. package/src/internal/funding/TransferReconciliation.ts +0 -264
  1138. package/src/internal/funding/providers/stargate.test.ts +0 -328
  1139. package/src/internal/funding/providers/stargate.ts +0 -856
  1140. /package/dist/apps/{funding → routes}/Inventory.d.ts +0 -0
  1141. /package/src/internal/{funding → routes}/Route.test.ts +0 -0
@@ -1,14 +1,22 @@
1
- import { Schema } from 'tapimo'
1
+ import { Db, Schema } from 'tapimo/server'
2
2
  import type * as z from 'zod/mini'
3
3
 
4
+ import * as Scope from '../../../Scope.js'
4
5
  import * as core_EarnVaults from '../../../db/tables/earnVaults.js'
6
+ import * as RewardAccounts from '../../../db/tables/rewardAccounts.js'
7
+ import * as RewardCampaigns from '../../../db/tables/rewardCampaigns.js'
8
+ import * as RewardEligibilityAssociations from '../../../db/tables/rewardEligibilityAssociations.js'
5
9
  import * as TestApp from '../../../../test/App.js'
6
10
  import * as TestEarn from '../../../../test/Earn.js'
7
11
  import * as Runtime from '../../../../test/runtime.js'
8
12
  import * as Cursor from '../../../internal/Cursor.js'
13
+ import * as EarnSharePrices from '../../../internal/EarnSharePrices.js'
14
+ import type * as Log from '../../../internal/Log.js'
9
15
  import * as Store from '../../../internal/Store.js'
10
16
  import * as Tidx from '../../../internal/Tidx.js'
17
+ import * as Ttl from '../../../internal/Ttl.js'
11
18
  import * as Value from '../../../internal/Value.js'
19
+ import * as Viem from '../../../internal/Viem.js'
12
20
  import * as Earn from './earn.js'
13
21
 
14
22
  /**
@@ -29,10 +37,16 @@ type OpenApiSchema = { $ref?: string }
29
37
 
30
38
  type OpenApiOperation = {
31
39
  description?: string
40
+ operationId?: string
32
41
  parameters?: readonly {
33
42
  description?: string
34
43
  name?: string
35
- schema?: { enum?: readonly unknown[]; examples?: readonly unknown[]; pattern?: string }
44
+ schema?: {
45
+ const?: unknown
46
+ enum?: readonly unknown[]
47
+ examples?: readonly unknown[]
48
+ pattern?: string
49
+ }
36
50
  }[]
37
51
  responses?: Record<
38
52
  string,
@@ -46,6 +60,7 @@ type OpenApiDocument = {
46
60
  string,
47
61
  {
48
62
  get?: OpenApiOperation
63
+ post?: OpenApiOperation
49
64
  }
50
65
  >
51
66
  }
@@ -62,6 +77,435 @@ function errorSchemas(document: OpenApiDocument, operation: OpenApiOperation | u
62
77
  )
63
78
  }
64
79
 
80
+ function successSchema(operation: OpenApiOperation | undefined) {
81
+ return operation?.responses?.['200']?.content?.['application/json']?.schema
82
+ }
83
+
84
+ function resolveSchema(
85
+ document: OpenApiDocument,
86
+ value: unknown,
87
+ seen: ReadonlySet<string> = new Set(),
88
+ ): unknown {
89
+ if (Array.isArray(value)) return value.map((item) => resolveSchema(document, item, seen))
90
+ if (!value || typeof value !== 'object') return value
91
+ const object = value as Record<string, unknown>
92
+ if (typeof object['$ref'] === 'string') {
93
+ const name = object['$ref'].split('/').at(-1)
94
+ if (!name || seen.has(name)) return value
95
+ return resolveSchema(document, document.components?.schemas?.[name], new Set([...seen, name]))
96
+ }
97
+ return Object.fromEntries(
98
+ Object.entries(object).map(([key, item]) => [key, resolveSchema(document, item, seen)]),
99
+ )
100
+ }
101
+
102
+ describe('schema.registerRewardEligibility.Body', () => {
103
+ test('parses a reward eligibility registration', () => {
104
+ expect(
105
+ Earn.schema.registerRewardEligibility.Body.parse({
106
+ chainId: 4217,
107
+ vaultAddress: `0x${'11'.repeat(20)}`,
108
+ walletAddress: `0x${'22'.repeat(20)}`,
109
+ }),
110
+ ).toMatchInlineSnapshot(`
111
+ {
112
+ "chainId": 4217,
113
+ "vaultAddress": "0x1111111111111111111111111111111111111111",
114
+ "walletAddress": "0x2222222222222222222222222222222222222222",
115
+ }
116
+ `)
117
+ })
118
+
119
+ test('rejects missing, invalid, and unknown fields', () => {
120
+ expect({
121
+ invalidAddress: Earn.schema.registerRewardEligibility.Body.safeParse({
122
+ chainId: 4217,
123
+ vaultAddress: `0x${'11'.repeat(20)}`,
124
+ walletAddress: 'invalid',
125
+ }).success,
126
+ invalidChainId: Earn.schema.registerRewardEligibility.Body.safeParse({
127
+ chainId: 0,
128
+ vaultAddress: `0x${'11'.repeat(20)}`,
129
+ walletAddress: `0x${'22'.repeat(20)}`,
130
+ }).success,
131
+ invalidTransactionHash: Earn.schema.registerRewardEligibility.Body.safeParse({
132
+ chainId: 4217,
133
+ transactionHash: '0x1234',
134
+ vaultAddress: `0x${'11'.repeat(20)}`,
135
+ walletAddress: `0x${'22'.repeat(20)}`,
136
+ }).success,
137
+ missing: Earn.schema.registerRewardEligibility.Body.safeParse({
138
+ chainId: 4217,
139
+ vaultAddress: `0x${'11'.repeat(20)}`,
140
+ }).success,
141
+ unknown: Earn.schema.registerRewardEligibility.Body.safeParse({
142
+ chainId: 4217,
143
+ source: 'other',
144
+ sourceInteractionId: 'interaction_1',
145
+ transactionHash: `0x${'33'.repeat(32)}`,
146
+ vaultAddress: `0x${'11'.repeat(20)}`,
147
+ walletAddress: `0x${'22'.repeat(20)}`,
148
+ }).success,
149
+ }).toEqual({
150
+ invalidAddress: false,
151
+ invalidChainId: false,
152
+ invalidTransactionHash: false,
153
+ missing: false,
154
+ unknown: false,
155
+ })
156
+ })
157
+ })
158
+
159
+ describe('schema.getRewardEligibility.Query', () => {
160
+ test('accepts up to 100 items per page', () => {
161
+ expect([
162
+ Earn.schema.getRewardEligibility.Query.parse({
163
+ chainId: 4217,
164
+ limit: '100',
165
+ vaultAddress: `0x${'11'.repeat(20)}`,
166
+ }).limit,
167
+ Earn.schema.getRewardEligibility.Query.parse({
168
+ chainId: 4217,
169
+ limit: '101',
170
+ vaultAddress: `0x${'11'.repeat(20)}`,
171
+ }).limit,
172
+ ]).toMatchInlineSnapshot(`
173
+ [
174
+ 100,
175
+ 100,
176
+ ]
177
+ `)
178
+ })
179
+ })
180
+
181
+ describe('POST /v1/earn/rewards/eligibility', () => {
182
+ const body = {
183
+ chainId: Viem.chainId.mainnet,
184
+ transactionHash: Schema.Hash.parse(`0x${'33'.repeat(32)}`),
185
+ vaultAddress: `0x${'Aa'.repeat(20)}`,
186
+ walletAddress: `0x${'Bb'.repeat(20)}`,
187
+ }
188
+ const legacyKey = {
189
+ id: 'key_rewards_writer',
190
+ orgId: 'org_test',
191
+ scopes: ['rewards:write'],
192
+ token: 'secret_rewards_writer',
193
+ } satisfies TestApp.kvStore.Key
194
+ const superAdminSecret = 'secret_rewards_super_admin'
195
+ const auth = { headers: { authorization: `Bearer ${superAdminSecret}` } }
196
+
197
+ test('is omitted from public OpenAPI documentation', async () => {
198
+ const app = TestApp.create()
199
+ // SAFETY: `/openapi.json` is the app's generated OpenAPI document.
200
+ const document = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
201
+
202
+ expect(document.paths['/v1/earn/rewards/eligibility']?.post).toBeUndefined()
203
+ })
204
+
205
+ test('requires authentication', async () => {
206
+ const response = await TestApp.create().request('/v1/earn/rewards/eligibility', {
207
+ body: JSON.stringify(body),
208
+ headers: { 'content-type': 'application/json' },
209
+ method: 'POST',
210
+ })
211
+
212
+ expect(response.status).toBe(401)
213
+ })
214
+
215
+ test('rejects an ordinary authenticated key', async () => {
216
+ const response = await TestApp.create().request('/v1/earn/rewards/eligibility', {
217
+ ...TestApp.auth,
218
+ body: JSON.stringify(body),
219
+ headers: { ...TestApp.auth.headers, 'content-type': 'application/json' },
220
+ method: 'POST',
221
+ })
222
+
223
+ expect(response.status).toBe(403)
224
+ })
225
+
226
+ test('rejects a legacy rewards writer key', async () => {
227
+ const response = await TestApp.create({ auth: { keys: [legacyKey] } }).request(
228
+ '/v1/earn/rewards/eligibility',
229
+ {
230
+ body: JSON.stringify(body),
231
+ headers: {
232
+ authorization: `Bearer ${legacyKey.token}`,
233
+ 'content-type': 'application/json',
234
+ },
235
+ method: 'POST',
236
+ },
237
+ )
238
+
239
+ expect(response.status).toBe(403)
240
+ })
241
+
242
+ test('accepts a provisioned wildcard key', async () => {
243
+ const key = {
244
+ id: 'key_rewards_operator',
245
+ orgId: 'org_tempo',
246
+ scopes: [Scope.wildcard],
247
+ token: 'secret_rewards_operator',
248
+ } satisfies TestApp.kvStore.Key
249
+ const response = await TestApp.create({ auth: { keys: [key] } }).request(
250
+ '/v1/earn/rewards/eligibility',
251
+ {
252
+ body: JSON.stringify(body),
253
+ headers: {
254
+ authorization: `Bearer ${key.token}`,
255
+ 'content-type': 'application/json',
256
+ },
257
+ method: 'POST',
258
+ },
259
+ )
260
+
261
+ expect(response.status).toBe(200)
262
+ })
263
+
264
+ test('persists the first write and idempotently refreshes a replay', async () => {
265
+ const db = TestApp.database()
266
+ const app = TestApp.create({ auth: { superAdmin: { secret: superAdminSecret } }, db })
267
+ const request = (input = body) =>
268
+ app.request('/v1/earn/rewards/eligibility', {
269
+ ...auth,
270
+ body: JSON.stringify(input),
271
+ headers: { ...auth.headers, 'content-type': 'application/json' },
272
+ method: 'POST',
273
+ })
274
+
275
+ const first = await TestApp.json(
276
+ await request(),
277
+ Earn.schema.registerRewardEligibility.Response,
278
+ )
279
+ const replay = await TestApp.json(
280
+ await request({
281
+ ...body,
282
+ transactionHash: `0x${'44'.repeat(32)}`,
283
+ }),
284
+ Earn.schema.registerRewardEligibility.Response,
285
+ )
286
+
287
+ expect({ first, replay }).toMatchObject({
288
+ first: {
289
+ association: {
290
+ vaultAddress: body.vaultAddress.toLowerCase(),
291
+ walletAddress: body.walletAddress.toLowerCase(),
292
+ },
293
+ created: true,
294
+ },
295
+ replay: {
296
+ association: {
297
+ firstRegisteredAt: first.association.firstRegisteredAt,
298
+ transactionHash: `0x${'44'.repeat(32)}`,
299
+ },
300
+ created: false,
301
+ },
302
+ })
303
+ })
304
+
305
+ test('rejects invalid and unsupported chain input', async () => {
306
+ const app = TestApp.create({ auth: { superAdmin: { secret: superAdminSecret } } })
307
+ const invalid = await app.request('/v1/earn/rewards/eligibility', {
308
+ ...auth,
309
+ body: JSON.stringify({ ...body, walletAddress: 'invalid' }),
310
+ headers: { ...auth.headers, 'content-type': 'application/json' },
311
+ method: 'POST',
312
+ })
313
+ const unsupported = await app.request('/v1/earn/rewards/eligibility', {
314
+ ...auth,
315
+ body: JSON.stringify({ ...body, chainId: 9_999_999 }),
316
+ headers: { ...auth.headers, 'content-type': 'application/json' },
317
+ method: 'POST',
318
+ })
319
+
320
+ expect([invalid.status, unsupported.status]).toEqual([400, 400])
321
+ })
322
+
323
+ test('accepts supported chains without data upstreams', async () => {
324
+ const chainId = 31_337
325
+ const response = await TestApp.create({
326
+ auth: { superAdmin: { secret: superAdminSecret } },
327
+ rpc: { url: {} },
328
+ supportedChainIds: [chainId],
329
+ tidx: { baseUrl: {} },
330
+ }).request('/v1/earn/rewards/eligibility', {
331
+ ...auth,
332
+ body: JSON.stringify({ ...body, chainId }),
333
+ headers: { ...auth.headers, 'content-type': 'application/json' },
334
+ method: 'POST',
335
+ })
336
+
337
+ expect(response.status).toBe(200)
338
+ })
339
+
340
+ test('accepts configured Zones for super admins', async () => {
341
+ const zone = TestApp.zone({
342
+ chainId: 421_700_001,
343
+ rpcUrl: 'https://zone.example',
344
+ })
345
+ const response = await TestApp.create({
346
+ auth: { superAdmin: { secret: superAdminSecret } },
347
+ zones: [zone],
348
+ }).request('/v1/earn/rewards/eligibility', {
349
+ ...auth,
350
+ body: JSON.stringify({ ...body, chainId: zone.id }),
351
+ headers: { ...auth.headers, 'content-type': 'application/json' },
352
+ method: 'POST',
353
+ })
354
+
355
+ expect(response.status).toBe(200)
356
+ })
357
+
358
+ test('surfaces database failures as operational errors', async () => {
359
+ const app = TestApp.create({
360
+ auth: { superAdmin: { secret: superAdminSecret } },
361
+ db: () => {
362
+ throw new Error('database unavailable')
363
+ },
364
+ })
365
+ const response = await app.request('/v1/earn/rewards/eligibility', {
366
+ ...auth,
367
+ body: JSON.stringify(body),
368
+ headers: { ...auth.headers, 'content-type': 'application/json' },
369
+ method: 'POST',
370
+ })
371
+
372
+ expect(response.status).toBe(500)
373
+ })
374
+ })
375
+
376
+ describe('GET /v1/earn/rewards/eligibility', () => {
377
+ const readKey = {
378
+ id: 'key_rewards_reader',
379
+ orgId: 'org_test',
380
+ scopes: ['rewards:read'],
381
+ token: 'secret_rewards_reader',
382
+ } satisfies TestApp.kvStore.Key
383
+ const vaultAddress = Schema.Address.parse(`0x${'Aa'.repeat(20)}`)
384
+ const input = {
385
+ chainId: Viem.chainId.mainnet,
386
+ transactionHash: Schema.Hash.parse(`0x${'33'.repeat(32)}`),
387
+ vaultAddress,
388
+ walletAddress: Schema.Address.parse(`0x${'Bb'.repeat(20)}`),
389
+ } as const
390
+
391
+ test('is omitted from public OpenAPI documentation', async () => {
392
+ const app = TestApp.create({ auth: { keys: [readKey] } })
393
+ // SAFETY: `/openapi.json` is the app's generated OpenAPI document.
394
+ const document = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
395
+
396
+ expect(document.paths['/v1/earn/rewards/eligibility']?.get).toBeUndefined()
397
+ })
398
+
399
+ test('requires the read scope', async () => {
400
+ const response = await TestApp.create().request(
401
+ `/v1/earn/rewards/eligibility?chainId=4217&vaultAddress=${vaultAddress}`,
402
+ TestApp.auth,
403
+ )
404
+
405
+ expect(response.status).toBe(403)
406
+ })
407
+
408
+ test('reads supported chains without data upstreams', async () => {
409
+ const chainId = 31_337
410
+ const db = TestApp.database()
411
+ await RewardEligibilityAssociations.upsert(db, { ...input, chainId })
412
+ const response = await TestApp.create({
413
+ auth: { keys: [readKey] },
414
+ db,
415
+ rpc: { url: {} },
416
+ supportedChainIds: [chainId],
417
+ tidx: { baseUrl: {} },
418
+ }).request(`/v1/earn/rewards/eligibility?chainId=${chainId}&vaultAddress=${vaultAddress}`, {
419
+ headers: { authorization: `Bearer ${readKey.token}` },
420
+ })
421
+
422
+ expect(response.status).toBe(200)
423
+ })
424
+
425
+ test('rejects sandbox reads from mainnet-backed Zones', async () => {
426
+ const zone = TestApp.zone({
427
+ chainId: 421_700_001,
428
+ rpcUrl: 'https://mainnet-zone.example',
429
+ sourceChainId: Viem.chainId.mainnet,
430
+ })
431
+ const key = {
432
+ ...readKey,
433
+ environment: 'sandbox',
434
+ scopes: [...readKey.scopes, `zone:${zone.id}:read`],
435
+ } satisfies TestApp.kvStore.Key
436
+ const response = await TestApp.create({ auth: { keys: [key] }, zones: [zone] }).request(
437
+ `/v1/earn/rewards/eligibility?chainId=${zone.id}&vaultAddress=${vaultAddress}`,
438
+ { headers: { authorization: `Bearer ${key.token}` } },
439
+ )
440
+
441
+ expect(response.status).toBe(403)
442
+ })
443
+
444
+ test('rejects sandbox reads from Zones without a source chain', async () => {
445
+ const { sourceId: _sourceId, ...zone } = TestApp.zone({
446
+ chainId: 421_700_001,
447
+ rpcUrl: 'https://unknown-zone.example',
448
+ })
449
+ const key = {
450
+ ...readKey,
451
+ environment: 'sandbox',
452
+ scopes: [...readKey.scopes, `zone:${zone.id}:read`],
453
+ } satisfies TestApp.kvStore.Key
454
+ const response = await TestApp.create({ auth: { keys: [key] }, zones: [zone] }).request(
455
+ `/v1/earn/rewards/eligibility?chainId=${zone.id}&vaultAddress=${vaultAddress}`,
456
+ { headers: { authorization: `Bearer ${key.token}` } },
457
+ )
458
+
459
+ expect(response.status).toBe(403)
460
+ })
461
+
462
+ test('returns checkpointed pages that exclude later registrations', async () => {
463
+ const db = TestApp.database()
464
+ const app = TestApp.create({ auth: { keys: [readKey] }, db })
465
+ const wallets = ['bb', 'cc', 'dd', 'ee', 'ff', '11']
466
+ for (const wallet of wallets)
467
+ await RewardEligibilityAssociations.upsert(db, {
468
+ ...input,
469
+ walletAddress: Schema.Address.parse(`0x${wallet.repeat(20)}`),
470
+ })
471
+ const request = (cursor?: string) => {
472
+ const query = new URLSearchParams({
473
+ chainId: String(input.chainId),
474
+ limit: '5',
475
+ vaultAddress,
476
+ })
477
+ if (cursor) query.set('cursor', cursor)
478
+ return app.request(`/v1/earn/rewards/eligibility?${query}`, {
479
+ headers: { authorization: `Bearer ${readKey.token}` },
480
+ })
481
+ }
482
+
483
+ const first = await TestApp.json(await request(), Earn.schema.getRewardEligibility.Response)
484
+ await RewardEligibilityAssociations.upsert(db, {
485
+ ...input,
486
+ walletAddress: Schema.Address.parse(`0x${'22'.repeat(20)}`),
487
+ })
488
+ if (!first.nextCursor) throw new Error('Expected another eligibility page.')
489
+ const next = await TestApp.json(
490
+ await request(first.nextCursor),
491
+ Earn.schema.getRewardEligibility.Response,
492
+ )
493
+
494
+ expect({ first, next }).toMatchObject({
495
+ first: {
496
+ chainId: input.chainId,
497
+ data: wallets.slice(0, 5).map((wallet) => `0x${wallet.repeat(20)}`),
498
+ vaultAddress,
499
+ },
500
+ next: {
501
+ chainId: input.chainId,
502
+ data: [`0x${'11'.repeat(20)}`],
503
+ nextCursor: null,
504
+ vaultAddress,
505
+ },
506
+ })
507
+ })
508
+ })
65
509
  describe('schema.getEarnVaults.Query', () => {
66
510
  test('parses collection filters', () => {
67
511
  const query = Earn.schema.getEarnVaults.Query.parse({
@@ -135,6 +579,30 @@ describe('parseIndexedBlockAtOrBefore', () => {
135
579
  })
136
580
  })
137
581
 
582
+ describe('schema.getEarnVaultSharePrices.Query', () => {
583
+ test('defaults to daily observations and accepts a 31-point range', () => {
584
+ expect(
585
+ Earn.schema.getEarnVaultSharePrices.Query.parse({
586
+ from: '2026-01-01T00:00:00Z',
587
+ to: '2026-01-31T00:00:00Z',
588
+ }).interval,
589
+ ).toBe('day')
590
+ })
591
+
592
+ test('rejects reversed and oversized ranges', () => {
593
+ expect({
594
+ oversized: Earn.schema.getEarnVaultSharePrices.Query.safeParse({
595
+ from: '2026-01-01T00:00:00Z',
596
+ to: '2026-02-01T00:00:00Z',
597
+ }).success,
598
+ reversed: Earn.schema.getEarnVaultSharePrices.Query.safeParse({
599
+ from: '2026-01-02T00:00:00Z',
600
+ to: '2026-01-01T00:00:00Z',
601
+ }).success,
602
+ }).toEqual({ oversized: false, reversed: false })
603
+ })
604
+ })
605
+
138
606
  describe('schema.getEarnVaultPosition.Query', () => {
139
607
  test('accepts offset-bearing ISO 8601 timestamps', () => {
140
608
  expect(
@@ -172,6 +640,32 @@ describe('schema.getEarnAddressPositions.Query', () => {
172
640
  })
173
641
  })
174
642
 
643
+ describe('schema.getEarnVaultPosition.Response', () => {
644
+ test('accepts distinct position and value tokens', () => {
645
+ const position = {
646
+ account: TestEarn.positionAddress,
647
+ assetAllowance: '0',
648
+ assetBalance: '250000000',
649
+ assetToken: TestEarn.assetTokenAddress,
650
+ chainId: TestEarn.chain.id,
651
+ id: TestEarn.positionAddress,
652
+ shareAllowance: '0',
653
+ shareBalance: '99500000',
654
+ shareToken: `0x20c0${'11'.repeat(18)}`,
655
+ value: '100000000',
656
+ valueToken: TestEarn.assetTokenAddress,
657
+ }
658
+
659
+ expect(
660
+ Earn.schema.getEarnVaultPosition.Response.safeParse({
661
+ ...position,
662
+ chainId: TestEarn.zone.id,
663
+ valueToken: `0x20c0${'22'.repeat(18)}`,
664
+ }).success,
665
+ ).toBe(true)
666
+ })
667
+ })
668
+
175
669
  describe('schema.getEarnVaultEarnings.Response', () => {
176
670
  test('enforces status-specific earnings fields', () => {
177
671
  const response = {
@@ -283,8 +777,18 @@ describe('schema.getEarnVaultEarnings.Response', () => {
283
777
  })
284
778
  })
285
779
 
780
+ describe('alignZoneSourceBlock', () => {
781
+ test('caps Zone reports at the L1 portal watermark', () => {
782
+ expect([
783
+ Earn.alignZoneSourceBlock({ reported: 122n, verified: 123n }),
784
+ Earn.alignZoneSourceBlock({ reported: 124n, verified: 123n }),
785
+ Earn.alignZoneSourceBlock({ verified: 123n }),
786
+ ]).toStrictEqual([122n, 123n, 123n])
787
+ })
788
+ })
789
+
286
790
  describe('serializeVault', () => {
287
- test('includes a non-null instant-liquidity valuation with TVL', () => {
791
+ test('includes valuations and uses the reward target as the net APY floor', () => {
288
792
  const assetToken = {
289
793
  address: TestEarn.assetTokenAddress,
290
794
  currency: 'USD',
@@ -295,8 +799,13 @@ describe('serializeVault', () => {
295
799
  verified: true,
296
800
  } as const
297
801
  const shareTokenAddress = `0x20c0${'11'.repeat(18)}` as const
298
- const vault = Earn.serializeVault({
299
- apy: null,
802
+ const options = {
803
+ apy: {
804
+ asOf: '2026-08-26T14:00:00.000Z',
805
+ methodology: 'share-price-growth-annualized:v1',
806
+ net: '0.041200',
807
+ window: '7d',
808
+ },
300
809
  assetToken,
301
810
  discovery: {
302
811
  assetToken,
@@ -322,13 +831,28 @@ describe('serializeVault', () => {
322
831
  },
323
832
  vaultAddress: TestEarn.vaultAddress,
324
833
  },
325
- include: ['tvl'],
834
+ include: ['apy', 'tvl'],
326
835
  instantLiquidityValue: {
327
836
  amount: '500000000',
328
837
  currency: 'USD',
329
838
  decimals: 6,
330
839
  formatted: '500',
331
840
  },
841
+ rewards: [
842
+ {
843
+ asset: {
844
+ address: shareTokenAddress,
845
+ chainId: TestEarn.chain.id,
846
+ decimals: 6,
847
+ },
848
+ calculatedThrough: 1788134700,
849
+ campaignId: 'rewards-test-moderato-boost-rewards',
850
+ currentRewardsAprBps: 195,
851
+ endsAt: 1790812800,
852
+ startsAt: 1788134400,
853
+ targetTotalAprBps: 700,
854
+ },
855
+ ],
332
856
  shareToken: {
333
857
  address: shareTokenAddress,
334
858
  currency: 'USD',
@@ -341,7 +865,8 @@ describe('serializeVault', () => {
341
865
  tvl: { amount: '1000000000', currency: 'USD', decimals: 6, formatted: '1000' },
342
866
  zoneRoutes: [],
343
867
  zones: [],
344
- })
868
+ } satisfies Earn.serializeVault.Options
869
+ const vault = Earn.serializeVault(options)
345
870
 
346
871
  expect(vault.instantLiquidityValue).toStrictEqual({
347
872
  amount: '500000000',
@@ -349,6 +874,97 @@ describe('serializeVault', () => {
349
874
  decimals: 6,
350
875
  formatted: '500',
351
876
  })
877
+ expect(vault.apy).toMatchInlineSnapshot(`
878
+ {
879
+ "asOf": "2026-08-26T14:00:00.000Z",
880
+ "methodology": "share-price-growth-annualized:v1",
881
+ "net": "0.0700",
882
+ "rewards": [
883
+ {
884
+ "apr": "0.0195",
885
+ "asset": {
886
+ "address": "0x20c0111111111111111111111111111111111111",
887
+ "chainId": 42431,
888
+ "decimals": 6,
889
+ },
890
+ "calculatedThrough": 1788134700,
891
+ "campaignId": "rewards-test-moderato-boost-rewards",
892
+ "endsAt": 1790812800,
893
+ "startsAt": 1788134400,
894
+ "targetTotalApr": "0.0700",
895
+ },
896
+ ],
897
+ "vault": "0.041200",
898
+ "window": "7d",
899
+ }
900
+ `)
901
+ const reward = options.rewards[0]
902
+ if (!reward) throw new Error('Expected reward fixture.')
903
+ // Rewards cannot produce a complete APY without a measured vault component.
904
+ expect(
905
+ Earn.serializeVault({
906
+ ...options,
907
+ apy: null,
908
+ rewards: [{ ...reward, currentRewardsAprBps: 700 }],
909
+ }).apy,
910
+ ).toBeNull()
911
+ expect(
912
+ Earn.serializeVault({
913
+ ...options,
914
+ apy: null,
915
+ rewards: [{ ...reward, currentRewardsAprBps: null }],
916
+ }).apy,
917
+ ).toBeNull()
918
+ expect(Earn.serializeVault({ ...options, apy: null, rewards: undefined }).apy).toBeNull()
919
+ expect(
920
+ Earn.serializeVault({
921
+ ...options,
922
+ rewards: [
923
+ ...options.rewards,
924
+ {
925
+ ...reward,
926
+ campaignId: 'second-reward',
927
+ currentRewardsAprBps: 5,
928
+ targetTotalAprBps: 800,
929
+ },
930
+ ],
931
+ }).apy?.net,
932
+ ).toBe('0.0800')
933
+ expect(Earn.serializeVault({ ...options, rewards: undefined }).apy).toMatchObject({
934
+ net: '0.041200',
935
+ vault: '0.041200',
936
+ })
937
+ expect(
938
+ Earn.serializeVault({
939
+ ...options,
940
+ rewards: [{ ...reward, currentRewardsAprBps: null }],
941
+ }).apy,
942
+ ).toMatchObject({
943
+ net: '0.0700',
944
+ rewards: [{ apr: null, targetTotalApr: '0.0700' }],
945
+ vault: '0.041200',
946
+ })
947
+ expect(
948
+ Earn.serializeVault({
949
+ ...options,
950
+ apy: { ...options.apy, net: '0.080000' },
951
+ }).apy?.net,
952
+ ).toBe('0.080000')
953
+ vi.useFakeTimers({ now: new Date('2026-09-01T01:30:00.000Z'), toFake: ['Date'] })
954
+ try {
955
+ expect(
956
+ Earn.serializeVault({
957
+ ...options,
958
+ rewards: [{ ...reward, startsAt: 1_788_229_800 }],
959
+ }).apy,
960
+ ).toMatchObject({
961
+ net: '0.041200',
962
+ rewards: [{ targetTotalApr: '0.0700' }],
963
+ vault: '0.041200',
964
+ })
965
+ } finally {
966
+ vi.useRealTimers()
967
+ }
352
968
  })
353
969
  })
354
970
 
@@ -378,6 +994,19 @@ describe('calculateWindowEarnings', () => {
378
994
  })
379
995
 
380
996
  describe('calculateActiveCostBasis', () => {
997
+ test('ignores zero-share transfers', () => {
998
+ expect(
999
+ Earn.calculateActiveCostBasis({
1000
+ actions: [
1001
+ { assets: 100n, kind: 'deposit', shares: 100n },
1002
+ { kind: 'unknown', shares: 0n },
1003
+ { kind: 'redeem', shares: 0n },
1004
+ ],
1005
+ shareBalance: 100n,
1006
+ }),
1007
+ ).toBe(100n)
1008
+ })
1009
+
381
1010
  test('allocates weighted-average basis across partial exits', () => {
382
1011
  expect(
383
1012
  Earn.calculateActiveCostBasis({
@@ -391,6 +1020,29 @@ describe('calculateActiveCostBasis', () => {
391
1020
  ).toBe(200n)
392
1021
  })
393
1022
 
1023
+ test('allocates zero-cost reward shares across partial exits without erasing unknown basis', () => {
1024
+ const reward = { assets: 0n, kind: 'deposit', shares: 20n } as const
1025
+ expect([
1026
+ Earn.calculateActiveCostBasis({
1027
+ actions: [
1028
+ { assets: 100n, kind: 'deposit', shares: 100n },
1029
+ reward,
1030
+ { kind: 'redeem', shares: 60n },
1031
+ ],
1032
+ shareBalance: 60n,
1033
+ }),
1034
+ Earn.calculateActiveCostBasis({
1035
+ actions: [{ kind: 'unknown', shares: 100n }, reward],
1036
+ shareBalance: 120n,
1037
+ }),
1038
+ ]).toMatchInlineSnapshot(`
1039
+ [
1040
+ 50n,
1041
+ undefined,
1042
+ ]
1043
+ `)
1044
+ })
1045
+
394
1046
  test('calculates remaining basis while an async redemption is pending', () => {
395
1047
  expect(
396
1048
  Earn.calculateActiveCostBasis({
@@ -870,6 +1522,40 @@ describe('GET /v1/earn/addresses/:address/positions', () => {
870
1522
  },
871
1523
  60_000,
872
1524
  )
1525
+ test('requires read access to a selected Zone', async () => {
1526
+ const app = TestApp.create({ cache, zones: [TestEarn.zone] })
1527
+ const response = await app.request(
1528
+ `/v1/earn/addresses/${TestEarn.positionAddress}/positions?chainId=${TestEarn.zone.id}`,
1529
+ { headers: { 'tempo-api-key': TestApp.key.token } },
1530
+ )
1531
+
1532
+ expect(response.status).toBe(403)
1533
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
1534
+ error: { code: 'api_key_forbidden' },
1535
+ })
1536
+ })
1537
+
1538
+ test('rejects Zone earnings includes', async () => {
1539
+ const key = {
1540
+ ...TestApp.key,
1541
+ id: 'key_earn_zone_positions',
1542
+ scopes: ['data:read', `zone:${TestEarn.zone.id}:read`],
1543
+ token: 'secret_earn_zone_positions',
1544
+ } satisfies TestApp.kvStore.Key
1545
+ const app = TestApp.create({ auth: { keys: [key] }, cache, zones: [TestEarn.zone] })
1546
+ const response = await app.request(
1547
+ `/v1/earn/addresses/${TestEarn.positionAddress}/positions?chainId=${TestEarn.zone.id}&include=earnings`,
1548
+ { headers: { 'tempo-api-key': key.token } },
1549
+ )
1550
+
1551
+ expect(response.status).toBe(400)
1552
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
1553
+ error: {
1554
+ code: 'query_invalid',
1555
+ message: 'Zone positions do not support the earnings include.',
1556
+ },
1557
+ })
1558
+ })
873
1559
 
874
1560
  test('returns chain selection errors', async () => {
875
1561
  const app = TestApp.create({ auth: false, cache })
@@ -1222,7 +1908,7 @@ describe('GET /v1/earn/vaults/:vaultId', () => {
1222
1908
  const apy = (await TestApp.json(response, Earn.schema.getEarnVault.Response)).apy
1223
1909
  expect(apy).toBeDefined()
1224
1910
  expect(apy).not.toBeNull()
1225
- if (!apy) return
1911
+ if (!apy?.asOf || apy.net === null) throw new Error('Expected a measured APY.')
1226
1912
  expect({
1227
1913
  bucketed: apy.asOf === new Date(apy.asOf).toISOString() && apy.asOf.endsWith(':00.000Z'),
1228
1914
  measured: /^-?\d+\.\d{6}$/.test(apy.net),
@@ -1263,7 +1949,7 @@ describe('GET /v1/earn/vaults/:vaultId', () => {
1263
1949
  )
1264
1950
 
1265
1951
  test.runIf(Runtime.get().mode === 'testnet')(
1266
- 'defaults to a seven-day window',
1952
+ 'uses a seven-day window when it is measurable',
1267
1953
  async () => {
1268
1954
  const app = TestApp.create({ auth: false, cache, zones: [TestEarn.zone] })
1269
1955
  const path = `/v1/earn/vaults/${TestEarn.vaultAddress}?chainId=${TestEarn.chain.id}`
@@ -1280,6 +1966,39 @@ describe('GET /v1/earn/vaults/:vaultId', () => {
1280
1966
  60_000,
1281
1967
  )
1282
1968
 
1969
+ test.runIf(Runtime.get().mode === 'testnet')(
1970
+ 'falls back to one hour when the preferred window is unavailable',
1971
+ async () => {
1972
+ // The vault was deployed on 2026-07-23, so seven days has no opening
1973
+ // quote while the current one-hour rate is measurable.
1974
+ vi.useFakeTimers({ now: new Date('2026-07-24T10:00:00Z'), toFake: ['Date'] })
1975
+ try {
1976
+ const app = TestApp.create({
1977
+ auth: false,
1978
+ cache: { edge: false, store: Store.memory() },
1979
+ zones: [TestEarn.zone],
1980
+ })
1981
+ const path = `/v1/earn/vaults/${TestEarn.vaultAddress}?chainId=${TestEarn.chain.id}`
1982
+ const request = { headers: { 'cache-control': 'no-store' } }
1983
+ const [defaulted, explicit] = await Promise.all([
1984
+ app.request(`${path}&include=apy`, request),
1985
+ app.request(`${path}&apy.window=7d`, request),
1986
+ ])
1987
+
1988
+ expect([defaulted.status, explicit.status]).toStrictEqual([200, 200])
1989
+ const [fallbackVault, explicitVault] = await Promise.all([
1990
+ TestApp.json(defaulted, Earn.schema.getEarnVault.Response),
1991
+ TestApp.json(explicit, Earn.schema.getEarnVault.Response),
1992
+ ])
1993
+ expect(fallbackVault.apy).toMatchObject({ window: '1h' })
1994
+ expect(explicitVault.apy).toBeNull()
1995
+ } finally {
1996
+ vi.useRealTimers()
1997
+ }
1998
+ },
1999
+ 90_000,
2000
+ )
2001
+
1283
2002
  test.runIf(Runtime.get().mode === 'testnet')(
1284
2003
  'measures rates and values assets only when requested',
1285
2004
  async () => {
@@ -1458,7 +2177,183 @@ describe('GET /v1/earn/vaults/:vaultId', () => {
1458
2177
  )
1459
2178
  })
1460
2179
 
2180
+ describe('GET /v1/earn/vaults/:vaultId/share-prices', () => {
2181
+ test('classifies TIDX failures for dependency alerting', () => {
2182
+ expect([
2183
+ Earn.sharePriceProviderFailure({
2184
+ cause: new EarnSharePrices.MalformedResponseError('malformed row'),
2185
+ chainId: TestEarn.chain.id,
2186
+ }),
2187
+ Earn.sharePriceProviderFailure({
2188
+ cause: new EarnSharePrices.TidxRequestError(new TypeError('network failed')),
2189
+ chainId: TestEarn.chain.id,
2190
+ }),
2191
+ ]).toMatchInlineSnapshot(`
2192
+ [
2193
+ {
2194
+ "chainId": 42431,
2195
+ "failure": "payload",
2196
+ "id": "tidx",
2197
+ "operation": "query",
2198
+ },
2199
+ {
2200
+ "chainId": 42431,
2201
+ "failure": "network",
2202
+ "id": "tidx",
2203
+ "operation": "query",
2204
+ },
2205
+ ]
2206
+ `)
2207
+ })
2208
+
2209
+ test('validates the vault and daily range before reading upstreams', async () => {
2210
+ const app = TestApp.create({ auth: false, cache })
2211
+ const [range, vault] = await Promise.all([
2212
+ app.request(
2213
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/share-prices?from=2026-07-02T00%3A00Z&to=2026-07-01T00%3A00Z`,
2214
+ ),
2215
+ app.request(
2216
+ '/v1/earn/vaults/not-an-address/share-prices?from=2026-07-01T00%3A00Z&to=2026-07-02T00%3A00Z',
2217
+ ),
2218
+ ])
2219
+
2220
+ expect([
2221
+ (await TestApp.json(range, Schema.ErrorResponse)).error.code,
2222
+ (await TestApp.json(vault, Schema.ErrorResponse)).error.code,
2223
+ ]).toStrictEqual(['query_invalid', 'vault_id_invalid'])
2224
+ })
2225
+
2226
+ test('requires both range boundaries', async () => {
2227
+ const response = await TestApp.create({ auth: false, cache }).request(
2228
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/share-prices?from=2026-07-01T00%3A00Z`,
2229
+ )
2230
+
2231
+ expect(response.status).toBe(400)
2232
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
2233
+ error: { code: 'query_invalid' },
2234
+ })
2235
+ })
2236
+
2237
+ test.runIf(Runtime.get().mode === 'testnet')(
2238
+ 'negative-caches incompatible vault discovery',
2239
+ async () => {
2240
+ const app = TestApp.create({ auth: false, cache })
2241
+ const url = `/v1/earn/vaults/${TestEarn.assetTokenAddress}/share-prices?chainId=${TestEarn.chain.id}&from=2026-07-01T00%3A00Z&to=2026-07-02T00%3A00Z`
2242
+ const first = await app.request(url)
2243
+ const second = await app.request(url)
2244
+
2245
+ expect({
2246
+ first: {
2247
+ discovery: first.headers.get('server-timing')?.includes('earn_vault_discovery'),
2248
+ status: first.status,
2249
+ },
2250
+ second: {
2251
+ discovery: second.headers.get('server-timing')?.includes('earn_vault_discovery'),
2252
+ status: second.status,
2253
+ },
2254
+ }).toMatchInlineSnapshot(`
2255
+ {
2256
+ "first": {
2257
+ "discovery": true,
2258
+ "status": 404,
2259
+ },
2260
+ "second": {
2261
+ "discovery": false,
2262
+ "status": 404,
2263
+ },
2264
+ }
2265
+ `)
2266
+ },
2267
+ 60_000,
2268
+ )
2269
+
2270
+ test.runIf(Runtime.get().mode === 'testnet')(
2271
+ 'reads historical share prices through a deployed JSON-RPC batch',
2272
+ async () => {
2273
+ const runtime = Runtime.get()
2274
+ const tidx = Tidx.getClient({
2275
+ chainId: runtime.chainId,
2276
+ tidx: { auth: process.env.TIDX_AUTH, baseUrl: runtime.tidxUrl },
2277
+ })
2278
+ const indexed = await tidx.fetch({
2279
+ engine: 'clickhouse',
2280
+ query: 'SELECT timestamp FROM blocks ORDER BY num DESC LIMIT 1 OFFSET 100',
2281
+ })
2282
+ const timestamp = Value.toIsoDateTime(indexed.rows[0]?.['timestamp'])
2283
+ if (timestamp === undefined) throw new Error('expected an indexed block')
2284
+ const from = new Date(Date.parse(timestamp) - Ttl.days(1)).toISOString()
2285
+ const response = await TestApp.create({ auth: false, cache }).request(
2286
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/share-prices?chainId=${TestEarn.chain.id}&from=${encodeURIComponent(from)}&to=${encodeURIComponent(timestamp)}`,
2287
+ )
2288
+
2289
+ expect(response.status).toBe(200)
2290
+ const body = await TestApp.json(response, Earn.schema.getEarnVaultSharePrices.Response)
2291
+ expect(body.data).toEqual(
2292
+ expect.arrayContaining([
2293
+ expect.objectContaining({
2294
+ sharePrice: expect.objectContaining({
2295
+ amount: expect.stringMatching(/^\d+$/),
2296
+ decimals: 6,
2297
+ }),
2298
+ timestamp,
2299
+ }),
2300
+ ]),
2301
+ )
2302
+ },
2303
+ 60_000,
2304
+ )
2305
+ })
2306
+
1461
2307
  describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
2308
+ test('accepts and validates the wallet APY include', () => {
2309
+ expect(Earn.schema.getEarnVaultPosition.Query.safeParse({ include: ['apy'] }).success).toBe(
2310
+ true,
2311
+ )
2312
+ expect(
2313
+ Earn.schema.getEarnVaultPosition.Response.safeParse({
2314
+ account: TestEarn.positionAddress,
2315
+ apy: {
2316
+ breakdown: [
2317
+ {
2318
+ assetAmount: { baseUnits: '25000000000', decimals: 6, formatted: '25000' },
2319
+ net: '0.07',
2320
+ type: 'boost',
2321
+ },
2322
+ {
2323
+ assetAmount: { baseUnits: '5000000000', decimals: 6, formatted: '5000' },
2324
+ net: '0.02',
2325
+ type: 'base',
2326
+ },
2327
+ ],
2328
+ net: '0.0616666666666667',
2329
+ },
2330
+ assetAllowance: '0',
2331
+ assetBalance: '0',
2332
+ assetToken: TestEarn.assetTokenAddress,
2333
+ chainId: TestEarn.chain.id,
2334
+ id: TestEarn.positionAddress,
2335
+ shareAllowance: '0',
2336
+ shareBalance: '30000000000',
2337
+ shareToken: '0x20c000000000000000000000300e14ab91a10769',
2338
+ value: '30000000000',
2339
+ valueToken: TestEarn.assetTokenAddress,
2340
+ }).success,
2341
+ ).toBe(true)
2342
+ })
2343
+
2344
+ test('requires read access to a selected Zone', async () => {
2345
+ const app = TestApp.create({ cache, zones: [TestEarn.zone] })
2346
+ const response = await app.request(
2347
+ `/v1/earn/vaults/${TestEarn.zoneVaultAddress}/positions/${TestEarn.positionAddress}?chainId=${TestEarn.zone.id}`,
2348
+ { headers: { 'tempo-api-key': TestApp.key.token } },
2349
+ )
2350
+
2351
+ expect(response.status).toBe(403)
2352
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
2353
+ error: { code: 'api_key_forbidden' },
2354
+ })
2355
+ })
2356
+
1462
2357
  test('rejects invalid as-of timestamps', async () => {
1463
2358
  const app = TestApp.create({ auth: false, cache })
1464
2359
  const [malformed, unix] = await Promise.all([
@@ -1560,6 +2455,25 @@ describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
1560
2455
  }
1561
2456
  })
1562
2457
 
2458
+ test('rejects reward includes on historical positions', async () => {
2459
+ const response = await TestApp.create({
2460
+ auth: false,
2461
+ cache,
2462
+ rpc: { url: { 31_337: 'http://127.0.0.1:1' } },
2463
+ tidx: { baseUrl: { 31_337: 'http://127.0.0.1:1' } },
2464
+ }).request(
2465
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/positions/${TestEarn.positionAddress}?chainId=31337&asOf=2026-07-21T09%3A00Z&include=rewards`,
2466
+ )
2467
+
2468
+ expect(response.status).toBe(400)
2469
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
2470
+ error: {
2471
+ code: 'query_invalid',
2472
+ message: 'Historical position enrichments are not available.',
2473
+ },
2474
+ })
2475
+ })
2476
+
1563
2477
  test('rejects malformed vault position parameters', async () => {
1564
2478
  const response = await TestApp.create({ auth: false, cache }).request(
1565
2479
  '/v1/earn/vaults/not-an-address/positions/not-an-address',
@@ -1603,6 +2517,157 @@ describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
1603
2517
  "shareToken": true,
1604
2518
  }
1605
2519
  `)
2520
+ expect(position).not.toHaveProperty('apy')
2521
+ },
2522
+ 60_000,
2523
+ )
2524
+
2525
+ test.runIf(Runtime.get().mode === 'testnet')(
2526
+ 'preserves the current position when APY resolution fails',
2527
+ async () => {
2528
+ const entries: Log.Entry[] = []
2529
+ const app = TestApp.create({
2530
+ auth: false,
2531
+ cache: { edge: false, store: Store.memory() },
2532
+ logger: (entry) => void entries.push(entry),
2533
+ tidx: { baseUrl: 'http://127.0.0.1:1' },
2534
+ })
2535
+ const path = `/v1/earn/vaults/${TestEarn.vaultAddress}/positions/${TestEarn.positionAddress}?chainId=${TestEarn.chain.id}`
2536
+ const [bareResponse, response] = await Promise.all([
2537
+ app.request(path),
2538
+ app.request(`${path}&include=apy`),
2539
+ ])
2540
+
2541
+ expect(bareResponse.status).toBe(200)
2542
+ expect(response.status).toBe(200)
2543
+ expect(response.headers.get('cache-control')).toBe('no-store')
2544
+ const [bare, position] = await Promise.all([
2545
+ TestApp.json(bareResponse, Earn.schema.getEarnVaultPosition.Response),
2546
+ TestApp.json(response, Earn.schema.getEarnVaultPosition.Response),
2547
+ ])
2548
+ expect(position.apy).toBeNull()
2549
+ expect({ shareBalance: position.shareBalance, value: position.value }).toStrictEqual({
2550
+ shareBalance: bare.shareBalance,
2551
+ value: bare.value,
2552
+ })
2553
+ expect(entries.find((entry) => entry.providerFailures)?.providerFailures).toEqual([
2554
+ {
2555
+ chainId: TestEarn.chain.id,
2556
+ failure: 'network',
2557
+ id: 'tidx',
2558
+ operation: 'query',
2559
+ },
2560
+ ])
2561
+ },
2562
+ 60_000,
2563
+ )
2564
+
2565
+ test.runIf(Runtime.get().mode === 'testnet')(
2566
+ 'preserves the current position when reward APY resolution fails',
2567
+ async () => {
2568
+ const entries: Log.Entry[] = []
2569
+ const app = TestApp.create({
2570
+ auth: false,
2571
+ cache,
2572
+ db: Db.postgres({ connectionString: 'postgresql://127.0.0.1:1/unavailable' }),
2573
+ logger: (entry) => void entries.push(entry),
2574
+ })
2575
+ const path = `/v1/earn/vaults/${TestEarn.vaultAddress}/positions/${TestEarn.positionAddress}?chainId=${TestEarn.chain.id}`
2576
+ const [bareResponse, response] = await Promise.all([
2577
+ app.request(path),
2578
+ app.request(`${path}&include=apy`),
2579
+ ])
2580
+
2581
+ expect(bareResponse.status).toBe(200)
2582
+ expect(response.status).toBe(200)
2583
+ expect(response.headers.get('cache-control')).toBe('no-store')
2584
+ const [bare, position] = await Promise.all([
2585
+ TestApp.json(bareResponse, Earn.schema.getEarnVaultPosition.Response),
2586
+ TestApp.json(response, Earn.schema.getEarnVaultPosition.Response),
2587
+ ])
2588
+ expect(position.apy).toBeNull()
2589
+ expect({ shareBalance: position.shareBalance, value: position.value }).toStrictEqual({
2590
+ shareBalance: bare.shareBalance,
2591
+ value: bare.value,
2592
+ })
2593
+ expect(entries.find((entry) => entry.providerFailures)?.providerFailures).toEqual([
2594
+ {
2595
+ chainId: TestEarn.chain.id,
2596
+ failure: 'unknown',
2597
+ id: 'earn-rewards',
2598
+ operation: 'getPositionApy',
2599
+ },
2600
+ ])
2601
+ },
2602
+ 60_000,
2603
+ )
2604
+
2605
+ test.runIf(Runtime.get().mode === 'testnet')(
2606
+ 'includes current reward state from Postgres',
2607
+ async () => {
2608
+ const db = TestApp.database()
2609
+ const now = Math.floor(Date.now() / 1_000)
2610
+ const startsAt = Math.floor(now / 300) * 300
2611
+ await core_EarnVaults.upsert(db, TestEarn.verifiedVault)
2612
+ await RewardCampaigns.upsert(db, {
2613
+ assetAddress: TestEarn.assetTokenAddress,
2614
+ assetDecimals: 6,
2615
+ chainId: TestEarn.chain.id,
2616
+ config: {
2617
+ boostRewards: {
2618
+ endTimestamp: startsAt + 3_600,
2619
+ excludedAddresses: [],
2620
+ funding: { wallet: '0x5000000000000000000000000000000000000005' },
2621
+ intervalSeconds: 300,
2622
+ perUserPrincipalCapAssets: '1000000',
2623
+ startTimestamp: startsAt,
2624
+ targetAnnualRateBps: 700,
2625
+ totalPrincipalCapAssets: '10000000',
2626
+ treasury: '0x6000000000000000000000000000000000000006',
2627
+ },
2628
+ },
2629
+ earnShareAddress: '0x2000000000000000000000000000000000000002',
2630
+ earnShareDecimals: 18,
2631
+ now: startsAt - 1,
2632
+ vaultAddress: TestEarn.vaultAddress,
2633
+ })
2634
+ await RewardAccounts.replace(db, {
2635
+ accounts: [
2636
+ {
2637
+ accrualRemainder: '0',
2638
+ allocatedPrincipalAssets: '100',
2639
+ cumulativeEntitlement: '15',
2640
+ cumulativePaid: '10',
2641
+ deferral: null,
2642
+ eligibilityRegisteredAt: null,
2643
+ lots: [],
2644
+ pendingRewardAssets: '0',
2645
+ publicEarnShares: '100',
2646
+ qualifiedEarnShares: '100',
2647
+ recipient: TestEarn.positionAddress,
2648
+ registrationOrder: '1',
2649
+ updatedAt: new Date().toISOString(),
2650
+ },
2651
+ ],
2652
+ chainId: TestEarn.chain.id,
2653
+ vaultAddress: TestEarn.vaultAddress,
2654
+ })
2655
+ const response = await TestApp.create({ auth: false, cache, db }).request(
2656
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/positions/${TestEarn.positionAddress}?chainId=${TestEarn.chain.id}&include=apy,rewards.proof`,
2657
+ )
2658
+
2659
+ expect(response.status).toBe(200)
2660
+ expect(response.headers.get('cache-control')).toBe('no-store')
2661
+ const position = await TestApp.json(response, Earn.schema.getEarnVaultPosition.Response)
2662
+ expect(position.apy).toMatchObject({
2663
+ breakdown: expect.any(Array),
2664
+ net: expect.any(String),
2665
+ })
2666
+ expect(position.rewards).toStrictEqual({
2667
+ cumulativeEntitlement: '15',
2668
+ cumulativePaid: '10',
2669
+ pending: '5',
2670
+ })
1606
2671
  },
1607
2672
  60_000,
1608
2673
  )
@@ -1725,6 +2790,108 @@ describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
1725
2790
  })
1726
2791
 
1727
2792
  describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2793
+ test.runIf(Runtime.get().mode === 'testnet')(
2794
+ 'counts registered reward payouts without treating external shares as deposits',
2795
+ async () => {
2796
+ const account = '0xa3b9eb50b9d1a3f584fbe1122a7bc82084eaae2f'
2797
+ const chainId = Viem.chainId.mainnet
2798
+ const previousDistributorAddress = '0x6c857bf1fe7de1bc1d5c639c721b2633f8fe34f3'
2799
+ const distributorAddress = '0xa65c6ed737b52543123817977d8d2c0e554bfc2d'
2800
+ const vaultAddress = '0xd730394f3bb85a4828e35fc5e361dcc9f894fa4f'
2801
+ const db = TestApp.database()
2802
+ const errors: Error[] = []
2803
+ const app = TestApp.create({
2804
+ auth: false,
2805
+ cache,
2806
+ db,
2807
+ logger: (_, error) => {
2808
+ if (error) errors.push(error)
2809
+ },
2810
+ tidx: {
2811
+ auth: process.env.TIDX_AUTH,
2812
+ baseUrl: Viem.resolveUrl(process.env.TIDX_URL, chainId) ?? Tidx.url[chainId],
2813
+ },
2814
+ })
2815
+ const read = async (period: 'lifetime' | '30d' | 'active') => {
2816
+ const response = await app.request(
2817
+ `/v1/earn/vaults/${vaultAddress}/earnings/${account}?chainId=${chainId}&period=${period}`,
2818
+ )
2819
+ expect(response.status, errors.map((error) => error.message).join('\n')).toBe(200)
2820
+ return TestApp.json(response, Earn.schema.getEarnVaultEarnings.Response)
2821
+ }
2822
+
2823
+ // This account's indexed share receipts include both vault mints and distributor payouts.
2824
+ expect((await read('lifetime')).status).toBe('incomplete_cost_basis')
2825
+ await core_EarnVaults.upsert(db, {
2826
+ chainId,
2827
+ description: null,
2828
+ label: 'Tempo Cash',
2829
+ privateInputTokens: [],
2830
+ privateOutputTokens: [],
2831
+ vaultAddress,
2832
+ zones: [],
2833
+ })
2834
+ await RewardCampaigns.upsert(db, {
2835
+ assetAddress: '0x20c0000000000000000000000000000000000000',
2836
+ assetDecimals: 6,
2837
+ chainId,
2838
+ config: {
2839
+ boostRewards: {
2840
+ enabled: false,
2841
+ endTimestamp: 1790812800,
2842
+ excludedAddresses: [],
2843
+ funding: { wallet: account },
2844
+ intervalSeconds: 300,
2845
+ perUserPrincipalCapAssets: '25000000000',
2846
+ startTimestamp: 1788206400,
2847
+ targetAnnualRateBps: 700,
2848
+ totalPrincipalCapAssets: '10000000000000',
2849
+ treasury: account,
2850
+ },
2851
+ },
2852
+ earnShareAddress: '0x20c000000000000000000000baac91f6ca72f768',
2853
+ earnShareDecimals: 6,
2854
+ now: 1788206399,
2855
+ vaultAddress,
2856
+ })
2857
+ await RewardCampaigns.setBindings(db, {
2858
+ chainId,
2859
+ distributorAddress: previousDistributorAddress,
2860
+ vaultAddress,
2861
+ })
2862
+ await RewardCampaigns.setBindings(db, { chainId, distributorAddress, vaultAddress })
2863
+ await RewardCampaigns.setPaused(db, { chainId, paused: true, vaultAddress })
2864
+
2865
+ // Pausing new rewards must not erase the cost-basis treatment of already paid rewards.
2866
+ const earnings = await Promise.all((['lifetime', '30d', 'active'] as const).map(read))
2867
+ expect(earnings.map(({ period, status }) => ({ period, status }))).toMatchInlineSnapshot(`
2868
+ [
2869
+ {
2870
+ "period": "lifetime",
2871
+ "status": "complete",
2872
+ },
2873
+ {
2874
+ "period": "30d",
2875
+ "status": "complete",
2876
+ },
2877
+ {
2878
+ "period": "active",
2879
+ "status": "complete",
2880
+ },
2881
+ ]
2882
+ `)
2883
+ const lifetime = earnings[0]!
2884
+ if (lifetime.status !== 'complete' || lifetime.period !== 'lifetime')
2885
+ throw new Error('Expected complete lifetime earnings.')
2886
+ expect(BigInt(lifetime.lifetimeEarnings)).toBe(
2887
+ BigInt(lifetime.currentValue) +
2888
+ BigInt(lifetime.totalWithdrawn) -
2889
+ BigInt(lifetime.totalDeposited),
2890
+ )
2891
+ },
2892
+ 120_000,
2893
+ )
2894
+
1728
2895
  test('returns chain selection errors', async () => {
1729
2896
  const app = TestApp.create({ auth: false, cache })
1730
2897
  const invalid = await app.request(
@@ -2019,12 +3186,98 @@ describe('GET /v1/earn/vaults', () => {
2019
3186
  })
2020
3187
 
2021
3188
  describe('OpenAPI', () => {
3189
+ test('publishes stable Earn components', async () => {
3190
+ const app = TestApp.create({ auth: false, cache })
3191
+ const spec = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
3192
+
3193
+ expect(
3194
+ Object.fromEntries(
3195
+ Object.entries(spec.paths)
3196
+ .filter(([path]) => path.startsWith('/v1/earn/'))
3197
+ .map(([path, item]) => [item.get?.operationId, [path, successSchema(item.get)?.$ref]]),
3198
+ ),
3199
+ ).toMatchInlineSnapshot(`
3200
+ {
3201
+ "getEarnAddressPositions": [
3202
+ "/v1/earn/addresses/{address}/positions",
3203
+ "#/components/schemas/EarnAddressPositionList",
3204
+ ],
3205
+ "getEarnVault": [
3206
+ "/v1/earn/vaults/{vaultId}",
3207
+ "#/components/schemas/EarnVaultDetail",
3208
+ ],
3209
+ "getEarnVaultEarnings": [
3210
+ "/v1/earn/vaults/{vaultId}/earnings/{address}",
3211
+ "#/components/schemas/EarnVaultEarnings",
3212
+ ],
3213
+ "getEarnVaultPosition": [
3214
+ "/v1/earn/vaults/{vaultId}/positions/{address}",
3215
+ "#/components/schemas/EarnVaultPosition",
3216
+ ],
3217
+ "getEarnVaultSharePrices": [
3218
+ "/v1/earn/vaults/{vaultId}/share-prices",
3219
+ "#/components/schemas/EarnVaultSharePriceList",
3220
+ ],
3221
+ "getEarnVaults": [
3222
+ "/v1/earn/vaults",
3223
+ "#/components/schemas/EarnVaultList",
3224
+ ],
3225
+ "getVerifiedEarnVaults": [
3226
+ "/v1/earn/vaults/verified",
3227
+ "#/components/schemas/VerifiedEarnVaultList",
3228
+ ],
3229
+ }
3230
+ `)
3231
+ expect(
3232
+ Object.keys(spec.components?.schemas ?? {})
3233
+ .filter((name) => name.startsWith('Earn') && !name.endsWith('Error'))
3234
+ .sort(),
3235
+ ).toMatchInlineSnapshot(`
3236
+ [
3237
+ "EarnAddressPosition",
3238
+ "EarnAddressPositionList",
3239
+ "EarnVault",
3240
+ "EarnVaultDetail",
3241
+ "EarnVaultEarnings",
3242
+ "EarnVaultEngine",
3243
+ "EarnVaultList",
3244
+ "EarnVaultPosition",
3245
+ "EarnVaultSharePriceList",
3246
+ "EarnVaultZone",
3247
+ "EarnVaultZoneRoute",
3248
+ ]
3249
+ `)
3250
+ expect(spec.components?.schemas).toHaveProperty('VerifiedEarnVault')
3251
+ expect(spec.components?.schemas).toHaveProperty('VerifiedEarnVaultList')
3252
+ expect(JSON.stringify(spec.components?.schemas?.['EarnAddressPosition'])).toContain(
3253
+ 'An account’s position in one earn vault.',
3254
+ )
3255
+ expect({
3256
+ detail:
3257
+ spec.paths['/v1/earn/vaults/{vaultId}']?.get?.responses?.['400']?.content?.[
3258
+ 'application/json'
3259
+ ]?.schema?.$ref,
3260
+ list: spec.paths['/v1/earn/vaults']?.get?.responses?.['400']?.content?.['application/json']
3261
+ ?.schema?.$ref,
3262
+ verified:
3263
+ spec.paths['/v1/earn/vaults/verified']?.get?.responses?.['400']?.content?.[
3264
+ 'application/json'
3265
+ ]?.schema?.$ref,
3266
+ }).toMatchInlineSnapshot(`
3267
+ {
3268
+ "detail": "#/components/schemas/ApiKeyMalformedOrChainIdInvalidOrChainIdUnsupportedOrQueryInvalidOrVaultIdInvalidError",
3269
+ "list": "#/components/schemas/ApiKeyMalformedOrChainIdInvalidOrChainIdUnsupportedOrQueryInvalidError",
3270
+ "verified": "#/components/schemas/ApiKeyMalformedOrChainIdInvalidOrChainIdUnsupportedOrQueryInvalidError",
3271
+ }
3272
+ `)
3273
+ })
3274
+
2022
3275
  test('publishes the flattened vault shape', async () => {
2023
3276
  const app = TestApp.create({ auth: false, cache })
2024
3277
  const spec = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
2025
3278
  const operation = spec.paths['/v1/earn/vaults']?.get
2026
3279
  const parameters = operation?.parameters?.map((parameter) => parameter.name)
2027
- const response = JSON.stringify(operation?.responses?.['200'])
3280
+ const response = JSON.stringify(resolveSchema(spec, successSchema(operation)))
2028
3281
 
2029
3282
  expect(Object.keys(spec.paths)).toEqual(
2030
3283
  expect.arrayContaining([
@@ -2034,6 +3287,7 @@ describe('OpenAPI', () => {
2034
3287
  '/v1/earn/vaults/{vaultId}',
2035
3288
  '/v1/earn/vaults/{vaultId}/earnings/{address}',
2036
3289
  '/v1/earn/vaults/{vaultId}/positions/{address}',
3290
+ '/v1/earn/vaults/{vaultId}/share-prices',
2037
3291
  ]),
2038
3292
  )
2039
3293
  expect(parameters).toContain('apy.window')
@@ -2082,9 +3336,11 @@ describe('OpenAPI', () => {
2082
3336
  expect(JSON.stringify(include?.schema)).toContain('"apy"')
2083
3337
  expect(JSON.stringify(include?.schema)).toContain('"tvl"')
2084
3338
  expect(JSON.stringify(include?.schema)).toContain('"zones"')
2085
- expect(JSON.stringify(spec.paths['/v1/earn/vaults/{vaultId}']?.get?.responses)).toContain(
2086
- 'Instant liquidity valued in USD',
2087
- )
3339
+ expect(
3340
+ JSON.stringify(
3341
+ resolveSchema(spec, successSchema(spec.paths['/v1/earn/vaults/{vaultId}']?.get)),
3342
+ ),
3343
+ ).toContain('Instant liquidity valued in USD')
2088
3344
  })
2089
3345
 
2090
3346
  test('documents vault-position inputs and responses', async () => {
@@ -2094,7 +3350,7 @@ describe('OpenAPI', () => {
2094
3350
  const address = operation?.parameters?.find((parameter) => parameter.name === 'address')
2095
3351
  const asOf = operation?.parameters?.find((parameter) => parameter.name === 'asOf')
2096
3352
  const errors = errorSchemas(spec, operation)
2097
- const response = JSON.stringify(operation?.responses)
3353
+ const response = JSON.stringify(resolveSchema(spec, successSchema(operation)))
2098
3354
  const vaultId = operation?.parameters?.find((parameter) => parameter.name === 'vaultId')
2099
3355
 
2100
3356
  expect(errors).toContain('"chain_id_invalid"')
@@ -2103,6 +3359,8 @@ describe('OpenAPI', () => {
2103
3359
  expect(errors).toContain('"query_invalid"')
2104
3360
  expect(errors).toContain('"earn_vault_not_found"')
2105
3361
  expect(response).toContain('Stable resource ID for this vault position')
3362
+ expect(response).toContain('Chain containing the account position')
3363
+ expect(response).toContain('Always zero for Zone-routed positions')
2106
3364
  expect(response).toContain('0x20c000000000000000000000b9537d11c60e8b50')
2107
3365
  expect(response).toContain('0x20c000000000000000000000300e14ab91a10769')
2108
3366
  expect(address?.schema?.examples).toStrictEqual([TestEarn.positionAddress])
@@ -2112,6 +3370,7 @@ describe('OpenAPI', () => {
2112
3370
  expect(response).toContain('Assets held by this account at the observation block')
2113
3371
  expect(response).toContain('Earn shares held by this account at the observation block')
2114
3372
  expect(response).toContain('Asset value of this account’s earn shares at the observation block')
3373
+ expect(response).toContain('TIP-20 asset denominating `value`')
2115
3374
  expect(response).not.toContain('Assets this account currently holds')
2116
3375
  expect(response).not.toContain('Earn shares this account currently holds')
2117
3376
  expect(operation?.responses?.['200']?.description).toBe(
@@ -2120,6 +3379,20 @@ describe('OpenAPI', () => {
2120
3379
  expect(vaultId?.schema?.examples).toStrictEqual([TestEarn.mainnetVaultAddress])
2121
3380
  })
2122
3381
 
3382
+ test('documents vault share-price inputs and responses', async () => {
3383
+ const app = TestApp.create({ auth: false, cache })
3384
+ const spec = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
3385
+ const operation = spec.paths['/v1/earn/vaults/{vaultId}/share-prices']?.get
3386
+ const interval = operation?.parameters?.find((parameter) => parameter.name === 'interval')
3387
+ const response = JSON.stringify(resolveSchema(spec, successSchema(operation)))
3388
+
3389
+ expect(interval?.schema?.const).toBe('day')
3390
+ expect(interval?.schema?.examples).toStrictEqual(['day'])
3391
+ expect(response).toContain('Assets returned for one whole Earn share')
3392
+ expect(response).toContain('Daily Earn vault share prices')
3393
+ expect(response).toContain('"formatted":"1"')
3394
+ })
3395
+
2123
3396
  test('documents address-position inputs and responses', async () => {
2124
3397
  const app = TestApp.create({ auth: false, cache })
2125
3398
  const spec = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
@@ -2131,7 +3404,7 @@ describe('OpenAPI', () => {
2131
3404
  const include = operation?.parameters?.find((parameter) => parameter.name === 'include')
2132
3405
  const verified = operation?.parameters?.find((parameter) => parameter.name === 'verified')
2133
3406
  const errors = errorSchemas(spec, operation)
2134
- const response = JSON.stringify(operation?.responses)
3407
+ const response = JSON.stringify(resolveSchema(spec, successSchema(operation)))
2135
3408
  const tokenReference = JSON.stringify(spec.components?.schemas?.['TokenReference'])
2136
3409
 
2137
3410
  expect(operation?.description).toContain('currently holds shares')
@@ -2146,13 +3419,17 @@ describe('OpenAPI', () => {
2146
3419
  expect(errors).toContain('"query_invalid"')
2147
3420
  expect(response).toContain('Stable resource ID for this position')
2148
3421
  expect(response).toContain('Current asset value of the held shares')
3422
+ expect(response).toContain('Chain containing the held shares')
2149
3423
  expect(response).toContain('"assetAmount"')
2150
3424
  expect(response).toContain('"shareAmount"')
2151
3425
  expect(response).toContain('"lifetimeCashFlows"')
2152
3426
  expect(response).toContain('"valuation"')
3427
+ expect(response).toContain('"valueToken"')
2153
3428
  expect(response).toContain('"vaultAddress"')
2154
3429
  expect(response).toContain('"nextCursor"')
2155
- expect(response).toContain('#/components/schemas/TokenReference')
3430
+ expect(JSON.stringify(spec.components?.schemas?.['EarnAddressPosition'])).toContain(
3431
+ '#/components/schemas/TokenReference',
3432
+ )
2156
3433
  // Token references retain display metadata through the shared component.
2157
3434
  expect(tokenReference).toContain('"symbol"')
2158
3435
  })
@@ -2163,7 +3440,7 @@ describe('OpenAPI', () => {
2163
3440
  const operation = spec.paths['/v1/earn/vaults/{vaultId}/earnings/{address}']?.get
2164
3441
  const errors = errorSchemas(spec, operation)
2165
3442
  const period = operation?.parameters?.find((parameter) => parameter.name === 'period')
2166
- const response = JSON.stringify(operation?.responses)
3443
+ const response = JSON.stringify(resolveSchema(spec, successSchema(operation)))
2167
3444
 
2168
3445
  expect(operation?.description).toContain('the trailing 30 days')
2169
3446
  expect(period?.description).toContain('trailing 30 days')