@upshiftfinance/sdk 0.0.0-stage → 0.1.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 (346) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +408 -2
  3. package/lib/abis/AddressResolver.d.ts +28 -0
  4. package/lib/abis/AddressResolver.js +23 -0
  5. package/lib/abis/ChainlinkV3.d.ts +87 -0
  6. package/lib/abis/ChainlinkV3.js +117 -0
  7. package/lib/abis/ERC20.d.ts +168 -0
  8. package/lib/abis/ERC20.js +226 -0
  9. package/lib/abis/ERC20_Bytes32.d.ts +139 -0
  10. package/lib/abis/ERC20_Bytes32.js +196 -0
  11. package/lib/abis/ERC4626.d.ts +364 -0
  12. package/lib/abis/ERC4626.js +507 -0
  13. package/lib/abis/ERC721.d.ts +231 -0
  14. package/lib/abis/ERC721.js +321 -0
  15. package/lib/abis/FeeOracle.d.ts +120 -0
  16. package/lib/abis/FeeOracle.js +162 -0
  17. package/lib/abis/LendingPool.d.ts +1393 -0
  18. package/lib/abis/LendingPool.js +1807 -0
  19. package/lib/abis/LendingPoolV2.d.ts +1413 -0
  20. package/lib/abis/LendingPoolV2.js +1833 -0
  21. package/lib/abis/LendingPoolV3.d.ts +1677 -0
  22. package/lib/abis/LendingPoolV3.js +1160 -0
  23. package/lib/abis/Loan.d.ts +837 -0
  24. package/lib/abis/Loan.js +1080 -0
  25. package/lib/abis/MultiAssetNativeDepositWrapper.d.ts +137 -0
  26. package/lib/abis/MultiAssetNativeDepositWrapper.js +125 -0
  27. package/lib/abis/Multicall3.d.ts +30 -0
  28. package/lib/abis/Multicall3.js +97 -0
  29. package/lib/abis/OFT.d.ts +116 -0
  30. package/lib/abis/OFT.js +85 -0
  31. package/lib/abis/PoolAdapter.d.ts +36 -0
  32. package/lib/abis/PoolAdapter.js +51 -0
  33. package/lib/abis/RewardDistributor.d.ts +267 -0
  34. package/lib/abis/RewardDistributor.js +352 -0
  35. package/lib/abis/RwaRedeemSubaccount.d.ts +747 -0
  36. package/lib/abis/RwaRedeemSubaccount.js +548 -0
  37. package/lib/abis/SmartAccount.d.ts +17 -0
  38. package/lib/abis/SmartAccount.js +19 -0
  39. package/lib/abis/SwapRouter.d.ts +953 -0
  40. package/lib/abis/SwapRouter.js +1228 -0
  41. package/lib/abis/TextResolver.d.ts +16 -0
  42. package/lib/abis/TextResolver.js +16 -0
  43. package/lib/abis/TokenizedVaultV2.d.ts +1364 -0
  44. package/lib/abis/TokenizedVaultV2.js +1041 -0
  45. package/lib/abis/TokenizedVaultV2DepositWithPermit.d.ts +1456 -0
  46. package/lib/abis/TokenizedVaultV2DepositWithPermit.js +1878 -0
  47. package/lib/abis/TokenizedVaultV2Receipt.d.ts +1568 -0
  48. package/lib/abis/TokenizedVaultV2Receipt.js +1061 -0
  49. package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.d.ts +454 -0
  50. package/lib/abis/TokenizedVaultV2SenderAllocationWhitelist.js +327 -0
  51. package/lib/abis/TokenizedVaultV2WhitelistedAllocation.d.ts +1466 -0
  52. package/lib/abis/TokenizedVaultV2WhitelistedAllocation.js +1092 -0
  53. package/lib/abis/TokenizedVaultV2WhitelistedAssets.d.ts +274 -0
  54. package/lib/abis/TokenizedVaultV2WhitelistedAssets.js +167 -0
  55. package/lib/abis/UniversalResolverResolve.d.ts +69 -0
  56. package/lib/abis/UniversalResolverResolve.js +35 -0
  57. package/lib/abis/UniversalSignatureValidator.d.ts +17 -0
  58. package/lib/abis/UniversalSignatureValidator.js +30 -0
  59. package/lib/abis/WrapperAdapter.d.ts +71 -0
  60. package/lib/abis/WrapperAdapter.js +77 -0
  61. package/lib/abis/index.d.ts +34 -0
  62. package/lib/abis/index.js +51 -0
  63. package/lib/adapters/evm/getters.d.ts +19 -0
  64. package/lib/adapters/evm/getters.js +249 -0
  65. package/lib/adapters/evm/index.d.ts +539 -0
  66. package/lib/adapters/evm/index.js +656 -0
  67. package/lib/adapters/evm/utils.d.ts +8 -0
  68. package/lib/adapters/evm/utils.js +51 -0
  69. package/lib/adapters/solana/confirm.d.ts +88 -0
  70. package/lib/adapters/solana/confirm.js +291 -0
  71. package/lib/adapters/solana/constants.d.ts +42 -0
  72. package/lib/adapters/solana/constants.js +59 -0
  73. package/lib/adapters/solana/getters.d.ts +42 -0
  74. package/lib/adapters/solana/getters.js +275 -0
  75. package/lib/adapters/solana/idl/vault-idl.d.ts +700 -0
  76. package/lib/adapters/solana/idl/vault-idl.js +2101 -0
  77. package/lib/adapters/solana/idl/withdrawal-queue-idl.d.ts +795 -0
  78. package/lib/adapters/solana/idl/withdrawal-queue-idl.js +1864 -0
  79. package/lib/adapters/solana/index.d.ts +372 -0
  80. package/lib/adapters/solana/index.js +459 -0
  81. package/lib/adapters/solana/pricing.d.ts +184 -0
  82. package/lib/adapters/solana/pricing.js +239 -0
  83. package/lib/adapters/solana/queue-hints.d.ts +29 -0
  84. package/lib/adapters/solana/queue-hints.js +59 -0
  85. package/lib/adapters/solana/queue.actions.d.ts +97 -0
  86. package/lib/adapters/solana/queue.actions.js +468 -0
  87. package/lib/adapters/solana/token-reads.d.ts +108 -0
  88. package/lib/adapters/solana/token-reads.js +145 -0
  89. package/lib/adapters/solana/types.d.ts +325 -0
  90. package/lib/adapters/solana/types.js +3 -0
  91. package/lib/adapters/solana/utils.d.ts +229 -0
  92. package/lib/adapters/solana/utils.js +773 -0
  93. package/lib/adapters/solana/vault.actions.d.ts +140 -0
  94. package/lib/adapters/solana/vault.actions.js +657 -0
  95. package/lib/adapters/solana/withdrawal-queue.d.ts +125 -0
  96. package/lib/adapters/solana/withdrawal-queue.js +301 -0
  97. package/lib/adapters/stellar/actions.d.ts +41 -0
  98. package/lib/adapters/stellar/actions.js +126 -0
  99. package/lib/adapters/stellar/constants.d.ts +43 -0
  100. package/lib/adapters/stellar/constants.js +53 -0
  101. package/lib/adapters/stellar/getters.d.ts +68 -0
  102. package/lib/adapters/stellar/getters.js +290 -0
  103. package/lib/adapters/stellar/index.d.ts +126 -0
  104. package/lib/adapters/stellar/index.js +187 -0
  105. package/lib/adapters/stellar/invocation.d.ts +55 -0
  106. package/lib/adapters/stellar/invocation.js +92 -0
  107. package/lib/adapters/stellar/soroban.d.ts +131 -0
  108. package/lib/adapters/stellar/soroban.js +617 -0
  109. package/lib/adapters/stellar/submit.d.ts +42 -0
  110. package/lib/adapters/stellar/submit.js +195 -0
  111. package/lib/adapters/stellar/types.d.ts +57 -0
  112. package/lib/adapters/stellar/types.js +6 -0
  113. package/lib/adapters/stellar/utils.d.ts +24 -0
  114. package/lib/adapters/stellar/utils.js +34 -0
  115. package/lib/adapters/sui/constants.d.ts +1 -0
  116. package/lib/adapters/sui/constants.js +9 -0
  117. package/lib/adapters/sui/getters.d.ts +24 -0
  118. package/lib/adapters/sui/getters.js +134 -0
  119. package/lib/adapters/sui/index.d.ts +53 -0
  120. package/lib/adapters/sui/index.js +96 -0
  121. package/lib/adapters/sui/transformer.d.ts +10 -0
  122. package/lib/adapters/sui/transformer.js +115 -0
  123. package/lib/adapters/sui/types.d.ts +70 -0
  124. package/lib/adapters/sui/types.js +3 -0
  125. package/lib/adapters/sui/utils.d.ts +8 -0
  126. package/lib/adapters/sui/utils.js +17 -0
  127. package/lib/core/analytics/app-name.d.ts +27 -0
  128. package/lib/core/analytics/app-name.js +48 -0
  129. package/lib/core/analytics/chain-name.d.ts +9 -0
  130. package/lib/core/analytics/chain-name.js +34 -0
  131. package/lib/core/analytics/constants.d.ts +15 -0
  132. package/lib/core/analytics/constants.js +28 -0
  133. package/lib/core/analytics/env.d.ts +46 -0
  134. package/lib/core/analytics/env.js +147 -0
  135. package/lib/core/analytics/index.d.ts +39 -0
  136. package/lib/core/analytics/index.js +83 -0
  137. package/lib/core/analytics/instrumentation.d.ts +29 -0
  138. package/lib/core/analytics/instrumentation.js +292 -0
  139. package/lib/core/analytics/method-taxonomy.d.ts +19 -0
  140. package/lib/core/analytics/method-taxonomy.js +156 -0
  141. package/lib/core/analytics/metrics.d.ts +48 -0
  142. package/lib/core/analytics/metrics.js +142 -0
  143. package/lib/core/analytics/sanitize.d.ts +57 -0
  144. package/lib/core/analytics/sanitize.js +272 -0
  145. package/lib/core/analytics/sentry-runtime.d.ts +15 -0
  146. package/lib/core/analytics/sentry-runtime.js +131 -0
  147. package/lib/core/analytics/sentry.d.ts +100 -0
  148. package/lib/core/analytics/sentry.js +696 -0
  149. package/lib/core/analytics/types.d.ts +55 -0
  150. package/lib/core/analytics/types.js +3 -0
  151. package/lib/core/analytics/user-identity.d.ts +55 -0
  152. package/lib/core/analytics/user-identity.js +218 -0
  153. package/lib/core/analytics/version.d.ts +6 -0
  154. package/lib/core/analytics/version.js +10 -0
  155. package/lib/core/attribution.d.ts +159 -0
  156. package/lib/core/attribution.js +194 -0
  157. package/lib/core/auth/index.d.ts +1 -0
  158. package/lib/core/auth/index.js +18 -0
  159. package/lib/core/auth/verify.d.ts +2 -0
  160. package/lib/core/auth/verify.js +35 -0
  161. package/lib/core/base.class.d.ts +193 -0
  162. package/lib/core/base.class.js +163 -0
  163. package/lib/core/cache.d.ts +9 -0
  164. package/lib/core/cache.js +31 -0
  165. package/lib/core/constants/adapters.d.ts +103 -0
  166. package/lib/core/constants/adapters.js +180 -0
  167. package/lib/core/constants/core.d.ts +162 -0
  168. package/lib/core/constants/core.js +281 -0
  169. package/lib/core/constants/swap-router.d.ts +180 -0
  170. package/lib/core/constants/swap-router.js +203 -0
  171. package/lib/core/constants/vaults.d.ts +93 -0
  172. package/lib/core/constants/vaults.js +277 -0
  173. package/lib/core/constants/web3.d.ts +106 -0
  174. package/lib/core/constants/web3.js +251 -0
  175. package/lib/core/errors/index.d.ts +177 -0
  176. package/lib/core/errors/index.js +257 -0
  177. package/lib/core/fetcher.d.ts +237 -0
  178. package/lib/core/fetcher.js +1103 -0
  179. package/lib/core/helpers/adapters.d.ts +13 -0
  180. package/lib/core/helpers/adapters.js +39 -0
  181. package/lib/core/helpers/chain-address.d.ts +13 -0
  182. package/lib/core/helpers/chain-address.js +47 -0
  183. package/lib/core/helpers/chain-error.d.ts +207 -0
  184. package/lib/core/helpers/chain-error.js +697 -0
  185. package/lib/core/helpers/chain-support.d.ts +98 -0
  186. package/lib/core/helpers/chain-support.js +139 -0
  187. package/lib/core/helpers/concurrency.d.ts +51 -0
  188. package/lib/core/helpers/concurrency.js +79 -0
  189. package/lib/core/helpers/core.d.ts +92 -0
  190. package/lib/core/helpers/core.js +368 -0
  191. package/lib/core/helpers/explorer-link.d.ts +16 -0
  192. package/lib/core/helpers/explorer-link.js +26 -0
  193. package/lib/core/helpers/multicall.d.ts +68 -0
  194. package/lib/core/helpers/multicall.js +103 -0
  195. package/lib/core/helpers/revert-decode.d.ts +248 -0
  196. package/lib/core/helpers/revert-decode.js +515 -0
  197. package/lib/core/helpers/signer.d.ts +61 -0
  198. package/lib/core/helpers/signer.js +184 -0
  199. package/lib/core/helpers/swap-router.d.ts +269 -0
  200. package/lib/core/helpers/swap-router.js +542 -0
  201. package/lib/core/helpers/vault-version.d.ts +24 -0
  202. package/lib/core/helpers/vault-version.js +83 -0
  203. package/lib/core/helpers/vaults.d.ts +89 -0
  204. package/lib/core/helpers/vaults.js +241 -0
  205. package/lib/core/helpers/web3.d.ts +366 -0
  206. package/lib/core/helpers/web3.js +1034 -0
  207. package/lib/core/index.d.ts +23 -0
  208. package/lib/core/index.js +40 -0
  209. package/lib/core/logger/curator-alert.d.ts +217 -0
  210. package/lib/core/logger/curator-alert.js +276 -0
  211. package/lib/core/logger/index.d.ts +99 -0
  212. package/lib/core/logger/index.js +163 -0
  213. package/lib/core/logger/slack.d.ts +49 -0
  214. package/lib/core/logger/slack.js +111 -0
  215. package/lib/core/vault-metadata.d.ts +12 -0
  216. package/lib/core/vault-metadata.js +42 -0
  217. package/lib/core/version-check.d.ts +58 -0
  218. package/lib/core/version-check.js +182 -0
  219. package/lib/evm/index.d.ts +2 -0
  220. package/lib/evm/index.js +19 -0
  221. package/lib/evm/methods/crossChainVault.d.ts +132 -0
  222. package/lib/evm/methods/crossChainVault.js +857 -0
  223. package/lib/evm/methods/crossChainVaultRegistry.d.ts +92 -0
  224. package/lib/evm/methods/crossChainVaultRegistry.js +239 -0
  225. package/lib/evm/methods/index.d.ts +2 -0
  226. package/lib/evm/methods/index.js +19 -0
  227. package/lib/evm/types/crossChain.d.ts +363 -0
  228. package/lib/evm/types/crossChain.js +20 -0
  229. package/lib/evm/types/index.d.ts +1 -0
  230. package/lib/evm/types/index.js +18 -0
  231. package/lib/index.d.ts +30 -0
  232. package/lib/index.js +52 -0
  233. package/lib/main.d.ts +596 -0
  234. package/lib/main.js +681 -0
  235. package/lib/modules/api/fetcher.d.ts +108 -0
  236. package/lib/modules/api/fetcher.js +187 -0
  237. package/lib/modules/api/index.d.ts +1 -0
  238. package/lib/modules/api/index.js +6 -0
  239. package/lib/modules/api/main.d.ts +587 -0
  240. package/lib/modules/api/main.js +911 -0
  241. package/lib/modules/sub-accounts/fetcher.d.ts +53 -0
  242. package/lib/modules/sub-accounts/fetcher.js +96 -0
  243. package/lib/modules/sub-accounts/index.d.ts +2 -0
  244. package/lib/modules/sub-accounts/index.js +19 -0
  245. package/lib/modules/sub-accounts/main.d.ts +249 -0
  246. package/lib/modules/sub-accounts/main.js +211 -0
  247. package/lib/modules/sub-accounts/utils.d.ts +106 -0
  248. package/lib/modules/sub-accounts/utils.js +112 -0
  249. package/lib/modules/vaults/adapter.helpers.d.ts +84 -0
  250. package/lib/modules/vaults/adapter.helpers.js +202 -0
  251. package/lib/modules/vaults/fetcher.d.ts +147 -0
  252. package/lib/modules/vaults/fetcher.js +357 -0
  253. package/lib/modules/vaults/getters.d.ts +1060 -0
  254. package/lib/modules/vaults/getters.js +4079 -0
  255. package/lib/modules/vaults/index.d.ts +20 -0
  256. package/lib/modules/vaults/index.js +44 -0
  257. package/lib/modules/vaults/main.d.ts +607 -0
  258. package/lib/modules/vaults/main.js +1687 -0
  259. package/lib/modules/vaults/prefetch.d.ts +65 -0
  260. package/lib/modules/vaults/prefetch.js +120 -0
  261. package/lib/modules/vaults/read.actions.d.ts +406 -0
  262. package/lib/modules/vaults/read.actions.js +891 -0
  263. package/lib/modules/vaults/types.d.ts +149 -0
  264. package/lib/modules/vaults/types.js +3 -0
  265. package/lib/modules/vaults/utils/call-data-decoder.d.ts +61 -0
  266. package/lib/modules/vaults/utils/call-data-decoder.js +194 -0
  267. package/lib/modules/vaults/utils/date-utils.d.ts +50 -0
  268. package/lib/modules/vaults/utils/date-utils.js +84 -0
  269. package/lib/modules/vaults/utils.d.ts +153 -0
  270. package/lib/modules/vaults/utils.js +818 -0
  271. package/lib/modules/vaults/write.actions.d.ts +812 -0
  272. package/lib/modules/vaults/write.actions.js +2377 -0
  273. package/lib/polyfills.d.ts +1 -0
  274. package/lib/polyfills.js +12 -0
  275. package/lib/sdk.d.ts +30154 -0
  276. package/lib/services/coingecko/fetcher.d.ts +15 -0
  277. package/lib/services/coingecko/fetcher.js +67 -0
  278. package/lib/services/coingecko/index.d.ts +2 -0
  279. package/lib/services/coingecko/index.js +19 -0
  280. package/lib/services/coingecko/utils.d.ts +1 -0
  281. package/lib/services/coingecko/utils.js +24 -0
  282. package/lib/services/debank/fetcher.d.ts +126 -0
  283. package/lib/services/debank/fetcher.js +47 -0
  284. package/lib/services/debank/index.d.ts +2 -0
  285. package/lib/services/debank/index.js +19 -0
  286. package/lib/services/debank/utils.d.ts +50 -0
  287. package/lib/services/debank/utils.js +325 -0
  288. package/lib/services/layerzero/deposits.d.ts +55 -0
  289. package/lib/services/layerzero/deposits.js +174 -0
  290. package/lib/services/layerzero/redeems.d.ts +20 -0
  291. package/lib/services/layerzero/redeems.js +92 -0
  292. package/lib/services/layerzero/utils.d.ts +9 -0
  293. package/lib/services/layerzero/utils.js +22 -0
  294. package/lib/services/octavfi/fetcher.d.ts +33 -0
  295. package/lib/services/octavfi/fetcher.js +39 -0
  296. package/lib/services/octavfi/index.d.ts +3 -0
  297. package/lib/services/octavfi/index.js +20 -0
  298. package/lib/services/octavfi/types.d.ts +34 -0
  299. package/lib/services/octavfi/types.js +3 -0
  300. package/lib/services/octavfi/utils.d.ts +16 -0
  301. package/lib/services/octavfi/utils.js +244 -0
  302. package/lib/services/subgraph/fetcher.d.ts +2 -0
  303. package/lib/services/subgraph/fetcher.js +66 -0
  304. package/lib/services/subgraph/index.d.ts +2 -0
  305. package/lib/services/subgraph/index.js +19 -0
  306. package/lib/services/subgraph/schema.d.ts +48 -0
  307. package/lib/services/subgraph/schema.js +87 -0
  308. package/lib/services/subgraph/vaults.d.ts +83 -0
  309. package/lib/services/subgraph/vaults.js +1282 -0
  310. package/lib/services/swap-quotes/index.d.ts +105 -0
  311. package/lib/services/swap-quotes/index.js +77 -0
  312. package/lib/services/swap-quotes/paraswap.d.ts +51 -0
  313. package/lib/services/swap-quotes/paraswap.js +138 -0
  314. package/lib/services/untangled/fetcher.d.ts +40 -0
  315. package/lib/services/untangled/fetcher.js +110 -0
  316. package/lib/services/untangled/index.d.ts +3 -0
  317. package/lib/services/untangled/index.js +20 -0
  318. package/lib/services/untangled/types.d.ts +83 -0
  319. package/lib/services/untangled/types.js +10 -0
  320. package/lib/services/untangled/utils.d.ts +91 -0
  321. package/lib/services/untangled/utils.js +339 -0
  322. package/lib/types/api.d.ts +498 -0
  323. package/lib/types/api.js +3 -0
  324. package/lib/types/index.d.ts +12 -0
  325. package/lib/types/index.js +28 -0
  326. package/lib/types/points.d.ts +28 -0
  327. package/lib/types/points.js +3 -0
  328. package/lib/types/pools.d.ts +144 -0
  329. package/lib/types/pools.js +3 -0
  330. package/lib/types/staking.d.ts +28 -0
  331. package/lib/types/staking.js +3 -0
  332. package/lib/types/sub-accounts.d.ts +150 -0
  333. package/lib/types/sub-accounts.js +3 -0
  334. package/lib/types/subgraph.d.ts +84 -0
  335. package/lib/types/subgraph.js +3 -0
  336. package/lib/types/typed-contract.d.ts +102 -0
  337. package/lib/types/typed-contract.js +3 -0
  338. package/lib/types/user.d.ts +1 -0
  339. package/lib/types/user.js +3 -0
  340. package/lib/types/vaults.d.ts +886 -0
  341. package/lib/types/vaults.js +30 -0
  342. package/lib/types/web3.d.ts +81 -0
  343. package/lib/types/web3.js +14 -0
  344. package/lib/types/webserver.d.ts +730 -0
  345. package/lib/types/webserver.js +3 -0
  346. package/package.json +78 -3
