tapimo 0.9.0 → 0.10.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 (319) hide show
  1. package/dist/ApiKey.d.ts +2 -1
  2. package/dist/ApiKey.d.ts.map +1 -1
  3. package/dist/ApiKeys.d.ts +4 -2
  4. package/dist/ApiKeys.d.ts.map +1 -1
  5. package/dist/ApiKeys.js +26 -1
  6. package/dist/ApiKeys.js.map +1 -1
  7. package/dist/App.d.ts +4292 -3708
  8. package/dist/App.d.ts.map +1 -1
  9. package/dist/App.js +1 -0
  10. package/dist/App.js.map +1 -1
  11. package/dist/Webhooks.d.ts +21 -20
  12. package/dist/Webhooks.d.ts.map +1 -1
  13. package/dist/Webhooks.js +66 -23
  14. package/dist/Webhooks.js.map +1 -1
  15. package/dist/admin/App.d.ts +91 -84
  16. package/dist/admin/App.d.ts.map +1 -1
  17. package/dist/admin/apps/api-keys.d.ts +26 -17
  18. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  19. package/dist/admin/apps/api-keys.js +6 -0
  20. package/dist/admin/apps/api-keys.js.map +1 -1
  21. package/dist/admin/apps/organizations.d.ts +4 -2
  22. package/dist/admin/apps/organizations.d.ts.map +1 -1
  23. package/dist/admin/apps/verified-tokens.d.ts +168 -168
  24. package/dist/admin/ui.generated.d.ts +1 -1
  25. package/dist/admin/ui.generated.js +69 -69
  26. package/dist/admin/ui.generated.js.map +1 -1
  27. package/dist/analytics/Analytics.d.ts.map +1 -1
  28. package/dist/analytics/Analytics.js +26 -0
  29. package/dist/analytics/Analytics.js.map +1 -1
  30. package/dist/apps/Zones.d.ts +4280 -84
  31. package/dist/apps/Zones.d.ts.map +1 -1
  32. package/dist/apps/Zones.js +30 -10
  33. package/dist/apps/Zones.js.map +1 -1
  34. package/dist/apps/data/App.d.ts +5799 -4929
  35. package/dist/apps/data/App.d.ts.map +1 -1
  36. package/dist/apps/data/FxOracle.d.ts +4 -5
  37. package/dist/apps/data/FxOracle.d.ts.map +1 -1
  38. package/dist/apps/data/FxOracle.js +19 -4
  39. package/dist/apps/data/FxOracle.js.map +1 -1
  40. package/dist/apps/data/routes/activities.d.ts +3391 -492
  41. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  42. package/dist/apps/data/routes/activities.js +372 -29
  43. package/dist/apps/data/routes/activities.js.map +1 -1
  44. package/dist/apps/data/routes/addresses.d.ts +853 -339
  45. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  46. package/dist/apps/data/routes/balances.d.ts +10 -10
  47. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  48. package/dist/apps/data/routes/balances.js +145 -83
  49. package/dist/apps/data/routes/balances.js.map +1 -1
  50. package/dist/apps/data/routes/blocks.d.ts +123 -123
  51. package/dist/apps/data/routes/coingecko.d.ts +169 -169
  52. package/dist/apps/data/routes/earn.d.ts +455 -1
  53. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  54. package/dist/apps/data/routes/earn.js +369 -45
  55. package/dist/apps/data/routes/earn.js.map +1 -1
  56. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  57. package/dist/apps/data/routes/exchanges.js +114 -118
  58. package/dist/apps/data/routes/exchanges.js.map +1 -1
  59. package/dist/apps/data/routes/fee-amm.d.ts +24 -24
  60. package/dist/apps/data/routes/indexer.d.ts +35 -34
  61. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  62. package/dist/apps/data/routes/indexer.js +3 -2
  63. package/dist/apps/data/routes/indexer.js.map +1 -1
  64. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  65. package/dist/apps/data/routes/receipts.js +68 -47
  66. package/dist/apps/data/routes/receipts.js.map +1 -1
  67. package/dist/apps/data/routes/rpc.d.ts +31 -31
  68. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  69. package/dist/apps/data/routes/rpc.js +5 -1
  70. package/dist/apps/data/routes/rpc.js.map +1 -1
  71. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  72. package/dist/apps/data/routes/tokens.d.ts +461 -459
  73. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  74. package/dist/apps/data/routes/transactions.d.ts +313 -305
  75. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  76. package/dist/apps/data/routes/transactions.js +25 -23
  77. package/dist/apps/data/routes/transactions.js.map +1 -1
  78. package/dist/apps/data/routes/transfers.d.ts +108 -86
  79. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  80. package/dist/apps/data/routes/transfers.js +618 -105
  81. package/dist/apps/data/routes/transfers.js.map +1 -1
  82. package/dist/apps/data/routes/valuation.d.ts +21 -21
  83. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  84. package/dist/apps/data/routes/valuation.js +2 -2
  85. package/dist/apps/data/routes/valuation.js.map +1 -1
  86. package/dist/apps/data/routes/webhooks.d.ts +519 -868
  87. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  88. package/dist/apps/data/routes/webhooks.js +642 -353
  89. package/dist/apps/data/routes/webhooks.js.map +1 -1
  90. package/dist/apps/data/routes/zones.d.ts +31 -31
  91. package/dist/apps/data/routes/zones.d.ts.map +1 -1
  92. package/dist/apps/data/routes/zones.js +4 -2
  93. package/dist/apps/data/routes/zones.js.map +1 -1
  94. package/dist/apps/funding/routes/deposit-addresses.js +1 -1
  95. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  96. package/dist/apps/funding/routes/providers.d.ts +13 -13
  97. package/dist/apps/funding/routes/quotes.d.ts +89 -89
  98. package/dist/apps/funding/routes/transfers.d.ts +36 -36
  99. package/dist/apps/funding/routes/transfers.js +1 -1
  100. package/dist/apps/funding/routes/transfers.js.map +1 -1
  101. package/dist/apps/management/App.d.ts +11 -309
  102. package/dist/apps/management/App.d.ts.map +1 -1
  103. package/dist/apps/management/routes/api-keys.d.ts +74 -74
  104. package/dist/apps/management/routes/billing.js +1 -1
  105. package/dist/apps/management/routes/billing.js.map +1 -1
  106. package/dist/apps/management/routes/faucet.d.ts +35 -35
  107. package/dist/apps/management/routes/faucet.js +2 -2
  108. package/dist/apps/management/routes/faucet.js.map +1 -1
  109. package/dist/apps/management/routes/invitations.d.ts +134 -134
  110. package/dist/apps/management/routes/invite-links.d.ts +80 -80
  111. package/dist/apps/management/routes/members.d.ts +69 -69
  112. package/dist/apps/management/routes/orgs.d.ts +98 -98
  113. package/dist/apps/management/routes/projects.d.ts +60 -60
  114. package/dist/apps/management/routes/usage.d.ts +72 -72
  115. package/dist/apps/management/routes/verified-token-requests.d.ts +83 -83
  116. package/dist/apps/management/routes/webhooks.d.ts +203 -618
  117. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  118. package/dist/apps/mcp.d.ts.map +1 -1
  119. package/dist/apps/mcp.js +4 -1
  120. package/dist/apps/mcp.js.map +1 -1
  121. package/dist/apps/mpp/App.d.ts +56 -44
  122. package/dist/apps/mpp/App.d.ts.map +1 -1
  123. package/dist/apps/mpp/Mpp.d.ts +3 -0
  124. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  125. package/dist/apps/mpp/Mpp.js +3 -0
  126. package/dist/apps/mpp/Mpp.js.map +1 -1
  127. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  128. package/dist/apps/mpp/internal/Adapter.js +9 -2
  129. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  130. package/dist/db/Db.d.ts +4 -2
  131. package/dist/db/Db.d.ts.map +1 -1
  132. package/dist/db/Db.js +75 -15
  133. package/dist/db/Db.js.map +1 -1
  134. package/dist/db/Schema.d.ts +19 -0
  135. package/dist/db/Schema.d.ts.map +1 -1
  136. package/dist/db/Schema.js +24 -0
  137. package/dist/db/Schema.js.map +1 -1
  138. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  139. package/dist/db/tables/sponsoredTransactions.js +4 -1
  140. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  141. package/dist/db/tables/webhookQueueEvents.d.ts +122 -0
  142. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -0
  143. package/dist/db/tables/webhookQueueEvents.js +160 -0
  144. package/dist/db/tables/webhookQueueEvents.js.map +1 -0
  145. package/dist/db/tables/webhookSubscriptions.d.ts +58 -3
  146. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  147. package/dist/db/tables/webhookSubscriptions.js +86 -3
  148. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  149. package/dist/internal/Auth.d.ts +3 -0
  150. package/dist/internal/Auth.d.ts.map +1 -1
  151. package/dist/internal/Auth.js +6 -4
  152. package/dist/internal/Auth.js.map +1 -1
  153. package/dist/internal/MetricSink.d.ts +139 -3
  154. package/dist/internal/MetricSink.d.ts.map +1 -1
  155. package/dist/internal/MetricSink.js +144 -4
  156. package/dist/internal/MetricSink.js.map +1 -1
  157. package/dist/internal/RateLimit.d.ts +4 -6
  158. package/dist/internal/RateLimit.d.ts.map +1 -1
  159. package/dist/internal/RateLimit.js +15 -14
  160. package/dist/internal/RateLimit.js.map +1 -1
  161. package/dist/internal/Schema.js +1 -1
  162. package/dist/internal/Schema.js.map +1 -1
  163. package/dist/internal/Store.d.ts +2 -1
  164. package/dist/internal/Store.d.ts.map +1 -1
  165. package/dist/internal/Store.js +57 -18
  166. package/dist/internal/Store.js.map +1 -1
  167. package/dist/internal/Tidx.d.ts +1 -3
  168. package/dist/internal/Tidx.d.ts.map +1 -1
  169. package/dist/internal/Tidx.js +1 -3
  170. package/dist/internal/Tidx.js.map +1 -1
  171. package/dist/internal/Value.d.ts +2 -0
  172. package/dist/internal/Value.d.ts.map +1 -1
  173. package/dist/internal/Value.js +25 -0
  174. package/dist/internal/Value.js.map +1 -1
  175. package/dist/internal/Viem.d.ts.map +1 -1
  176. package/dist/internal/Viem.js +2 -1
  177. package/dist/internal/Viem.js.map +1 -1
  178. package/dist/internal/WebhookDestination.d.ts +2 -0
  179. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  180. package/dist/internal/WebhookDestination.js +11 -0
  181. package/dist/internal/WebhookDestination.js.map +1 -1
  182. package/dist/internal/WebhookTransfer.d.ts +75 -0
  183. package/dist/internal/WebhookTransfer.d.ts.map +1 -0
  184. package/dist/internal/WebhookTransfer.js +299 -0
  185. package/dist/internal/WebhookTransfer.js.map +1 -0
  186. package/dist/internal/Webhooks.d.ts +176 -0
  187. package/dist/internal/Webhooks.d.ts.map +1 -1
  188. package/dist/internal/Webhooks.js +216 -20
  189. package/dist/internal/Webhooks.js.map +1 -1
  190. package/dist/internal/funding/Provider.d.ts +4 -0
  191. package/dist/internal/funding/Provider.d.ts.map +1 -1
  192. package/dist/internal/funding/Provider.js +11 -7
  193. package/dist/internal/funding/Provider.js.map +1 -1
  194. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  195. package/dist/internal/funding/Reconciliation.js +128 -0
  196. package/dist/internal/funding/Reconciliation.js.map +1 -1
  197. package/dist/internal/funding/providers/relay.d.ts +6 -4
  198. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  199. package/dist/internal/funding/providers/relay.js +71 -9
  200. package/dist/internal/funding/providers/relay.js.map +1 -1
  201. package/package.json +4 -4
  202. package/src/ApiKeys.test.ts +20 -0
  203. package/src/ApiKeys.ts +28 -1
  204. package/src/App.test.ts +10 -8
  205. package/src/App.ts +1 -0
  206. package/src/Client.test-d.ts +61 -5
  207. package/src/Webhooks.bench.ts +714 -0
  208. package/src/Webhooks.memory.bench.ts +250 -0
  209. package/src/Webhooks.test.ts +77 -6
  210. package/src/Webhooks.ts +85 -29
  211. package/src/admin/apps/api-keys.test.ts +9 -0
  212. package/src/admin/apps/api-keys.ts +15 -0
  213. package/src/admin/ui/src/lib/query-client.ts +3 -2
  214. package/src/admin/ui/src/routes/api-keys.tsx +31 -9
  215. package/src/admin/ui.generated.ts +69 -69
  216. package/src/analytics/Analytics.test.ts +8 -0
  217. package/src/analytics/Analytics.ts +26 -0
  218. package/src/apps/Zones.test.ts +23 -5
  219. package/src/apps/Zones.ts +31 -10
  220. package/src/apps/composition.test.ts +1 -0
  221. package/src/apps/data/App.test.ts +2 -2
  222. package/src/apps/data/FxOracle.test.ts +18 -0
  223. package/src/apps/data/FxOracle.ts +28 -5
  224. package/src/apps/data/routes/activities.bench.ts +41 -0
  225. package/src/apps/data/routes/activities.test.ts +122 -2
  226. package/src/apps/data/routes/activities.ts +435 -32
  227. package/src/apps/data/routes/balances.bench.ts +21 -0
  228. package/src/apps/data/routes/balances.test.ts +119 -10
  229. package/src/apps/data/routes/balances.ts +164 -97
  230. package/src/apps/data/routes/blocks.bench.ts +34 -0
  231. package/src/apps/data/routes/blocks.test.ts +12 -6
  232. package/src/apps/data/routes/coingecko.bench.ts +53 -0
  233. package/src/apps/data/routes/earn.bench.ts +71 -0
  234. package/src/apps/data/routes/earn.test.ts +197 -0
  235. package/src/apps/data/routes/earn.ts +487 -45
  236. package/src/apps/data/routes/exchanges.bench.ts +85 -0
  237. package/src/apps/data/routes/exchanges.test.ts +7 -6
  238. package/src/apps/data/routes/exchanges.ts +124 -117
  239. package/src/apps/data/routes/fee-amm.bench.ts +13 -0
  240. package/src/apps/data/routes/indexer.bench.ts +8 -0
  241. package/src/apps/data/routes/indexer.test.ts +2 -1
  242. package/src/apps/data/routes/indexer.ts +3 -2
  243. package/src/apps/data/routes/receipts.bench.ts +39 -0
  244. package/src/apps/data/routes/receipts.test.ts +24 -7
  245. package/src/apps/data/routes/receipts.ts +67 -50
  246. package/src/apps/data/routes/rpc.bench.ts +14 -0
  247. package/src/apps/data/routes/rpc.test.ts +27 -0
  248. package/src/apps/data/routes/rpc.ts +5 -1
  249. package/src/apps/data/routes/tokenlist.bench.ts +3 -0
  250. package/src/apps/data/routes/tokens.bench.ts +76 -0
  251. package/src/apps/data/routes/tokens.test.ts +51 -0
  252. package/src/apps/data/routes/transactions.bench.ts +40 -0
  253. package/src/apps/data/routes/transactions.test.ts +42 -0
  254. package/src/apps/data/routes/transactions.ts +44 -39
  255. package/src/apps/data/routes/transfers.bench.ts +28 -0
  256. package/src/apps/data/routes/transfers.test.ts +402 -24
  257. package/src/apps/data/routes/transfers.ts +708 -101
  258. package/src/apps/data/routes/valuation.bench.ts +14 -0
  259. package/src/apps/data/routes/valuation.test.ts +26 -0
  260. package/src/apps/data/routes/valuation.ts +6 -2
  261. package/src/apps/data/routes/verified-tokens.bench.ts +8 -0
  262. package/src/apps/data/routes/webhooks.bench.ts +26 -0
  263. package/src/apps/data/routes/webhooks.scan.test.ts +326 -0
  264. package/src/apps/data/routes/webhooks.test.ts +466 -135
  265. package/src/apps/data/routes/webhooks.ts +820 -429
  266. package/src/apps/data/routes/zones.bench.ts +32 -0
  267. package/src/apps/data/routes/zones.test.ts +1 -1
  268. package/src/apps/data/routes/zones.ts +7 -2
  269. package/src/apps/funding/routes/chains.test.ts +1 -1
  270. package/src/apps/funding/routes/deposit-addresses.test.ts +1 -1
  271. package/src/apps/funding/routes/deposit-addresses.ts +1 -1
  272. package/src/apps/funding/routes/providers.test.ts +1 -1
  273. package/src/apps/funding/routes/quotes.test.ts +2 -2
  274. package/src/apps/funding/routes/transfers.test.ts +3 -6
  275. package/src/apps/funding/routes/transfers.ts +1 -1
  276. package/src/apps/management/routes/billing.ts +1 -1
  277. package/src/apps/management/routes/faucet.ts +2 -2
  278. package/src/apps/management/routes/me.test.ts +31 -0
  279. package/src/apps/mcp.ts +4 -1
  280. package/src/apps/mpp/Mpp.test.ts +13 -1
  281. package/src/apps/mpp/Mpp.ts +8 -0
  282. package/src/apps/mpp/internal/Adapter.ts +10 -2
  283. package/src/db/Db.test.ts +40 -6
  284. package/src/db/Db.ts +114 -19
  285. package/src/db/Schema.ts +32 -0
  286. package/src/db/tables/sponsoredTransactions.ts +9 -2
  287. package/src/db/tables/webhookQueueEvents.ts +285 -0
  288. package/src/db/tables/webhookSubscriptions.ts +131 -4
  289. package/src/internal/Auth.test.ts +61 -50
  290. package/src/internal/Auth.ts +9 -4
  291. package/src/internal/EarnVaults.test.ts +2 -2
  292. package/src/internal/MetricSink.test.ts +575 -0
  293. package/src/internal/MetricSink.ts +325 -10
  294. package/src/internal/RateLimit.test.ts +23 -18
  295. package/src/internal/RateLimit.ts +23 -15
  296. package/src/internal/Schema.ts +1 -1
  297. package/src/internal/Store.test.ts +99 -13
  298. package/src/internal/Store.ts +52 -17
  299. package/src/internal/Tidx.test.ts +4 -4
  300. package/src/internal/Tidx.ts +1 -3
  301. package/src/internal/Value.test.ts +25 -0
  302. package/src/internal/Value.ts +29 -0
  303. package/src/internal/Viem.test.ts +8 -0
  304. package/src/internal/Viem.ts +2 -1
  305. package/src/internal/WebhookDestination.test.ts +20 -0
  306. package/src/internal/WebhookDestination.ts +10 -0
  307. package/src/internal/WebhookTransfer.test.ts +89 -0
  308. package/src/internal/WebhookTransfer.ts +430 -0
  309. package/src/internal/Webhooks.test.ts +616 -0
  310. package/src/internal/Webhooks.ts +412 -24
  311. package/src/internal/funding/Provider.test.ts +48 -8
  312. package/src/internal/funding/Provider.ts +12 -7
  313. package/src/internal/funding/Reconciliation.local.test.ts +3 -1
  314. package/src/internal/funding/Reconciliation.test.ts +1240 -0
  315. package/src/internal/funding/Reconciliation.ts +136 -0
  316. package/src/internal/funding/SourceObservation.test.ts +1 -0
  317. package/src/internal/funding/providers/index.test.ts +73 -3
  318. package/src/internal/funding/providers/relay.test.ts +2 -9
  319. package/src/internal/funding/providers/relay.ts +72 -13
