tapimo 0.7.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/README.md +10 -7
  2. package/dist/ApiKey.d.ts +3 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +10 -0
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +7 -3
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +9 -2
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +20434 -19484
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +62 -4
  13. package/dist/App.js.map +1 -1
  14. package/dist/admin/App.d.ts +84 -74
  15. package/dist/admin/App.d.ts.map +1 -1
  16. package/dist/admin/apps/api-keys.d.ts +14 -1
  17. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  18. package/dist/admin/apps/api-keys.js +6 -2
  19. package/dist/admin/apps/api-keys.js.map +1 -1
  20. package/dist/admin/apps/organizations.d.ts +2 -0
  21. package/dist/admin/apps/organizations.d.ts.map +1 -1
  22. package/dist/admin/apps/verified-tokens.d.ts +168 -168
  23. package/dist/admin/ui.generated.d.ts +1 -1
  24. package/dist/admin/ui.generated.js +67 -67
  25. package/dist/admin/ui.generated.js.map +1 -1
  26. package/dist/analytics/Analytics.d.ts +2 -0
  27. package/dist/analytics/Analytics.d.ts.map +1 -1
  28. package/dist/analytics/Analytics.js +3 -0
  29. package/dist/analytics/Analytics.js.map +1 -1
  30. package/dist/apps/data/App.d.ts +10305 -12785
  31. package/dist/apps/data/App.d.ts.map +1 -1
  32. package/dist/apps/data/App.js +4 -8
  33. package/dist/apps/data/App.js.map +1 -1
  34. package/dist/apps/data/routes/activities.d.ts +24 -24
  35. package/dist/apps/data/routes/addresses.d.ts +288 -288
  36. package/dist/apps/data/routes/balances.d.ts +6 -6
  37. package/dist/apps/data/routes/blocks.d.ts +39 -39
  38. package/dist/apps/data/routes/coingecko.d.ts +170 -170
  39. package/dist/apps/data/routes/earn.d.ts +436 -6
  40. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  41. package/dist/apps/data/routes/earn.js +631 -4
  42. package/dist/apps/data/routes/earn.js.map +1 -1
  43. package/dist/apps/data/routes/exchanges.d.ts +10 -10
  44. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  45. package/dist/apps/data/routes/indexer.d.ts +6 -6
  46. package/dist/apps/data/routes/indexer.js +4 -1
  47. package/dist/apps/data/routes/indexer.js.map +1 -1
  48. package/dist/apps/data/routes/receipts.d.ts +235 -235
  49. package/dist/apps/data/routes/rpc.d.ts +1 -1
  50. package/dist/apps/data/routes/rpc.js +4 -1
  51. package/dist/apps/data/routes/rpc.js.map +1 -1
  52. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  53. package/dist/apps/data/routes/tokens.d.ts +6 -6
  54. package/dist/apps/data/routes/transactions.d.ts +2 -2
  55. package/dist/apps/data/routes/transfers.d.ts +1 -1
  56. package/dist/apps/data/routes/valuation.d.ts +1 -1
  57. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  58. package/dist/apps/data/routes/webhooks.d.ts +9 -9
  59. package/dist/apps/data/routes/zones.d.ts +14 -14
  60. package/dist/apps/funding/Access.d.ts +16 -0
  61. package/dist/apps/funding/Access.d.ts.map +1 -0
  62. package/dist/apps/funding/Access.js +22 -0
  63. package/dist/apps/funding/Access.js.map +1 -0
  64. package/dist/apps/{data/routes/funding.d.ts → funding/App.d.ts} +1717 -3035
  65. package/dist/apps/funding/App.d.ts.map +1 -0
  66. package/dist/apps/funding/App.js +46 -0
  67. package/dist/apps/funding/App.js.map +1 -0
  68. package/dist/apps/funding/Inventory.d.ts +5 -0
  69. package/dist/apps/funding/Inventory.d.ts.map +1 -0
  70. package/dist/apps/funding/Inventory.js +25 -0
  71. package/dist/apps/funding/Inventory.js.map +1 -0
  72. package/dist/apps/funding/ProviderAttempts.d.ts +5 -0
  73. package/dist/apps/funding/ProviderAttempts.d.ts.map +1 -0
  74. package/dist/apps/funding/ProviderAttempts.js +24 -0
  75. package/dist/apps/funding/ProviderAttempts.js.map +1 -0
  76. package/dist/apps/funding/index.d.ts +2 -0
  77. package/dist/apps/funding/index.d.ts.map +1 -0
  78. package/dist/apps/funding/index.js +2 -0
  79. package/dist/apps/funding/index.js.map +1 -0
  80. package/dist/apps/funding/routes/chains.d.ts +169 -0
  81. package/dist/apps/funding/routes/chains.d.ts.map +1 -0
  82. package/dist/apps/funding/routes/chains.js +80 -0
  83. package/dist/apps/funding/routes/chains.js.map +1 -0
  84. package/dist/apps/funding/routes/deposit-addresses.d.ts +2388 -0
  85. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -0
  86. package/dist/apps/funding/routes/deposit-addresses.js +860 -0
  87. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -0
  88. package/dist/apps/funding/routes/providers.d.ts +91 -0
  89. package/dist/apps/funding/routes/providers.d.ts.map +1 -0
  90. package/dist/apps/funding/routes/providers.js +56 -0
  91. package/dist/apps/funding/routes/providers.js.map +1 -0
  92. package/dist/apps/funding/routes/quotes.d.ts +426 -0
  93. package/dist/apps/funding/routes/quotes.d.ts.map +1 -0
  94. package/dist/apps/funding/routes/quotes.js +188 -0
  95. package/dist/apps/funding/routes/quotes.js.map +1 -0
  96. package/dist/apps/funding/routes/transfers.d.ts +1999 -0
  97. package/dist/apps/funding/routes/transfers.d.ts.map +1 -0
  98. package/dist/apps/funding/routes/transfers.js +614 -0
  99. package/dist/apps/funding/routes/transfers.js.map +1 -0
  100. package/dist/apps/index.d.ts +1 -0
  101. package/dist/apps/index.d.ts.map +1 -1
  102. package/dist/apps/index.js +1 -0
  103. package/dist/apps/index.js.map +1 -1
  104. package/dist/apps/management/App.d.ts +430 -165
  105. package/dist/apps/management/App.d.ts.map +1 -1
  106. package/dist/apps/management/routes/api-keys.d.ts +298 -21
  107. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  108. package/dist/apps/management/routes/api-keys.js +75 -1
  109. package/dist/apps/management/routes/api-keys.js.map +1 -1
  110. package/dist/apps/management/routes/billing.d.ts +6 -6
  111. package/dist/apps/management/routes/faucet.d.ts +35 -35
  112. package/dist/apps/management/routes/invitations.d.ts +48 -48
  113. package/dist/apps/management/routes/invite-links.d.ts +38 -38
  114. package/dist/apps/management/routes/members.d.ts +69 -69
  115. package/dist/apps/management/routes/orgs.d.ts +37 -37
  116. package/dist/apps/management/routes/projects.d.ts +25 -25
  117. package/dist/apps/management/routes/scopes.d.ts +1 -1
  118. package/dist/apps/management/routes/usage.d.ts +72 -72
  119. package/dist/apps/management/routes/verified-token-requests.d.ts +18 -18
  120. package/dist/apps/management/routes/webhooks.d.ts +128 -128
  121. package/dist/apps/mcp.d.ts +2 -3
  122. package/dist/apps/mcp.d.ts.map +1 -1
  123. package/dist/apps/mcp.js +16 -14
  124. package/dist/apps/mcp.js.map +1 -1
  125. package/dist/apps/metadata.d.ts +4 -0
  126. package/dist/apps/metadata.d.ts.map +1 -1
  127. package/dist/apps/metadata.js +10 -0
  128. package/dist/apps/metadata.js.map +1 -1
  129. package/dist/apps/mpp/App.d.ts +2 -2
  130. package/dist/cloudflare.d.ts +50 -0
  131. package/dist/cloudflare.d.ts.map +1 -1
  132. package/dist/cloudflare.js +178 -0
  133. package/dist/cloudflare.js.map +1 -1
  134. package/dist/db/Db.d.ts +2 -0
  135. package/dist/db/Db.d.ts.map +1 -1
  136. package/dist/db/Db.js +37 -0
  137. package/dist/db/Db.js.map +1 -1
  138. package/dist/db/Schema.d.ts +12 -0
  139. package/dist/db/Schema.d.ts.map +1 -1
  140. package/dist/db/Schema.js +20 -0
  141. package/dist/db/Schema.js.map +1 -1
  142. package/dist/db/tables/fundingDepositAddresses.d.ts +13 -0
  143. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
  144. package/dist/db/tables/fundingDepositAddresses.js +12 -0
  145. package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
  146. package/dist/db/tables/fundingDepositRequestObservations.d.ts +45 -0
  147. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +1 -0
  148. package/dist/db/tables/fundingDepositRequestObservations.js +46 -0
  149. package/dist/db/tables/fundingDepositRequestObservations.js.map +1 -0
  150. package/dist/db/tables/fundingDeposits.d.ts +57 -1
  151. package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
  152. package/dist/db/tables/fundingDeposits.js +82 -0
  153. package/dist/db/tables/fundingDeposits.js.map +1 -1
  154. package/dist/internal/Auth.d.ts +11 -11
  155. package/dist/internal/Auth.d.ts.map +1 -1
  156. package/dist/internal/Auth.js +41 -15
  157. package/dist/internal/Auth.js.map +1 -1
  158. package/dist/internal/Cache.js +1 -1
  159. package/dist/internal/Cache.js.map +1 -1
  160. package/dist/internal/EdgeCache.d.ts +2 -2
  161. package/dist/internal/EdgeCache.d.ts.map +1 -1
  162. package/dist/internal/EdgeCache.js +10 -4
  163. package/dist/internal/EdgeCache.js.map +1 -1
  164. package/dist/internal/IpAllowlist.d.ts +15 -0
  165. package/dist/internal/IpAllowlist.d.ts.map +1 -0
  166. package/dist/internal/IpAllowlist.js +27 -0
  167. package/dist/internal/IpAllowlist.js.map +1 -0
  168. package/dist/internal/OpenApi.d.ts +1 -1
  169. package/dist/internal/OpenApi.js +1 -1
  170. package/dist/internal/OpenApi.js.map +1 -1
  171. package/dist/internal/Tidx.d.ts +6 -0
  172. package/dist/internal/Tidx.d.ts.map +1 -1
  173. package/dist/internal/Tidx.js +13 -3
  174. package/dist/internal/Tidx.js.map +1 -1
  175. package/dist/internal/Viem.d.ts +8 -0
  176. package/dist/internal/Viem.d.ts.map +1 -1
  177. package/dist/internal/Viem.js +12 -5
  178. package/dist/internal/Viem.js.map +1 -1
  179. package/dist/internal/funding/Deposit.d.ts +42 -0
  180. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  181. package/dist/internal/funding/Deposit.js +37 -5
  182. package/dist/internal/funding/Deposit.js.map +1 -1
  183. package/dist/internal/funding/Evidence.d.ts +1 -5
  184. package/dist/internal/funding/Evidence.d.ts.map +1 -1
  185. package/dist/internal/funding/Evidence.js +4 -3
  186. package/dist/internal/funding/Evidence.js.map +1 -1
  187. package/dist/internal/funding/Provider.d.ts +102 -0
  188. package/dist/internal/funding/Provider.d.ts.map +1 -1
  189. package/dist/internal/funding/Provider.js +5 -0
  190. package/dist/internal/funding/Provider.js.map +1 -1
  191. package/dist/internal/funding/Reconciliation.d.ts +16 -2
  192. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  193. package/dist/internal/funding/Reconciliation.js +257 -48
  194. package/dist/internal/funding/Reconciliation.js.map +1 -1
  195. package/dist/internal/funding/SourceObservation.d.ts +108 -0
  196. package/dist/internal/funding/SourceObservation.d.ts.map +1 -0
  197. package/dist/internal/funding/SourceObservation.js +143 -0
  198. package/dist/internal/funding/SourceObservation.js.map +1 -0
  199. package/dist/internal/funding/Subsidy.d.ts +2 -2
  200. package/dist/internal/funding/Subsidy.d.ts.map +1 -1
  201. package/dist/internal/funding/Subsidy.js +1 -1
  202. package/dist/internal/funding/Subsidy.js.map +1 -1
  203. package/dist/internal/funding/index.d.ts +1 -0
  204. package/dist/internal/funding/index.d.ts.map +1 -1
  205. package/dist/internal/funding/index.js +1 -0
  206. package/dist/internal/funding/index.js.map +1 -1
  207. package/dist/internal/funding/providers/relay.d.ts +43 -1
  208. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  209. package/dist/internal/funding/providers/relay.js +434 -27
  210. package/dist/internal/funding/providers/relay.js.map +1 -1
  211. package/package.json +3 -3
  212. package/src/ApiKey.test.ts +35 -0
  213. package/src/ApiKey.ts +27 -0
  214. package/src/ApiKeys.test.ts +29 -0
  215. package/src/ApiKeys.ts +11 -3
  216. package/src/App.test.ts +23 -5
  217. package/src/App.ts +76 -5
  218. package/src/Client.test-d.ts +171 -19
  219. package/src/admin/apps/api-keys.test.ts +25 -1
  220. package/src/admin/apps/api-keys.ts +6 -2
  221. package/src/admin/ui.generated.ts +67 -67
  222. package/src/analytics/Analytics.ts +4 -0
  223. package/src/apps/composition.test.ts +100 -2
  224. package/src/apps/data/App.test.ts +0 -12
  225. package/src/apps/data/App.ts +4 -8
  226. package/src/apps/data/routes/earn.test.ts +283 -0
  227. package/src/apps/data/routes/earn.ts +800 -3
  228. package/src/apps/data/routes/indexer.ts +2 -1
  229. package/src/apps/data/routes/rpc.ts +2 -0
  230. package/src/apps/data/routes/tokens.test.ts +6 -8
  231. package/src/apps/funding/Access.ts +26 -0
  232. package/src/apps/funding/App.test.ts +78 -0
  233. package/src/apps/funding/App.ts +63 -0
  234. package/src/apps/funding/Inventory.ts +30 -0
  235. package/src/apps/funding/ProviderAttempts.ts +26 -0
  236. package/src/apps/funding/index.ts +1 -0
  237. package/src/apps/funding/routes/chains.test.ts +78 -0
  238. package/src/apps/funding/routes/chains.ts +101 -0
  239. package/src/apps/funding/routes/deposit-addresses.test.ts +1628 -0
  240. package/src/apps/funding/routes/deposit-addresses.ts +1015 -0
  241. package/src/apps/funding/routes/providers.test.ts +165 -0
  242. package/src/apps/funding/routes/providers.ts +73 -0
  243. package/src/apps/funding/routes/quotes.test.ts +511 -0
  244. package/src/apps/funding/routes/quotes.ts +205 -0
  245. package/src/apps/funding/routes/transfers.test.ts +1255 -0
  246. package/src/apps/funding/routes/transfers.ts +704 -0
  247. package/src/apps/index.ts +1 -0
  248. package/src/apps/management/routes/api-keys.test.ts +98 -0
  249. package/src/apps/management/routes/api-keys.ts +96 -1
  250. package/src/apps/mcp.test.ts +17 -2
  251. package/src/apps/mcp.ts +18 -13
  252. package/src/apps/metadata.ts +12 -0
  253. package/src/apps/mpp/internal/Policy.test.ts +7 -1
  254. package/src/cloudflare.ts +279 -0
  255. package/src/db/Db.ts +62 -0
  256. package/src/db/Schema.ts +24 -0
  257. package/src/db/tables/fundingDepositAddresses.ts +28 -0
  258. package/src/db/tables/fundingDepositRequestObservations.test.ts +106 -0
  259. package/src/db/tables/fundingDepositRequestObservations.ts +99 -0
  260. package/src/db/tables/fundingDeposits.test.ts +138 -0
  261. package/src/db/tables/fundingDeposits.ts +145 -1
  262. package/src/internal/Auth.test.ts +177 -5
  263. package/src/internal/Auth.ts +48 -18
  264. package/src/internal/Cache.test.ts +37 -3
  265. package/src/internal/Cache.ts +1 -1
  266. package/src/internal/EdgeCache.test.ts +7 -7
  267. package/src/internal/EdgeCache.ts +13 -4
  268. package/src/internal/IpAllowlist.test.ts +52 -0
  269. package/src/internal/IpAllowlist.ts +39 -0
  270. package/src/internal/Log.test.ts +7 -1
  271. package/src/internal/OpenApi.ts +1 -1
  272. package/src/internal/Tidx.test.ts +28 -0
  273. package/src/internal/Tidx.ts +19 -3
  274. package/src/internal/Viem.test.ts +28 -0
  275. package/src/internal/Viem.ts +21 -5
  276. package/src/internal/funding/Deposit.ts +74 -5
  277. package/src/internal/funding/Evidence.test.ts +2 -2
  278. package/src/internal/funding/Evidence.ts +4 -9
  279. package/src/internal/funding/Provider.ts +115 -0
  280. package/src/internal/funding/Reconciliation.local.test.ts +7 -0
  281. package/src/internal/funding/Reconciliation.test.ts +1052 -35
  282. package/src/internal/funding/Reconciliation.ts +328 -56
  283. package/src/internal/funding/SourceObservation.test.ts +301 -0
  284. package/src/internal/funding/SourceObservation.ts +267 -0
  285. package/src/internal/funding/Subsidy.ts +2 -2
  286. package/src/internal/funding/index.test.ts +1 -0
  287. package/src/internal/funding/index.ts +1 -0
  288. package/src/internal/funding/providers/relay.test.ts +94 -4
  289. package/src/internal/funding/providers/relay.ts +528 -27
  290. package/dist/apps/data/routes/funding.d.ts.map +0 -1
  291. package/dist/apps/data/routes/funding.js +0 -1557
  292. package/dist/apps/data/routes/funding.js.map +0 -1
  293. package/src/apps/data/routes/funding.test.ts +0 -2994
  294. package/src/apps/data/routes/funding.ts +0 -1821
