tapimo 0.15.1 → 0.18.1

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 (709) hide show
  1. package/README.md +137 -0
  2. package/dist/ApiKey.d.ts +1 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +4 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +37 -11
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +163 -10
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +13085 -11974
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +46 -15
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +1 -1
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +1 -1
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +893 -191
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +5 -1
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +70 -70
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +8 -3
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +66 -27
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  28. package/dist/admin/apps/earn-vaults.js +36 -7
  29. package/dist/admin/apps/earn-vaults.js.map +1 -1
  30. package/dist/admin/apps/organizations.d.ts +25 -25
  31. package/dist/admin/apps/organizations.d.ts.map +1 -1
  32. package/dist/admin/apps/organizations.js +5 -4
  33. package/dist/admin/apps/organizations.js.map +1 -1
  34. package/dist/admin/apps/route-policies.d.ts +632 -0
  35. package/dist/admin/apps/route-policies.d.ts.map +1 -0
  36. package/dist/admin/apps/route-policies.js +257 -0
  37. package/dist/admin/apps/route-policies.js.map +1 -0
  38. package/dist/admin/apps/routes-support.js +39 -3
  39. package/dist/admin/apps/routes-support.js.map +1 -1
  40. package/dist/admin/apps/routes.d.ts +529 -76
  41. package/dist/admin/apps/routes.d.ts.map +1 -1
  42. package/dist/admin/apps/routes.js +82 -1
  43. package/dist/admin/apps/routes.js.map +1 -1
  44. package/dist/admin/apps/verified-tokens.d.ts +157 -157
  45. package/dist/admin/index.d.ts +0 -1
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +0 -1
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/ui.generated.d.ts +1 -1
  50. package/dist/admin/ui.generated.d.ts.map +1 -1
  51. package/dist/admin/ui.generated.js +205 -201
  52. package/dist/admin/ui.generated.js.map +1 -1
  53. package/dist/analytics/Analytics.d.ts.map +1 -1
  54. package/dist/analytics/Analytics.js +65 -1
  55. package/dist/analytics/Analytics.js.map +1 -1
  56. package/dist/analytics/tables/requestEvents.d.ts +1 -1
  57. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  58. package/dist/analytics/tables/requestEvents.js +58 -59
  59. package/dist/analytics/tables/requestEvents.js.map +1 -1
  60. package/dist/apps/data/App.d.ts +2709 -2670
  61. package/dist/apps/data/App.d.ts.map +1 -1
  62. package/dist/apps/data/routes/activities.d.ts +357 -357
  63. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  64. package/dist/apps/data/routes/activities.js +50 -0
  65. package/dist/apps/data/routes/activities.js.map +1 -1
  66. package/dist/apps/data/routes/addresses.d.ts +248 -248
  67. package/dist/apps/data/routes/balances.d.ts +22 -22
  68. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  69. package/dist/apps/data/routes/balances.js +5 -7
  70. package/dist/apps/data/routes/balances.js.map +1 -1
  71. package/dist/apps/data/routes/blocks.d.ts +125 -125
  72. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  73. package/dist/apps/data/routes/earn.d.ts +103 -12
  74. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  75. package/dist/apps/data/routes/earn.js +456 -220
  76. package/dist/apps/data/routes/earn.js.map +1 -1
  77. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  78. package/dist/apps/data/routes/exchanges.js +267 -97
  79. package/dist/apps/data/routes/exchanges.js.map +1 -1
  80. package/dist/apps/data/routes/fee-amm.d.ts +109 -127
  81. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  82. package/dist/apps/data/routes/fee-amm.js +83 -54
  83. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  84. package/dist/apps/data/routes/indexer.d.ts +43 -43
  85. package/dist/apps/data/routes/receipts.d.ts +235 -235
  86. package/dist/apps/data/routes/rpc.d.ts +30 -30
  87. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  88. package/dist/apps/data/routes/tokens.js +11 -6
  89. package/dist/apps/data/routes/tokens.js.map +1 -1
  90. package/dist/apps/data/routes/transactions.d.ts +2 -0
  91. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  92. package/dist/apps/data/routes/transactions.js +30 -22
  93. package/dist/apps/data/routes/transactions.js.map +1 -1
  94. package/dist/apps/data/routes/transfers.d.ts +77 -77
  95. package/dist/apps/data/routes/valuation.d.ts +32 -32
  96. package/dist/apps/data/routes/verified-tokens.d.ts +86 -86
  97. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  98. package/dist/apps/data/routes/webhooks.js +1 -1
  99. package/dist/apps/data/routes/webhooks.js.map +1 -1
  100. package/dist/apps/data/routes/zones.d.ts +31 -31
  101. package/dist/apps/management/App.d.ts +2909 -2064
  102. package/dist/apps/management/App.d.ts.map +1 -1
  103. package/dist/apps/management/App.js +2 -0
  104. package/dist/apps/management/App.js.map +1 -1
  105. package/dist/apps/management/Billing.d.ts +2 -4
  106. package/dist/apps/management/Billing.d.ts.map +1 -1
  107. package/dist/apps/management/Billing.js +65 -26
  108. package/dist/apps/management/Billing.js.map +1 -1
  109. package/dist/apps/management/routes/api-keys.d.ts +257 -245
  110. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  111. package/dist/apps/management/routes/api-keys.js +70 -11
  112. package/dist/apps/management/routes/api-keys.js.map +1 -1
  113. package/dist/apps/management/routes/billing.d.ts +84 -84
  114. package/dist/apps/management/routes/cli.d.ts +912 -0
  115. package/dist/apps/management/routes/cli.d.ts.map +1 -0
  116. package/dist/apps/management/routes/cli.js +416 -0
  117. package/dist/apps/management/routes/cli.js.map +1 -0
  118. package/dist/apps/management/routes/faucet.d.ts +8 -8
  119. package/dist/apps/management/routes/invitations.d.ts +138 -138
  120. package/dist/apps/management/routes/invite-links.d.ts +172 -172
  121. package/dist/apps/management/routes/members.d.ts +16 -16
  122. package/dist/apps/management/routes/orgs.d.ts +104 -104
  123. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  124. package/dist/apps/management/routes/orgs.js +8 -2
  125. package/dist/apps/management/routes/orgs.js.map +1 -1
  126. package/dist/apps/management/routes/projects.d.ts +125 -125
  127. package/dist/apps/management/routes/usage.d.ts +8 -8
  128. package/dist/apps/management/routes/verified-token-requests.d.ts +86 -86
  129. package/dist/apps/management/routes/webhooks.d.ts +485 -485
  130. package/dist/apps/mpp/App.d.ts +44 -44
  131. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  132. package/dist/apps/mpp/internal/Policy.js +4 -2
  133. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  134. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  135. package/dist/apps/mpp/internal/Sponsorship.js +6 -4
  136. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  137. package/dist/apps/relay/App.d.ts +8 -0
  138. package/dist/apps/relay/App.d.ts.map +1 -1
  139. package/dist/apps/relay/App.js +16 -4
  140. package/dist/apps/relay/App.js.map +1 -1
  141. package/dist/apps/relay/Sponsorships.d.ts +4 -6
  142. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  143. package/dist/apps/relay/Sponsorships.js +71 -60
  144. package/dist/apps/relay/Sponsorships.js.map +1 -1
  145. package/dist/apps/routes/Access.d.ts +53 -0
  146. package/dist/apps/routes/Access.d.ts.map +1 -1
  147. package/dist/apps/routes/Access.js +121 -0
  148. package/dist/apps/routes/Access.js.map +1 -1
  149. package/dist/apps/routes/App.d.ts +397 -158
  150. package/dist/apps/routes/App.d.ts.map +1 -1
  151. package/dist/apps/routes/App.js.map +1 -1
  152. package/dist/apps/routes/routes/chains.d.ts +25 -25
  153. package/dist/apps/routes/routes/deposit-addresses.d.ts +169 -61
  154. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -1
  155. package/dist/apps/routes/routes/deposit-addresses.js +217 -32
  156. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -1
  157. package/dist/apps/routes/routes/quotes.d.ts +171 -81
  158. package/dist/apps/routes/routes/quotes.d.ts.map +1 -1
  159. package/dist/apps/routes/routes/quotes.js +101 -27
  160. package/dist/apps/routes/routes/quotes.js.map +1 -1
  161. package/dist/apps/routes/routes/transfers.d.ts +532 -480
  162. package/dist/apps/routes/routes/transfers.d.ts.map +1 -1
  163. package/dist/apps/routes/routes/transfers.js +182 -37
  164. package/dist/apps/routes/routes/transfers.js.map +1 -1
  165. package/dist/cli/ApiKeys.d.ts +120 -0
  166. package/dist/cli/ApiKeys.d.ts.map +1 -0
  167. package/dist/cli/ApiKeys.js +138 -0
  168. package/dist/cli/ApiKeys.js.map +1 -0
  169. package/dist/cli/Cli.d.ts +92 -34
  170. package/dist/cli/Cli.d.ts.map +1 -1
  171. package/dist/cli/Cli.js +188 -11
  172. package/dist/cli/Cli.js.map +1 -1
  173. package/dist/cli/Credentials.d.ts +95 -0
  174. package/dist/cli/Credentials.d.ts.map +1 -0
  175. package/dist/cli/Credentials.js +110 -0
  176. package/dist/cli/Credentials.js.map +1 -0
  177. package/dist/cli/Spec.d.ts +59 -0
  178. package/dist/cli/Spec.d.ts.map +1 -0
  179. package/dist/cli/Spec.js +77 -0
  180. package/dist/cli/Spec.js.map +1 -0
  181. package/dist/cli/bin.js +5 -1
  182. package/dist/cli/bin.js.map +1 -1
  183. package/dist/cli/commands/admin.d.ts +5 -5
  184. package/dist/cli/commands/admin.d.ts.map +1 -1
  185. package/dist/cli/commands/auth.d.ts +73 -0
  186. package/dist/cli/commands/auth.d.ts.map +1 -0
  187. package/dist/cli/commands/auth.js +204 -0
  188. package/dist/cli/commands/auth.js.map +1 -0
  189. package/dist/cli/commands/keys.d.ts +17 -0
  190. package/dist/cli/commands/keys.d.ts.map +1 -0
  191. package/dist/cli/commands/keys.js +109 -0
  192. package/dist/cli/commands/keys.js.map +1 -0
  193. package/dist/cloudflare.d.ts +27 -2
  194. package/dist/cloudflare.d.ts.map +1 -1
  195. package/dist/cloudflare.js +144 -17
  196. package/dist/cloudflare.js.map +1 -1
  197. package/dist/db/Db.d.ts +23 -0
  198. package/dist/db/Db.d.ts.map +1 -1
  199. package/dist/db/Db.js +413 -1
  200. package/dist/db/Db.js.map +1 -1
  201. package/dist/db/Schema.d.ts +44 -1
  202. package/dist/db/Schema.d.ts.map +1 -1
  203. package/dist/db/Schema.js +56 -3
  204. package/dist/db/Schema.js.map +1 -1
  205. package/dist/db/tables/apiKeyAdmissions.d.ts +28 -2
  206. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -1
  207. package/dist/db/tables/apiKeyAdmissions.js +65 -9
  208. package/dist/db/tables/apiKeyAdmissions.js.map +1 -1
  209. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +2 -0
  210. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -1
  211. package/dist/db/tables/apiKeyOwnerTombstones.js +2 -2
  212. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -1
  213. package/dist/db/tables/authAccounts.d.ts.map +1 -1
  214. package/dist/db/tables/authAccounts.js +1 -0
  215. package/dist/db/tables/authAccounts.js.map +1 -1
  216. package/dist/db/tables/earnVaults.d.ts +5 -1
  217. package/dist/db/tables/earnVaults.d.ts.map +1 -1
  218. package/dist/db/tables/earnVaults.js +12 -1
  219. package/dist/db/tables/earnVaults.js.map +1 -1
  220. package/dist/db/tables/organizations.d.ts +4 -2
  221. package/dist/db/tables/organizations.d.ts.map +1 -1
  222. package/dist/db/tables/organizations.js +8 -34
  223. package/dist/db/tables/organizations.js.map +1 -1
  224. package/dist/db/tables/requestUsage.d.ts +5 -1
  225. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  226. package/dist/db/tables/requestUsage.js +10 -2
  227. package/dist/db/tables/requestUsage.js.map +1 -1
  228. package/dist/db/tables/rewardEligibilityAssociations.d.ts +13 -0
  229. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -1
  230. package/dist/db/tables/rewardEligibilityAssociations.js +11 -0
  231. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -1
  232. package/dist/db/tables/rewardRuns.d.ts.map +1 -1
  233. package/dist/db/tables/rewardRuns.js +4 -0
  234. package/dist/db/tables/rewardRuns.js.map +1 -1
  235. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -1
  236. package/dist/db/tables/rewardTransactionAttempts.js +2 -0
  237. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -1
  238. package/dist/db/tables/routesDepositAddresses.d.ts +29 -0
  239. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -1
  240. package/dist/db/tables/routesDepositAddresses.js +84 -31
  241. package/dist/db/tables/routesDepositAddresses.js.map +1 -1
  242. package/dist/db/tables/routesDeposits.d.ts.map +1 -1
  243. package/dist/db/tables/routesDeposits.js +31 -21
  244. package/dist/db/tables/routesDeposits.js.map +1 -1
  245. package/dist/db/tables/routesIdempotency.d.ts.map +1 -1
  246. package/dist/db/tables/routesIdempotency.js +2 -0
  247. package/dist/db/tables/routesIdempotency.js.map +1 -1
  248. package/dist/db/tables/routesPolicies.d.ts +58 -0
  249. package/dist/db/tables/routesPolicies.d.ts.map +1 -0
  250. package/dist/db/tables/routesPolicies.js +198 -0
  251. package/dist/db/tables/routesPolicies.js.map +1 -0
  252. package/dist/db/tables/routesTransferSubsidies.d.ts +22 -0
  253. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -1
  254. package/dist/db/tables/routesTransferSubsidies.js +41 -0
  255. package/dist/db/tables/routesTransferSubsidies.js.map +1 -1
  256. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -1
  257. package/dist/db/tables/routesTransferSubsidyNonces.js +12 -4
  258. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -1
  259. package/dist/db/tables/routesTransfers.d.ts +26 -1
  260. package/dist/db/tables/routesTransfers.d.ts.map +1 -1
  261. package/dist/db/tables/routesTransfers.js +36 -6
  262. package/dist/db/tables/routesTransfers.js.map +1 -1
  263. package/dist/db/tables/sponsoredTransactions.d.ts +45 -13
  264. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  265. package/dist/db/tables/sponsoredTransactions.js +144 -33
  266. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  267. package/dist/db/tables/users.d.ts +2 -0
  268. package/dist/db/tables/users.d.ts.map +1 -1
  269. package/dist/db/tables/users.js +11 -0
  270. package/dist/db/tables/users.js.map +1 -1
  271. package/dist/handlers/internal/multisig.d.ts +1 -1
  272. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  273. package/dist/handlers/internal/multisig.js +3 -2
  274. package/dist/handlers/internal/multisig.js.map +1 -1
  275. package/dist/handlers/relay.d.ts +2 -0
  276. package/dist/handlers/relay.d.ts.map +1 -1
  277. package/dist/handlers/relay.js +34 -15
  278. package/dist/handlers/relay.js.map +1 -1
  279. package/dist/internal/Auth.d.ts +57 -6
  280. package/dist/internal/Auth.d.ts.map +1 -1
  281. package/dist/internal/Auth.js +182 -78
  282. package/dist/internal/Auth.js.map +1 -1
  283. package/dist/internal/BetterAuth.d.ts +22 -0
  284. package/dist/internal/BetterAuth.d.ts.map +1 -1
  285. package/dist/internal/BetterAuth.js +17 -14
  286. package/dist/internal/BetterAuth.js.map +1 -1
  287. package/dist/internal/Cache.d.ts +5 -0
  288. package/dist/internal/Cache.d.ts.map +1 -1
  289. package/dist/internal/Cache.js +3 -1
  290. package/dist/internal/Cache.js.map +1 -1
  291. package/dist/internal/CliAuth.d.ts +243 -0
  292. package/dist/internal/CliAuth.d.ts.map +1 -0
  293. package/dist/internal/CliAuth.js +249 -0
  294. package/dist/internal/CliAuth.js.map +1 -0
  295. package/dist/internal/EarnSharePrices.d.ts +1 -1
  296. package/dist/internal/EarnSharePrices.d.ts.map +1 -1
  297. package/dist/internal/EarnSharePrices.js +7 -3
  298. package/dist/internal/EarnSharePrices.js.map +1 -1
  299. package/dist/internal/EarnVaults.d.ts +47 -0
  300. package/dist/internal/EarnVaults.d.ts.map +1 -1
  301. package/dist/internal/EarnVaults.js +188 -4
  302. package/dist/internal/EarnVaults.js.map +1 -1
  303. package/dist/internal/EarnWithdrawals.d.ts +73 -0
  304. package/dist/internal/EarnWithdrawals.d.ts.map +1 -0
  305. package/dist/internal/EarnWithdrawals.js +189 -0
  306. package/dist/internal/EarnWithdrawals.js.map +1 -0
  307. package/dist/internal/ExecutionContext.d.ts +21 -0
  308. package/dist/internal/ExecutionContext.d.ts.map +1 -0
  309. package/dist/internal/ExecutionContext.js +16 -0
  310. package/dist/internal/ExecutionContext.js.map +1 -0
  311. package/dist/internal/Log.d.ts +7 -3
  312. package/dist/internal/Log.d.ts.map +1 -1
  313. package/dist/internal/Log.js +163 -130
  314. package/dist/internal/Log.js.map +1 -1
  315. package/dist/internal/MetricSink.d.ts.map +1 -1
  316. package/dist/internal/MetricSink.js +26 -1
  317. package/dist/internal/MetricSink.js.map +1 -1
  318. package/dist/internal/RateLimit.d.ts +67 -0
  319. package/dist/internal/RateLimit.d.ts.map +1 -1
  320. package/dist/internal/RateLimit.js +174 -27
  321. package/dist/internal/RateLimit.js.map +1 -1
  322. package/dist/internal/Store.d.ts +6 -0
  323. package/dist/internal/Store.d.ts.map +1 -1
  324. package/dist/internal/Store.js +4 -5
  325. package/dist/internal/Store.js.map +1 -1
  326. package/dist/internal/Timing.d.ts +6 -0
  327. package/dist/internal/Timing.d.ts.map +1 -1
  328. package/dist/internal/Timing.js +21 -1
  329. package/dist/internal/Timing.js.map +1 -1
  330. package/dist/internal/Tron.d.ts +124 -0
  331. package/dist/internal/Tron.d.ts.map +1 -0
  332. package/dist/internal/Tron.js +202 -0
  333. package/dist/internal/Tron.js.map +1 -0
  334. package/dist/internal/Viem.d.ts +4 -0
  335. package/dist/internal/Viem.d.ts.map +1 -1
  336. package/dist/internal/Viem.js +25 -6
  337. package/dist/internal/Viem.js.map +1 -1
  338. package/dist/internal/rewards/Read.d.ts +2 -2
  339. package/dist/internal/rewards/Read.d.ts.map +1 -1
  340. package/dist/internal/rewards/Read.js +11 -2
  341. package/dist/internal/rewards/Read.js.map +1 -1
  342. package/dist/internal/routes/Action.d.ts +27 -0
  343. package/dist/internal/routes/Action.d.ts.map +1 -1
  344. package/dist/internal/routes/Action.js +49 -1
  345. package/dist/internal/routes/Action.js.map +1 -1
  346. package/dist/internal/routes/Chain.d.ts +2 -0
  347. package/dist/internal/routes/Chain.d.ts.map +1 -1
  348. package/dist/internal/routes/Chain.js +4 -0
  349. package/dist/internal/routes/Chain.js.map +1 -1
  350. package/dist/internal/routes/DepositAddress.d.ts.map +1 -1
  351. package/dist/internal/routes/DepositAddress.js +5 -0
  352. package/dist/internal/routes/DepositAddress.js.map +1 -1
  353. package/dist/internal/routes/Evidence.d.ts.map +1 -1
  354. package/dist/internal/routes/Evidence.js +6 -2
  355. package/dist/internal/routes/Evidence.js.map +1 -1
  356. package/dist/internal/routes/EvmTransferSettlement.d.ts +17 -0
  357. package/dist/internal/routes/EvmTransferSettlement.d.ts.map +1 -0
  358. package/dist/internal/routes/EvmTransferSettlement.js +196 -0
  359. package/dist/internal/routes/EvmTransferSettlement.js.map +1 -0
  360. package/dist/internal/routes/Policy.d.ts +161 -0
  361. package/dist/internal/routes/Policy.d.ts.map +1 -0
  362. package/dist/internal/routes/Policy.js +249 -0
  363. package/dist/internal/routes/Policy.js.map +1 -0
  364. package/dist/internal/routes/Provider.d.ts +66 -3
  365. package/dist/internal/routes/Provider.d.ts.map +1 -1
  366. package/dist/internal/routes/Provider.js +106 -27
  367. package/dist/internal/routes/Provider.js.map +1 -1
  368. package/dist/internal/routes/Quota.d.ts +57 -0
  369. package/dist/internal/routes/Quota.d.ts.map +1 -0
  370. package/dist/internal/routes/Quota.js +144 -0
  371. package/dist/internal/routes/Quota.js.map +1 -0
  372. package/dist/internal/routes/Reconciliation.d.ts.map +1 -1
  373. package/dist/internal/routes/Reconciliation.js +163 -47
  374. package/dist/internal/routes/Reconciliation.js.map +1 -1
  375. package/dist/internal/routes/SolanaTransferSettlement.d.ts +12 -0
  376. package/dist/internal/routes/SolanaTransferSettlement.d.ts.map +1 -0
  377. package/dist/internal/routes/SolanaTransferSettlement.js +220 -0
  378. package/dist/internal/routes/SolanaTransferSettlement.js.map +1 -0
  379. package/dist/internal/routes/SolanaTransferSubsidy.d.ts +172 -0
  380. package/dist/internal/routes/SolanaTransferSubsidy.d.ts.map +1 -0
  381. package/dist/internal/routes/SolanaTransferSubsidy.js +564 -0
  382. package/dist/internal/routes/SolanaTransferSubsidy.js.map +1 -0
  383. package/dist/internal/routes/Subsidy.d.ts +2 -2
  384. package/dist/internal/routes/Subsidy.d.ts.map +1 -1
  385. package/dist/internal/routes/Subsidy.js +2 -2
  386. package/dist/internal/routes/Subsidy.js.map +1 -1
  387. package/dist/internal/routes/Transfer.d.ts +229 -1
  388. package/dist/internal/routes/Transfer.d.ts.map +1 -1
  389. package/dist/internal/routes/Transfer.js +644 -7
  390. package/dist/internal/routes/Transfer.js.map +1 -1
  391. package/dist/internal/routes/TransferReconciliation.d.ts +6 -0
  392. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -1
  393. package/dist/internal/routes/TransferReconciliation.js +83 -159
  394. package/dist/internal/routes/TransferReconciliation.js.map +1 -1
  395. package/dist/internal/routes/TransferSettlement.d.ts +45 -0
  396. package/dist/internal/routes/TransferSettlement.d.ts.map +1 -0
  397. package/dist/internal/routes/TransferSettlement.js +2 -0
  398. package/dist/internal/routes/TransferSettlement.js.map +1 -0
  399. package/dist/internal/routes/TransferSubsidy.d.ts +23 -8
  400. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -1
  401. package/dist/internal/routes/TransferSubsidy.js +64 -5
  402. package/dist/internal/routes/TransferSubsidy.js.map +1 -1
  403. package/dist/internal/routes/TronTransferSettlement.d.ts +12 -0
  404. package/dist/internal/routes/TronTransferSettlement.d.ts.map +1 -0
  405. package/dist/internal/routes/TronTransferSettlement.js +201 -0
  406. package/dist/internal/routes/TronTransferSettlement.js.map +1 -0
  407. package/dist/internal/routes/TronTransferSubsidy.d.ts +174 -0
  408. package/dist/internal/routes/TronTransferSubsidy.d.ts.map +1 -0
  409. package/dist/internal/routes/TronTransferSubsidy.js +439 -0
  410. package/dist/internal/routes/TronTransferSubsidy.js.map +1 -0
  411. package/dist/internal/routes/index.d.ts +3 -0
  412. package/dist/internal/routes/index.d.ts.map +1 -1
  413. package/dist/internal/routes/index.js +3 -0
  414. package/dist/internal/routes/index.js.map +1 -1
  415. package/dist/internal/routes/providers/across.d.ts +3 -0
  416. package/dist/internal/routes/providers/across.d.ts.map +1 -1
  417. package/dist/internal/routes/providers/across.js +11 -0
  418. package/dist/internal/routes/providers/across.js.map +1 -1
  419. package/dist/internal/routes/providers/legacyMesh.d.ts +29 -0
  420. package/dist/internal/routes/providers/legacyMesh.d.ts.map +1 -0
  421. package/dist/internal/routes/providers/legacyMesh.js +474 -0
  422. package/dist/internal/routes/providers/legacyMesh.js.map +1 -0
  423. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts +59 -0
  424. package/dist/internal/routes/providers/legacyMeshDelivery.d.ts.map +1 -0
  425. package/dist/internal/routes/providers/legacyMeshDelivery.js +229 -0
  426. package/dist/internal/routes/providers/legacyMeshDelivery.js.map +1 -0
  427. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts +19 -0
  428. package/dist/internal/routes/providers/legacyMeshOutbound.d.ts.map +1 -0
  429. package/dist/internal/routes/providers/legacyMeshOutbound.js +457 -0
  430. package/dist/internal/routes/providers/legacyMeshOutbound.js.map +1 -0
  431. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts +123 -0
  432. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.d.ts.map +1 -0
  433. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js +333 -0
  434. package/dist/internal/routes/providers/legacyMeshOutboundDelivery.js.map +1 -0
  435. package/dist/internal/routes/providers/propAmm.d.ts +70 -0
  436. package/dist/internal/routes/providers/propAmm.d.ts.map +1 -0
  437. package/dist/internal/routes/providers/propAmm.js +524 -0
  438. package/dist/internal/routes/providers/propAmm.js.map +1 -0
  439. package/dist/internal/routes/providers/relay.d.ts +3 -0
  440. package/dist/internal/routes/providers/relay.d.ts.map +1 -1
  441. package/dist/internal/routes/providers/relay.js +352 -41
  442. package/dist/internal/routes/providers/relay.js.map +1 -1
  443. package/dist/internal/routes/providers/rhino.d.ts +3 -0
  444. package/dist/internal/routes/providers/rhino.d.ts.map +1 -1
  445. package/dist/internal/routes/providers/rhino.js +11 -0
  446. package/dist/internal/routes/providers/rhino.js.map +1 -1
  447. package/dist/internal/routes/providers/squid.d.ts +3 -0
  448. package/dist/internal/routes/providers/squid.d.ts.map +1 -1
  449. package/dist/internal/routes/providers/squid.js +19 -0
  450. package/dist/internal/routes/providers/squid.js.map +1 -1
  451. package/dist/internal/routes/providers/stargate.d.ts.map +1 -1
  452. package/dist/internal/routes/providers/stargate.js +22 -9
  453. package/dist/internal/routes/providers/stargate.js.map +1 -1
  454. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -1
  455. package/dist/internal/routes/providers/symbiosis.js +13 -17
  456. package/dist/internal/routes/providers/symbiosis.js.map +1 -1
  457. package/dist/providers/index.d.ts +14 -0
  458. package/dist/providers/index.d.ts.map +1 -1
  459. package/dist/providers/index.js +6 -0
  460. package/dist/providers/index.js.map +1 -1
  461. package/package.json +16 -6
  462. package/src/ApiKey.ts +7 -3
  463. package/src/ApiKeys.test.ts +652 -8
  464. package/src/ApiKeys.ts +191 -11
  465. package/src/App.test.ts +405 -18
  466. package/src/App.ts +51 -15
  467. package/src/Client.test-d.ts +157 -10
  468. package/src/Client.test.ts +4 -4
  469. package/src/Scope.ts +1 -2
  470. package/src/admin/App.ts +11 -5
  471. package/src/admin/apps/api-keys.test.ts +98 -2
  472. package/src/admin/apps/api-keys.ts +21 -12
  473. package/src/admin/apps/earn-vaults.test.ts +76 -7
  474. package/src/admin/apps/earn-vaults.ts +47 -8
  475. package/src/admin/apps/organizations.test.ts +147 -31
  476. package/src/admin/apps/organizations.ts +5 -4
  477. package/src/admin/apps/route-policies.test.ts +220 -0
  478. package/src/admin/apps/route-policies.ts +322 -0
  479. package/src/admin/apps/routes-support.test.ts +107 -2
  480. package/src/admin/apps/routes-support.ts +43 -3
  481. package/src/admin/apps/routes.test.ts +150 -0
  482. package/src/admin/apps/routes.ts +97 -1
  483. package/src/admin/apps/scopes.test.ts +1 -1
  484. package/src/admin/index.ts +0 -1
  485. package/src/admin/ui/plugin.ts +2 -1
  486. package/src/admin/ui/src/components/Dialog.tsx +1 -1
  487. package/src/admin/ui/src/components/EarnVaultForm.tsx +45 -0
  488. package/src/admin/ui/src/components/RoutePicker.tsx +79 -0
  489. package/src/admin/ui/src/lib/earn-vaults.ts +1 -1
  490. package/src/admin/ui/src/lib/route-policies.test.ts +452 -0
  491. package/src/admin/ui/src/lib/route-policies.ts +232 -0
  492. package/src/admin/ui/src/lib/routes.ts +34 -0
  493. package/src/admin/ui/src/routeTree.gen.ts +21 -0
  494. package/src/admin/ui/src/routes/api-keys.tsx +21 -2
  495. package/src/admin/ui/src/routes/early-access.tsx +1 -0
  496. package/src/admin/ui/src/routes/earn.vaults.tsx +1 -0
  497. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +22 -0
  498. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +10 -0
  499. package/src/admin/ui/src/routes/organizations.tsx +1 -0
  500. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +18 -3
  501. package/src/admin/ui/src/routes/route-policies.tsx +678 -0
  502. package/src/admin/ui/src/routes/routes.tsx +85 -2
  503. package/src/admin/ui/src/routes/routes_.support.tsx +6 -22
  504. package/src/admin/ui/src/routes/subsidies.tsx +1 -0
  505. package/src/admin/ui/src/routes/verified-tokens.tsx +1 -0
  506. package/src/admin/ui.generated.ts +258 -202
  507. package/src/analytics/Analytics.test.ts +4 -50
  508. package/src/analytics/Analytics.ts +65 -1
  509. package/src/analytics/tables/requestEvents.test.ts +402 -1
  510. package/src/analytics/tables/requestEvents.ts +62 -93
  511. package/src/apps/data/routes/activities.test.ts +315 -14
  512. package/src/apps/data/routes/activities.ts +60 -0
  513. package/src/apps/data/routes/balances.ts +5 -7
  514. package/src/apps/data/routes/earn.bench.ts +18 -0
  515. package/src/apps/data/routes/earn.local.test.ts +507 -0
  516. package/src/apps/data/routes/earn.test.ts +405 -127
  517. package/src/apps/data/routes/earn.ts +660 -270
  518. package/src/apps/data/routes/exchanges.bench.ts +3 -1
  519. package/src/apps/data/routes/exchanges.test.ts +166 -2
  520. package/src/apps/data/routes/exchanges.ts +308 -101
  521. package/src/apps/data/routes/fee-amm.test.ts +134 -2
  522. package/src/apps/data/routes/fee-amm.ts +122 -60
  523. package/src/apps/data/routes/receipts.test.ts +21 -18
  524. package/src/apps/data/routes/rpc.test.ts +2 -2
  525. package/src/apps/data/routes/tokens.provenance.test.ts +157 -0
  526. package/src/apps/data/routes/tokens.test.ts +4 -4
  527. package/src/apps/data/routes/tokens.ts +11 -6
  528. package/src/apps/data/routes/transactions.test.ts +29 -0
  529. package/src/apps/data/routes/transactions.ts +33 -22
  530. package/src/apps/data/routes/webhooks.test.ts +12 -3
  531. package/src/apps/data/routes/webhooks.ts +2 -1
  532. package/src/apps/management/App.ts +4 -0
  533. package/src/apps/management/Billing.test.ts +253 -27
  534. package/src/apps/management/Billing.ts +83 -29
  535. package/src/apps/management/routes/api-keys.test.ts +1 -1
  536. package/src/apps/management/routes/api-keys.ts +85 -11
  537. package/src/apps/management/routes/billing.test.ts +68 -4
  538. package/src/apps/management/routes/cli.test.ts +370 -0
  539. package/src/apps/management/routes/cli.ts +533 -0
  540. package/src/apps/management/routes/me.test.ts +14 -4
  541. package/src/apps/management/routes/orgs.test.ts +108 -4
  542. package/src/apps/management/routes/orgs.ts +7 -2
  543. package/src/apps/management/routes/usage.test.ts +2 -2
  544. package/src/apps/mpp/internal/Policy.test.ts +51 -4
  545. package/src/apps/mpp/internal/Policy.ts +6 -2
  546. package/src/apps/mpp/internal/Sponsorship.test.ts +29 -0
  547. package/src/apps/mpp/internal/Sponsorship.ts +6 -4
  548. package/src/apps/relay/App.test.ts +85 -1
  549. package/src/apps/relay/App.ts +28 -4
  550. package/src/apps/relay/Sponsorships.test.ts +97 -1
  551. package/src/apps/relay/Sponsorships.ts +77 -66
  552. package/src/apps/routes/Access.test.ts +319 -0
  553. package/src/apps/routes/Access.ts +147 -0
  554. package/src/apps/routes/App.ts +10 -0
  555. package/src/apps/routes/routes/chains.test.ts +3 -2
  556. package/src/apps/routes/routes/deposit-addresses.test.ts +978 -34
  557. package/src/apps/routes/routes/deposit-addresses.ts +243 -32
  558. package/src/apps/routes/routes/propAmm.local.test.ts +951 -0
  559. package/src/apps/routes/routes/quotes.test.ts +81 -8
  560. package/src/apps/routes/routes/quotes.ts +109 -27
  561. package/src/apps/routes/routes/transfers.test.ts +252 -15
  562. package/src/apps/routes/routes/transfers.ts +212 -33
  563. package/src/cli/ApiKeys.test.ts +265 -0
  564. package/src/cli/ApiKeys.ts +189 -0
  565. package/src/cli/Cli.test.ts +188 -0
  566. package/src/cli/Cli.ts +280 -12
  567. package/src/cli/Credentials.test.ts +122 -0
  568. package/src/cli/Credentials.ts +144 -0
  569. package/src/cli/Spec.test.ts +133 -0
  570. package/src/cli/Spec.ts +132 -0
  571. package/src/cli/bin.test.ts +49 -0
  572. package/src/cli/bin.ts +5 -1
  573. package/src/cli/commands/auth.test.ts +138 -0
  574. package/src/cli/commands/auth.ts +254 -0
  575. package/src/cli/commands/keys.test.ts +68 -0
  576. package/src/cli/commands/keys.ts +125 -0
  577. package/src/cloudflare.ts +184 -36
  578. package/src/db/Db.test.ts +877 -0
  579. package/src/db/Db.ts +498 -1
  580. package/src/db/Schema.ts +75 -4
  581. package/src/db/tables/apiKeyAdmissions.test.ts +57 -0
  582. package/src/db/tables/apiKeyAdmissions.ts +101 -11
  583. package/src/db/tables/apiKeyOwnerTombstones.ts +2 -2
  584. package/src/db/tables/authAccounts.test.ts +30 -0
  585. package/src/db/tables/authAccounts.ts +1 -0
  586. package/src/db/tables/earnVaults.test.ts +34 -0
  587. package/src/db/tables/earnVaults.ts +17 -2
  588. package/src/db/tables/organizations.test.ts +148 -84
  589. package/src/db/tables/organizations.ts +11 -43
  590. package/src/db/tables/requestUsage.ts +13 -2
  591. package/src/db/tables/rewardCampaigns.test.ts +163 -0
  592. package/src/db/tables/rewardEligibilityAssociations.test.ts +14 -0
  593. package/src/db/tables/rewardEligibilityAssociations.ts +24 -0
  594. package/src/db/tables/rewardRuns.ts +4 -0
  595. package/src/db/tables/rewardTransactionAttempts.ts +2 -0
  596. package/src/db/tables/routesDepositAddresses.test.ts +263 -0
  597. package/src/db/tables/routesDepositAddresses.ts +118 -34
  598. package/src/db/tables/routesDeposits.test.ts +66 -5
  599. package/src/db/tables/routesDeposits.ts +47 -26
  600. package/src/db/tables/routesIdempotency.test.ts +80 -0
  601. package/src/db/tables/routesIdempotency.ts +2 -0
  602. package/src/db/tables/routesPolicies.test.ts +143 -0
  603. package/src/db/tables/routesPolicies.ts +251 -0
  604. package/src/db/tables/routesTransferSubsidies.ts +64 -0
  605. package/src/db/tables/routesTransferSubsidyNonces.ts +16 -4
  606. package/src/db/tables/routesTransfers.test.ts +183 -2
  607. package/src/db/tables/routesTransfers.ts +65 -6
  608. package/src/db/tables/sponsoredTransactions.test.ts +351 -76
  609. package/src/db/tables/sponsoredTransactions.ts +182 -38
  610. package/src/db/tables/users.test.ts +51 -0
  611. package/src/db/tables/users.ts +12 -0
  612. package/src/handlers/internal/multisig.store.test.ts +120 -0
  613. package/src/handlers/internal/multisig.test.ts +389 -0
  614. package/src/handlers/internal/multisig.ts +13 -10
  615. package/src/handlers/relay.test.ts +259 -83
  616. package/src/handlers/relay.ts +36 -17
  617. package/src/internal/Auth.test.ts +291 -8
  618. package/src/internal/Auth.ts +227 -96
  619. package/src/internal/BetterAuth.test.ts +58 -22
  620. package/src/internal/BetterAuth.ts +23 -17
  621. package/src/internal/Cache.ts +3 -1
  622. package/src/internal/CliAuth.test.ts +279 -0
  623. package/src/internal/CliAuth.ts +319 -0
  624. package/src/internal/EarnSharePrices.test.ts +25 -0
  625. package/src/internal/EarnSharePrices.ts +9 -2
  626. package/src/internal/EarnVaults.test.ts +67 -0
  627. package/src/internal/EarnVaults.ts +299 -4
  628. package/src/internal/EarnWithdrawals.test.ts +315 -0
  629. package/src/internal/EarnWithdrawals.ts +266 -0
  630. package/src/internal/ExecutionContext.ts +31 -0
  631. package/src/internal/Log.test.ts +210 -0
  632. package/src/internal/Log.ts +180 -142
  633. package/src/internal/MetricSink.test.ts +190 -15
  634. package/src/internal/MetricSink.ts +27 -1
  635. package/src/internal/RateLimit.test.ts +144 -8
  636. package/src/internal/RateLimit.ts +254 -26
  637. package/src/internal/Store.ts +4 -5
  638. package/src/internal/Timing.test.ts +32 -0
  639. package/src/internal/Timing.ts +20 -1
  640. package/src/internal/Tron.test-d.ts +22 -0
  641. package/src/internal/Tron.test.ts +94 -0
  642. package/src/internal/Tron.ts +289 -0
  643. package/src/internal/Viem.rpc.test.ts +76 -0
  644. package/src/internal/Viem.ts +29 -6
  645. package/src/internal/rewards/Read.test.ts +109 -0
  646. package/src/internal/rewards/Read.ts +13 -4
  647. package/src/internal/routes/Action.test.ts +70 -0
  648. package/src/internal/routes/Action.ts +76 -1
  649. package/src/internal/routes/Chain.test.ts +18 -0
  650. package/src/internal/routes/Chain.ts +5 -0
  651. package/src/internal/routes/DepositAddress.ts +5 -0
  652. package/src/internal/routes/Evidence.test.ts +64 -0
  653. package/src/internal/routes/Evidence.ts +11 -3
  654. package/src/internal/routes/EvmTransferSettlement.ts +213 -0
  655. package/src/internal/routes/Policy.test.ts +316 -0
  656. package/src/internal/routes/Policy.ts +399 -0
  657. package/src/internal/routes/Provider.test.ts +103 -2
  658. package/src/internal/routes/Provider.ts +149 -27
  659. package/src/internal/routes/Quota.test.ts +149 -0
  660. package/src/internal/routes/Quota.ts +226 -0
  661. package/src/internal/routes/Reconciliation.local.test.ts +285 -0
  662. package/src/internal/routes/Reconciliation.test.ts +371 -13
  663. package/src/internal/routes/Reconciliation.ts +193 -42
  664. package/src/internal/routes/SolanaTransferSettlement.ts +232 -0
  665. package/src/internal/routes/SolanaTransferSubsidy.test.ts +471 -0
  666. package/src/internal/routes/SolanaTransferSubsidy.ts +760 -0
  667. package/src/internal/routes/SourceObservation.test.ts +221 -0
  668. package/src/internal/routes/Subsidy.local.test.ts +46 -0
  669. package/src/internal/routes/Subsidy.ts +4 -2
  670. package/src/internal/routes/Transfer.solana.test.ts +389 -0
  671. package/src/internal/routes/Transfer.test.ts +130 -1
  672. package/src/internal/routes/Transfer.tron.test.ts +172 -0
  673. package/src/internal/routes/Transfer.ts +866 -8
  674. package/src/internal/routes/TransferReconciliation.test.ts +26 -4
  675. package/src/internal/routes/TransferReconciliation.ts +91 -166
  676. package/src/internal/routes/TransferSettlement.ts +48 -0
  677. package/src/internal/routes/TransferSubsidy.local.test.ts +143 -0
  678. package/src/internal/routes/TransferSubsidy.test.ts +34 -4
  679. package/src/internal/routes/TransferSubsidy.ts +87 -12
  680. package/src/internal/routes/TronTransferSettlement.ts +212 -0
  681. package/src/internal/routes/TronTransferSubsidy.test.ts +109 -0
  682. package/src/internal/routes/TronTransferSubsidy.ts +619 -0
  683. package/src/internal/routes/index.test.ts +3 -0
  684. package/src/internal/routes/index.ts +3 -0
  685. package/src/internal/routes/providers/across.ts +13 -0
  686. package/src/internal/routes/providers/index.test.ts +141 -0
  687. package/src/internal/routes/providers/legacyMesh.test.ts +484 -0
  688. package/src/internal/routes/providers/legacyMesh.ts +633 -0
  689. package/src/internal/routes/providers/legacyMeshDelivery.test.ts +306 -0
  690. package/src/internal/routes/providers/legacyMeshDelivery.ts +320 -0
  691. package/src/internal/routes/providers/legacyMeshOutbound.test.ts +401 -0
  692. package/src/internal/routes/providers/legacyMeshOutbound.ts +566 -0
  693. package/src/internal/routes/providers/legacyMeshOutboundDelivery.ts +473 -0
  694. package/src/internal/routes/providers/propAmm.ts +640 -0
  695. package/src/internal/routes/providers/relay.test.ts +1263 -41
  696. package/src/internal/routes/providers/relay.ts +423 -38
  697. package/src/internal/routes/providers/rhino.ts +14 -1
  698. package/src/internal/routes/providers/squid.ts +21 -0
  699. package/src/internal/routes/providers/stargate.test.ts +105 -1
  700. package/src/internal/routes/providers/stargate.ts +22 -9
  701. package/src/internal/routes/providers/symbiosis.ts +13 -47
  702. package/src/providers/index.test.ts +2 -0
  703. package/src/providers/index.ts +18 -0
  704. package/dist/admin/Access.d.ts +0 -39
  705. package/dist/admin/Access.d.ts.map +0 -1
  706. package/dist/admin/Access.js +0 -73
  707. package/dist/admin/Access.js.map +0 -1
  708. package/src/admin/Access.test.ts +0 -130
  709. package/src/admin/Access.ts +0 -85