@@ -0,0 +1,53 @@
1
+ import * as QueryBench from '../../../../test/QueryBench.js'
2
+
3
+ const pairId = {
4
+ 4217: '0xc91fa403390f4eaf7f555b1ee33f54408befc79c5665728a2ac7e7ffa39c42ef',
5
+ 42431: '0xb2b3f6d58ad8554d56200ebcd347ee2461a07276b764e0c0daf56b192bc7d341',
6
+ } as const
7
+
8
+ const block = { 4217: 34_335_551, 42431: 30_469_074 } as const
9
+
10
+ QueryBench.bench({
11
+ chainId: false,
12
+ name: 'coingeckoLatestBlock',
13
+ path: { 4217: '/gecko/4217/latest-block', 42431: '/gecko/42431/latest-block' },
14
+ })
15
+
16
+ QueryBench.bench({
17
+ chainId: false,
18
+ name: 'coingeckoAsset',
19
+ path: {
20
+ 4217: `/gecko/4217/assets/${QueryBench.pathUsd}`,
21
+ 42431: `/gecko/42431/assets/${QueryBench.pathUsd}`,
22
+ },
23
+ })
24
+
25
+ QueryBench.bench({
26
+ chainId: false,
27
+ name: 'coingeckoPairs',
28
+ path: { 4217: '/gecko/4217/pairs', 42431: '/gecko/42431/pairs' },
29
+ })
30
+
31
+ QueryBench.bench({
32
+ chainId: false,
33
+ name: 'coingeckoPair',
34
+ path: {
35
+ 4217: `/gecko/4217/pairs/${pairId[4217]}`,
36
+ 42431: `/gecko/42431/pairs/${pairId[42431]}`,
37
+ },
38
+ })
39
+
40
+ QueryBench.bench({
41
+ chainId: false,
42
+ name: 'coingeckoEvents',
43
+ path: { 4217: '/gecko/4217/events', 42431: '/gecko/42431/events' },
44
+ })
45
+
46
+ QueryBench.bench({
47
+ chainId: false,
48
+ name: 'coingeckoEvents?fromBlock&toBlock',
49
+ path: {
50
+ 4217: `/gecko/4217/events?fromBlock=${block[4217] - 100}&toBlock=${block[4217]}`,
51
+ 42431: `/gecko/42431/events?fromBlock=${block[42431] - 100}&toBlock=${block[42431]}`,
52
+ },
53
+ })
@@ -0,0 +1,71 @@
1
+ import * as QueryBench from '../../../../test/QueryBench.js'
2
+
3
+ const fixtures = {
4
+ 4217: {
5
+ address: '0xbe058e1c4df8a4366a387bf595b284246a93039e',
6
+ vault: '0xf06e5740e5c72f61a10cf8149fa145fee48e560e',
7
+ },
8
+ 42431: {
9
+ address: '0x68f94cfca22e5969c0553bbeab00a2acde88939b',
10
+ vault: '0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a',
11
+ },
12
+ } as const
13
+
14
+ const vaultQueries = [
15
+ 'apy.window=1d',
16
+ 'include=access',
17
+ 'include=apy',
18
+ 'include=capabilities',
19
+ 'include=token.logoUri',
20
+ 'include=tvl',
21
+ 'include=zone',
22
+ ] as const
23
+
24
+ const collectionQueries = ['capability=deposit', ...vaultQueries] as const
25
+
26
+ QueryBench.bench({
27
+ name: 'getEarnVaults',
28
+ path: '/v1/earn/vaults',
29
+ queries: collectionQueries,
30
+ })
31
+
32
+ QueryBench.bench({
33
+ name: 'getVerifiedEarnVaults',
34
+ path: '/v1/earn/vaults/verified',
35
+ queries: collectionQueries,
36
+ })
37
+
38
+ QueryBench.bench({
39
+ name: 'getEarnAddressPositions',
40
+ path: {
41
+ 4217: `/v1/earn/addresses/${fixtures[4217].address}/positions`,
42
+ 42431: `/v1/earn/addresses/${fixtures[42431].address}/positions`,
43
+ },
44
+ queries: ['valuation.currency=USD', 'verified=true'],
45
+ })
46
+
47
+ QueryBench.bench({
48
+ name: 'getEarnVaultPosition',
49
+ path: {
50
+ 4217: `/v1/earn/vaults/${fixtures[4217].vault}/positions/${fixtures[4217].address}`,
51
+ 42431: `/v1/earn/vaults/${fixtures[42431].vault}/positions/${fixtures[42431].address}`,
52
+ },
53
+ })
54
+
55
+ QueryBench.bench({
56
+ name: 'getEarnVaultEarnings',
57
+ path: {
58
+ 4217: `/v1/earn/vaults/${fixtures[4217].vault}/earnings/${fixtures[4217].address}`,
59
+ 42431: `/v1/earn/vaults/${fixtures[42431].vault}/earnings/${fixtures[42431].address}`,
60
+ },
61
+ queries: ['period=30d', 'period=active'],
62
+ })
63
+
64
+ QueryBench.bench({
65
+ name: 'getEarnVault',
66
+ path: {
67
+ 4217: `/v1/earn/vaults/${fixtures[4217].vault}`,
68
+ 42431: `/v1/earn/vaults/${fixtures[42431].vault}`,
69
+ },
70
+ queries: vaultQueries,
71
+ })
@@ -88,6 +88,33 @@ describe('schema.getEarnVaults.Query', () => {
88
88
  })