@@ -5,6 +5,7 @@ import {
5
5
  ContractFunctionExecutionError,
6
6
  ContractFunctionRevertedError,
7
7
  ContractFunctionZeroDataError,
8
+ zeroAddress,
8
9
  } from 'viem'
9
10
  import * as z from 'zod/mini'
10
11
 
@@ -20,6 +21,7 @@ import * as OpenApi from '../../../internal/OpenApi.js'
20
21
  import * as Response from '../../../internal/Response.js'
21
22
  import * as Schema from '../../../internal/Schema.js'
22
23
  import * as Store from '../../../internal/Store.js'
24
+ import * as Tidx from '../../../internal/Tidx.js'
23
25
  import * as Timing from '../../../internal/Timing.js'
24
26
  import * as Ttl from '../../../internal/Ttl.js'
25
27
  import * as Value from '../../../internal/Value.js'
@@ -31,6 +33,27 @@ import * as Valuation from './valuation.js'
31
33
  const deployedSignature =
32
34
  'event EarnStackDeployed(address indexed earnVault,address indexed earnShare,address indexed earnFees,address engine,address asset,address owner,bytes32 deploymentId,address emergencyGuardian,address asyncJanitor,uint8 migrationMode,bytes32 earnShareSalt,bytes32 controlConfigHash,bytes32 feeConfigHash,bytes32 earnFeesSalt)'