@@ -185,7 +185,7 @@ describe('POST /v1/earn/rewards/eligibility', () => {
185
185
  vaultAddress: `0x${'Aa'.repeat(20)}`,
186
186
  walletAddress: `0x${'Bb'.repeat(20)}`,
187
187
  }
188
- const legacyKey = {
188
+ const scopedKey = {
189
189
  id: 'key_rewards_writer',
190
190
  orgId: 'org_test',
191
191
  scopes: ['rewards:write'],
@@ -223,20 +223,62 @@ describe('POST /v1/earn/rewards/eligibility', () => {
223
223
  expect(response.status).toBe(403)
224
224
  })
225
225
 
226
- test('rejects a legacy rewards writer key', async () => {
227
- const response = await TestApp.create({ auth: { keys: [legacyKey] } }).request(
226
+ test('accepts a rewards writer key', async () => {
227
+ const response = await TestApp.create({ auth: { keys: [scopedKey] } }).request(
228
228
  '/v1/earn/rewards/eligibility',
229
229
  {
230
230
  body: JSON.stringify(body),
231
231
  headers: {
232
- authorization: `Bearer ${legacyKey.token}`,
232
+ authorization: `Bearer ${scopedKey.token}`,
233
233
  'content-type': 'application/json',
234
234
  },
235
235
  method: 'POST',
236
236
  },
237
237
  )
238
238
 
239
- expect(response.status).toBe(403)
239
+ expect(response.status).toBe(200)
240
+ })
241
+
242
+ test('uses the body chain for sandbox authorization', async () => {
243
+ const sandbox = { ...scopedKey, environment: 'sandbox' } satisfies TestApp.kvStore.Key
244
+ const app = TestApp.create({ auth: { keys: [sandbox] } })
245
+ const request = (chainId: number) =>
246
+ app.request('/v1/earn/rewards/eligibility', {
247
+ body: JSON.stringify({ ...body, chainId }),
248
+ headers: {
249
+ authorization: `Bearer ${sandbox.token}`,
250
+ 'content-type': 'application/json',
251
+ },
252
+ method: 'POST',
253
+ })
254
+
255
+ expect([
256
+ (await request(Viem.chainId.testnet)).status,
257
+ (await request(Viem.chainId.mainnet)).status,
258
+ ]).toEqual([200, 403])
259
+ })
260
+
261
+ test('rejects Zone chain IDs for rewards registration', async () => {
262
+ const zone = TestApp.zone({ chainId: 421_700_001, rpcUrl: 'https://zone.example' })
263
+ const response = await TestApp.create({ auth: { keys: [scopedKey] }, zones: [zone] }).request(
264
+ '/v1/earn/rewards/eligibility',
265
+ {
266
+ body: JSON.stringify({ ...body, chainId: zone.id }),
267
+ headers: {
268
+ authorization: `Bearer ${scopedKey.token}`,
269
+ 'content-type': 'application/json',
270
+ },
271
+ method: 'POST',
272
+ },
273
+ )
274
+
275
+ expect(response.status).toBe(400)
276
+ expect(await response.json()).toMatchObject({
277
+ error: {
278
+ code: 'chain_id_unsupported',
279
+ message: `Zone chain ID ${zone.id} is not supported for rewards registration.`,
280
+ },
281
+ })
240
282
  })
241
283
 
242
284
  test('accepts a provisioned wildcard key', async () => {
@@ -337,7 +379,7 @@ describe('POST /v1/earn/rewards/eligibility', () => {
337
379
  expect(response.status).toBe(200)
338
380
  })
339
381
 
340
- test('accepts configured Zones for super admins', async () => {
382
+ test('rejects configured Zones for super admins', async () => {
341
383
  const zone = TestApp.zone({
342
384
  chainId: 421_700_001,
343
385
  rpcUrl: 'https://zone.example',
@@ -352,7 +394,13 @@ describe('POST /v1/earn/rewards/eligibility', () => {
352
394
  method: 'POST',
353
395
  })
354
396
 
355
- expect(response.status).toBe(200)
397
+ expect(response.status).toBe(400)
398
+ expect(await response.json()).toMatchObject({
399
+ error: {
400
+ code: 'chain_id_unsupported',
401
+ message: `Zone chain ID ${zone.id} is not supported for rewards registration.`,
402
+ },
403
+ })
356
404
  })
357
405
 
358
406
  test('surfaces database failures as operational errors', async () => {
@@ -674,6 +722,11 @@ describe('schema.getEarnVaultEarnings.Response', () => {
674
722
  currentValue: '1000000',
675
723
  id: TestEarn.earningsAddress,
676
724
  }
725
+ const window = {
726
+ ...response,
727
+ end: '2026-09-18T00:00:00.000Z',
728
+ start: '2026-09-11T00:00:00.000Z',
729
+ }
677
730
 
678
731
  expect({
679
732
  active: Earn.schema.getEarnVaultEarnings.Response.safeParse({
@@ -699,7 +752,7 @@ describe('schema.getEarnVaultEarnings.Response', () => {
699
752
  status: 'incomplete_cost_basis',
700
753
  }).success,
701
754
  incompleteWindow: Earn.schema.getEarnVaultEarnings.Response.safeParse({
702
- ...response,
755
+ ...window,
703
756
  period: '30d',
704
757
  status: 'incomplete_cost_basis',
705
758
  }).success,
@@ -728,7 +781,7 @@ describe('schema.getEarnVaultEarnings.Response', () => {
728
781
  status: 'pending_redemption',
729
782
  }).success,
730
783
  pendingWindow: Earn.schema.getEarnVaultEarnings.Response.safeParse({
731
- ...response,
784
+ ...window,
732
785
  period: '30d',
733
786
  status: 'pending_redemption',
734
787
  }).success,
@@ -740,19 +793,19 @@ describe('schema.getEarnVaultEarnings.Response', () => {
740
793
  totalWithdrawn: '500000',
741
794
  }).success,
742
795
  window: Earn.schema.getEarnVaultEarnings.Response.safeParse({
743
- ...response,
796
+ ...window,
744
797
  period: '30d',
745
798
  status: 'complete',
746
799
  windowEarnings: '0',
747
800
  }).success,
748
801
  windowWithActiveEarnings: Earn.schema.getEarnVaultEarnings.Response.safeParse({
749
- ...response,
802
+ ...window,
750
803
  activeEarnings: '0',
751
804
  period: '30d',
752
805
  status: 'complete',
753
806
  }).success,
754
807
  windowWithoutEarnings: Earn.schema.getEarnVaultEarnings.Response.safeParse({
755
- ...response,
808
+ ...window,
756
809
  period: '30d',
757
810
  status: 'complete',
758
811
  }).success,
@@ -972,9 +1025,38 @@ describe('schema.getEarnVaultEarnings.Query', () => {
972
1025
  test('defaults to lifetime and accepts active and trailing earnings', () => {
973
1026
  expect([
974
1027
  Earn.schema.getEarnVaultEarnings.Query.parse({}).period,
1028
+ Earn.schema.getEarnVaultEarnings.Query.parse({ period: '7d' }).period,
975
1029
  Earn.schema.getEarnVaultEarnings.Query.parse({ period: '30d' }).period,
976
1030
  Earn.schema.getEarnVaultEarnings.Query.parse({ period: 'active' }).period,
977
- ]).toStrictEqual(['lifetime', '30d', 'active'])
1031
+ ]).toStrictEqual(['lifetime', '7d', '30d', 'active'])
1032
+ })
1033
+
1034
+ test('requires an ordered explicit interval only for custom periods', () => {
1035
+ const start = '2026-09-11T00:00:00.000Z'
1036
+ const end = '2026-09-18T00:00:00.000Z'
1037
+ expect(Earn.schema.getEarnVaultEarnings.Query.parse({ end, period: 'custom', start }))
1038
+ .toMatchInlineSnapshot(`
1039
+ {
1040
+ "end": "2026-09-18T00:00:00.000Z",
1041
+ "period": "custom",
1042
+ "start": "2026-09-11T00:00:00.000Z",
1043
+ }
1044
+ `)
1045
+ for (const query of [
1046
+ { period: 'custom' },
1047
+ { period: 'custom', start },
1048
+ { end, period: 'custom' },
1049
+ { end: start, period: 'custom', start },
1050
+ { end: start, period: 'custom', start: end },
1051
+ { end, period: 'custom', start: '2026-02-30T00:00:00Z' },
1052
+ { end, period: 'custom', start: '2026-09-11T00:00:00' },
1053
+ { end, start },
1054
+ { end, period: '7d', start },
1055
+ { end, period: 'lifetime', start },
1056
+ // The local dates look ordered, but their UTC instants are reversed.
1057
+ { end: '2026-09-18T01:00:00+02:00', period: 'custom', start: '2026-09-18T00:00:00Z' },
1058
+ ])
1059
+ expect(Earn.schema.getEarnVaultEarnings.Query.safeParse(query).success).toBe(false)
978
1060
  })
979
1061
  })
980
1062
 
@@ -1146,110 +1228,6 @@ describe('GET /v1/earn/vaults/verified', () => {
1146
1228
  })
1147
1229
  })
1148
1230
 
1149
- test.runIf(Runtime.get().mode === 'testnet')(
1150
- 'folds scoped Zone routes into vault capabilities',
1151
- async () => {
1152
- const db = TestApp.database()
1153
- await core_EarnVaults.upsert(db, TestEarn.zoneVerifiedVault)
1154
- const otherZoneId = TestEarn.zone.id + 1
1155
- const scopedKey = {
1156
- ...TestApp.key,
1157
- id: 'key_earn_zones',
1158
- scopes: ['data:read', `zone:${otherZoneId}:read`, `zone:${TestEarn.zone.id}:read`],
1159
- token: 'secret_earn_zones',
1160
- } satisfies TestApp.kvStore.Key
1161
- const unrelatedKey = {
1162
- ...TestApp.key,
1163
- id: 'key_earn_other_zone',
1164
- scopes: ['data:read', `zone:${otherZoneId}:read`],
1165
- token: 'secret_earn_other_zone',
1166
- } satisfies TestApp.kvStore.Key
1167
- const writeOnlyKey = {
1168
- ...TestApp.key,
1169
- id: 'key_earn_write_zone',
1170
- scopes: ['data:read', `zone:${TestEarn.zone.id}:write`],
1171
- token: 'secret_earn_write_zone',
1172
- } satisfies TestApp.kvStore.Key
1173
- const wildcardKey = {
1174
- ...TestApp.key,
1175
- id: 'key_earn_all_zones',
1176
- scopes: ['*'],
1177
- token: 'secret_earn_all_zones',
1178
- } satisfies TestApp.kvStore.Key
1179
- const app = TestApp.create({
1180
- auth: { keys: [scopedKey, unrelatedKey, wildcardKey, writeOnlyKey] },
1181
- cache,
1182
- db,
1183
- zones: [TestEarn.zone],
1184
- })
1185
- const base = `/v1/earn/vaults/verified?chainId=${TestEarn.chain.id}&limit=5`
1186
- const included = `${base}&include=capabilities,zone,zones`
1187
- const filtered = `${included}&capability=privateRouting`
1188
- // Fill the query-credential cache entry before checking callers without its Zone scope.
1189
- const scopedResponse = await app.request(`${filtered}&key=${scopedKey.token}`)
1190
- const [
1191
- defaultResponse,
1192
- unrelatedResponse,
1193
- publicResponse,
1194
- wildcardResponse,
1195
- writeOnlyResponse,
1196
- ] = await Promise.all([
1197
- app.request(base, { headers: { 'tempo-api-key': scopedKey.token } }),
1198
- app.request(included, { headers: { 'tempo-api-key': unrelatedKey.token } }),
1199
- app.request(filtered),
1200
- app.request(filtered, { headers: { 'tempo-api-key': wildcardKey.token } }),
1201
- app.request(filtered, { headers: { 'tempo-api-key': writeOnlyKey.token } }),
1202
- ])
1203
-
1204
- expect([
1205
- defaultResponse.status,
1206
- scopedResponse.status,
1207
- unrelatedResponse.status,
1208
- publicResponse.status,
1209
- wildcardResponse.status,
1210
- writeOnlyResponse.status,
1211
- ]).toStrictEqual([200, 200, 200, 200, 200, 200])
1212
- const [defaultBody, scopedBody, unrelatedBody, publicBody, wildcardBody, writeOnlyBody] =
1213
- await Promise.all([
1214
- TestApp.json(defaultResponse, Earn.schema.getVerifiedEarnVaults.Response),
1215
- TestApp.json(scopedResponse, Earn.schema.getVerifiedEarnVaults.Response),
1216
- TestApp.json(unrelatedResponse, Earn.schema.getVerifiedEarnVaults.Response),
1217
- TestApp.json(publicResponse, Earn.schema.getVerifiedEarnVaults.Response),
1218
- TestApp.json(wildcardResponse, Earn.schema.getVerifiedEarnVaults.Response),
1219
- TestApp.json(writeOnlyResponse, Earn.schema.getVerifiedEarnVaults.Response),
1220
- ])
1221
- expect(defaultBody.data[0]).not.toHaveProperty('zone')
1222
- expect(defaultBody.data[0]).not.toHaveProperty('zones')
1223
- expect(unrelatedBody.data[0]).toMatchObject({
1224
- capabilities: { privateRouting: true, routerSwaps: true },
1225
- zone: null,
1226
- zones: [],
1227
- })
1228
- expect(publicBody.data[0]).toMatchObject({
1229
- capabilities: { privateRouting: true, routerSwaps: true },
1230
- zone: null,
1231
- zones: [],
1232
- })
1233
- expect(writeOnlyBody.data[0]).toMatchObject({ zone: null, zones: [] })
1234
- const vault = scopedBody.data[0]
1235
- expect(vault?.capabilities).toMatchObject({ privateRouting: true, routerSwaps: true })
1236
- expect(vault?.zones).toHaveLength(1)
1237
- expect(vault?.zones?.[0]).toMatchObject(TestEarn.zoneRoute)
1238
- expect(vault?.zone).toStrictEqual(
1239
- vault?.zones?.[0]
1240
- ? {
1241
- chainId: vault.zones[0].chainId,
1242
- inputTokens: vault.zones[0].inputTokens,
1243
- name: vault.zones[0].name,
1244
- outputTokens: vault.zones[0].outputTokens,
1245
- }
1246
- : null,
1247
- )
1248
- expect(wildcardBody.data[0]).toStrictEqual(vault)
1249
- },
1250
- 90_000,
1251
- )
1252
-
1253
1231
  test.runIf(Runtime.get().mode === 'testnet')(
1254
1232
  'returns null for an inaccessible legacy Zone route',
1255
1233
  async () => {
@@ -2305,6 +2283,13 @@ describe('GET /v1/earn/vaults/:vaultId/share-prices', () => {
2305
2283
  })
2306
2284
 
2307
2285
  describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
2286
+ const zoneKey = {
2287
+ ...TestApp.key,
2288
+ id: 'key_earn_zone_vault_position',
2289
+ scopes: ['data:read', `zone:${TestEarn.zone.id}:read`],
2290
+ token: 'secret_earn_zone_vault_position',
2291
+ } satisfies TestApp.kvStore.Key
2292
+
2308
2293
  test('accepts and validates the wallet APY include', () => {
2309
2294
  expect(Earn.schema.getEarnVaultPosition.Query.safeParse({ include: ['apy'] }).success).toBe(
2310
2295
  true,
@@ -2354,6 +2339,26 @@ describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
2354
2339
  })
2355
2340
  })
2356
2341
 
2342
+ test.runIf(Runtime.get().mode === 'testnet')(
2343
+ 'returns not found for an incompatible public parent vault selected through a Zone',
2344
+ async () => {
2345
+ const response = await TestApp.create({
2346
+ auth: { keys: [zoneKey] },
2347
+ cache,
2348
+ zones: [TestEarn.zone],
2349
+ }).request(
2350
+ `/v1/earn/vaults/${TestEarn.assetTokenAddress}/positions/${TestEarn.positionAddress}?chainId=${TestEarn.zone.id}`,
2351
+ { headers: { 'tempo-api-key': zoneKey.token } },
2352
+ )
2353
+
2354
+ expect(response.status).toBe(404)
2355
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
2356
+ error: { code: 'earn_vault_not_found' },
2357
+ })
2358
+ },
2359
+ 60_000,
2360
+ )
2361
+
2357
2362
  test('rejects invalid as-of timestamps', async () => {
2358
2363
  const app = TestApp.create({ auth: false, cache })
2359
2364
  const [malformed, unix] = await Promise.all([
@@ -2631,6 +2636,26 @@ describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
2631
2636
  now: startsAt - 1,
2632
2637
  vaultAddress: TestEarn.vaultAddress,
2633
2638
  })
2639
+ await RewardEligibilityAssociations.upsert(db, {
2640
+ chainId: TestEarn.chain.id,
2641
+ vaultAddress: TestEarn.vaultAddress,
2642
+ walletAddress: TestEarn.positionAddress,
2643
+ })
2644
+ const freshResponse = await TestApp.create({ auth: false, cache, db }).request(
2645
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/positions/${TestEarn.positionAddress}?chainId=${TestEarn.chain.id}&include=apy`,
2646
+ )
2647
+ expect(freshResponse.status).toBe(200)
2648
+ const fresh = await TestApp.json(freshResponse, Earn.schema.getEarnVaultPosition.Response)
2649
+ expect(fresh.apy?.breakdown).toMatchObject([
2650
+ {
2651
+ assetAmount: { baseUnits: '0', decimals: 6, formatted: '0' },
2652
+ net: '0.0700',
2653
+ type: 'boost',
2654
+ },
2655
+ { assetAmount: { baseUnits: fresh.value }, type: 'base' },
2656
+ ])
2657
+ expect(Number(fresh.apy?.net)).toBe(Number(fresh.apy?.breakdown[1]?.net))
2658
+
2634
2659
  await RewardAccounts.replace(db, {
2635
2660
  accounts: [
2636
2661
  {
@@ -2791,7 +2816,95 @@ describe('GET /v1/earn/vaults/:vaultId/positions/:address', () => {
2791
2816
 
2792
2817
  describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2793
2818
  test.runIf(Runtime.get().mode === 'testnet')(
2794
- 'counts registered reward payouts without treating external shares as deposits',
2819
+ 'recognizes card withdrawals with only incoming rewards configured and no campaign',
2820
+ async () => {
2821
+ const account = '0x504a128461f2ee15b52a9d33812769e8cc31bc0d'
2822
+ const vaultAddress = '0xd730394f3bb85a4828e35fc5e361dcc9f894fa4f'
2823
+ const chainId = Viem.chainId.mainnet
2824
+ const db = TestApp.database()
2825
+ const tidx = {
2826
+ auth: process.env.TIDX_AUTH,
2827
+ baseUrl: Viem.resolveUrl(process.env.TIDX_URL, chainId) ?? Tidx.url[chainId],
2828
+ }
2829
+ const errors: Error[] = []
2830
+ const app = TestApp.create({
2831
+ auth: false,
2832
+ cache,
2833
+ db,
2834
+ logger: (_, error) => {
2835
+ if (error) errors.push(error)
2836
+ },
2837
+ tidx,
2838
+ })
2839
+ const input = {
2840
+ chainId,
2841
+ description: null,
2842
+ label: 'Tempo Cash',
2843
+ privateInputTokens: [],
2844
+ privateOutputTokens: [],
2845
+ vaultAddress,
2846
+ zones: [],
2847
+ } as const
2848
+ const read = async (period: '30d' | 'lifetime' | 'active') => {
2849
+ const response = await app.request(
2850
+ `/v1/earn/vaults/${vaultAddress}/earnings/${account}?chainId=${chainId}&period=${period}`,
2851
+ { headers: { 'cache-control': 'no-store' } },
2852
+ )
2853
+ expect(response.status, errors.map((error) => error.message).join('\n')).toBe(200)
2854
+ return TestApp.json(response, Earn.schema.getEarnVaultEarnings.Response)
2855
+ }
2856
+ await core_EarnVaults.upsert(db, {
2857
+ ...input,
2858
+ earnings: { rewardDistributors: [] },
2859
+ })
2860
+ // Lifetime history retains the known rewards after they leave the trailing window.
2861
+ expect((await read('lifetime')).status).toBe('incomplete_cost_basis')
2862
+ await core_EarnVaults.upsert(db, {
2863
+ ...input,
2864
+ earnings: {
2865
+ rewardDistributors: ['0xa65c6ed737b52543123817977d8d2c0e554bfc2d'],
2866
+ },
2867
+ })
2868
+ expect((await read('30d')).status).toBe('complete')
2869
+ expect((await read('active')).status).toBe('complete')
2870
+ // Sample direct exits before lifetime earnings so later activity cannot increase only the baseline.
2871
+ const direct = await Tidx.getClient({ chainId, tidx }).fetch({
2872
+ engine: 'clickhouse',
2873
+ query: `SELECT toString(sum(toUInt256(assets))) AS assets FROM (
2874
+ SELECT assets FROM Redeemed WHERE address = '${vaultAddress}' AND caller = '${account}'
2875
+ UNION ALL SELECT assets FROM WithdrewExact WHERE address = '${vaultAddress}' AND caller = '${account}'
2876
+ )`,
2877
+ signatures: [
2878
+ 'event Redeemed(address indexed caller,address indexed receiver,uint256 earnShares,uint256 assets)',
2879
+ 'event WithdrewExact(address indexed caller,address indexed receiver,uint256 assets,uint256 earnSharesBurned)',
2880
+ ],
2881
+ })
2882
+ const lifetime = await read('lifetime')
2883
+ if (lifetime.status !== 'complete' || lifetime.period !== 'lifetime')
2884
+ throw new Error('Expected complete lifetime earnings.')
2885
+ // This live wallet can spend again; EarnWithdrawals.read's fixed-block regression proves the captured $1 is counted exactly once.
2886
+ expect(
2887
+ BigInt(lifetime.totalWithdrawn) - BigInt(String(direct.rows[0]?.['assets'])),
2888
+ ).toBeGreaterThanOrEqual(1_000_000n)
2889
+ const positions = await app.request(
2890
+ `/v1/earn/addresses/${account}/positions?chainId=${chainId}&include=earnings&verified=true`,
2891
+ { headers: { 'cache-control': 'no-store' } },
2892
+ )
2893
+ expect(positions.status).toBe(200)
2894
+ const body = await TestApp.json(positions, Earn.schema.getEarnAddressPositions.Response)
2895
+ expect(
2896
+ body.data.find((position) => position.vaultAddress === vaultAddress)?.lifetimeCashFlows,
2897
+ ).toEqual({
2898
+ status: 'complete',
2899
+ totalDeposited: lifetime.totalDeposited,
2900
+ totalWithdrawn: lifetime.totalWithdrawn,
2901
+ })
2902
+ },
2903
+ 180_000,
2904
+ )
2905
+
2906
+ test.runIf(Runtime.get().mode === 'testnet')(
2907
+ 'combines additional distributors with campaign history without erasing past rewards',
2795
2908
  async () => {
2796
2909
  const account = '0xa3b9eb50b9d1a3f584fbe1122a7bc82084eaae2f'
2797
2910
  const chainId = Viem.chainId.mainnet
@@ -2815,6 +2928,7 @@ describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2815
2928
  const read = async (period: 'lifetime' | '30d' | 'active') => {
2816
2929
  const response = await app.request(
2817
2930
  `/v1/earn/vaults/${vaultAddress}/earnings/${account}?chainId=${chainId}&period=${period}`,
2931
+ { headers: { 'cache-control': 'no-store' } },
2818
2932
  )
2819
2933
  expect(response.status, errors.map((error) => error.message).join('\n')).toBe(200)
2820
2934
  return TestApp.json(response, Earn.schema.getEarnVaultEarnings.Response)
@@ -2822,7 +2936,7 @@ describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2822
2936
 
2823
2937
  // This account's indexed share receipts include both vault mints and distributor payouts.
2824
2938
  expect((await read('lifetime')).status).toBe('incomplete_cost_basis')
2825
- await core_EarnVaults.upsert(db, {
2939
+ const vault = await core_EarnVaults.upsert(db, {
2826
2940
  chainId,
2827
2941
  description: null,
2828
2942
  label: 'Tempo Cash',
@@ -2859,8 +2973,19 @@ describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2859
2973
  distributorAddress: previousDistributorAddress,
2860
2974
  vaultAddress,
2861
2975
  })
2976
+ // Neither the old campaign distributor nor the extra alone covers this account's receipts.
2977
+ expect((await read('lifetime')).status).toBe('incomplete_cost_basis')
2978
+ await core_EarnVaults.upsert(db, {
2979
+ ...vault,
2980
+ earnings: { rewardDistributors: [distributorAddress] },
2981
+ })
2982
+ for (const period of ['lifetime', '30d', 'active'] as const)
2983
+ expect((await read(period)).status).toBe('complete')
2984
+
2985
+ // Recording a future campaign binding keeps its history even after clearing the extra list.
2862
2986
  await RewardCampaigns.setBindings(db, { chainId, distributorAddress, vaultAddress })
2863
2987
  await RewardCampaigns.setPaused(db, { chainId, paused: true, vaultAddress })
2988
+ await core_EarnVaults.upsert(db, { ...vault, earnings: { rewardDistributors: [] } })
2864
2989
 
2865
2990
  // Pausing new rewards must not erase the cost-basis treatment of already paid rewards.
2866
2991
  const earnings = await Promise.all((['lifetime', '30d', 'active'] as const).map(read))
@@ -2888,8 +3013,10 @@ describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2888
3013
  BigInt(lifetime.totalWithdrawn) -
2889
3014
  BigInt(lifetime.totalDeposited),
2890
3015
  )
3016
+ await core_EarnVaults.upsert(db, { ...vault, earnings: null })
3017
+ expect((await read('lifetime')).status).toBe('complete')
2891
3018
  },
2892
- 120_000,
3019
+ 180_000,
2893
3020
  )
2894
3021
 
2895
3022
  test('returns chain selection errors', async () => {
@@ -2991,6 +3118,148 @@ describe('GET /v1/earn/vaults/:vaultId/earnings/:address', () => {
2991
3118
  60_000,
2992
3119
  )
2993
3120
 
3121
+ test.runIf(Runtime.get().mode === 'testnet')(
3122
+ 'matches weekly and explicit windows and preserves historical cash-flow boundaries',
3123
+ async () => {
3124
+ const account = '0x504a128461f2ee15b52a9d33812769e8cc31bc0d'
3125
+ const vaultAddress = '0xd730394f3bb85a4828e35fc5e361dcc9f894fa4f'
3126
+ const chainId = Viem.chainId.mainnet
3127
+ const db = TestApp.database()
3128
+ await core_EarnVaults.upsert(db, {
3129
+ chainId,
3130
+ description: null,
3131
+ earnings: { rewardDistributors: ['0xa65c6ed737b52543123817977d8d2c0e554bfc2d'] },
3132
+ label: 'Tempo Cash',
3133
+ privateInputTokens: [],
3134
+ privateOutputTokens: [],
3135
+ vaultAddress,
3136
+ zones: [],
3137
+ })
3138
+ const errors: Error[] = []
3139
+ const app = TestApp.create({
3140
+ auth: false,
3141
+ cache,
3142
+ db,
3143
+ logger: (_, error) => {
3144
+ if (error) errors.push(error)
3145
+ },
3146
+ tidx: {
3147
+ auth: process.env.TIDX_AUTH,
3148
+ baseUrl: Viem.resolveUrl(process.env.TIDX_URL, chainId) ?? Tidx.url[chainId],
3149
+ },
3150
+ })
3151
+ const path = `/v1/earn/vaults/${vaultAddress}/earnings/${account}`
3152
+ const read = async (query: Record<string, string>) => {
3153
+ const response = await app.request(
3154
+ `${path}?${new URLSearchParams({ chainId: String(chainId), ...query })}`,
3155
+ { headers: { 'cache-control': 'no-store' } },
3156
+ )
3157
+ expect(response.status, errors.map((error) => error.stack).join('\n')).toBe(200)
3158
+ const body = await TestApp.json(response, Earn.schema.getEarnVaultEarnings.Response)
3159
+ if (body.status !== 'complete' || !('windowEarnings' in body))
3160
+ throw new Error('Expected complete window earnings.')
3161
+ return body
3162
+ }
3163
+ const week = await read({ period: '7d' })
3164
+ expect(Date.parse(week.end) - Date.parse(week.start)).toBe(7 * 24 * 60 * 60 * 1000)
3165
+ const explicit = await read({ end: week.end, period: 'custom', start: week.start })
3166
+ expect(explicit).toEqual({ ...week, period: 'custom' })
3167
+
3168
+ // This fixed historical interval includes deposits, rewards and card exits.
3169
+ const start = '2026-09-11T00:00:00.000Z'
3170
+ const middle = '2026-09-15T00:00:00.000Z'
3171
+ const end = '2026-09-18T00:00:00.000Z'
3172
+ const full = await read({ end, period: 'custom', start })
3173
+ const left = await read({ end: middle, period: 'custom', start })
3174
+ const right = await read({ end, period: 'custom', start: middle })
3175
+ expect(BigInt(full.windowEarnings)).toBeGreaterThan(0n)
3176
+ expect(BigInt(left.windowEarnings) + BigInt(right.windowEarnings)).toBe(
3177
+ BigInt(full.windowEarnings),
3178
+ )
3179
+ expect(left.currentValue).not.toBe(full.currentValue)
3180
+ expect(right.currentValue).toBe(full.currentValue)
3181
+ const historical = await app.request(
3182
+ `/v1/earn/vaults/${vaultAddress}/positions/${account}?${new URLSearchParams({
3183
+ asOf: end,
3184
+ chainId: String(chainId),
3185
+ })}`,
3186
+ )
3187
+ expect(historical.status).toBe(200)
3188
+ expect(
3189
+ (await TestApp.json(historical, Earn.schema.getEarnVaultPosition.Response)).value,
3190
+ ).toBe(full.currentValue)
3191
+ const offset = await read({
3192
+ end: '2026-09-18T02:00:00+02:00',
3193
+ period: 'custom',
3194
+ start: '2026-09-10T19:00:00-05:00',
3195
+ })
3196
+ expect(offset).toEqual(full)
3197
+ },
3198
+ 180_000,
3199
+ )
3200
+
3201
+ test.runIf(Runtime.get().mode === 'testnet')(
3202
+ 'rejects earnings windows beyond indexed coverage',
3203
+ async () => {
3204
+ const end = new Date(Date.now() + Ttl.days(365)).toISOString()
3205
+ const response = await TestApp.create({ auth: false, cache }).request(
3206
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/earnings/${TestEarn.earningsAddress}?${new URLSearchParams(
3207
+ {
3208
+ chainId: String(TestEarn.chain.id),
3209
+ end,
3210
+ period: 'custom',
3211
+ start: '2026-09-11T00:00:00.000Z',
3212
+ },
3213
+ )}`,
3214
+ )
3215
+ expect(response.status).toBe(400)
3216
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
3217
+ error: { code: 'query_invalid', message: `Indexed history does not yet cover ${end}.` },
3218
+ })
3219
+ expect(response.headers.get('cache-control')).toBe('no-store')
3220
+ },
3221
+ 60_000,
3222
+ )
3223
+
3224
+ test.runIf(Runtime.get().mode === 'testnet')(
3225
+ 'reports historical earnings dependency failures through request alerts',
3226
+ async () => {
3227
+ const entries: Log.Entry[] = []
3228
+ const errors: Error[] = []
3229
+ const app = TestApp.create({
3230
+ auth: false,
3231
+ cache,
3232
+ logger: (entry, error) => {
3233
+ entries.push(entry)
3234
+ if (error) errors.push(error)
3235
+ },
3236
+ tidx: { baseUrl: 'http://127.0.0.1:1' },
3237
+ })
3238
+ const response = await app.request(
3239
+ `/v1/earn/vaults/${TestEarn.vaultAddress}/earnings/${TestEarn.earningsAddress}?${new URLSearchParams(
3240
+ {
3241
+ chainId: String(TestEarn.chain.id),
3242
+ end: '2026-09-18T00:00:00.000Z',
3243
+ period: 'custom',
3244
+ start: '2026-09-11T00:00:00.000Z',
3245
+ },
3246
+ )}`,
3247
+ )
3248
+ expect(response.status).toBe(502)
3249
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
3250
+ error: { code: 'upstream_error' },
3251
+ })
3252
+ expect(errors).toHaveLength(1)
3253
+ expect(entries[0]).toMatchObject({
3254
+ errorCode: 'upstream_error',
3255
+ route: '/v1/earn/vaults/:vaultId/earnings/:address',
3256
+ status: 502,
3257
+ })
3258
+ expect(response.headers.get('cache-control')).toBe('no-store')
3259
+ },
3260
+ 60_000,
3261
+ )
3262
+
2994
3263
  test.runIf(Runtime.get().mode === 'testnet')(
2995
3264
  'omits lifetime earnings when venue shares make the cost basis incomplete',
2996
3265
  async () => {
@@ -3367,7 +3636,9 @@ describe('OpenAPI', () => {
3367
3636
  expect(asOf?.description).toContain('latest indexed block at or before')
3368
3637
  expect(asOf?.schema?.examples).toStrictEqual(['2026-07-21T09:00:00.000Z'])
3369
3638
  expect(response).toContain('Indexed block used for a historical Earn position observation')
3370
- expect(response).toContain('Assets held by this account at the observation block')
3639
+ expect(response).toContain('Public vault assets held by this account at the observation block')
3640
+ expect(response).toContain('Private Zone assets held by this account at the observation block')
3641
+ expect(response).toContain('TIP-20 private asset used by the validated Zone route')
3371
3642
  expect(response).toContain('Earn shares held by this account at the observation block')
3372
3643
  expect(response).toContain('Asset value of this account’s earn shares at the observation block')
3373
3644
  expect(response).toContain('TIP-20 asset denominating `value`')
@@ -3442,17 +3713,24 @@ describe('OpenAPI', () => {
3442
3713
  const period = operation?.parameters?.find((parameter) => parameter.name === 'period')
3443
3714
  const response = JSON.stringify(resolveSchema(spec, successSchema(operation)))
3444
3715
 
3445
- expect(operation?.description).toContain('the trailing 30 days')
3446
- expect(period?.description).toContain('trailing 30 days')
3447
- expect(period?.schema?.enum).toStrictEqual(['30d', 'active', 'lifetime'])
3716
+ expect(operation?.description).toContain('rolling or custom time window')
3717
+ expect(period?.description).toContain('trailing 7 or 30 days')
3718
+ expect(period?.schema?.enum).toStrictEqual(['7d', '30d', 'active', 'custom', 'lifetime'])
3448
3719
  expect(period?.schema?.examples).toStrictEqual(['lifetime'])
3720
+ for (const name of ['start', 'end']) {
3721
+ const parameter = operation?.parameters?.find((parameter) => parameter.name === name)
3722
+ expect(parameter?.description).toContain('Required with period=custom')
3723
+ expect(parameter?.schema?.examples).toHaveLength(1)
3724
+ }
3449
3725
  expect(errors).toContain('"earn_vault_not_found"')
3450
3726
  expect(response).toContain('Stable resource ID for these vault earnings')
3451
- expect(response).toContain('Current share value plus completed redemptions')
3727
+ expect(response).toContain(
3728
+ 'Current share value plus withdrawals, including outgoing shares valued when transferred',
3729
+ )
3452
3730
  expect(response).toContain('Assets deposited with this account as receiver')
3453
- expect(response).toContain('Assets returned by completed redemptions')
3731
+ expect(response).toContain('regardless of recipient or spender')
3454
3732
  expect(response).toContain('weighted-average asset cost basis')
3455
- expect(response).toContain('Ending share value plus realized assets')
3733
+ expect(response).toContain('Ending share value plus withdrawals')
3456
3734
  expect(response).toContain('cannot reconstruct the asset cost basis for the requested period')
3457
3735
  expect(response).toContain('"active"')
3458
3736
  expect(response).toContain('"30d"')