89
89
  })
90
90
 
91
+ describe('schema.getEarnAddressPositions.Query', () => {
92
+ test('parses collection filters', () => {
93
+ const query = Earn.schema.getEarnAddressPositions.Query.parse({
94
+ limit: '5',
95
+ 'valuation.currency': 'usd',
96
+ verified: 'true',
97
+ })
98
+
99
+ expect(query.limit).toBe(5)
100
+ expect(query['valuation.currency']).toBe('USD')
101
+ expect(query.verified).toBe(true)
102
+ })
103
+
104
+ test('defaults the page size', () => {
105
+ expect(Earn.schema.getEarnAddressPositions.Query.parse({}).limit).toBe(10)
106
+ })
107
+
108
+ test('rejects vault-collection filters', () => {
109
+ expect(() =>
110
+ Earn.schema.getEarnAddressPositions.Query.parse({ capability: 'deposit' }),
111
+ ).toThrow()
112
+ expect(() =>
113
+ Earn.schema.getEarnAddressPositions.Query.parse({ asset: `0x${'aa'.repeat(20)}` }),
114
+ ).toThrow()
115
+ })
116
+ })
117
+
91
118
  describe('schema.getEarnVaultEarnings.Response', () => {
92
119
  test('enforces status-specific earnings fields', () => {
93
120
  const response = {
@@ -540,6 +567,144 @@ describe('GET /v1/earn/vaults/verified', () => {
540
567
  )
541
568
  })
542
569
 
570
+ describe('GET /v1/earn/addresses/:address/positions', () => {
571
+ test('returns chain selection errors', async () => {
572
+ const app = TestApp.create({ auth: false, cache })
573
+ const invalid = await app.request(
574
+ `/v1/earn/addresses/${TestEarn.positionAddress}/positions?chainId=abc`,
575
+ )
576
+ const unsupported = await app.request(
577
+ `/v1/earn/addresses/${TestEarn.positionAddress}/positions?chainId=999999`,
578
+ )
579
+
580
+ expect([
581
+ (await TestApp.json(invalid, Schema.ErrorResponse)).error.code,
582
+ (await TestApp.json(unsupported, Schema.ErrorResponse)).error.code,
583
+ ]).toStrictEqual(['chain_id_invalid', 'chain_id_unsupported'])
584
+ })
585
+
586
+ test('rejects a malformed account address', async () => {
587
+ const response = await TestApp.create({ auth: false, cache }).request(
588
+ '/v1/earn/addresses/not-an-address/positions',
589
+ )
590
+
591
+ expect(response.status).toBe(400)
592
+ expect(await TestApp.json(response, Schema.ErrorResponse)).toMatchObject({
593
+ error: { code: 'positions_invalid' },
594
+ })
595
+ })
596
+
597
+ test('returns an empty verified page without curated vaults', async () => {
598
+ const app = TestApp.create({ auth: false, cache })
599
+ const response = await app.request(
600
+ `/v1/earn/addresses/${TestEarn.positionAddress}/positions?verified=true`,
601
+ )
602
+
603
+ expect(response.status).toBe(200)
604
+ expect(
605
+ await TestApp.json(response, Earn.schema.getEarnAddressPositions.Response),
606
+ ).toStrictEqual({ data: [], nextCursor: null })
607
+ })
608
+
609
+ test.runIf(Runtime.get().mode === 'testnet')(
610
+ 'lists non-zero verified positions for an account',
611
+ async () => {
612
+ const db = TestApp.database()
613
+ // Valuation resolves through the curated verified list, so seed it.
614
+ await TestApp.verifiedSeed(db, TestEarn.chain.id)
615
+ await core_EarnVaults.upsert(db, TestEarn.verifiedVault)
616
+ await core_EarnVaults.upsert(db, {
617
+ ...TestEarn.verifiedVault,
618
+ description: 'Active-earnings Earn deployment.',
619
+ label: 'Active btPATHUSD Earn',
620
+ vaultAddress: TestEarn.activeEarningsVaultAddress,
621
+ })
622
+ const app = TestApp.create({ auth: false, cache, db, zones: [TestEarn.zone] })
623
+ const response = await app.request(
624
+ `/v1/earn/addresses/${TestEarn.activeEarningsAddress}/positions?chainId=${TestEarn.chain.id}&verified=true&valuation.currency=USD`,
625
+ )
626
+
627
+ expect(response.status).toBe(200)
628
+ const body = await TestApp.json(response, Earn.schema.getEarnAddressPositions.Response)
629
+ expect(body.data.every((position) => BigInt(position.shareAmount.amount) > 0n)).toBe(true)
630
+ const row = body.data.find(
631
+ (position) => position.vaultAddress === TestEarn.activeEarningsVaultAddress,
632
+ )
633
+ expect(row).toBeDefined()
634
+ if (!row) return
635
+ // Amounts render in their own token's display currency and precision.
636
+ expect(row.shareAmount.currency).toBe(row.shareToken.currency)
637
+ expect(row.shareAmount.decimals).toBe(row.shareToken.decimals)
638
+ expect(row.assetAmount.currency).toBe(row.assetToken.currency)
639
+ expect(row.assetAmount.decimals).toBe(row.assetToken.decimals)
640
+ // A USD-denominated asset values identically without consulting rates.
641
+ expect(row.valuation).toStrictEqual({ amount: row.assetAmount.formatted, currency: 'USD' })
642
+ expect(body.meta).toBeUndefined()
643
+ expect({
644
+ assetToken: row.assetToken.address,
645
+ formattedShape: /^\d+(\.\d+)?$/.test(row.assetAmount.formatted),
646
+ id: row.id,
647
+ sharesHeld: BigInt(row.shareAmount.amount) > 0n,
648
+ valued: BigInt(row.assetAmount.amount) > 0n,
649
+ vaultAddress: row.vaultAddress,
650
+ verified: row.verified,
651
+ }).toMatchInlineSnapshot(`
652
+ {
653
+ "assetToken": "0x20c0000000000000000000000000000000000001",
654
+ "formattedShape": true,
655
+ "id": "0x3e4405801a1bee1b58394228ea0b44b667e222fc",
656
+ "sharesHeld": true,
657
+ "valued": true,
658
+ "vaultAddress": "0x3e4405801a1bee1b58394228ea0b44b667e222fc",
659
+ "verified": true,
660
+ }
661
+ `)
662
+ },
663
+ 60_000,
664
+ )
665
+
666
+ test.runIf(Runtime.get().mode === 'testnet')(
667
+ 'discovers held vaults from indexed share balances',
668
+ async () => {
669
+ const app = TestApp.create({ auth: false, cache, zones: [TestEarn.zone] })
670
+ const response = await app.request(
671
+ `/v1/earn/addresses/${TestEarn.activeEarningsAddress}/positions?chainId=${TestEarn.chain.id}`,
672
+ )
673
+
674
+ expect(response.status).toBe(200)
675
+ const body = await TestApp.json(response, Earn.schema.getEarnAddressPositions.Response)
676
+ expect(body.data.map((position) => position.vaultAddress)).toContain(
677
+ TestEarn.activeEarningsVaultAddress,
678
+ )
679
+ expect(
680
+ body.data.every(
681
+ (position) =>
682
+ position.id === position.vaultAddress &&
683
+ !position.verified &&
684
+ /^\d+$/.test(position.assetAmount.amount) &&
685
+ BigInt(position.shareAmount.amount) > 0n &&
686
+ position.assetToken.address.startsWith('0x20c0') &&
687
+ position.shareToken.address.startsWith('0x20c0'),
688
+ ),
689
+ ).toBe(true)
690
+
691
+ // An address-keyset cursor excludes every vault at or before it.
692
+ const cursor = Cursor.encode([TestEarn.activeEarningsVaultAddress])
693
+ const paged = await app.request(
694
+ `/v1/earn/addresses/${TestEarn.activeEarningsAddress}/positions?chainId=${TestEarn.chain.id}&cursor=${encodeURIComponent(cursor)}`,
695
+ )
696
+ expect(paged.status).toBe(200)
697
+ const pagedBody = await TestApp.json(paged, Earn.schema.getEarnAddressPositions.Response)
698
+ expect(
699
+ pagedBody.data.every(
700
+ (position) => position.vaultAddress > TestEarn.activeEarningsVaultAddress,
701
+ ),
702
+ ).toBe(true)
703
+ },
704
+ 90_000,
705
+ )
706
+ })
707
+
543
708
  describe('GET /v1/earn/vaults/:vaultId', () => {
544
709
  test('rejects a malformed vault address', async () => {
545
710
  const app = TestApp.create({ auth: false, cache })
@@ -1375,6 +1540,7 @@ describe('OpenAPI', () => {
1375
1540
 
1376
1541
  expect(Object.keys(spec.paths)).toEqual(
1377
1542
  expect.arrayContaining([
1543
+ '/v1/earn/addresses/{address}/positions',
1378
1544
  '/v1/earn/vaults',
1379
1545
  '/v1/earn/vaults/verified',
1380
1546
  '/v1/earn/vaults/{vaultId}',
@@ -1446,6 +1612,37 @@ describe('OpenAPI', () => {
1446
1612
  expect(vaultId?.schema?.examples).toStrictEqual([TestEarn.mainnetVaultAddress])
1447
1613
  })
1448
1614
 
1615
+ test('documents address-position inputs and responses', async () => {
1616
+ const app = TestApp.create({ auth: false, cache })
1617
+ const spec = (await (await app.request('/openapi.json')).json()) as OpenApiDocument
1618
+ const operation = spec.paths['/v1/earn/addresses/{address}/positions']?.get
1619
+ const address = operation?.parameters?.find((parameter) => parameter.name === 'address')
1620
+ const denomination = operation?.parameters?.find(
1621
+ (parameter) => parameter.name === 'valuation.currency',
1622
+ )
1623
+ const verified = operation?.parameters?.find((parameter) => parameter.name === 'verified')
1624
+ const response = JSON.stringify(operation?.responses)
1625
+
1626
+ expect(operation?.description).toContain('currently holds shares')
1627
+ expect(address?.schema?.examples).toStrictEqual([TestEarn.positionAddress])
1628
+ expect(denomination?.description).toContain('nominal value')
1629
+ expect(verified?.description).toContain('registry-curated')
1630
+ expect(verified?.schema?.examples).toStrictEqual([true])
1631
+ expect(response).toContain('"chain_id_invalid"')
1632
+ expect(response).toContain('"chain_id_unsupported"')
1633
+ expect(response).toContain('"positions_invalid"')
1634
+ expect(response).toContain('"query_invalid"')
1635
+ expect(response).toContain('Stable resource ID for this position')
1636
+ expect(response).toContain('Current asset value of the held shares')
1637
+ expect(response).toContain('"assetAmount"')
1638
+ expect(response).toContain('"shareAmount"')
1639
+ expect(response).toContain('"valuation"')
1640
+ expect(response).toContain('"vaultAddress"')
1641
+ expect(response).toContain('"nextCursor"')
1642
+ // Token references embed the trimmed token object, not a bare address.
1643
+ expect(response).toContain('"symbol"')
1644
+ })
1645
+
1449
1646
  test('documents vault-earnings variants', async () => {
1450
1647
  const app = TestApp.create({ auth: false, cache })
1451
1648
  const spec = (await (await app.request('/openapi.json')).json()) as OpenApiDocument