33
35
 
36
+ const depositedSignature =
37
+ 'event Deposited(address indexed caller,address indexed receiver,uint256 assets,uint256 earnShares)'
38
+
39
+ const redeemedSignature =
40
+ 'event Redeemed(address indexed caller,address indexed receiver,uint256 earnShares,uint256 assets)'
41
+
42
+ const withdrewExactSignature =
43
+ 'event WithdrewExact(address indexed caller,address indexed receiver,uint256 assets,uint256 earnSharesBurned)'
44
+
45
+ const redeemFinalizedSignature =
46
+ 'event RedeemFinalized(bytes32 indexed requestId,address indexed receiver,uint256 earnShares,address asset,uint256 assets)'
47
+
48
+ const redeemCancelledSignature =
49
+ 'event RedeemCancelled(bytes32 indexed requestId,address indexed receiver,uint256 earnShares)'
50
+
51
+ const redeemRequestedSignature =
52
+ 'event RedeemRequested(bytes32 indexed requestId,address indexed requester,address indexed receiver,uint256 earnShares)'
53
+
54
+ const venueSharesDepositedSignature =
55
+ 'event VenueSharesDeposited(address indexed caller,address indexed receiver,uint256 requestedVenueShares,uint256 receivedVenueShares,uint256 earnShares)'
56
+
34
57
  const maxScannedDeployments = 250
35
58
  const scanLimit = 50
36
59
 
@@ -300,6 +323,105 @@ export namespace schema {
300
323
  ),