@@ -0,0 +1,1282 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isOldSubgraphSchema = isOldSubgraphSchema;
4
+ exports.getSubgraphWithdrawRequests = getSubgraphWithdrawRequests;
5
+ exports.getSubgraphWithdrawProccessed = getSubgraphWithdrawProccessed;
6
+ exports.getSubgraphAllWithdrawals = getSubgraphAllWithdrawals;
7
+ exports.getSubgraphUserHistory = getSubgraphUserHistory;
8
+ exports.getSubgraphVaultHistory = getSubgraphVaultHistory;
9
+ exports.getSubgraphUserTransfers = getSubgraphUserTransfers;
10
+ exports.getSubgraphUserReserveDeposits = getSubgraphUserReserveDeposits;
11
+ const ethers_1 = require("ethers");
12
+ const slack_1 = require("../../core/logger/slack");
13
+ const fetcher_1 = require("./fetcher");
14
+ const schema_1 = require("./schema");
15
+ const core_1 = require("../../core");
16
+ const fetcher_2 = require("../../modules/vaults/fetcher");
17
+ /**
18
+ * Utils
19
+ */
20
+ const GOLDSKY_API_KEY = '';
21
+ // Dedupe window for "Missing Subgraph" alerts (per pool).
22
+ const MISSING_SUBGRAPH_ALERT_TTL_MS = 60 * 60 * 1000; // 1 hour
23
+ /**
24
+ * Emit a "Missing Subgraph" Slack alert at most once per pool per TTL.
25
+ *
26
+ * `getDefaultSubgraphUrl` now returns `undefined` for vaults with no metadata or
27
+ * hardcoded subgraph URL, which makes the readers' `if (!goldskyUrl)` branches
28
+ * reachable (previously the fabricated URL was always truthy, so they were dead
29
+ * code). Portfolio/history flows loop over every vault, so alerting on each read
30
+ * would flood the webhook for every metadata-less vault. Deduping per pool
31
+ * surfaces a genuinely-missing subgraph without the flood.
32
+ *
33
+ * This is the durable signal for BOTH ways a vault's subgraph can be broken — no
34
+ * URL configured, and a URL that answers non-200 (a deleted subgraph 404s). The
35
+ * readers deliberately log those per-request at `warn` rather than `error`: at
36
+ * `error` each one became a billed Sentry issue on every portfolio read, which
37
+ * cost over 2M events in 30 days across a handful of vaults. The volume is
38
+ * per-request, but the condition is per-vault, so this alert is where it belongs.
39
+ *
40
+ * @param args.source - Reader function name, for the alert body.
41
+ * @param args.pool - Vault address (used as the dedupe key, lowercased).
42
+ * @param args.chainId - Chain id for the alert context, or a thunk resolving
43
+ * it. Every current caller has the id in scope and passes it directly. The
44
+ * thunk form exists for a caller that would otherwise have to resolve the id
45
+ * eagerly on every non-200 response — it is invoked only after the dedupe
46
+ * gate passes, so a suppressed alert costs nothing. No such caller exists
47
+ * today; if none appears, this union and the deferred branch below can go.
48
+ * @param args.reason - Why the subgraph is unusable. Defaults to the
49
+ * missing-URL case; pass the HTTP status for a URL that resolved but failed.
50
+ * @param args.slackWebookUrl - Optional override webhook URL.
51
+ */
52
+ function alertMissingSubgraphOnce(args) {
53
+ const key = `missing-subgraph-alert-${args.pool.toLowerCase()}`;
54
+ if (core_1.CACHE.has(key))
55
+ return;
56
+ core_1.CACHE.set(key, true, { ttl: MISSING_SUBGRAPH_ALERT_TTL_MS });
57
+ const send = (chainId) => slack_1.SLACK.error({
58
+ title: 'Missing Subgraph',
59
+ error: `#${args.source}: ${args.reason ?? 'goldsky url is undefined'}`,
60
+ poolAddress: args.pool,
61
+ chainId,
62
+ slackWebookUrl: args.slackWebookUrl || '',
63
+ });
64
+ if (typeof args.chainId === 'number') {
65
+ send(args.chainId);
66
+ return;
67
+ }
68
+ // Deferred id: the dedupe key is already set, so a rejection here would mute
69
+ // this pool for the full TTL without ever alerting. Release the key instead,
70
+ // leaving the next non-200 free to try again.
71
+ void args
72
+ .chainId()
73
+ .then(send, (e) => {
74
+ core_1.CACHE.delete(key);
75
+ core_1.Logger.log.warn('alertMissingSubgraphOnce', `chain id unresolved, alert skipped: ${e}`);
76
+ })
77
+ // `send` itself can reject (SLACK.error does its own fetch). Without this
78
+ // it escapes as an unhandled rejection instead of being contained here.
79
+ .catch((e) => {
80
+ core_1.Logger.log.warn('alertMissingSubgraphOnce', `alert send failed: ${e}`);
81
+ });
82
+ }
83
+ /**
84
+ * earnAUSD exists on both Ethereum and Monad, so it needs a _monad suffix
85
+ * to distinguish its Monad subgraph from the Ethereum one.
86
+ * Other Monad-native vaults (sausd, supermon, etc.) don't need this.
87
+ */
88
+ function needsMonadSuffix(chainId, symbol) {
89
+ return chainId === 143 && symbol.toLowerCase() === 'earnausd';
90
+ }
91
+ /**
92
+ * Read the decimals of every distinct deposit asset in a batch of deposit
93
+ * rows, keyed by lowercased token address.
94
+ *
95
+ * Pre-deposit / evm-2 vaults accept multiple deposit assets whose decimals can
96
+ * differ from the vault's own (e.g. RLUSD at 18 deposited into a 6-decimal
97
+ * sentUSD vault). `transformUserHistory` must normalize each deposit against
98
+ * its own asset's decimals rather than the vault's, or an 18-decimal amount
99
+ * normalized at 6 decimals renders ~1e12× too large (a 0.5 deposit shows as
100
+ * "500B"). `getDecimals` is cached and in-flight-deduped, and the distinct-asset
101
+ * set is tiny (typically 1-3), so this is at most a handful of RPC reads.
102
+ *
103
+ * Native-token deposits carry a sentinel `assetIn` — either the zero address or
104
+ * {@link NATIVE_ADDRESS} — that has no on-chain `decimals()`. These are mapped
105
+ * directly to {@link EVM_NATIVE_DECIMALS} (18 on every supported EVM chain)
106
+ * instead of being read. Without this guard `getDecimals(ZeroAddress)` returns
107
+ * `0`, which the caller's `?? decimals` fallback cannot override (0 is not
108
+ * nullish), overstating a native deposit ~1e18×; and `getDecimals(NATIVE_ADDRESS)`
109
+ * reverts, silently dropping to the vault's decimals which may differ.
110
+ *
111
+ * Only successfully-read decimals are entered in the map; a non-native asset
112
+ * whose `decimals()` read fails is omitted so the caller falls back to the
113
+ * vault's decimals. This also lets the vault-decimals read run in parallel with
114
+ * this one (no fallback value is needed up front).
115
+ *
116
+ * @param provider - EVM contract runner used to read `decimals()`.
117
+ * @param deposits - Deposit rows from the subgraph; `assetIn` may be absent.
118
+ * @returns Map of lowercased asset address to decimals (native sentinels and
119
+ * successful reads only).
120
+ */
121
+ async function buildDepositAssetDecimals(provider, deposits) {
122
+ const map = new Map();
123
+ // Lowercased native-token sentinels: no ERC-20 `decimals()` exists to read.
124
+ const nativeSentinels = new Set([
125
+ ethers_1.ZeroAddress.toLowerCase(),
126
+ core_1.NATIVE_ADDRESS.toLowerCase(),
127
+ ]);
128
+ const unique = new Set();
129
+ for (const d of deposits ?? []) {
130
+ if (d?.assetIn)
131
+ unique.add(d.assetIn.toLowerCase());
132
+ }
133
+ await Promise.all([...unique].map(async (addr) => {
134
+ if (nativeSentinels.has(addr)) {
135
+ map.set(addr, core_1.EVM_NATIVE_DECIMALS);
136
+ return;
137
+ }
138
+ const dec = await (0, core_1.getDecimals)(provider, addr, false);
139
+ if (typeof dec === 'number')
140
+ map.set(addr, dec);
141
+ }));
142
+ return map;
143
+ }
144
+ function transformUserHistory(data, chainId, decimals, poolAddress, assetDecimals) {
145
+ //ok to return dupes even though withdraws will return dupe because we parse out duplicate txn hash on the FE
146
+ return [
147
+ ...(data.withdraws?.map((item) => ({
148
+ ...item,
149
+ contractId_: item.contractId_ || poolAddress,
150
+ address: item.receiver,
151
+ amount: item.assets,
152
+ chainId: chainId,
153
+ type: 'withdraw-processed',
154
+ transactionHash: item.transactionHash_,
155
+ timestamp: item.timestamp_,
156
+ decimals: decimals,
157
+ isInstant: true,
158
+ })) || []),
159
+ ...(data.withdrawalRequesteds?.map((item) => ({
160
+ ...item,
161
+ contractId_: item.contractId_ || poolAddress,
162
+ address: item.receiverAddr,
163
+ amount: item?.assets || item?.shares,
164
+ chainId: chainId,
165
+ type: 'withdraw-request',
166
+ transactionHash: item.transactionHash_,
167
+ timestamp: item.timestamp_,
168
+ decimals: decimals,
169
+ })) || []),
170
+ ...(data.withdrawalProcesseds?.map((item) => ({
171
+ ...item,
172
+ contractId_: item.contractId_ || poolAddress,
173
+ address: item.receiverAddr,
174
+ amount: item.assetsAmount,
175
+ chainId: chainId,
176
+ type: 'withdraw-processed',
177
+ transactionHash: item.transactionHash_,
178
+ timestamp: item.timestamp_,
179
+ decimals: decimals,
180
+ })) || []),
181
+ ...(data.deposits?.map((item) => {
182
+ // Pair the decimals to the amount's denomination. `assets` (evm-1) is
183
+ // already in the vault's underlying, so it keeps the vault decimals.
184
+ // Only `amountIn` (evm-2 / pre-deposit) is denominated in `assetIn`,
185
+ // which may differ from the vault (e.g. RLUSD 18 → sentUSD 6) and would
186
+ // otherwise overstate the amount ~1e12×. Using the same source for both
187
+ // avoids a denomination/decimals mismatch, and the truthy `assetIn`
188
+ // guard drops empty-string addresses back to the vault decimals.
189
+ const assetKey = !item?.assets && item.assetIn ? item.assetIn.toLowerCase() : undefined;
190
+ return {
191
+ ...item,
192
+ contractId_: item.contractId_ || poolAddress,
193
+ chainId: chainId,
194
+ type: 'deposit',
195
+ address: item?.sender || item?.senderAddr,
196
+ amount: item?.assets || item?.amountIn,
197
+ transactionHash: item.transactionHash_,
198
+ timestamp: item.timestamp_,
199
+ decimals: (assetKey ? assetDecimals?.get(assetKey) : undefined) ?? decimals,
200
+ };
201
+ }) || []),
202
+ ];
203
+ }
204
+ function sortUserHistory(data, chainId, decimals, poolAddress, assetDecimals) {
205
+ if (!(data && chainId && decimals))
206
+ return [];
207
+ return transformUserHistory(data, chainId, decimals, poolAddress, assetDecimals).sort((a, b) => Number(a.timestamp_) - Number(b.timestamp_));
208
+ }
209
+ // queries
210
+ const WITHDRAWALS_REQUESTED_QUERY_PROPS = `
211
+ id
212
+ day
213
+ month
214
+ year
215
+ shares
216
+ assets
217
+ receiverAddr
218
+ ownerAddr
219
+ block_number
220
+ timestamp_
221
+ transactionHash_
222
+ contractId_
223
+ `;
224
+ const EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS = `
225
+ id
226
+ shares
227
+ receiverAddr
228
+ holderAddr
229
+ block_number
230
+ timestamp_
231
+ transactionHash_
232
+ contractId_
233
+ `;
234
+ const WITHDRAWALS_QUERY_PROPS = `
235
+ id
236
+ transactionHash_
237
+ timestamp_
238
+ block_number
239
+ contractId_
240
+ assets
241
+ receiver
242
+ sender
243
+ `;
244
+ const EVM_V2_WITHDRAWALS_QUERY_PROPS = `
245
+ id
246
+ transactionHash_
247
+ timestamp_
248
+ block_number
249
+ contractId_
250
+ assets
251
+ receiver
252
+ sender
253
+ shares
254
+ owner
255
+ `;
256
+ const WITHDRAWALS_PROCESSED_QUERY_PROPS = `
257
+ id
258
+ processedOn
259
+ requestedOn
260
+ receiverAddr
261
+ assetsAmount
262
+ block_number
263
+ timestamp_
264
+ contractId_
265
+ transactionHash_
266
+ `;
267
+ const EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS = `
268
+ id
269
+ receiverAddr
270
+ assetsAmount
271
+ block_number
272
+ timestamp_
273
+ contractId_
274
+ transactionHash_
275
+ `;
276
+ const DEPOSIT_QUERY_PROPS = `
277
+ id
278
+ assets
279
+ transactionHash_
280
+ timestamp_
281
+ contractId_
282
+ sender
283
+ shares
284
+ owner
285
+ `;
286
+ const EVM_V2_DEPOSIT_QUERY_PROPS = `
287
+ id
288
+ assetIn
289
+ amountIn
290
+ transactionHash_
291
+ timestamp_
292
+ contractId_
293
+ senderAddr
294
+ receiverAddr
295
+ `;
296
+ // New deployment process uses a different subgraph schema (no trailing underscores).
297
+ // Vaults in SUBGRAPH_VAULT_URLS use the old schema; everything else uses the new schema.
298
+ // GraphQL aliases map new-schema fields to what the SDK expects internally.
299
+ function isOldSubgraphSchema(vaultSymbol) {
300
+ return (vaultSymbol?.toLowerCase() in
301
+ core_1.SUBGRAPH_VAULT_URLS);
302
+ }
303
+ // New schema query props (shared across evm-1 and evm-2 — the new subgraph schema
304
+ // normalized field names, so no per-version variants are needed)
305
+ const NEW_DEPOSIT_QUERY_PROPS = `
306
+ id
307
+ assetIn
308
+ amountIn
309
+ transactionHash_: transactionHash
310
+ timestamp_: blockTimestamp
311
+ senderAddr
312
+ receiverAddr
313
+ `;
314
+ // The `block_number: blockNumber` alias on these new-schema withdrawal prop
315
+ // sets is required, not cosmetic: getWithdrawalRequestsWithStatus prunes by
316
+ // `Number(req.block_number) >= blockCutoff` (per the ISubgraphBase contract).
317
+ // New-schema subgraphs expose the field as `blockNumber`, so without the alias
318
+ // it reads undefined → Number(undefined) is NaN → every request is pruned
319
+ // (AUGUST-6514). Only the REQUESTED set is read today; the processed/withdrawals
320
+ // aliases below are kept for the same type contract so the NaN prune can't recur.
321
+ const NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS = `
322
+ id
323
+ shares
324
+ receiverAddr
325
+ holderAddr
326
+ block_number: blockNumber
327
+ transactionHash_: transactionHash
328
+ timestamp_: blockTimestamp
329
+ `;
330
+ const NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS = `
331
+ id
332
+ receiverAddr
333
+ assetsAmount
334
+ block_number: blockNumber
335
+ transactionHash_: transactionHash
336
+ timestamp_: blockTimestamp
337
+ `;
338
+ const NEW_WITHDRAWALS_QUERY_PROPS = `
339
+ id
340
+ transactionHash_: transactionHash
341
+ timestamp_: blockTimestamp
342
+ block_number: blockNumber
343
+ assets
344
+ receiver
345
+ sender
346
+ shares
347
+ owner
348
+ `;
349
+ // New schema: transfer query props
350
+ const NEW_TRANSFER_QUERY_PROPS = `
351
+ id
352
+ from
353
+ to
354
+ value
355
+ transactionHash_: transactionHash
356
+ timestamp_: blockTimestamp
357
+ block_number: blockNumber
358
+ `;
359
+ const TRANSFER_QUERY_PROPS = `
360
+ id
361
+ from
362
+ to
363
+ value
364
+ transactionHash_
365
+ timestamp_
366
+ block_number
367
+ contractId_
368
+ `;
369
+ /**
370
+ * Goldsky caps every list field at 1000 rows per request, so a busy vault's
371
+ * withdrawal entities silently truncate unless we page on `skip`. Both bounds
372
+ * are shared by every withdrawal reader below.
373
+ */
374
+ const WITHDRAWAL_PAGE_SIZE = 1000;
375
+ /**
376
+ * Upper bound on pages fetched per withdrawal reader (20 × 1000 = 20 000 rows
377
+ * per entity). A vault past this bound is logged and returns the rows gathered
378
+ * so far rather than looping on a subgraph that keeps reporting full pages.
379
+ */
380
+ const WITHDRAWAL_MAX_PAGES = 20;
381
+ /**
382
+ * Page a withdrawal query on `skip` until every requested entity returns a
383
+ * short page (fewer than {@link WITHDRAWAL_PAGE_SIZE} rows).
384
+ *
385
+ * Why: `withdrawalRequesteds` / `withdrawalProcesseds` were previously read
386
+ * with a single `first: 1000` request, so vaults with more than 1000 events
387
+ * lost their oldest rows (and `getWithdrawalRequestsWithStatus` under-counted
388
+ * pending requests). Mirrors the lockstep paging in
389
+ * {@link getSubgraphVaultHistory}; ordering is whatever `buildQuery` encodes
390
+ * (newest-first), and pages are concatenated in fetch order so the result
391
+ * stays sorted.
392
+ *
393
+ * @param source - Caller name for log attribution.
394
+ * @param goldskyUrl - Subgraph endpoint.
395
+ * @param buildQuery - Renders the GraphQL document for one page. Every entity
396
+ * in `entityKeys` must carry `first: pageSize, skip: skip`.
397
+ * @param entityKeys - Top-level `data` keys to accumulate across pages.
398
+ * @returns The first page's HTTP status (so callers keep their existing
399
+ * non-200 warn/alert path) plus the accumulated rows per entity. A later
400
+ * page failing is logged and the rows gathered so far are returned.
401
+ *
402
+ * RPC budget: 1 request per 1000 rows of the largest entity, capped at
403
+ * {@link WITHDRAWAL_MAX_PAGES} requests.
404
+ */
405
+ async function fetchPagedWithdrawals(source, goldskyUrl, buildQuery, entityKeys) {
406
+ const data = Object.fromEntries(entityKeys.map((key) => [key, []]));
407
+ let skip = 0;
408
+ for (let page = 0; page < WITHDRAWAL_MAX_PAGES; page++) {
409
+ const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, buildQuery(WITHDRAWAL_PAGE_SIZE, skip), GOLDSKY_API_KEY);
410
+ if (result.status !== 200) {
411
+ // First page failing is the caller's existing error path; a later page
412
+ // failing still yields whatever earlier pages accumulated.
413
+ if (skip === 0) {
414
+ return { status: result.status, statusText: result.statusText, data };
415
+ }
416
+ core_1.Logger.log.warn(source, `${result.statusText}::${result.status}: page fetch failed, returning partial rows`, { skip });
417
+ break;
418
+ }
419
+ const json = (await result.json());
420
+ let needMore = false;
421
+ for (const key of entityKeys) {
422
+ const rows = json?.data?.[key] ?? [];
423
+ data[key].push(...rows);
424
+ if (rows.length === WITHDRAWAL_PAGE_SIZE)
425
+ needMore = true;
426
+ }
427
+ if (!needMore)
428
+ break;
429
+ skip += WITHDRAWAL_PAGE_SIZE;
430
+ if (page === WITHDRAWAL_MAX_PAGES - 1) {
431
+ core_1.Logger.log.warn(source, `hit the ${WITHDRAWAL_MAX_PAGES}-page cap; older withdrawal rows were not fetched`, { skip });
432
+ }
433
+ }
434
+ return { status: 200, statusText: 'OK', data };
435
+ }
436
+ /**
437
+ *
438
+ * @param pool
439
+ * @param provider
440
+ * @returns
441
+ */
442
+ async function getSubgraphWithdrawRequests(pool, provider, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)()) {
443
+ // setup
444
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
445
+ if (vaultSymbol === undefined) {
446
+ core_1.Logger.log.warn('getSubgraphWithdrawRequests', `cannot find vault symbol for pool: ${pool}`);
447
+ return [];
448
+ }
449
+ const networkValue = await provider.provider.getNetwork();
450
+ const network = Number(networkValue.chainId);
451
+ if (needsMonadSuffix(network, vaultSymbol)) {
452
+ vaultSymbol = vaultSymbol.concat('_monad');
453
+ }
454
+ // sanitize
455
+ if (vaultSymbol === 'testWETHTSA') {
456
+ return [];
457
+ }
458
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
459
+ const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
460
+ const goldskyUrl = subgraph ||
461
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
462
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
463
+ const requests = [];
464
+ if (!goldskyUrl) {
465
+ const chainId = await (0, core_1.getChainId)(provider);
466
+ core_1.Logger.log.warn('getSubgraphWithdrawRequests', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
467
+ alertMissingSubgraphOnce({
468
+ source: 'getSubgraphWithdrawRequests',
469
+ pool,
470
+ chainId,
471
+ slackWebookUrl,
472
+ });
473
+ return [];
474
+ }
475
+ const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
476
+ const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
477
+ // Probe the deployed subgraph to learn its actual field schema (cached per
478
+ // URL) instead of guessing from the vault symbol. See resolveSubgraphSchema —
479
+ // the old symbol-map heuristic silently emptied this set for vaults deployed
480
+ // on the old template but absent from SUBGRAPH_VAULT_URLS (AUGUST-6568).
481
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
482
+ const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
483
+ const withdrawalRequestedProps = useOldSchema
484
+ ? version === 'evm-2'
485
+ ? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
486
+ : WITHDRAWALS_REQUESTED_QUERY_PROPS
487
+ : NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
488
+ const result = await fetchPagedWithdrawals('getSubgraphWithdrawRequests', goldskyUrl, (pageSize, skip) => `{
489
+ withdrawalRequesteds(
490
+ first: ${pageSize},
491
+ skip: ${skip},
492
+ orderBy: ${orderByTimestamp},
493
+ orderDirection: desc,
494
+ ) {
495
+ ${withdrawalRequestedProps}
496
+ }
497
+ }`, ['withdrawalRequesteds']);
498
+ if (result.status !== 200) {
499
+ core_1.Logger.log.warn('getSubgraphWithdrawRequests', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
500
+ alertMissingSubgraphOnce({
501
+ source: 'getSubgraphWithdrawRequests',
502
+ pool,
503
+ // Already resolved at the top of this function — no re-fetch, and the
504
+ // alert fires synchronously.
505
+ chainId: network,
506
+ reason: `subgraph returned ${result.status} ${result.statusText}`,
507
+ slackWebookUrl,
508
+ });
509
+ return [];
510
+ }
511
+ requests.push(...result.data.withdrawalRequesteds);
512
+ return requests;
513
+ }
514
+ async function getSubgraphWithdrawProccessed(pool, provider, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)()) {
515
+ try {
516
+ // setup
517
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
518
+ if (vaultSymbol === undefined) {
519
+ core_1.Logger.log.warn('getSubgraphWithdrawProccessed', `cannot find vault symbol for pool: ${pool}`);
520
+ return [];
521
+ }
522
+ const networkValue = await provider.provider.getNetwork();
523
+ const network = Number(networkValue.chainId);
524
+ if (needsMonadSuffix(network, vaultSymbol)) {
525
+ vaultSymbol = vaultSymbol.concat('_monad');
526
+ }
527
+ const noWithdrawalProcessed = vaultSymbol === 'agETH';
528
+ // sanitize
529
+ if (vaultSymbol === 'testWETHTSA' || noWithdrawalProcessed) {
530
+ return [];
531
+ }
532
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
533
+ const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
534
+ const goldskyUrl = subgraph ||
535
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
536
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
537
+ const requests = [];
538
+ if (!goldskyUrl) {
539
+ const chainId = await (0, core_1.getChainId)(provider);
540
+ core_1.Logger.log.warn('getSubgraphWithdrawProccessed.missing-subgraph-url', `goldsky url is undefined: ${vaultSymbol}::${pool}`, { chainId });
541
+ alertMissingSubgraphOnce({
542
+ source: 'getSubgraphWithdrawProccessed',
543
+ pool,
544
+ chainId,
545
+ slackWebookUrl,
546
+ });
547
+ return [];
548
+ }
549
+ const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
550
+ const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
551
+ // Probe the deployed subgraph's actual field schema (cached per URL) rather
552
+ // than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
553
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
554
+ const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
555
+ const withdrawalProcessedProps = useOldSchema
556
+ ? version === 'evm-2'
557
+ ? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
558
+ : WITHDRAWALS_PROCESSED_QUERY_PROPS
559
+ : NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
560
+ const result = await fetchPagedWithdrawals('getSubgraphWithdrawProccessed', goldskyUrl, (pageSize, skip) => `{
561
+ withdrawalProcesseds (
562
+ first: ${pageSize},
563
+ skip: ${skip},
564
+ orderBy: ${orderByTimestamp},
565
+ orderDirection: desc,
566
+ ) {
567
+ ${withdrawalProcessedProps}
568
+ }
569
+ }`, ['withdrawalProcesseds']);
570
+ if (result.status !== 200) {
571
+ core_1.Logger.log.warn('getSubgraphWithdrawProccessed', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
572
+ alertMissingSubgraphOnce({
573
+ source: 'getSubgraphWithdrawProccessed',
574
+ pool,
575
+ // Already resolved at the top of this function — no re-fetch, and the
576
+ // alert fires synchronously.
577
+ chainId: network,
578
+ reason: `subgraph returned ${result.status} ${result.statusText}`,
579
+ slackWebookUrl,
580
+ });
581
+ return [];
582
+ }
583
+ requests.push(...result.data.withdrawalProcesseds);
584
+ return requests;
585
+ }
586
+ catch (e) {
587
+ core_1.Logger.log.error('getSubgraphWithdrawProccessed', e, { pool });
588
+ return [];
589
+ }
590
+ }
591
+ /**
592
+ * Fetch a vault's `withdrawalRequesteds` and `withdrawalProcesseds` from its
593
+ * Goldsky subgraph in one paged query.
594
+ *
595
+ * Without `receiver`, every wallet's rows are returned (up to the page cap) —
596
+ * on busy vaults that is ~0.9 MB per call. Pass `receiver` when the caller only
597
+ * needs one wallet's rows: both entities are then filtered server-side with
598
+ * `where: { receiverAddr }` (the same filter {@link getSubgraphUserHistory}
599
+ * uses), which shrinks the response to that wallet's rows (AUGUST-8317).
600
+ *
601
+ * Side effects: one schema probe per subgraph URL (cached) plus one Goldsky
602
+ * POST per 1,000-row page.
603
+ *
604
+ * @param pool - Vault contract address.
605
+ * @param provider - Contract runner, used to resolve the vault symbol/network.
606
+ * @param options - Optional settings.
607
+ * @param options.slackWebookUrl - Webhook for missing-subgraph alerts.
608
+ * Defaults to {@link resolveSlackWebhookUrl}.
609
+ * @param options.receiver - Optional wallet; when a valid EVM address, only
610
+ * rows whose `receiverAddr` matches it (case-insensitive) are fetched.
611
+ * @returns Both entity lists, newest first. Empty lists on any failure.
612
+ */
613
+ async function getSubgraphAllWithdrawals(pool, provider, { slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)(), receiver, } = {}) {
614
+ let query = '';
615
+ try {
616
+ // setup
617
+ const errorReturnObj = {
618
+ withdrawalRequesteds: [],
619
+ withdrawalProcesseds: [],
620
+ };
621
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
622
+ if (vaultSymbol === undefined) {
623
+ core_1.Logger.log.warn('getSubgraphAllWithdrawals', `cannot find vault symbol for pool: ${pool}`);
624
+ return errorReturnObj;
625
+ }
626
+ const networkValue = await provider.provider.getNetwork();
627
+ const network = Number(networkValue.chainId);
628
+ if (needsMonadSuffix(network, vaultSymbol)) {
629
+ vaultSymbol = vaultSymbol.concat('_monad');
630
+ }
631
+ const noWithdrawalProcessed = vaultSymbol === 'agETH';
632
+ // sanitize
633
+ if (vaultSymbol === 'testWETHTSA') {
634
+ return errorReturnObj;
635
+ }
636
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
637
+ const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
638
+ const goldskyUrl = subgraph ||
639
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
640
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
641
+ if (!goldskyUrl) {
642
+ const chainId = await (0, core_1.getChainId)(provider);
643
+ core_1.Logger.log.warn('getSubgraphAllWithdrawals', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
644
+ alertMissingSubgraphOnce({
645
+ source: 'getSubgraphAllWithdrawals',
646
+ pool,
647
+ chainId,
648
+ slackWebookUrl,
649
+ });
650
+ return errorReturnObj;
651
+ }
652
+ const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
653
+ const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
654
+ // Probe the deployed subgraph's actual field schema (cached per URL) rather
655
+ // than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
656
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
657
+ const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
658
+ const withdrawalRequestedProps = useOldSchema
659
+ ? version === 'evm-2'
660
+ ? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
661
+ : WITHDRAWALS_REQUESTED_QUERY_PROPS
662
+ : NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
663
+ const withdrawalProcessedProps = useOldSchema
664
+ ? version === 'evm-2'
665
+ ? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
666
+ : WITHDRAWALS_PROCESSED_QUERY_PROPS
667
+ : NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
668
+ // Subgraph stores addresses lowercased; only interpolate a validated
669
+ // address into the query.
670
+ const receiverWhere = receiver && (0, ethers_1.isAddress)(receiver)
671
+ ? `where: { receiverAddr: "${receiver.toLowerCase()}" },`
672
+ : '';
673
+ const buildQuery = (pageSize, skip) => {
674
+ // Keep the last-rendered document in the outer `query` so the catch
675
+ // below can log it on failure.
676
+ query = `{
677
+ withdrawalRequesteds(
678
+ first: ${pageSize},
679
+ skip: ${skip},
680
+ orderBy: ${orderByTimestamp},
681
+ orderDirection: desc,
682
+ ${receiverWhere}
683
+ ) {
684
+ ${withdrawalRequestedProps}
685
+ }
686
+ ${noWithdrawalProcessed
687
+ ? ''
688
+ : `withdrawalProcesseds (
689
+ first: ${pageSize},
690
+ skip: ${skip},
691
+ orderBy: ${orderByTimestamp},
692
+ orderDirection: desc,
693
+ ${receiverWhere}
694
+ ) {
695
+ ${withdrawalProcessedProps}
696
+ }
697
+ `}
698
+ }`;
699
+ return query;
700
+ };
701
+ const result = await fetchPagedWithdrawals('getSubgraphAllWithdrawals', goldskyUrl, buildQuery, ['withdrawalRequesteds', 'withdrawalProcesseds']);
702
+ if (result.status !== 200) {
703
+ core_1.Logger.log.warn('getSubgraphAllWithdrawals', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
704
+ alertMissingSubgraphOnce({
705
+ source: 'getSubgraphAllWithdrawals',
706
+ pool,
707
+ chainId: network,
708
+ reason: `subgraph returned ${result.status} ${result.statusText}`,
709
+ slackWebookUrl,
710
+ });
711
+ return errorReturnObj;
712
+ }
713
+ const requests = {
714
+ withdrawalRequesteds: result.data
715
+ .withdrawalRequesteds,
716
+ withdrawalProcesseds: result.data
717
+ .withdrawalProcesseds,
718
+ };
719
+ return requests;
720
+ }
721
+ catch (e) {
722
+ core_1.Logger.log.error('getSubgraphAllWithdrawals', `${pool}::${e}::${query}`);
723
+ return {
724
+ withdrawalRequesteds: [],
725
+ withdrawalProcesseds: [],
726
+ };
727
+ }
728
+ }
729
+ /**
730
+ * Fetch a user's deposit/withdraw history for an archived vault from the backend
731
+ * Mongo snapshot (`/upshift/vault_history`) instead of its retired subgraph.
732
+ *
733
+ * Returns the same {@link ISubgraphUserHistoryItem} shape as the subgraph path,
734
+ * so the caller's downstream transform/normalization is unchanged. `amount` is
735
+ * the raw deposited-asset amount (base units); `decimals` is attached so the
736
+ * caller can normalize, mirroring the subgraph path.
737
+ *
738
+ * Pre-deposit vaults accept multiple deposit assets with differing decimals
739
+ * (e.g. USDS at 18, USDC at 6). When the backend supplies `asset_address` per
740
+ * row, it is propagated as {@link ISubgraphUserHistoryItem.assetIn} (and, when
741
+ * present, `asset_decimals` is used for that row's `decimals`) so lifetime PnL
742
+ * resolves each deposit against its own token rather than the vault decimals —
743
+ * without it, an 18-decimal deposit normalized at the vault's 6 decimals
744
+ * inflates the cost basis by ~1e12. This mirrors the subgraph path, whose
745
+ * deposit rows already carry `assetIn`.
746
+ *
747
+ * Side effects: one RPC read (`getDecimals`) and one HTTP GET to the public API.
748
+ *
749
+ * @param user - The wallet whose history to fetch.
750
+ * @param provider - Contract runner, used to read the vault's decimals.
751
+ * @param pool - The (archived) vault contract address.
752
+ * @returns The user's deposits and settled withdrawals. Empty on a non-200
753
+ * response.
754
+ */
755
+ async function getArchivedVaultUserHistory(user, provider, pool) {
756
+ const decimals = await (0, core_1.getDecimals)(provider, pool);
757
+ const response = await (0, core_1.fetchUpshiftPublic)(core_1.WEBSERVER_ENDPOINTS.public.tokenizedVault.userHistory(pool, user));
758
+ if (response.status !== 200) {
759
+ core_1.Logger.log.error('getArchivedVaultUserHistory', `non-200 from vault_history for ${pool}: ${response.status}`);
760
+ return [];
761
+ }
762
+ const rows = (await response.json());
763
+ // The backend already stores final ISubgraphUserHistoryItem.type values, so
764
+ // no translation is needed. Two row-level guards before mapping, since both
765
+ // bad shapes propagate destructively downstream:
766
+ // - amount_raw must be a non-negative integer: the caller does
767
+ // BigInt(amount) outside a try/catch, and one bad row would throw and
768
+ // wipe the user's entire (all-vault) history.
769
+ // - timestamp must parse to a real time: a malformed value makes getTime()
770
+ // return NaN, which stringifies to "NaN" and then sorts/normalizes
771
+ // incorrectly downstream. Drop the row rather than emit a "NaN" stamp.
772
+ return (rows
773
+ .filter((row) => /^\d+$/.test(row.amount_raw) &&
774
+ !Number.isNaN(new Date(row.timestamp).getTime()))
775
+ .map((row) => ({
776
+ id: row.transaction_hash,
777
+ contractId_: pool,
778
+ timestamp_: String(Math.floor(new Date(row.timestamp).getTime() / 1000)),
779
+ transactionHash_: row.transaction_hash,
780
+ block_number: row.block_number != null ? String(row.block_number) : '0',
781
+ address: row.wallet,
782
+ amount: row.amount_raw,
783
+ type: row.type,
784
+ // Per-asset decimals when known, else the vault's. PnL re-resolves
785
+ // decimals from `assetIn` anyway; this keeps display/normalization
786
+ // correct for any consumer that reads the row's `decimals` directly.
787
+ decimals: row.asset_decimals ?? decimals,
788
+ // Carry the deposit asset through so mixed-decimal deposits normalize
789
+ // against their own token, not the vault's. Omitted when unknown.
790
+ ...(row.asset_address ? { assetIn: row.asset_address } : {}),
791
+ }))
792
+ // Match the subgraph path's ordering contract: sortUserHistory sorts
793
+ // ascending by unix timestamp_, and downstream consumers rely on that
794
+ // chronology. The backend returns rows in arbitrary order, so re-sort here.
795
+ .sort((a, b) => Number(a.timestamp_) - Number(b.timestamp_)));
796
+ }
797
+ async function getSubgraphUserHistory(user, provider, pool, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)()) {
798
+ try {
799
+ // This path is EVM-only: it reads chain id and network from an EVM
800
+ // JsonRpcProvider (eth_chainId / getNetwork) and queries an EVM subgraph.
801
+ // A non-EVM (Solana / Stellar) vault address routed here would call
802
+ // eth_chainId against a Solana/Stellar RPC and fail with a 400
803
+ // ("eth_chainId is not available on SOLANA_MAINNET"). Bail early so non-EVM
804
+ // vaults are simply skipped rather than throwing on every history fetch.
805
+ if (!(0, ethers_1.isAddress)(pool)) {
806
+ return [];
807
+ }
808
+ // Archived vaults: serve history from the backend Mongo snapshot instead of
809
+ // the (retired) subgraph. The archived set is fetched from the backend (the
810
+ // routing source of truth) so a vault is only rerouted once its history is
811
+ // backfilled. Same return shape keeps downstream unchanged.
812
+ const archivedVaults = await (0, fetcher_2.fetchArchivedVaults)();
813
+ if (archivedVaults.has(pool.toLowerCase())) {
814
+ return await getArchivedVaultUserHistory(user, provider, pool);
815
+ }
816
+ // setup
817
+ const chainId = await (0, core_1.getChainId)(provider);
818
+ const requests = [];
819
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
820
+ if (vaultSymbol === undefined) {
821
+ core_1.Logger.log.warn('getSubgraphUserHistory', `cannot find vault symbol for pool: ${pool}`);
822
+ return requests;
823
+ }
824
+ const networkValue = await provider.provider.getNetwork();
825
+ const network = Number(networkValue.chainId);
826
+ if (needsMonadSuffix(network, vaultSymbol)) {
827
+ vaultSymbol = vaultSymbol.concat('_monad');
828
+ }
829
+ const noWithdrawalProcessed = vaultSymbol === 'agETH';
830
+ // sanitize
831
+ if (vaultSymbol === 'testWETHTSA') {
832
+ return requests;
833
+ }
834
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
835
+ const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
836
+ const goldskyUrl = subgraph ||
837
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
838
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
839
+ if (!goldskyUrl) {
840
+ core_1.Logger.log.warn('getSubgraphUserHistory', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
841
+ alertMissingSubgraphOnce({
842
+ source: 'getSubgraphUserHistory',
843
+ pool,
844
+ chainId,
845
+ slackWebookUrl,
846
+ });
847
+ return requests;
848
+ }
849
+ const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
850
+ const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
851
+ // Probe the deployed subgraph's actual field schema (cached per URL) rather
852
+ // than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
853
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
854
+ const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
855
+ const depositProps = useOldSchema
856
+ ? version === 'evm-2'
857
+ ? EVM_V2_DEPOSIT_QUERY_PROPS
858
+ : DEPOSIT_QUERY_PROPS
859
+ : NEW_DEPOSIT_QUERY_PROPS;
860
+ const withdrawProps = useOldSchema
861
+ ? version === 'evm-2'
862
+ ? EVM_V2_WITHDRAWALS_QUERY_PROPS
863
+ : WITHDRAWALS_QUERY_PROPS
864
+ : NEW_WITHDRAWALS_QUERY_PROPS;
865
+ const withdrawalRequestedProps = useOldSchema
866
+ ? version === 'evm-2'
867
+ ? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
868
+ : WITHDRAWALS_REQUESTED_QUERY_PROPS
869
+ : NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
870
+ const withdrawalProcessedProps = useOldSchema
871
+ ? version === 'evm-2'
872
+ ? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
873
+ : WITHDRAWALS_PROCESSED_QUERY_PROPS
874
+ : NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
875
+ // The Deposit filter field must follow the subgraph schema, not the vault
876
+ // version: the new schema has no `owner` at all (it is `receiverAddr` for
877
+ // every version, see NEW_DEPOSIT_QUERY_PROPS), so an evm-1 vault on a new
878
+ // subgraph used to send `where: { owner }` and get a field error → empty
879
+ // history. Only the old schema differs per version (`owner` on evm-1,
880
+ // `receiverAddr` on evm-2).
881
+ const depositFilterField = useOldSchema && version !== 'evm-2' ? 'owner' : 'receiverAddr';
882
+ const depositQuery = `deposits (
883
+ first: 1000,
884
+ orderBy: ${orderByTimestamp},
885
+ orderDirection: desc,
886
+ where: { ${depositFilterField}: "${user?.toLowerCase()}" }
887
+ ) {
888
+ ${depositProps}
889
+ }`;
890
+ const fullRequest = `{
891
+ withdraws (
892
+ first: 1000,
893
+ orderBy: ${orderByTimestamp},
894
+ orderDirection: desc,
895
+ where: { receiver: "${user?.toLowerCase()}" }
896
+ ) {
897
+ ${withdrawProps}
898
+ }
899
+ withdrawalRequesteds (
900
+ first: 1000,
901
+ orderBy: ${orderByTimestamp},
902
+ orderDirection: desc,
903
+ where: { receiverAddr: "${user?.toLowerCase()}" }
904
+ ) {
905
+ ${withdrawalRequestedProps}
906
+ }
907
+ ${noWithdrawalProcessed
908
+ ? ''
909
+ : `withdrawalProcesseds (
910
+ first: 1000,
911
+ orderBy: ${orderByTimestamp},
912
+ orderDirection: desc,
913
+ where: { receiverAddr: "${user?.toLowerCase()}" }
914
+ ) {
915
+ ${withdrawalProcessedProps}
916
+ }
917
+ `}
918
+ ${depositQuery}
919
+ }`;
920
+ const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, fullRequest, GOLDSKY_API_KEY);
921
+ if (result.status !== 200) {
922
+ core_1.Logger.log.warn('getSubgraphUserHistory', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`);
923
+ alertMissingSubgraphOnce({
924
+ source: 'getSubgraphUserHistory',
925
+ pool,
926
+ chainId,
927
+ reason: `subgraph returned ${result.status} ${result.statusText}`,
928
+ slackWebookUrl,
929
+ });
930
+ return requests;
931
+ }
932
+ const json = (await result.json());
933
+ // Format data — vault decimals and per-asset decimals are independent reads.
934
+ const [decimals, assetDecimals] = await Promise.all([
935
+ (0, core_1.getDecimals)(provider, pool),
936
+ buildDepositAssetDecimals(provider, json.data?.deposits),
937
+ ]);
938
+ const formattedRequests = sortUserHistory(json.data, chainId, decimals, pool, assetDecimals);
939
+ return formattedRequests;
940
+ }
941
+ catch (e) {
942
+ core_1.Logger.log.error('getSubgraphUserHistory', `${pool}::${e}`);
943
+ return [];
944
+ }
945
+ }
946
+ async function getSubgraphVaultHistory(provider, pool, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)(), opts = {}) {
947
+ try {
948
+ // setup
949
+ const requests = [];
950
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
951
+ if (vaultSymbol === undefined) {
952
+ core_1.Logger.log.warn('getSubgraphVaultHistory', `cannot find vault symbol for pool: ${pool}`);
953
+ return requests;
954
+ }
955
+ const networkValue = await provider.provider.getNetwork();
956
+ const network = Number(networkValue.chainId);
957
+ if (needsMonadSuffix(network, vaultSymbol)) {
958
+ vaultSymbol = vaultSymbol.concat('_monad');
959
+ } // sanitize
960
+ if (vaultSymbol === 'testWETHTSA') {
961
+ return requests;
962
+ }
963
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
964
+ const { subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
965
+ const goldskyUrl = subgraph ||
966
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
967
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
968
+ if (!goldskyUrl) {
969
+ const chainId = await (0, core_1.getChainId)(provider);
970
+ core_1.Logger.log.warn('getSubgraphVaultHistory', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
971
+ alertMissingSubgraphOnce({
972
+ source: 'getSubgraphVaultHistory',
973
+ pool,
974
+ chainId,
975
+ slackWebookUrl,
976
+ });
977
+ return requests;
978
+ }
979
+ const tokenizedVault = (await (0, core_1.fetchTokenizedVault)(pool, undefined, false, false))?.[0];
980
+ const version = (0, core_1.getVaultVersionV2)(tokenizedVault);
981
+ // Probe the deployed subgraph's actual field schema (cached per URL) rather
982
+ // than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
983
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
984
+ const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
985
+ const withdrawProps = useOldSchema
986
+ ? version === 'evm-2'
987
+ ? EVM_V2_WITHDRAWALS_QUERY_PROPS
988
+ : WITHDRAWALS_QUERY_PROPS
989
+ : NEW_WITHDRAWALS_QUERY_PROPS;
990
+ const withdrawalRequestedProps = useOldSchema
991
+ ? version === 'evm-2'
992
+ ? EVM_V2_WITHDRAWALS_REQUESTED_QUERY_PROPS
993
+ : WITHDRAWALS_REQUESTED_QUERY_PROPS
994
+ : NEW_WITHDRAWALS_REQUESTED_QUERY_PROPS;
995
+ const withdrawalProcessedProps = useOldSchema
996
+ ? version === 'evm-2'
997
+ ? EVM_V2_WITHDRAWALS_PROCESSED_QUERY_PROPS
998
+ : WITHDRAWALS_PROCESSED_QUERY_PROPS
999
+ : NEW_WITHDRAWALS_PROCESSED_QUERY_PROPS;
1000
+ const depositProps = useOldSchema
1001
+ ? version === 'evm-2'
1002
+ ? EVM_V2_DEPOSIT_QUERY_PROPS
1003
+ : DEPOSIT_QUERY_PROPS
1004
+ : NEW_DEPOSIT_QUERY_PROPS;
1005
+ // Each of the four event entities is capped at 1000 rows per request, so
1006
+ // a busy vault would silently truncate. Page all four in lockstep on a
1007
+ // shared `skip` cursor (rows are ordered newest-first) and keep going while
1008
+ // any entity returned a full page. When `sinceTs` is set we can stop early:
1009
+ // once an entity's oldest row in the page predates the window, no later
1010
+ // page can contain in-window rows for it.
1011
+ const PAGE_SIZE = 1000;
1012
+ const accumulated = {
1013
+ withdraws: [],
1014
+ withdrawalRequesteds: [],
1015
+ withdrawalProcesseds: [],
1016
+ deposits: [],
1017
+ };
1018
+ let skip = 0;
1019
+ for (;;) {
1020
+ const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, `{
1021
+ withdraws (
1022
+ first: ${PAGE_SIZE},
1023
+ skip: ${skip},
1024
+ orderBy: ${orderByTimestamp},
1025
+ orderDirection: desc,
1026
+ ) {
1027
+ ${withdrawProps}
1028
+ }
1029
+ withdrawalRequesteds (
1030
+ first: ${PAGE_SIZE},
1031
+ skip: ${skip},
1032
+ orderBy: ${orderByTimestamp},
1033
+ orderDirection: desc,
1034
+ ) {
1035
+ ${withdrawalRequestedProps}
1036
+ }
1037
+ withdrawalProcesseds (
1038
+ first: ${PAGE_SIZE},
1039
+ skip: ${skip},
1040
+ orderBy: ${orderByTimestamp},
1041
+ orderDirection: desc,
1042
+ ) {
1043
+ ${withdrawalProcessedProps}
1044
+ }
1045
+ deposits (
1046
+ first: ${PAGE_SIZE},
1047
+ skip: ${skip},
1048
+ orderBy: ${orderByTimestamp},
1049
+ orderDirection: desc,
1050
+ ) {
1051
+ ${depositProps}
1052
+ }
1053
+ }`, GOLDSKY_API_KEY);
1054
+ if (result.status !== 200) {
1055
+ core_1.Logger.log.warn('getSubgraphVaultHistory', `${result.statusText}::${result.status}: ${vaultSymbol}::${pool}`, { skip });
1056
+ alertMissingSubgraphOnce({
1057
+ source: 'getSubgraphVaultHistory',
1058
+ pool,
1059
+ chainId: network,
1060
+ reason: `subgraph returned ${result.status} ${result.statusText}`,
1061
+ slackWebookUrl,
1062
+ });
1063
+ // First page failed → nothing to return. A later page failing still
1064
+ // yields whatever earlier pages accumulated.
1065
+ if (skip === 0)
1066
+ return requests;
1067
+ break;
1068
+ }
1069
+ const json = (await result.json());
1070
+ const page = json.data;
1071
+ accumulated.withdraws.push(...(page?.withdraws ?? []));
1072
+ accumulated.withdrawalRequesteds.push(...(page?.withdrawalRequesteds ?? []));
1073
+ accumulated.withdrawalProcesseds.push(...(page?.withdrawalProcesseds ?? []));
1074
+ accumulated.deposits.push(...(page?.deposits ?? []));
1075
+ const entities = [
1076
+ page?.withdraws,
1077
+ page?.withdrawalRequesteds,
1078
+ page?.withdrawalProcesseds,
1079
+ page?.deposits,
1080
+ ];
1081
+ const needMore = entities.some((rows) => {
1082
+ if ((rows?.length ?? 0) < PAGE_SIZE)
1083
+ return false;
1084
+ if (opts.sinceTs === undefined)
1085
+ return true;
1086
+ const oldest = Number(rows?.[rows.length - 1]?.timestamp_);
1087
+ return !Number.isFinite(oldest) || oldest >= opts.sinceTs;
1088
+ });
1089
+ if (!needMore)
1090
+ break;
1091
+ skip += PAGE_SIZE;
1092
+ }
1093
+ // Format data — vault decimals and per-asset decimals are independent reads.
1094
+ const chainId = await (0, core_1.getChainId)(provider);
1095
+ const [decimals, assetDecimals] = await Promise.all([
1096
+ (0, core_1.getDecimals)(provider, pool),
1097
+ buildDepositAssetDecimals(provider, accumulated?.deposits),
1098
+ ]);
1099
+ const formattedRequests = sortUserHistory(accumulated, chainId, decimals, pool, assetDecimals);
1100
+ return formattedRequests;
1101
+ }
1102
+ catch (e) {
1103
+ core_1.Logger.log.error('getSubgraphVaultHistory', e, { pool });
1104
+ return [];
1105
+ }
1106
+ }
1107
+ /**
1108
+ * Every transfer of the vault's share token into or out of `user`, oldest
1109
+ * first. Transfers to or from the reward distributors are excluded.
1110
+ *
1111
+ * @param user - Wallet address.
1112
+ * @param provider - EVM provider for the vault's chain.
1113
+ * @param pool - Vault address.
1114
+ * @param slackWebookUrl - Where a missing-subgraph alert is posted.
1115
+ * @param options - `receiptSubgraph: true` reads the vault's receipt-token
1116
+ * subgraph when the registry has one: evm-2 shares are a separate receipt
1117
+ * token, which the base subgraph does not index. Falls back to the base
1118
+ * subgraph, which indexes the shares of vaults that are their own token.
1119
+ * @returns The transfers, or `[]` when the subgraph is missing or the query
1120
+ * fails.
1121
+ */
1122
+ async function getSubgraphUserTransfers(user, provider, pool, slackWebookUrl = (0, slack_1.resolveSlackWebhookUrl)(), options = {}) {
1123
+ try {
1124
+ // setup
1125
+ let amountOfTransfers = 0;
1126
+ let userTransfers = [];
1127
+ let hasNoData = false;
1128
+ const chainId = await (0, core_1.getChainId)(provider);
1129
+ const walletAddress = user.toLocaleLowerCase();
1130
+ const rewardDistributorAddresses = (0, core_1.REWARD_DISTRIBUTOR_ADDRESS)(chainId).filter((addr) => addr !== '0x0000000000000000000000000000000000000000');
1131
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
1132
+ if (vaultSymbol === undefined) {
1133
+ core_1.Logger.log.warn('getSubgraphUserTransfers', `cannot find vault symbol for pool: ${pool}`);
1134
+ return userTransfers;
1135
+ }
1136
+ const networkValue = await provider.provider.getNetwork();
1137
+ const network = Number(networkValue.chainId);
1138
+ if (needsMonadSuffix(network, vaultSymbol)) {
1139
+ vaultSymbol = vaultSymbol.concat('_monad');
1140
+ } // sanitize
1141
+ if (vaultSymbol === 'testWETHTSA') {
1142
+ return userTransfers;
1143
+ }
1144
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
1145
+ const { subgraph, receipt_subgraph } = vaultsMetadata?.[vaultSymbol?.toLowerCase()] || {};
1146
+ const goldskyUrl = (options.receiptSubgraph && receipt_subgraph) ||
1147
+ subgraph ||
1148
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol?.toLowerCase()] ||
1149
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
1150
+ if (!goldskyUrl) {
1151
+ const chainId = await (0, core_1.getChainId)(provider);
1152
+ core_1.Logger.log.warn('getSubgraphUserTransfers', `goldsky url is undefined: ${vaultSymbol}::${pool}`);
1153
+ alertMissingSubgraphOnce({
1154
+ source: 'getSubgraphUserTransfers',
1155
+ pool,
1156
+ chainId,
1157
+ slackWebookUrl,
1158
+ });
1159
+ return userTransfers;
1160
+ }
1161
+ // Probe the deployed subgraph's actual field schema (cached per URL) rather
1162
+ // than guessing from the vault symbol — see resolveSubgraphSchema (AUGUST-6568).
1163
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
1164
+ const orderByTimestamp = useOldSchema ? 'timestamp_' : 'blockTimestamp';
1165
+ const transferProps = useOldSchema
1166
+ ? TRANSFER_QUERY_PROPS
1167
+ : NEW_TRANSFER_QUERY_PROPS;
1168
+ do {
1169
+ // get all the transfers, includes redeem requests and deposits, excludes stake and withdraw events
1170
+ const where = `
1171
+ where: {
1172
+ and: [
1173
+ {
1174
+ or: [
1175
+ {from: "${walletAddress}"},
1176
+ {to: "${walletAddress}"}
1177
+ ]
1178
+ },
1179
+ ${rewardDistributorAddresses.length
1180
+ ? `
1181
+ {
1182
+ from_not_in: [
1183
+ ${rewardDistributorAddresses.map((addr) => `"${addr.toLocaleLowerCase()}"`).join(', ')}
1184
+ ],
1185
+ to_not_in: [${rewardDistributorAddresses.map((addr) => `"${addr.toLocaleLowerCase()}"`).join(', ')}]
1186
+ }
1187
+ `
1188
+ : ''}
1189
+ ]
1190
+ },
1191
+ `;
1192
+ if (!pool) {
1193
+ throw new Error('Pool address is required for HyperEVM');
1194
+ }
1195
+ const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, `{
1196
+ transfers(
1197
+ first: 1000, skip: ${amountOfTransfers},
1198
+ ${where}
1199
+ orderBy: ${orderByTimestamp}, orderDirection: asc
1200
+ ) {
1201
+ ${transferProps}
1202
+ }
1203
+ }`, GOLDSKY_API_KEY);
1204
+ const json = (await result.json());
1205
+ const { data } = json;
1206
+ userTransfers = [...userTransfers, ...(data?.transfers || [])];
1207
+ amountOfTransfers += data?.transfers?.length || 0;
1208
+ hasNoData = !data?.transfers?.length;
1209
+ } while ((amountOfTransfers === 0 || amountOfTransfers % 1000 === 0) &&
1210
+ !hasNoData);
1211
+ return userTransfers;
1212
+ }
1213
+ catch (e) {
1214
+ core_1.Logger.log.error('getSubgraphUserTransfers', e, { pool });
1215
+ return [];
1216
+ }
1217
+ }
1218
+ /**
1219
+ * Fetch the `ReserveDeposit` events that minted vault shares to `user`.
1220
+ *
1221
+ * Some vaults mint shares without an ERC-4626 `Deposit` event: High Growth ETH
1222
+ * emits `ReserveDeposit(account, shares, assets)` for deposits made through
1223
+ * Kelp's gain adapter, so {@link getSubgraphUserHistory} never sees them. Its
1224
+ * subgraph indexes the event as `reserveDeposits`.
1225
+ *
1226
+ * Side effects: one `getVaultSymbol` RPC read (cached), the vault metadata and
1227
+ * schema probes (cached), and one subgraph query.
1228
+ *
1229
+ * @param user - The wallet the shares were minted to.
1230
+ * @param provider - Contract runner for the vault's chain.
1231
+ * @param pool - The vault contract address.
1232
+ * @returns Up to 1000 events, oldest first. Empty when the vault's subgraph
1233
+ * has no `reserveDeposits` entity, has no URL, or the query fails.
1234
+ * @example
1235
+ * ```ts
1236
+ * const reserveDeposits = await getSubgraphUserReserveDeposits(wallet, provider, vault);
1237
+ * ```
1238
+ */
1239
+ async function getSubgraphUserReserveDeposits(user, provider, pool) {
1240
+ try {
1241
+ let vaultSymbol = await (0, core_1.getVaultSymbol)(pool, provider);
1242
+ if (vaultSymbol === undefined)
1243
+ return [];
1244
+ const networkValue = await provider.provider.getNetwork();
1245
+ if (needsMonadSuffix(Number(networkValue.chainId), vaultSymbol)) {
1246
+ vaultSymbol = vaultSymbol.concat('_monad');
1247
+ }
1248
+ const vaultsMetadata = await (0, fetcher_2.fetchVaultMetadata)();
1249
+ const { subgraph } = vaultsMetadata?.[vaultSymbol.toLowerCase()] || {};
1250
+ const goldskyUrl = subgraph ||
1251
+ core_1.SUBGRAPH_VAULT_URLS[vaultSymbol.toLowerCase()] ||
1252
+ (0, core_1.getDefaultSubgraphUrl)(networkValue.name, vaultSymbol);
1253
+ if (!goldskyUrl)
1254
+ return [];
1255
+ const useOldSchema = (await (0, schema_1.resolveSubgraphSchema)(goldskyUrl, GOLDSKY_API_KEY)) === 'old';
1256
+ const props = useOldSchema
1257
+ ? 'id account shares assets transactionHash_ timestamp_ block_number'
1258
+ : 'id account shares assets transactionHash_: transactionHash timestamp_: blockTimestamp block_number: blockNumber';
1259
+ const result = await (0, fetcher_1.fetchSubgraph)(goldskyUrl, `{
1260
+ reserveDeposits(
1261
+ first: 1000,
1262
+ orderBy: ${useOldSchema ? 'timestamp_' : 'blockTimestamp'},
1263
+ orderDirection: asc,
1264
+ where: { account: "${user.toLowerCase()}" }
1265
+ ) {
1266
+ ${props}
1267
+ }
1268
+ }`, GOLDSKY_API_KEY);
1269
+ if (result.status !== 200)
1270
+ return [];
1271
+ const json = (await result.json());
1272
+ if (json.errors?.length && !(0, schema_1.isSubgraphSchemaFieldError)(json.errors)) {
1273
+ core_1.Logger.log.warn('getSubgraphUserReserveDeposits', `${pool}::${JSON.stringify(json.errors).slice(0, 200)}`);
1274
+ }
1275
+ return json.data?.reserveDeposits ?? [];
1276
+ }
1277
+ catch (e) {
1278
+ core_1.Logger.log.warn('getSubgraphUserReserveDeposits', `${pool}::${e}`);
1279
+ return [];
1280
+ }
1281
+ }
1282
+ //# sourceMappingURL=vaults.js.map