301
324
  })
302
325
 
326
+ const earningsBase = z.strictObject({
327
+ account: Schema.Address.check(
328
+ z.describe('Account whose vault earnings were calculated.'),
329
+ z.meta({ examples: ['0x68f94cfca22e5969c0553bbeab00a2acde88939b'] }),
330
+ ),
331
+ assetToken: Schema.TokenAddress.check(
332
+ z.describe('TIP-20 asset token accepted by the vault.'),
333
+ z.meta({ examples: ['0x20c000000000000000000000ff04042ee92fd449'] }),
334
+ ),
335
+ currentValue: Schema.DecimalString.check(
336
+ z.describe(
337
+ 'Asset value of the account’s active Earn shares at the latest indexed block, in asset base units.',
338
+ ),
339
+ z.meta({ examples: ['600000'] }),
340
+ ),
341
+ id: Schema.Address.check(
342
+ z.describe('Stable resource ID for these vault earnings, equal to the account address.'),
343
+ z.meta({ examples: ['0x68f94cfca22e5969c0553bbeab00a2acde88939b'] }),
344
+ ),
345
+ })
346
+
347
+ const earningsPeriod = z
348
+ .enum(['active', 'lifetime'])
349
+ .check(z.describe('Earnings period to calculate.'), z.meta({ examples: ['lifetime'] }))
350
+
351
+ const earnings = z.union([
352
+ z.extend(earningsBase, {
353
+ lifetimeEarnings: z
354
+ .string()
355
+ .check(
356
+ z.regex(/^-?\d+$/),
357
+ z.describe(
358
+ 'Current share value plus completed redemptions, exact withdrawals, and finalized async assets, minus asset deposits, at the latest indexed block.',
359
+ ),
360
+ z.meta({ examples: ['0'] }),
361
+ ),
362
+ period: z
363
+ .literal('lifetime')
364
+ .check(
365
+ z.describe('Returns lifetime net asset earnings.'),
366
+ z.meta({ examples: ['lifetime'] }),
367
+ ),
368
+ status: z
369
+ .literal('complete')
370
+ .check(
371
+ z.describe('Earnings include a complete asset-denominated cost basis.'),
372
+ z.meta({ examples: ['complete'] }),
373
+ ),
374
+ }),
375
+ z.extend(earningsBase, {
376
+ activeEarnings: z
377
+ .string()
378
+ .check(
379
+ z.regex(/^-?\d+$/),
380
+ z.describe(
381
+ 'Current share value minus the weighted-average asset cost basis of shares still held, at the latest indexed block.',
382
+ ),
383
+ z.meta({ examples: ['0'] }),
384
+ ),
385
+ period: z
386
+ .literal('active')
387
+ .check(
388
+ z.describe('Returns earnings on shares still held.'),
389
+ z.meta({ examples: ['active'] }),
390
+ ),
391
+ status: z
392
+ .literal('complete')
393
+ .check(
394
+ z.describe('Earnings include a complete asset-denominated cost basis.'),
395
+ z.meta({ examples: ['complete'] }),
396
+ ),
397
+ }),
398
+ z.extend(earningsBase, {
399
+ period: earningsPeriod,
400
+ status: z
401
+ .literal('incomplete_cost_basis')
402
+ .check(
403
+ z.describe(
404
+ 'Earnings are unavailable when indexed activity cannot reconstruct the remaining asset cost basis.',
405
+ ),
406
+ z.meta({ examples: ['incomplete_cost_basis'] }),
407
+ ),
408
+ }),
409
+ z.extend(earningsBase, {
410
+ period: z
411
+ .literal('lifetime')
412
+ .check(
413
+ z.describe('Returns lifetime net asset earnings.'),
414
+ z.meta({ examples: ['lifetime'] }),
415
+ ),
416
+ status: z
417
+ .literal('pending_redemption')
418
+ .check(
419
+ z.describe('Earnings are unavailable while an async redemption remains open.'),
420
+ z.meta({ examples: ['pending_redemption'] }),
421
+ ),
422
+ }),
423
+ ])
424
+
303
425
  const meta = z
304
426
  .object({
305
427
  valuation: z
@@ -428,6 +550,33 @@ export namespace schema {
428
550
  'Current asset and Earn-share balances, allowances, and asset value for an account in one Earn vault.',
429
551
  )
430
552
  }
553
+
554
+ /** Schemas for the getEarnVaultEarnings operation. */
555
+ export namespace getEarnVaultEarnings {
556
+ /** Path parameters identifying the Earn vault and account. */
557
+ export const Params = z
558
+ .strictObject({
559
+ address: Schema.Address.check(z.describe('Account whose vault earnings to read.')),
560
+ vaultId: Schema.address('0xf4ae63687d6753a78e7f551d2eda1d0d31a5ea3a').check(
561
+ z.describe('Earn vault contract address.'),
562
+ ),
563
+ })
564
+ .check(z.describe('Path parameters identifying an Earn vault account.'))
565
+
566
+ /** Query parameters selecting the chain containing the vault. */
567
+ export const Query = z
568
+ .strictObject({
569
+ chainId: Schema.ChainIdQuery,
570
+ period: z._default(earningsPeriod, 'lifetime'),
571
+ })
572
+ .check(z.describe('Query parameters selecting an Earn vault account.'))
573
+
574
+ /** Earnings for one account and period in one Earn vault. */
575
+ export const Response = Schema.describe(
576
+ earnings,
577
+ 'Indexed asset value and cost-basis-aware earnings for an account in one Earn vault.',
578
+ )
579
+ }
431
580
  }
432
581
 
433
582
  /** Creates the public Earn-vault handlers. */
@@ -452,7 +601,7 @@ export function earn(options: earn.Options = {}) {
452
601
  schema: schema.getEarnVaults.Response,
453
602
  },
454
603
  }),
455
- summary: 'List Earn vaults',
604
+ summary: 'List vaults',
456
605
  tags: ['Earn'],
457
606
  }),
458
607
  // Live state and rate enrichment are embedded, so every vault read caches
@@ -560,7 +709,7 @@ export function earn(options: earn.Options = {}) {
560
709
  schema: schema.getEarnVaultPosition.Response,
561
710
  },
562
711
  }),
563
- summary: 'Get vault position',
712
+ summary: 'Get account position',
564
713
  tags: ['Earn'],
565
714
  }),
566
715
  Cache.response<App.Environment>({
@@ -629,6 +778,101 @@ export function earn(options: earn.Options = {}) {
629
778
  }
630
779
  },
631
780
  )
781
+ .get(
782
+ '/v1/earn/vaults/:vaultId/earnings/:address',
783
+ Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
784
+ OpenApi.validate('param', schema.getEarnVaultEarnings.Params, {
785
+ code: 'earnings_invalid',
786
+ message: 'Invalid vault earnings',
787
+ }),
788
+ OpenApi.validate('query', schema.getEarnVaultEarnings.Query, {
789
+ code: 'query_invalid',
790
+ message: 'Invalid query parameters',
791
+ }),
792
+ OpenApi.describeRoute({
793
+ description:
794
+ 'Gets an account’s indexed asset value and earnings for lifetime history or shares still held.',
795
+ operationId: 'getEarnVaultEarnings',
796
+ responses: OpenApi.responses({
797
+ errors: {
798
+ 400: {
799
+ codes: [
800
+ 'chain_id_invalid',
801
+ 'chain_id_unsupported',
802
+ 'earnings_invalid',
803
+ 'query_invalid',
804
+ ],
805
+ },
806
+ 404: {
807
+ codes: ['earn_vault_not_found'],
808
+ description: 'No compatible Earn vault was found at this address.',
809
+ },
810
+ 502: 'Could not read the Earn vault earnings.',
811
+ },
812
+ success: {
813
+ description: 'Cost-basis-aware earnings for one account in one vault.',
814
+ schema: schema.getEarnVaultEarnings.Response,
815
+ },
816
+ }),
817
+ summary: 'Get vault earnings',
818
+ tags: ['Earn'],
819
+ }),
820
+ Cache.response<App.Environment>({
821
+ cacheControl: Cache.policies.state,
822
+ key: (c) => Cache.urlKey(c, schema.getEarnVaultEarnings.Query),
823
+ name: 'tempo-api:earn-vault-earnings:v2',
824
+ }),
825
+ async (c) => {
826
+ if (Auth.narrowAccess) return Auth.paidAccessError(c)
827
+ if (OpenApi.narrowValidation)
828
+ return Response.error(c, {
829
+ code: 'chain_id_invalid',
830
+ message: 'Invalid chain id',
831
+ status: 400,
832
+ })
833
+ if (OpenApi.narrowValidation)
834
+ return Response.error(c, {
835
+ code: 'chain_id_unsupported',
836
+ message: 'Unsupported chain id',
837
+ status: 400,
838
+ })
839
+ if (OpenApi.narrowValidation)
840
+ return OpenApi.validationError(c, {
841
+ code: 'earnings_invalid',
842
+ message: 'Invalid request parameters',
843
+ })
844
+ if (OpenApi.narrowValidation)
845
+ return OpenApi.validationError(c, {
846
+ code: 'query_invalid',
847
+ message: 'Invalid query parameters',
848
+ })
849
+
850
+ const { address, vaultId } = c.req.valid('param')
851
+ const query = c.req.valid('query')
852
+ const chainId = query.chainId ?? c.get('chainId')
853
+ try {
854
+ const data = await getVaultEarnings(c, {
855
+ account: address,
856
+ chainId,
857
+ period: query.period,
858
+ vault: vaultId,
859
+ })
860
+ return c.json(Response.validated(schema.getEarnVaultEarnings.Response, data), 200)
861
+ } catch (cause) {
862
+ try {
863
+ await resolveVaultDiscovery(c, { chainId, include: [], vaultAddress: vaultId })
864
+ } catch (vaultCause) {
865
+ if (isIncompatible(vaultCause))
866
+ return Response.error(c, {
867
+ code: 'earn_vault_not_found',
868
+ message: 'Earn vault not found',
869
+ status: 404,
870
+ })
871
+ }
872
+ return Response.upstream(c, cause)
873
+ }
874
+ },
875
+ )
632
876
  .get(
633
877
  '/v1/earn/vaults/:vaultId',
634
878
  Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
@@ -657,7 +901,7 @@ export function earn(options: earn.Options = {}) {
657
901
  schema: schema.getEarnVault.Response,
658
902
  },
659
903
  }),
660
- summary: 'Get Earn vault',
904
+ summary: 'Get vault',
661
905
  tags: ['Earn'],
662
906
  }),
663
907
  Cache.response<App.Environment>({
@@ -711,6 +955,559 @@ export declare namespace earn {
711
955
  }
712
956
  }
713
957
 
958
+ /** Reads one account's indexed value and returns earnings when the history is complete. */
959
+ export async function getVaultEarnings(
960
+ c: Context<App.Environment>,
961
+ options: getVaultEarnings.Options,
962
+ ) {
963
+ const client = c.get('getClient')(options.chainId)
964
+ const tidx = c.get('getTidx')(options.chainId)
965
+ const blockNumber = await getLatestIndexedBlockNumber(tidx)
966
+ const position = client.earn.getPosition({
967
+ account: options.account,
968
+ blockNumber: BigInt(blockNumber),
969
+ vault: options.vault,
970
+ })
971
+ if (options.period === 'active') {
972
+ const current = await position
973
+ const base = {
974
+ account: options.account,
975
+ assetToken: current.assetToken,
976
+ currentValue: current.value.toString(),
977
+ id: options.account,
978
+ period: options.period,
979
+ }
980
+ const activeCostBasis = await getActiveCostBasis(tidx, {
981
+ account: options.account,
982
+ blockNumber,
983
+ shareBalance: current.shareBalance,
984
+ shareToken: current.shareToken,
985
+ vault: options.vault,
986
+ })
987
+ if (activeCostBasis === undefined) return { ...base, status: 'incomplete_cost_basis' as const }
988
+ return {
989
+ ...base,
990
+ activeEarnings: (current.value - activeCostBasis).toString(),
991
+ status: 'complete' as const,
992
+ }
993
+ }
994
+ const [history, current] = await Promise.all([
995
+ getVaultEarningsHistory(tidx, {
996
+ account: options.account,
997
+ blockNumber,
998
+ vault: options.vault,
999
+ }),
1000
+ position,
1001
+ ])
1002
+ const externalShareTransfer = await hasExternalShareTransfer(tidx, {
1003
+ account: options.account,
1004
+ blockNumber,
1005
+ shareToken: current.shareToken,
1006
+ vault: options.vault,
1007
+ })
1008
+ const base = {
1009
+ account: options.account,
1010
+ assetToken: current.assetToken,
1011
+ currentValue: current.value.toString(),
1012
+ id: options.account,
1013
+ period: options.period,
1014
+ }
1015
+ if (history.incompleteCostBasis || externalShareTransfer)
1016
+ return { ...base, status: 'incomplete_cost_basis' as const }
1017
+ if (history.pendingRedemption) return { ...base, status: 'pending_redemption' as const }
1018
+ const lifetimeEarnings =
1019
+ current.value + history.redeemed + history.withdrewExact + history.finalized - history.deposited
1020
+ return { ...base, lifetimeEarnings: lifetimeEarnings.toString(), status: 'complete' as const }
1021
+ }
1022
+
1023
+ export declare namespace getVaultEarnings {
1024
+ /** Inputs identifying the account and vault to calculate. */
1025
+ type Options = {
1026
+ account: z.output<typeof Schema.Address>
1027
+ chainId: z.output<typeof Schema.ChainId>
1028
+ period: z.output<typeof schema.getEarnVaultEarnings.Query>['period']
1029
+ vault: z.output<typeof Schema.Address>
1030
+ }
1031
+ }
1032
+
1033
+ /** Reads the latest block whose indexed logs back the earnings calculation. */
1034
+ async function getLatestIndexedBlockNumber(tidx: Tidx.Client) {
1035
+ const result = await tidx.fetch({
1036
+ engine: 'clickhouse',
1037
+ query: 'SELECT num FROM blocks ORDER BY num DESC LIMIT 1' as string,
1038
+ })
1039
+ const blockNumber = Value.toNumber(result.rows[0]?.['num'])
1040
+ if (blockNumber === undefined) throw new Error('TIDX returned no indexed block.')
1041
+ return blockNumber
1042
+ }
1043
+
1044
+ /** Reads the indexed cash flows and exceptional states behind one earnings calculation. */
1045
+ async function getVaultEarningsHistory(
1046
+ tidx: Tidx.Client,
1047
+ options: getVaultEarningsHistory.Options,
1048
+ ) {
1049
+ const result = await tidx.fetch({
1050
+ engine: 'clickhouse',
1051
+ query: `
1052
+ SELECT
1053
+ (
1054
+ SELECT toString(sum(toUInt256(assets)))
1055
+ FROM Deposited
1056
+ WHERE address = '${options.vault}'
1057
+ AND receiver = '${options.account}'
1058
+ AND block_num <= ${options.blockNumber}
1059
+ ) AS deposited_assets,
1060
+ (
1061
+ SELECT toString(sum(toUInt256(finalized.assets)))
1062
+ FROM RedeemFinalized AS finalized
1063
+ INNER JOIN RedeemRequested AS requested
1064
+ ON requested.address = finalized.address
1065
+ AND requested."requestId" = finalized."requestId"
1066
+ WHERE finalized.address = '${options.vault}'
1067
+ AND requested.requester = '${options.account}'
1068
+ AND finalized.block_num <= ${options.blockNumber}
1069
+ AND requested.block_num <= ${options.blockNumber}
1070
+ ) AS finalized_assets,
1071
+ (
1072
+ SELECT count()
1073
+ FROM RedeemRequested AS requested
1074
+ LEFT ANTI JOIN RedeemFinalized AS finalized
1075
+ ON finalized.address = requested.address
1076
+ AND finalized."requestId" = requested."requestId"
1077
+ AND finalized.block_num <= ${options.blockNumber}
1078
+ LEFT ANTI JOIN RedeemCancelled AS cancelled
1079
+ ON cancelled.address = requested.address
1080
+ AND cancelled."requestId" = requested."requestId"
1081
+ AND cancelled.block_num <= ${options.blockNumber}
1082
+ WHERE requested.address = '${options.vault}'
1083
+ AND requested.requester = '${options.account}'
1084
+ AND requested.block_num <= ${options.blockNumber}
1085
+ ) AS pending_redemptions,
1086
+ (
1087
+ SELECT toString(sum(toUInt256(assets)))
1088
+ FROM Redeemed
1089
+ WHERE address = '${options.vault}'
1090
+ AND caller = '${options.account}'
1091
+ AND block_num <= ${options.blockNumber}
1092
+ ) AS redeemed_assets,
1093
+ (
1094
+ SELECT count()
1095
+ FROM RedeemCancelled AS cancelled
1096
+ INNER JOIN RedeemRequested AS requested
1097
+ ON requested.address = cancelled.address
1098
+ AND requested."requestId" = cancelled."requestId"
1099
+ WHERE cancelled.address = '${options.vault}'
1100
+ AND cancelled.block_num <= ${options.blockNumber}
1101
+ AND requested.block_num <= ${options.blockNumber}
1102
+ AND requested.requester != cancelled.receiver
1103
+ AND (
1104
+ requested.requester = '${options.account}'
1105
+ OR cancelled.receiver = '${options.account}'
1106
+ )
1107
+ ) AS transferred_cancellations,
1108
+ (
1109
+ SELECT count()
1110
+ FROM VenueSharesDeposited
1111
+ WHERE address = '${options.vault}'
1112
+ AND receiver = '${options.account}'
1113
+ AND block_num <= ${options.blockNumber}
1114
+ ) AS venue_deposits,
1115
+ (
1116
+ SELECT toString(sum(toUInt256(assets)))
1117
+ FROM WithdrewExact
1118
+ WHERE address = '${options.vault}'
1119
+ AND caller = '${options.account}'
1120
+ AND block_num <= ${options.blockNumber}
1121
+ ) AS withdrew_exact
1122
+ ` as string,
1123
+ signatures: [
1124
+ depositedSignature,
1125
+ redeemCancelledSignature,
1126
+ redeemFinalizedSignature,
1127
+ redeemRequestedSignature,
1128
+ redeemedSignature,
1129
+ venueSharesDepositedSignature,
1130
+ withdrewExactSignature,
1131
+ ],
1132
+ })
1133
+ const row = result.rows[0]
1134
+ const deposited = Value.toIntegerString(row?.['deposited_assets'])
1135
+ const finalized = Value.toIntegerString(row?.['finalized_assets'])
1136
+ const pendingRedemptions = Value.toNumber(row?.['pending_redemptions'])
1137
+ const redeemed = Value.toIntegerString(row?.['redeemed_assets'])
1138
+ const transferredCancellations = Value.toNumber(row?.['transferred_cancellations'])
1139
+ const venueDeposits = Value.toNumber(row?.['venue_deposits'])
1140
+ const withdrewExact = Value.toIntegerString(row?.['withdrew_exact'])
1141
+ if (
1142
+ deposited === undefined ||
1143
+ finalized === undefined ||
1144
+ pendingRedemptions === undefined ||
1145
+ redeemed === undefined ||
1146
+ transferredCancellations === undefined ||
1147
+ venueDeposits === undefined ||
1148
+ withdrewExact === undefined
1149
+ )
1150
+ throw new Error('TIDX returned invalid Earn earnings history.')
1151
+ return {
1152
+ deposited: BigInt(deposited),
1153
+ finalized: BigInt(finalized),
1154
+ incompleteCostBasis: transferredCancellations > 0 || venueDeposits > 0,
1155
+ pendingRedemption: pendingRedemptions > 0,
1156
+ redeemed: BigInt(redeemed),
1157
+ withdrewExact: BigInt(withdrewExact),
1158
+ }
1159
+ }
1160
+
1161
+ declare namespace getVaultEarningsHistory {
1162
+ type Options = {
1163
+ account: z.output<typeof Schema.Address>
1164
+ blockNumber: number
1165
+ vault: z.output<typeof Schema.Address>
1166
+ }
1167
+ }
1168
+
1169
+ /** Returns whether an account sent or received Earn shares outside known vault flows. */
1170
+ async function hasExternalShareTransfer(
1171
+ tidx: Tidx.Client,
1172
+ options: hasExternalShareTransfer.Options,
1173
+ ) {
1174
+ // Vault exits pull shares into the vault before burning. Reconcile counts by transaction and amount so unmatched direct sends remain external.
1175
+ const result = await tidx.fetch({
1176
+ engine: 'clickhouse',
1177
+ query: `
1178
+ SELECT
1179
+ (
1180
+ SELECT count()
1181
+ FROM token_transfers
1182
+ WHERE token = '${options.shareToken.toLowerCase()}'
1183
+ AND block_num <= ${options.blockNumber}
1184
+ AND (
1185
+ ("from" = '${options.account}' AND "to" != '${options.vault}')
1186
+ OR ("to" = '${options.account}' AND "from" != '${zeroAddress}')
1187
+ )
1188
+ ) + (
1189
+ SELECT count()
1190
+ FROM (
1191
+ SELECT tx_hash, toUInt256(amount) AS amount, count() AS transfer_count
1192
+ FROM token_transfers
1193
+ WHERE token = '${options.shareToken.toLowerCase()}'
1194
+ AND "from" = '${options.account}'
1195
+ AND "to" = '${options.vault}'
1196
+ AND block_num <= ${options.blockNumber}
1197
+ GROUP BY tx_hash, amount
1198
+ ) AS candidate
1199
+ LEFT JOIN (
1200
+ SELECT tx_hash, amount, count() AS exit_count
1201
+ FROM (
1202
+ SELECT tx_hash, toUInt256(earnShares) AS amount
1203
+ FROM Redeemed
1204
+ WHERE address = '${options.vault}'
1205
+ AND caller = '${options.account}'
1206
+ AND block_num <= ${options.blockNumber}
1207
+ UNION ALL
1208
+ SELECT tx_hash, toUInt256(earnShares) AS amount
1209
+ FROM RedeemRequested
1210
+ WHERE address = '${options.vault}'
1211
+ AND requester = '${options.account}'
1212
+ AND block_num <= ${options.blockNumber}
1213
+ UNION ALL
1214
+ SELECT tx_hash, toUInt256(earnSharesBurned) AS amount
1215
+ FROM WithdrewExact
1216
+ WHERE address = '${options.vault}'
1217
+ AND caller = '${options.account}'
1218
+ AND block_num <= ${options.blockNumber}
1219
+ ) AS protocol_exit
1220
+ GROUP BY tx_hash, amount
1221
+ ) AS matched
1222
+ ON matched.tx_hash = candidate.tx_hash AND matched.amount = candidate.amount
1223
+ WHERE candidate.transfer_count > coalesce(matched.exit_count, 0)
1224
+ ) AS count
1225
+ ` as string,
1226
+ signatures: [redeemedSignature, redeemRequestedSignature, withdrewExactSignature],
1227
+ })
1228
+ const count = Value.toNumber(result.rows[0]?.['count'])
1229
+ if (count === undefined) throw new Error('TIDX returned an invalid Earn-share transfer count.')
1230
+ return count > 0
1231
+ }
1232
+
1233
+ declare namespace hasExternalShareTransfer {
1234
+ type Options = {
1235
+ account: z.output<typeof Schema.Address>
1236
+ blockNumber: number
1237
+ shareToken: z.output<typeof Schema.Address>
1238
+ vault: z.output<typeof Schema.Address>
1239
+ }
1240
+ }
1241
+
1242
+ /** Calculates the asset cost basis attached to an account's remaining Earn shares. */
1243
+ export function calculateActiveCostBasis(options: calculateActiveCostBasis.Options) {
1244
+ const requests = new Map<string, { costBasis: bigint | undefined; shares: bigint }>()
1245
+ let costBasis: bigint | undefined = 0n
1246
+ let shares = 0n
1247
+
1248
+ const remove = (burned: bigint) => {
1249
+ if (burned > shares || shares === 0n) return undefined
1250
+ const removed = (() => {
1251
+ if (costBasis === undefined) return undefined
1252
+ return burned === shares ? costBasis : (costBasis * burned) / shares
1253
+ })()
1254
+ if (burned === shares) costBasis = 0n
1255
+ else if (costBasis !== undefined && removed !== undefined) costBasis -= removed
1256
+ shares -= burned
1257
+ return { costBasis: removed }
1258
+ }
1259
+
1260
+ for (const action of options.actions) {
1261
+ if (action.kind === 'deposit') {
1262
+ if (costBasis !== undefined) costBasis += action.assets
1263
+ shares += action.shares
1264
+ continue
1265
+ }
1266
+ if (action.kind === 'unknown') {
1267
+ costBasis = undefined
1268
+ shares += action.shares
1269
+ continue
1270
+ }
1271
+ if (action.kind === 'cancel') {
1272
+ const restored = requests.get(action.requestId)
1273
+ if (restored === undefined || restored.shares !== action.shares) return undefined
1274
+ if (costBasis === undefined || restored.costBasis === undefined) costBasis = undefined
1275
+ else costBasis += restored.costBasis
1276
+ shares += restored.shares
1277
+ requests.delete(action.requestId)
1278
+ continue
1279
+ }
1280
+ const removed = remove(action.shares)
1281
+ if (removed === undefined) return undefined
1282
+ if (action.kind === 'request')
1283
+ requests.set(action.requestId, { costBasis: removed.costBasis, shares: action.shares })
1284
+ }
1285
+
1286
+ return shares === options.shareBalance && costBasis !== undefined ? costBasis : undefined
1287
+ }
1288
+
1289
+ export declare namespace calculateActiveCostBasis {
1290
+ /** One indexed share or cost-basis mutation. */
1291
+ export type Action =
1292
+ | {
1293
+ /** Action discriminator. */
1294
+ kind: 'cancel'
1295
+ /** Async redemption request being cancelled. */
1296
+ requestId: string
1297
+ /** Shares restored to the account. */
1298
+ shares: bigint
1299
+ }
1300
+ | {
1301
+ /** Assets added to the account's cost basis. */
1302
+ assets: bigint
1303
+ /** Action discriminator. */
1304
+ kind: 'deposit'
1305
+ /** Shares issued for the deposit. */
1306
+ shares: bigint
1307
+ }
1308
+ | {
1309
+ /** Action discriminator. */
1310
+ kind: 'redeem'
1311
+ /** Shares removed from the account. */
1312
+ shares: bigint
1313
+ }
1314
+ | {
1315
+ /** Action discriminator. */
1316
+ kind: 'request'
1317
+ /** Async redemption request holding the removed basis. */
1318
+ requestId: string
1319
+ /** Shares removed from the account. */
1320
+ shares: bigint
1321
+ }
1322
+ | {
1323
+ /** Action discriminator. */
1324
+ kind: 'unknown'
1325
+ /** Shares received without an asset-denominated cost basis. */
1326
+ shares: bigint
1327
+ }
1328
+
1329
+ /** Inputs for calculating the remaining cost basis. */
1330
+ export type Options = {
1331
+ /** Indexed mutations in chain order. */
1332
+ actions: readonly Action[]
1333
+ /** Share balance read at the same indexed block. */
1334
+ shareBalance: bigint
1335
+ }
1336
+ }
1337
+
1338
+ /** Reads the active asset cost basis for shares held at one indexed block. */
1339
+ async function getActiveCostBasis(tidx: Tidx.Client, options: getActiveCostBasis.Options) {
1340
+ const result = await tidx.fetch({
1341
+ engine: 'clickhouse',
1342
+ query: `
1343
+ SELECT kind, request_id, shares, assets
1344
+ FROM (
1345
+ SELECT
1346
+ 'deposit' AS kind,
1347
+ block_num,
1348
+ log_idx,
1349
+ '' AS request_id,
1350
+ toString(toUInt256(earnShares)) AS shares,
1351
+ toString(toUInt256(assets)) AS assets
1352
+ FROM Deposited
1353
+ WHERE address = '${options.vault}'
1354
+ AND receiver = '${options.account}'
1355
+ AND block_num <= ${options.blockNumber}
1356
+ UNION ALL
1357
+ SELECT
1358
+ 'redeem' AS kind,
1359
+ block_num,
1360
+ log_idx,
1361
+ '' AS request_id,
1362
+ toString(toUInt256(earnShares)) AS shares,
1363
+ '0' AS assets
1364
+ FROM Redeemed
1365
+ WHERE address = '${options.vault}'
1366
+ AND caller = '${options.account}'
1367
+ AND block_num <= ${options.blockNumber}
1368
+ UNION ALL
1369
+ SELECT
1370
+ 'redeem' AS kind,
1371
+ block_num,
1372
+ log_idx,
1373
+ '' AS request_id,
1374
+ toString(toUInt256(earnSharesBurned)) AS shares,
1375
+ '0' AS assets
1376
+ FROM WithdrewExact
1377
+ WHERE address = '${options.vault}'
1378
+ AND caller = '${options.account}'
1379
+ AND block_num <= ${options.blockNumber}
1380
+ UNION ALL
1381
+ SELECT
1382
+ 'request' AS kind,
1383
+ block_num,
1384
+ log_idx,
1385
+ "requestId" AS request_id,
1386
+ toString(toUInt256(earnShares)) AS shares,
1387
+ '0' AS assets
1388
+ FROM RedeemRequested
1389
+ WHERE address = '${options.vault}'
1390
+ AND requester = '${options.account}'
1391
+ AND block_num <= ${options.blockNumber}
1392
+ UNION ALL
1393
+ SELECT
1394
+ 'cancel' AS kind,
1395
+ cancelled.block_num AS block_num,
1396
+ cancelled.log_idx AS log_idx,
1397
+ cancelled."requestId" AS request_id,
1398
+ toString(toUInt256(cancelled.earnShares)) AS shares,
1399
+ '0' AS assets
1400
+ FROM RedeemCancelled AS cancelled
1401
+ INNER JOIN RedeemRequested AS requested
1402
+ ON requested.address = cancelled.address
1403
+ AND requested."requestId" = cancelled."requestId"
1404
+ WHERE cancelled.address = '${options.vault}'
1405
+ AND requested.requester = '${options.account}'
1406
+ AND cancelled.receiver = '${options.account}'
1407
+ AND cancelled.block_num <= ${options.blockNumber}
1408
+ AND requested.block_num <= ${options.blockNumber}
1409
+ UNION ALL
1410
+ SELECT
1411
+ 'unknown' AS kind,
1412
+ block_num,
1413
+ log_idx,
1414
+ '' AS request_id,
1415
+ toString(toUInt256(earnShares)) AS shares,
1416
+ '0' AS assets
1417
+ FROM VenueSharesDeposited
1418
+ WHERE address = '${options.vault}'
1419
+ AND receiver = '${options.account}'
1420
+ AND block_num <= ${options.blockNumber}
1421
+ UNION ALL
1422
+ SELECT
1423
+ 'unknown' AS kind,
1424
+ block_num,
1425
+ log_idx,
1426
+ '' AS request_id,
1427
+ toString(toUInt256(amount)) AS shares,
1428
+ '0' AS assets
1429
+ FROM token_transfers
1430
+ WHERE token = '${options.shareToken.toLowerCase()}'
1431
+ AND "to" = '${options.account}'
1432
+ AND "from" != '${zeroAddress}'
1433
+ AND "from" != '${options.vault}'
1434
+ AND block_num <= ${options.blockNumber}
1435
+ UNION ALL
1436
+ SELECT
1437
+ 'redeem' AS kind,
1438
+ block_num,
1439
+ log_idx,
1440
+ '' AS request_id,
1441
+ toString(toUInt256(amount)) AS shares,
1442
+ '0' AS assets
1443
+ FROM token_transfers
1444
+ WHERE token = '${options.shareToken.toLowerCase()}'
1445
+ AND "from" = '${options.account}'
1446
+ AND "to" != '${options.vault}'
1447
+ AND block_num <= ${options.blockNumber}
1448
+ ) AS actions
1449
+ ORDER BY block_num, log_idx
1450
+ ` as string,
1451
+ signatures: [
1452
+ depositedSignature,
1453
+ redeemCancelledSignature,
1454
+ redeemRequestedSignature,
1455
+ redeemedSignature,
1456
+ venueSharesDepositedSignature,
1457
+ withdrewExactSignature,
1458
+ ],
1459
+ })
1460
+ const actions: calculateActiveCostBasis.Action[] = []
1461
+ for (const row of result.rows) {
1462
+ const kind = Value.toText(row['kind'])
1463
+ if (kind === 'deposit') {
1464
+ const assets = Value.toIntegerString(row['assets'])
1465
+ const shares = Value.toIntegerString(row['shares'])
1466
+ if (assets === undefined || shares === undefined) return undefined
1467
+ actions.push({ assets: BigInt(assets), kind, shares: BigInt(shares) })
1468
+ continue
1469
+ }
1470
+ if (kind === 'redeem') {
1471
+ const shares = Value.toIntegerString(row['shares'])
1472
+ if (shares === undefined) return undefined
1473
+ actions.push({ kind, shares: BigInt(shares) })
1474
+ continue
1475
+ }
1476
+ if (kind === 'cancel') {
1477
+ const requestId = Value.toText(row['request_id'])
1478
+ const shares = Value.toIntegerString(row['shares'])
1479
+ if (requestId === undefined || shares === undefined) return undefined
1480
+ actions.push({ kind, requestId, shares: BigInt(shares) })
1481
+ continue
1482
+ }
1483
+ if (kind === 'request') {
1484
+ const requestId = Value.toText(row['request_id'])
1485
+ const shares = Value.toIntegerString(row['shares'])
1486
+ if (requestId === undefined || shares === undefined) return undefined
1487
+ actions.push({ kind, requestId, shares: BigInt(shares) })
1488
+ continue
1489
+ }
1490
+ if (kind === 'unknown') {
1491
+ const shares = Value.toIntegerString(row['shares'])
1492
+ if (shares === undefined) return undefined
1493
+ actions.push({ kind, shares: BigInt(shares) })
1494
+ continue
1495
+ }
1496
+ return undefined
1497
+ }
1498
+ return calculateActiveCostBasis({ actions, shareBalance: options.shareBalance })
1499
+ }
1500
+
1501
+ declare namespace getActiveCostBasis {
1502
+ type Options = {
1503
+ account: z.output<typeof Schema.Address>
1504
+ blockNumber: number
1505
+ shareBalance: bigint
1506
+ shareToken: z.output<typeof Schema.Address>
1507
+ vault: z.output<typeof Schema.Address>
1508
+ }
1509
+ }
1510
+
714
1511
  /** Lists compatible deployed Earn vaults. */
715
1512
  export async function listVaults(c: Context<App.Environment>, options: listVaults.Options) {
716
1513
  const db = Db.get(c.get('dbCached'))