@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,1103 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setSafeCache = exports.getSafeCache = exports.CACHE = void 0;
4
+ exports.setSdkRequestTimeout = setSdkRequestTimeout;
5
+ exports.getSdkRequestTimeout = getSdkRequestTimeout;
6
+ exports.setSdkAppName = setSdkAppName;
7
+ exports.setPublicApiBaseUrl = setPublicApiBaseUrl;
8
+ exports.getPublicApiBaseUrl = getPublicApiBaseUrl;
9
+ exports.fetchUpshiftWithKey = fetchUpshiftWithKey;
10
+ exports.fetchUpshiftPublic = fetchUpshiftPublic;
11
+ exports.fetchUpshiftWithBearer = fetchUpshiftWithBearer;
12
+ exports.isRetryableError = isRetryableError;
13
+ exports.withRetry = withRetry;
14
+ exports.fetchTokenizedVault = fetchTokenizedVault;
15
+ exports.fetchTokenizedVaults = fetchTokenizedVaults;
16
+ exports.fetchTokenPrice = fetchTokenPrice;
17
+ exports.fetchTokenPriceByAddress = fetchTokenPriceByAddress;
18
+ exports.fetchTokenizedVaultLoans = fetchTokenizedVaultLoans;
19
+ exports.fetchTokenizedVaultSubaccountLoans = fetchTokenizedVaultSubaccountLoans;
20
+ exports.fetchVaultHistoricalTimeseries = fetchVaultHistoricalTimeseries;
21
+ exports.promiseSettle = promiseSettle;
22
+ const core_1 = require("./helpers/core");
23
+ const ethers_1 = require("ethers");
24
+ const abis_1 = require("../abis");
25
+ const lru_cache_1 = require("lru-cache");
26
+ const chain_address_1 = require("./helpers/chain-address");
27
+ const chain_error_1 = require("./helpers/chain-error");
28
+ const fetcher_1 = require("../services/coingecko/fetcher");
29
+ const logger_1 = require("./logger");
30
+ const ethers_2 = require("ethers");
31
+ const web3_1 = require("./constants/web3");
32
+ const core_2 = require("./constants/core");
33
+ const vault_version_1 = require("./helpers/vault-version");
34
+ const analytics_1 = require("./analytics");
35
+ const sanitize_1 = require("./analytics/sanitize");
36
+ const sentry_1 = require("./analytics/sentry");
37
+ const errors_1 = require("./errors");
38
+ /** Map an HTTP status to the appropriate typed SDK error subclass. */
39
+ function errorFromResponseStatus(status, message, options) {
40
+ if (status === 401) {
41
+ return new errors_1.UpshiftAuthError('AUTH_UNAUTHORIZED', message, options);
42
+ }
43
+ if (status === 403) {
44
+ return new errors_1.UpshiftAuthError('AUTH_FORBIDDEN', message, options);
45
+ }
46
+ if (status === 429) {
47
+ return new errors_1.UpshiftRateLimitError(message, options);
48
+ }
49
+ return new errors_1.UpshiftServerError(status, message, options);
50
+ }
51
+ let SDK_REQUEST_TIMEOUT_OVERRIDE = null;
52
+ /**
53
+ * Override the default request timeout used by every Upshift fetcher helper
54
+ * when the caller doesn't supply a per-call `timeoutMs`. Pass `null` (or
55
+ * call with no arguments) to clear the override and fall back to the
56
+ * compiled-in `REQUEST_TIMEOUT_MS`.
57
+ *
58
+ * @param ms - Positive number of milliseconds to wait before aborting, or
59
+ * `null` to clear.
60
+ */
61
+ function setSdkRequestTimeout(ms = null) {
62
+ if (ms === null) {
63
+ SDK_REQUEST_TIMEOUT_OVERRIDE = null;
64
+ return;
65
+ }
66
+ if (!Number.isFinite(ms) || ms <= 0) {
67
+ logger_1.Logger.log.warn('setSdkRequestTimeout', 'Ignoring non-positive timeout', {
68
+ ms,
69
+ });
70
+ return;
71
+ }
72
+ SDK_REQUEST_TIMEOUT_OVERRIDE = ms;
73
+ }
74
+ /**
75
+ * Read the active default request timeout — the SDK-level override if set,
76
+ * otherwise the compiled-in `REQUEST_TIMEOUT_MS`.
77
+ */
78
+ function getSdkRequestTimeout() {
79
+ return SDK_REQUEST_TIMEOUT_OVERRIDE ?? core_2.REQUEST_TIMEOUT_MS;
80
+ }
81
+ let SDK_APP_NAME = null;
82
+ /**
83
+ * Record the consuming application's `appName` so every request to the
84
+ * Upshift backend carries it as `x-august-app`, next to
85
+ * `x-august-sdk-version`. This gives the backend per-integrator request
86
+ * counts that do not depend on Sentry sampling.
87
+ *
88
+ * Process-global, last writer wins — the same contract as
89
+ * `setSdkRequestTimeout` and `setPublicApiBaseUrl`. The `UpshiftSDK`
90
+ * constructor calls this with its validated `appName`.
91
+ *
92
+ * @param appName - Validated app-name slug, or `null` to stop sending it.
93
+ */
94
+ function setSdkAppName(appName = null) {
95
+ SDK_APP_NAME = appName;
96
+ }
97
+ /**
98
+ * Client-identification headers merged into every backend fetcher's
99
+ * defaults. Both values are low-cardinality slugs, never credentials.
100
+ */
101
+ function sdkClientHeaders() {
102
+ const headers = {
103
+ 'x-august-sdk-version': (0, sentry_1.getSDKVersion)(),
104
+ };
105
+ if (SDK_APP_NAME)
106
+ headers['x-august-app'] = SDK_APP_NAME;
107
+ return headers;
108
+ }
109
+ let PUBLIC_API_BASE_OVERRIDE = null;
110
+ /**
111
+ * Override the base URL used for `WEBSERVER_URL.public` requests — the
112
+ * unauthenticated vault-catalog API that `getVault` / `fetchTokenizedVault`
113
+ * (and the other `fetchUpshiftPublic` callers) read from. Defaults to the
114
+ * compiled-in prod base (`https://api.augustdigital.io/api/v1`); pass `null`
115
+ * (or call with no arguments) to clear.
116
+ *
117
+ * Intended for non-prod deployments that run against an ISOLATED backend
118
+ * (e.g. a staging API): set it once at construction via
119
+ * `IUpshiftBase.publicApiBaseUrl` so a staging-only vault resolves. Production
120
+ * leaves it unset, so behaviour is unchanged.
121
+ *
122
+ * This is a process-global override on the fetcher helpers. The SDK constructor
123
+ * calls it on EVERY instantiation (with `null` when `publicApiBaseUrl` is
124
+ * omitted), so the last `UpshiftSDK` instantiated is authoritative — a prod
125
+ * instance resets it to the default even after a prior staging instance set it.
126
+ * An invalid or non-http(s) URL is treated as "no override": it RESETS to the
127
+ * compiled-in default (warned) rather than retaining a prior value, so a bad env
128
+ * value can neither break fetches nor silently leave a previous instance's base
129
+ * in place.
130
+ *
131
+ * Whenever the effective base CHANGES, the shared public-response cache is
132
+ * cleared, so catalog data fetched from the previous backend is never served for
133
+ * the new one (e.g. a prod-cached vault leaking into a staging instance). Base
134
+ * changes happen at construction, when the cache is cold, so this is ~free.
135
+ *
136
+ * @param url - Absolute http(s) base URL (trailing slash is trimmed). `null`, or
137
+ * an invalid / non-http(s) value, resets to the compiled-in public base.
138
+ */
139
+ function setPublicApiBaseUrl(url = null) {
140
+ const previous = PUBLIC_API_BASE_OVERRIDE;
141
+ if (url === null) {
142
+ PUBLIC_API_BASE_OVERRIDE = null;
143
+ }
144
+ else {
145
+ let parsed = null;
146
+ try {
147
+ parsed = new URL(url);
148
+ }
149
+ catch {
150
+ parsed = null;
151
+ }
152
+ if (!parsed ||
153
+ (parsed.protocol !== 'https:' && parsed.protocol !== 'http:')) {
154
+ // Reset to the default rather than retaining a stale prior override, so
155
+ // each construction stays authoritative and a bad env value fails safe to
156
+ // prod instead of inheriting another instance's base.
157
+ logger_1.Logger.log.warn('setPublicApiBaseUrl', 'Ignoring invalid/non-http(s) URL; resetting to the default public base', { url });
158
+ PUBLIC_API_BASE_OVERRIDE = null;
159
+ }
160
+ else {
161
+ // Store WITHOUT a trailing slash: buildUpshiftUrl concatenates
162
+ // `${base}${relativeUrl}` (relativeUrl starts with '/'), so a trailing
163
+ // slash on the base would produce a double slash.
164
+ PUBLIC_API_BASE_OVERRIDE = url.replace(/\/+$/, '');
165
+ }
166
+ }
167
+ if (PUBLIC_API_BASE_OVERRIDE !== previous) {
168
+ // The public base moved (or reset). Drop cached public-catalog responses
169
+ // keyed against the previous base (see fetchTokenizedVault(s) etc.) so they
170
+ // aren't served for the new backend.
171
+ cache_1.CACHE.clear();
172
+ }
173
+ }
174
+ /**
175
+ * Read the active base for the `public` server — the SDK-level override if set,
176
+ * otherwise the compiled-in `WEBSERVER_URL.public`.
177
+ */
178
+ function getPublicApiBaseUrl() {
179
+ return PUBLIC_API_BASE_OVERRIDE ?? core_2.WEBSERVER_URL.public;
180
+ }
181
+ /**
182
+ * Combine the per-request timeout signal with any caller-supplied signal.
183
+ * Uses `AbortSignal.any` (Node 22+) with a manual relay fallback.
184
+ *
185
+ * Returns `timedOut()` (a closure over an internal flag set when the timeout
186
+ * fires) so the caller can distinguish "we timed out" from "caller cancelled",
187
+ * and `cleanup()` to release the fallback-relay listener.
188
+ */
189
+ function buildRequestAbortSignal(options) {
190
+ const timeoutMs = options?.timeoutMs ?? SDK_REQUEST_TIMEOUT_OVERRIDE ?? core_2.REQUEST_TIMEOUT_MS;
191
+ const timeoutController = new AbortController();
192
+ let didTimeout = false;
193
+ const timeoutId = setTimeout(() => {
194
+ didTimeout = true;
195
+ timeoutController.abort();
196
+ }, timeoutMs);
197
+ let signal = timeoutController.signal;
198
+ // No-op by default; replaced with a real listener-removal closure only when
199
+ // the manual relay fallback path below registers an 'abort' listener.
200
+ let relayCleanup = () => undefined;
201
+ if (options?.signal) {
202
+ // Capture in a local so the cleanup closure below keeps the non-nullable
203
+ // narrowing (a closure over `options.signal` would otherwise be re-widened).
204
+ const callerSignal = options.signal;
205
+ if (typeof AbortSignal.any === 'function') {
206
+ signal = AbortSignal.any([timeoutController.signal, callerSignal]);
207
+ }
208
+ else if (callerSignal.aborted) {
209
+ timeoutController.abort();
210
+ }
211
+ else {
212
+ const relay = () => timeoutController.abort();
213
+ callerSignal.addEventListener('abort', relay, { once: true });
214
+ relayCleanup = () => callerSignal.removeEventListener('abort', relay);
215
+ }
216
+ }
217
+ return {
218
+ signal,
219
+ timeoutId,
220
+ timeoutMs,
221
+ timedOut: () => didTimeout,
222
+ cleanup: () => {
223
+ clearTimeout(timeoutId);
224
+ relayCleanup();
225
+ },
226
+ };
227
+ }
228
+ /**
229
+ * Build the `UpshiftTimeoutError` a fetcher throws when its own timeout fired,
230
+ * and record it as a breadcrumb rather than a Sentry issue.
231
+ *
232
+ * Severity rationale: the error is *thrown* to the caller, so whoever owns the
233
+ * request decides whether it is fatal. Logging it at `error` here as well made
234
+ * every timeout a standalone Sentry issue even when the caller swallowed it
235
+ * (`Promise.allSettled` fan-outs in `getVaultAllocations` do exactly that) — a
236
+ * single stalled render produced 20–30 identical issues in the same second and
237
+ * ~40k events a week, none of them separately actionable. As a breadcrumb the
238
+ * timeout still rides along with whatever the caller ultimately reports, with
239
+ * the endpoint and elapsed budget attached.
240
+ *
241
+ * @param tag - Call-site tag (`fetchUpshiftPublic`, …) used as the breadcrumb label.
242
+ * @param relativeUrl - Endpoint path that timed out; sanitized before use.
243
+ * @param timeoutMs - Timeout budget that elapsed, in milliseconds.
244
+ * @returns The error to throw. Never throws.
245
+ * @internal
246
+ */
247
+ function timeoutErrorFor(tag, relativeUrl, timeoutMs) {
248
+ const timeoutError = new errors_1.UpshiftTimeoutError((0, sanitize_1.sanitizeString)(`Request timeout after ${timeoutMs / 1000}s: ${relativeUrl}`), timeoutMs);
249
+ logger_1.Logger.log.warn(tag, { relativeUrl, timeoutMs, reason: 'request timeout' });
250
+ return timeoutError;
251
+ }
252
+ let _overrideDeprecationWarned = false;
253
+ function warnOverrideDeprecation(callerTag) {
254
+ if (_overrideDeprecationWarned)
255
+ return;
256
+ _overrideDeprecationWarned = true;
257
+ // Deliberately a direct console.warn, not Logger.log.warn: a deprecation
258
+ // notice must surface in the integrator's console in every environment.
259
+ // Logger.log.warn would downgrade it to a prod-silent Sentry breadcrumb.
260
+ // biome-ignore lint/suspicious/noConsole: integrator-facing deprecation notice must surface in every environment; Logger.log.warn would downgrade it to a prod-silent Sentry breadcrumb.
261
+ console.warn(`[@upshiftfinance/sdk] ${callerTag}: option "override" is deprecated and has no effect — an absent apiKey already sends an anonymous request. It will be removed in a future major version; drop it.`);
262
+ }
263
+ /**
264
+ * LRU cache for API responses and frequently accessed data.
265
+ * 24-hour TTL with 1000 item capacity.
266
+ */
267
+ /**
268
+ * Read a response header tolerantly. Real `fetch` returns a `Headers` instance,
269
+ * but some test mocks supply a plain object; both shapes are supported here.
270
+ */
271
+ function readResponseHeader(headers, name) {
272
+ if (!headers)
273
+ return undefined;
274
+ const h = headers;
275
+ if (typeof h.get === 'function') {
276
+ return h.get(name) ?? undefined;
277
+ }
278
+ const v = headers[name];
279
+ return typeof v === 'string' ? v : undefined;
280
+ }
281
+ const cache_1 = require("./cache");
282
+ Object.defineProperty(exports, "CACHE", { enumerable: true, get: function () { return cache_1.CACHE; } });
283
+ Object.defineProperty(exports, "getSafeCache", { enumerable: true, get: function () { return cache_1.getSafeCache; } });
284
+ Object.defineProperty(exports, "setSafeCache", { enumerable: true, get: function () { return cache_1.setSafeCache; } });
285
+ /**
286
+ * TTL for the per-vault "active loans" lists returned by
287
+ * {@link fetchTokenizedVaultLoans} / {@link fetchTokenizedVaultSubaccountLoans}.
288
+ *
289
+ * Loan state changes as borrowers draw and repay, so these lists must not sit
290
+ * on the 24 h `CACHE` default — a loan that was repaid an hour ago would still
291
+ * be reported as active. 10 minutes matches the vault-catalog TTL used by
292
+ * `fetchTokenizedVault`.
293
+ */
294
+ const ACTIVE_LOANS_TTL_MS = 10 * 60 * 1000;
295
+ /**
296
+ * Drop `null` / `undefined` entries from a header map before it reaches
297
+ * `fetch`.
298
+ *
299
+ * Why: `UpshiftBase.monitoring` starts life as
300
+ * `{ 'x-user-id': undefined, 'x-environment': 'PROD' }` and is spread straight
301
+ * into request headers. `fetch` stringifies header values, so an `undefined`
302
+ * slot is sent on the wire as the literal string `"undefined"` — the backend
303
+ * then sees a bogus user id until `updateWallet` runs. Stripping nullish
304
+ * values here means "not set" is actually absent from the request.
305
+ *
306
+ * @param headers - Header map that may contain nullish values (an
307
+ * `IWSMonitorHeaders` object or a spread of one). `undefined` as a whole
308
+ * yields `{}`.
309
+ * @returns A new map containing only the entries whose value is a string.
310
+ * Never mutates the input.
311
+ * @internal
312
+ */
313
+ function compactHeaders(headers) {
314
+ const out = {};
315
+ if (!headers)
316
+ return out;
317
+ for (const [name, value] of Object.entries(headers)) {
318
+ if (typeof value === 'string')
319
+ out[name] = value;
320
+ }
321
+ return out;
322
+ }
323
+ /**
324
+ * Dedicated cache for token prices with short TTL to prevent rate limiting.
325
+ * 30-second TTL with 500 item capacity.
326
+ */
327
+ const PRICE_CACHE = new lru_cache_1.LRUCache({
328
+ max: 500,
329
+ ttl: 1000 * 30, // 30 seconds
330
+ allowStale: false,
331
+ });
332
+ /**
333
+ * Cache for failed price requests to prevent retry storms.
334
+ * 5-second TTL to allow quick retry after temporary failures.
335
+ */
336
+ const PRICE_ERROR_CACHE = new lru_cache_1.LRUCache({
337
+ max: 100,
338
+ ttl: 1000 * 5, // 5 seconds
339
+ allowStale: false,
340
+ });
341
+ /**
342
+ * In-flight price requests to prevent duplicate simultaneous API calls.
343
+ */
344
+ const PRICE_REQUESTS = new Map();
345
+ /**
346
+ * In-flight `/tokenized_vault` requests, keyed by the same cache key the
347
+ * response is stored under.
348
+ *
349
+ * The response cache alone only de-duplicates *sequential* calls: a cold
350
+ * process (a fresh serverless container, a hard page load) fans out N
351
+ * concurrent `getVault` calls for the same vault before any of them has
352
+ * populated the cache, so all N hit the backend. Under load that self-inflicted
353
+ * stampede is what pushed `/tokenized_vault/{address}` past its timeout — the
354
+ * single largest source of `UpshiftTimeoutError` in production.
355
+ *
356
+ * Joining concurrent callers onto one promise collapses that fan-out to a
357
+ * single request. Entries are removed as soon as the request settles, so a
358
+ * failure is never cached — the next caller retries.
359
+ */
360
+ const TOKENIZED_VAULT_REQUESTS = new Map();
361
+ /**
362
+ * Run `factory` at most once per `key` while it is in flight, joining any
363
+ * concurrent caller onto the same promise.
364
+ *
365
+ * This is a de-duplication primitive, not a cache: the entry lives only for the
366
+ * duration of the request and is cleared on both success and failure, so errors
367
+ * are never shared beyond the callers that were already waiting.
368
+ *
369
+ * @param registry - Map holding the in-flight promises for this resource type.
370
+ * @param key - Identity of the request; callers sharing a key share a result.
371
+ * @param factory - Produces the promise to run when no request is in flight.
372
+ * @returns The shared promise for `key`.
373
+ * @internal
374
+ */
375
+ function dedupeInFlight(registry, key, factory) {
376
+ const existing = registry.get(key);
377
+ if (existing)
378
+ return existing;
379
+ const request = factory().finally(() => {
380
+ registry.delete(key);
381
+ });
382
+ registry.set(key, request);
383
+ return request;
384
+ }
385
+ /**
386
+ * Build an Upshift backend URL, rejecting unknown server keys and any
387
+ * `relativeUrl` that would escape the configured origin.
388
+ * Throws `UpshiftValidationError` with `code: 'INVALID_URL'`.
389
+ */
390
+ function buildUpshiftUrl(server, relativeUrl) {
391
+ const serverKey = server;
392
+ // The `public` base is overridable (setPublicApiBaseUrl / IUpshiftBase
393
+ // .publicApiBaseUrl) so non-prod deployments can point vault-catalog reads at
394
+ // an isolated backend. Resolved once here via getPublicApiBaseUrl() (single
395
+ // source of truth), so the origin check below validates against the OVERRIDDEN
396
+ // origin.
397
+ const base = serverKey === 'public' ? getPublicApiBaseUrl() : core_2.WEBSERVER_URL[serverKey];
398
+ if (!base) {
399
+ throw new errors_1.UpshiftValidationError('INVALID_URL', `Unknown Upshift server "${String(server)}". Expected one of: ${Object.keys(core_2.WEBSERVER_URL).join(', ')}`);
400
+ }
401
+ if (typeof relativeUrl !== 'string' || relativeUrl.length === 0) {
402
+ throw new errors_1.UpshiftValidationError('INVALID_URL', 'relativeUrl must be a non-empty string');
403
+ }
404
+ // Reject anything that looks like a scheme or protocol-relative authority.
405
+ if (/^\s*[a-z][a-z0-9+.-]*:|^\s*\/\//i.test(relativeUrl)) {
406
+ throw new errors_1.UpshiftValidationError('INVALID_URL', `relativeUrl must be a path, not an absolute or protocol-relative URL`);
407
+ }
408
+ // Concat (rather than `new URL(rel, base)`) preserves base paths like /api/v1
409
+ // when relativeUrl starts with `/`. Origin check below is a second line.
410
+ const candidate = `${base}${relativeUrl}`;
411
+ let url;
412
+ try {
413
+ url = new URL(candidate);
414
+ }
415
+ catch {
416
+ throw new errors_1.UpshiftValidationError('INVALID_URL', `Invalid URL path: ${(0, sanitize_1.sanitizeString)(relativeUrl)}`);
417
+ }
418
+ const baseOrigin = new URL(base).origin;
419
+ if (url.origin !== baseOrigin) {
420
+ throw new errors_1.UpshiftValidationError('INVALID_URL', `URL origin mismatch: refusing to fetch ${url.origin} from a "${serverKey}" request scoped to ${baseOrigin}`);
421
+ }
422
+ return url.toString();
423
+ }
424
+ /**
425
+ * Make requests to Upshift backend services, sending an API key when one is
426
+ * configured. Many backend routes — vault-linked sub-account reads, the two
427
+ * collateral risk routes, timelock requests — answer anonymous callers, so a
428
+ * missing key is not an error here: the request goes out without the
429
+ * `x-api-key` header and the backend decides. Routes that do require a key
430
+ * answer `401`, which surfaces as an `UpshiftAuthError` with code
431
+ * `AUTH_UNAUTHORIZED`.
432
+ * Automatically logs errors with correlation IDs for debugging.
433
+ * @param apiKey - Upshift API key, or `undefined` for an anonymous request
434
+ * @param relativeUrl - Endpoint path relative to base URL
435
+ * @param options - Request configuration including method and headers
436
+ * @returns Response object if successful
437
+ * @throws Error with correlation ID if request fails
438
+ */
439
+ async function fetchUpshiftWithKey(apiKey, relativeUrl, options) {
440
+ if (options?.override) {
441
+ warnOverrideDeprecation('fetchUpshiftWithKey');
442
+ }
443
+ const defaultHeaders = {
444
+ ...sdkClientHeaders(),
445
+ ...(apiKey ? { 'x-api-key': apiKey } : {}),
446
+ 'content-type': 'application/json',
447
+ accept: 'application/json',
448
+ };
449
+ const { signal: requestSignal, timeoutMs: effectiveTimeoutMs, timedOut, cleanup, } = buildRequestAbortSignal(options);
450
+ const startTime = performance.now();
451
+ const server = options?.server || 'production';
452
+ // Set once the response has been recorded with its real status, so the
453
+ // `catch` below does not record the same non-OK request a second time as
454
+ // status 0 (which double-counted every 4xx/5xx in the API-call metrics).
455
+ let tracked = false;
456
+ try {
457
+ const safeUrl = buildUpshiftUrl(server, relativeUrl);
458
+ const res = await fetch(safeUrl, {
459
+ headers: compactHeaders({
460
+ ...defaultHeaders,
461
+ ...options?.headers,
462
+ }),
463
+ method: options?.method ?? 'GET',
464
+ body: JSON.stringify(options?.data),
465
+ signal: requestSignal,
466
+ });
467
+ cleanup();
468
+ // Track API call
469
+ (0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, res.status, server);
470
+ tracked = true;
471
+ const correlationId = readResponseHeader(res.headers, 'x-correlation-id');
472
+ const logger = logger_1.Logger.getLogger();
473
+ if (!res.ok) {
474
+ if (correlationId && logger) {
475
+ logger.setTag('correlation_id', correlationId);
476
+ }
477
+ const error = errorFromResponseStatus(res.status, `Request failed: ${res.status}`, { correlationId });
478
+ logger?.captureException(error, { correlationId, status: res.status });
479
+ throw error;
480
+ }
481
+ return res;
482
+ }
483
+ catch (error) {
484
+ cleanup();
485
+ if (!tracked) {
486
+ (0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, 0, server);
487
+ }
488
+ const err = error instanceof Error ? error : new Error(String(error));
489
+ if (err.name === 'AbortError') {
490
+ if (!timedOut()) {
491
+ throw err;
492
+ }
493
+ throw timeoutErrorFor('fetchUpshiftWithKey', relativeUrl, effectiveTimeoutMs);
494
+ }
495
+ throw err;
496
+ }
497
+ }
498
+ /**
499
+ * Make unauthenticated requests to Upshift public API endpoints.
500
+ * Used for fetching vault metadata and public market data.
501
+ * @param relativeUrl - Endpoint path relative to public API base URL
502
+ * @param options - Request configuration including method and headers
503
+ * @returns Response object if successful
504
+ * @throws Error with correlation ID if request fails
505
+ */
506
+ async function fetchUpshiftPublic(relativeUrl, options) {
507
+ const defaultHeaders = {
508
+ ...sdkClientHeaders(),
509
+ 'content-type': 'application/json',
510
+ accept: 'application/json',
511
+ };
512
+ const { signal: requestSignal, timeoutMs: effectiveTimeoutMs, timedOut, cleanup, } = buildRequestAbortSignal(options);
513
+ const startTime = performance.now();
514
+ // See fetchUpshiftWithKey: prevents a second status-0 record for non-OK responses.
515
+ let tracked = false;
516
+ try {
517
+ const safeUrl = buildUpshiftUrl('public', relativeUrl);
518
+ const res = await fetch(safeUrl, {
519
+ headers: compactHeaders({
520
+ ...defaultHeaders,
521
+ ...options?.headers,
522
+ }),
523
+ method: options?.method ?? 'GET',
524
+ body: JSON.stringify(options?.data),
525
+ signal: requestSignal,
526
+ });
527
+ cleanup();
528
+ (0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, res.status, 'public');
529
+ tracked = true;
530
+ const correlationId = readResponseHeader(res.headers, 'x-correlation-id');
531
+ const logger = logger_1.Logger.getLogger();
532
+ if (!res.ok) {
533
+ if (correlationId && logger) {
534
+ logger.setTag('correlation_id', correlationId);
535
+ }
536
+ const error = errorFromResponseStatus(res.status, `Request failed: ${res.status}`, { correlationId });
537
+ logger?.captureException(error, { correlationId, status: res.status });
538
+ throw error;
539
+ }
540
+ return res;
541
+ }
542
+ catch (error) {
543
+ cleanup();
544
+ if (!tracked) {
545
+ (0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, 0, 'public');
546
+ }
547
+ const err = error instanceof Error ? error : new Error(String(error));
548
+ if (err.name === 'AbortError') {
549
+ if (!timedOut()) {
550
+ throw err;
551
+ }
552
+ throw timeoutErrorFor('fetchUpshiftPublic', relativeUrl, effectiveTimeoutMs);
553
+ }
554
+ throw err;
555
+ }
556
+ }
557
+ /**
558
+ * Make authenticated requests using Bearer token authentication.
559
+ * Typically used for user-specific operations requiring OAuth tokens.
560
+ * @param bearerToken - OAuth bearer token
561
+ * @param relativeUrl - Endpoint path relative to base URL
562
+ * @param options - Request configuration including method and headers
563
+ * @returns Response object if successful
564
+ * @throws Error with correlation ID if request fails
565
+ */
566
+ async function fetchUpshiftWithBearer(bearerToken, relativeUrl, options) {
567
+ const defaultHeaders = {
568
+ ...sdkClientHeaders(),
569
+ authorization: `Bearer ${bearerToken}`,
570
+ 'content-type': 'application/json',
571
+ accept: 'application/json',
572
+ };
573
+ const { signal: requestSignal, timeoutMs: effectiveTimeoutMs, timedOut, cleanup, } = buildRequestAbortSignal(options);
574
+ const startTime = performance.now();
575
+ const server = options?.server ?? 'production';
576
+ // See fetchUpshiftWithKey: prevents a second status-0 record for non-OK responses.
577
+ let tracked = false;
578
+ try {
579
+ const safeUrl = buildUpshiftUrl(server, relativeUrl);
580
+ const res = await fetch(safeUrl, {
581
+ headers: compactHeaders({
582
+ ...defaultHeaders,
583
+ ...options?.headers,
584
+ }),
585
+ method: options?.method ?? 'GET',
586
+ body: JSON.stringify(options?.data),
587
+ signal: requestSignal,
588
+ });
589
+ cleanup();
590
+ (0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, res.status, server);
591
+ tracked = true;
592
+ const correlationId = readResponseHeader(res.headers, 'x-correlation-id');
593
+ const logger = logger_1.Logger.getLogger();
594
+ if (!res.ok) {
595
+ if (correlationId && logger) {
596
+ logger.setTag('correlation_id', correlationId);
597
+ }
598
+ const error = errorFromResponseStatus(res.status, `Request failed: ${res.status}`, { correlationId });
599
+ logger?.captureException(error, { correlationId, status: res.status });
600
+ throw error;
601
+ }
602
+ return res;
603
+ }
604
+ catch (error) {
605
+ cleanup();
606
+ if (!tracked) {
607
+ (0, analytics_1.trackApiCall)(relativeUrl, options?.method ?? 'GET', startTime, 0, server);
608
+ }
609
+ const err = error instanceof Error ? error : new Error(String(error));
610
+ if (err.name === 'AbortError') {
611
+ if (!timedOut()) {
612
+ throw err;
613
+ }
614
+ throw timeoutErrorFor('fetchUpshiftWithBearer', relativeUrl, effectiveTimeoutMs);
615
+ }
616
+ throw err;
617
+ }
618
+ }
619
+ /**
620
+ * Check if an error is network-related and suitable for retry.
621
+ * Identifies timeouts, connection resets, and fetch failures.
622
+ */
623
+ function isRetryableError(error) {
624
+ return ((error instanceof TypeError && error.message.includes('fetch failed')) ||
625
+ error.name === 'AbortError' ||
626
+ error.message.includes('ETIMEDOUT') ||
627
+ error.message.includes('timeout') ||
628
+ error.message.includes('ECONNRESET') ||
629
+ error.message.includes('ENOTFOUND') ||
630
+ error.message.includes('ECONNREFUSED'));
631
+ }
632
+ /**
633
+ * Wrap async operations with exponential backoff retry logic.
634
+ * Retries on network errors with increasing delays between attempts.
635
+ * @param fn - Async function to execute with retry logic
636
+ * @param maxRetries - Maximum number of retry attempts
637
+ * @param baseDelay - Initial delay in milliseconds (doubles each retry)
638
+ * @param shouldRetry - Custom function to determine if error is retryable
639
+ * @returns Result of successful function execution
640
+ * @throws Last error if all retries exhausted
641
+ */
642
+ async function withRetry(fn, maxRetries = 3, baseDelay = 1000, shouldRetry = isRetryableError) {
643
+ let lastError;
644
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
645
+ try {
646
+ return await fn();
647
+ }
648
+ catch (error) {
649
+ lastError = error;
650
+ if (attempt < maxRetries && shouldRetry(error)) {
651
+ const delay = baseDelay * 2 ** attempt;
652
+ logger_1.Logger.log.warn('withRetry', `Attempt ${attempt + 1} failed, retrying in ${delay}ms: ${error.message}`);
653
+ await new Promise((resolve) => setTimeout(resolve, delay));
654
+ continue;
655
+ }
656
+ throw error;
657
+ }
658
+ }
659
+ // Unreachable in practice: the final attempt re-throws inside the loop. This
660
+ // satisfies the compiler's control-flow analysis without a non-null assertion.
661
+ throw lastError ?? new Error('withRetry exhausted retries without an error');
662
+ }
663
+ /**
664
+ * Fetch tokenized vault configurations from backend API.
665
+ * Results are cached to reduce API calls. Optionally filter by specific vault address.
666
+ * @param pool - Optional vault address to filter results
667
+ * @param headers - Monitoring headers for request tracking
668
+ * @returns Array of tokenized vault configurations
669
+ */
670
+ async function fetchTokenizedVault(pool, headers, loadSubaccounts, loadSnapshots) {
671
+ if (!pool) {
672
+ return [];
673
+ }
674
+ // Build cache key based on loading options
675
+ const keyParts = [`tokenized-vault-${pool}`];
676
+ if (loadSubaccounts === false)
677
+ keyParts.push('no-subaccounts');
678
+ if (loadSnapshots === false)
679
+ keyParts.push('no-snapshots');
680
+ const key = keyParts.join('-');
681
+ let tokenizedVault;
682
+ const cachedResponse = await (0, cache_1.getSafeCache)(key);
683
+ if (cachedResponse) {
684
+ tokenizedVault = cachedResponse;
685
+ }
686
+ if (!tokenizedVault) {
687
+ // Concurrent callers for the same vault share one request; see
688
+ // TOKENIZED_VAULT_REQUESTS.
689
+ tokenizedVault = await dedupeInFlight(TOKENIZED_VAULT_REQUESTS, key, async () => {
690
+ // Build endpoint URL with optional query parameters
691
+ let endpoint = core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.byVaultAddress(pool);
692
+ const params = new URLSearchParams();
693
+ if (loadSubaccounts === false) {
694
+ params.set('load_subaccounts', 'false');
695
+ }
696
+ if (loadSnapshots === false) {
697
+ params.set('load_snapshots', 'false');
698
+ }
699
+ const queryString = params.toString();
700
+ if (queryString) {
701
+ endpoint += `?${queryString}`;
702
+ }
703
+ const tokenizedVaultsResponse = await fetchUpshiftPublic(endpoint, {
704
+ headers: headers,
705
+ });
706
+ const parsed = (await tokenizedVaultsResponse.json());
707
+ cache_1.CACHE.set(key, parsed, { ttl: 1000 * 60 * 10 }); // Cache for 10 minutes
708
+ return parsed;
709
+ });
710
+ }
711
+ // Filter by specific vault if address provided
712
+ if (pool &&
713
+ ((0, ethers_1.isAddress)(pool) ||
714
+ (0, chain_address_1.isSolanaAddress)(pool) ||
715
+ (0, chain_address_1.isStellarAddress)(pool) ||
716
+ (0, chain_address_1.isSuiAddress)(pool))) {
717
+ return tokenizedVault ? [tokenizedVault] : [];
718
+ }
719
+ return [tokenizedVault];
720
+ }
721
+ /**
722
+ * Fetch tokenized vault configurations from backend API.
723
+ * Results are cached to reduce API calls. Optionally filter by specific vault address.
724
+ * @param pool - Optional vault address to filter results
725
+ * @param headers - Monitoring headers for request tracking
726
+ * @param loadSubaccounts - Optional flag to load subaccounts and EOA operators (defaults to true on API)
727
+ * @returns Array of tokenized vault configurations
728
+ */
729
+ async function fetchTokenizedVaults(pool, headers, loadSubaccounts, loadSnapshots) {
730
+ // Build cache key from the request shape only. `pool` is NOT part of the
731
+ // request (the endpoint always returns the full catalog), so keying on it
732
+ // would store one full catalog copy per pool address and refetch it for
733
+ // every new pool. The pool filter is applied after the cached read below.
734
+ const keyParts = ['tokenized-vaults'];
735
+ if (loadSubaccounts === false)
736
+ keyParts.push('no-subaccounts');
737
+ if (loadSnapshots === false)
738
+ keyParts.push('no-snapshots');
739
+ const key = keyParts.join('-');
740
+ let tokenizedVaults;
741
+ const cachedResponse = await (0, cache_1.getSafeCache)(key);
742
+ if (cachedResponse) {
743
+ tokenizedVaults = cachedResponse;
744
+ }
745
+ if (!tokenizedVaults) {
746
+ // The vault list is requested by every vault page at once on a cold
747
+ // process; join concurrent callers onto one request.
748
+ tokenizedVaults = await dedupeInFlight(TOKENIZED_VAULT_REQUESTS, key, async () => {
749
+ // Build endpoint URL with optional query parameters
750
+ let endpoint = core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.list;
751
+ const params = new URLSearchParams();
752
+ if (loadSubaccounts === false) {
753
+ params.set('load_subaccounts', 'false');
754
+ }
755
+ if (loadSnapshots === false) {
756
+ params.set('load_snapshots', 'false');
757
+ }
758
+ const queryString = params.toString();
759
+ if (queryString) {
760
+ endpoint += `?${queryString}`;
761
+ }
762
+ const tokenizedVaultsResponse = await fetchUpshiftPublic(endpoint, {
763
+ headers: headers,
764
+ });
765
+ const parsed = (await tokenizedVaultsResponse.json());
766
+ const ttl = 1000 * 60 * 15; // 15 minute cache
767
+ cache_1.CACHE.set(key, parsed, { ttl });
768
+ return parsed;
769
+ });
770
+ }
771
+ // Filter by specific vault if address provided
772
+ if (pool &&
773
+ ((0, ethers_1.isAddress)(pool) ||
774
+ (0, chain_address_1.isSolanaAddress)(pool) ||
775
+ (0, chain_address_1.isStellarAddress)(pool) ||
776
+ (0, chain_address_1.isSuiAddress)(pool))) {
777
+ const foundObj = tokenizedVaults.find((t) => t.address.toLowerCase() === pool.toLowerCase());
778
+ return foundObj ? [foundObj] : [];
779
+ }
780
+ return tokenizedVaults;
781
+ }
782
+ /**
783
+ * Fetch current USD price for a token symbol or vault LP token.
784
+ * For vault LP tokens, calculates share price using totalAssets/totalSupply ratio.
785
+ * Falls back to CoinGecko if primary source fails.
786
+ * @param symbol - Token symbol or contract address
787
+ * @param provider - Optional web3 provider for on-chain price calculations
788
+ * @param coinGeckoKey - Optional CoinGecko API key for fallback pricing
789
+ * @param headers - Monitoring headers for request tracking
790
+ * @returns Token price in USD
791
+ */
792
+ async function fetchTokenPrice(symbol, provider, coinGeckoKey, headers) {
793
+ if (!symbol) {
794
+ logger_1.Logger.log.error('fetchTokenPrice', 'symbol parameter is undefined');
795
+ return 0;
796
+ }
797
+ // Normalize symbol and apply aliases BEFORE generating cache key
798
+ let normalizedSymbol = symbol.toLowerCase();
799
+ normalizedSymbol = normalizedSymbol === 'xbtc' ? 'btc' : normalizedSymbol;
800
+ normalizedSymbol = normalizedSymbol === 'strbtc' ? 'btc' : normalizedSymbol;
801
+ // Generate cache key based on normalized symbol and provider presence
802
+ const cacheKey = `price:${normalizedSymbol}:${provider ? 'with-provider' : 'no-provider'}`;
803
+ // Check error cache to prevent retry storms after failures
804
+ const cachedError = PRICE_ERROR_CACHE.get(cacheKey);
805
+ if (cachedError) {
806
+ logger_1.Logger.log.info('fetchTokenPrice', `Error cache HIT for ${normalizedSymbol} - throwing cached error`);
807
+ throw cachedError;
808
+ }
809
+ // Check price cache first to avoid rate limiting
810
+ const cachedPrice = PRICE_CACHE.get(cacheKey);
811
+ if (cachedPrice !== undefined) {
812
+ logger_1.Logger.log.info('fetchTokenPrice', `Cache HIT for ${normalizedSymbol}: $${cachedPrice}`);
813
+ return cachedPrice;
814
+ }
815
+ // Check for in-flight request to deduplicate simultaneous calls
816
+ const inflightRequest = PRICE_REQUESTS.get(cacheKey);
817
+ if (inflightRequest) {
818
+ logger_1.Logger.log.info('fetchTokenPrice', `In-flight request deduplication for ${normalizedSymbol}`);
819
+ return inflightRequest;
820
+ }
821
+ // Create the price fetching promise
822
+ const pricePromise = (async () => {
823
+ try {
824
+ const price = await _fetchTokenPriceInternal(symbol, provider, coinGeckoKey, headers);
825
+ // Cache the successful result
826
+ PRICE_CACHE.set(cacheKey, price);
827
+ // Clear any previous error cache on success
828
+ PRICE_ERROR_CACHE.delete(cacheKey);
829
+ return price;
830
+ }
831
+ catch (error) {
832
+ // Cache the error temporarily to prevent retry storms
833
+ const err = error instanceof Error ? error : new Error(String(error));
834
+ PRICE_ERROR_CACHE.set(cacheKey, err);
835
+ logger_1.Logger.log.info('fetchTokenPrice', `Cached error for ${normalizedSymbol}: ${err.message}`);
836
+ throw err;
837
+ }
838
+ finally {
839
+ // Clean up in-flight request tracking
840
+ PRICE_REQUESTS.delete(cacheKey);
841
+ }
842
+ })();
843
+ // Track this request to prevent duplicates
844
+ PRICE_REQUESTS.set(cacheKey, pricePromise);
845
+ return pricePromise;
846
+ }
847
+ // Normalize both raw integers to the same decimal scale BEFORE dividing —
848
+ // dividing the raw bigints first floors the ratio to ~1 and loses all
849
+ // fractional precision. Returns 1 for an empty vault (priced 1:1).
850
+ function normalizedSharePrice(totalAssets, totalSupply, decimals) {
851
+ const supply = Number((0, core_1.toNormalizedBn)(totalSupply, decimals).normalized);
852
+ if (!supply)
853
+ return 1;
854
+ return Number((0, core_1.toNormalizedBn)(totalAssets, decimals).normalized) / supply;
855
+ }
856
+ /**
857
+ * Internal price fetching implementation.
858
+ * This is separated to allow caching and request deduplication in the public function.
859
+ */
860
+ async function _fetchTokenPriceInternal(symbol, provider, coinGeckoKey, headers) {
861
+ // Fetch vault metadata to check if symbol is a vault LP token
862
+ const tokenizedVaults = await fetchTokenizedVaults(undefined, headers, false, false);
863
+ const vaultArray = tokenizedVaults.map((vault) => ({
864
+ vault: vault.address,
865
+ symbol: vault.receipt_token_symbol,
866
+ }));
867
+ const foundVaultLpAsset = vaultArray.find((v) => v.symbol?.toLowerCase() === symbol?.toLowerCase());
868
+ // @todo: handle multi-asset vaults
869
+ const tokenizedVault = tokenizedVaults.find((vault) => vault.address === foundVaultLpAsset?.vault);
870
+ const version = (0, vault_version_1.getVaultVersionV2)(tokenizedVault);
871
+ if (foundVaultLpAsset?.vault && provider && version === 'evm-2') {
872
+ try {
873
+ const vaultContract = new ethers_2.Contract((0, ethers_1.getAddress)(foundVaultLpAsset?.vault), abis_1.ABI_TOKENIZED_VAULT_V2, provider);
874
+ // Same bounded, no-fallback retry the write paths use for this selector
875
+ // (`getReceiptTokenAddressOrThrow` in `core/helpers/web3`). It cannot be
876
+ // reused here: `helpers/web3` imports `fetchTokenizedVault` from this
877
+ // module, so importing it back would be a circular dependency (CLAUDE.md
878
+ // §9). A transient empty `eth_call` response is absorbed; a vault that
879
+ // genuinely lacks `lpTokenAddress()` still falls into the catch below
880
+ // after the attempts are spent.
881
+ const receiptAddress = await (0, chain_error_1.retryOnTransientRpc)('fetchTokenPrice:receiptToken', () => vaultContract.lpTokenAddress(), { vault: foundVaultLpAsset.vault }, (error) => (0, chain_error_1.isRetryableRpcError)(error) ||
882
+ (0, chain_error_1.isEmptyViewResponse)(error, chain_error_1.LP_TOKEN_ADDRESS_SELECTOR));
883
+ const receiptContract = new ethers_2.Contract(receiptAddress, [web3_1.MIN_ABIS.decimals], provider);
884
+ const decimals = Number(await receiptContract.decimals());
885
+ const sharePrice = await vaultContract.getSharePrice();
886
+ return Number((0, core_1.toNormalizedBn)(sharePrice, decimals).normalized);
887
+ }
888
+ catch {
889
+ throw new Error('failed to fetch token price for evm-2 vault');
890
+ }
891
+ }
892
+ // Apply symbol normalization and aliases for API calls
893
+ let _symbol = symbol?.toLowerCase();
894
+ _symbol = _symbol === 'xbtc' ? 'btc' : _symbol;
895
+ _symbol = _symbol === 'strbtc' ? 'btc' : _symbol;
896
+ try {
897
+ // Fetch base token price from Upshift backend
898
+ const res = await fetch(`https://prices.augustdigital.io/price/${_symbol}`, { headers: compactHeaders(headers) });
899
+ if (res.status !== 200) {
900
+ throw new Error(`fetching ${_symbol} price: ${res?.statusText}`);
901
+ }
902
+ const json = (await res.json());
903
+ // For vault LP tokens, calculate share price using on-chain ratio
904
+ if (foundVaultLpAsset && provider) {
905
+ const vaultContract = new ethers_2.Contract((0, ethers_1.getAddress)(foundVaultLpAsset.vault), abis_1.ABI_LENDING_POOL_V2, provider);
906
+ const [totalAssets, totalSupply, rawDecimals] = await Promise.all([
907
+ vaultContract.totalAssets(),
908
+ vaultContract.totalSupply(),
909
+ vaultContract.decimals(),
910
+ ]);
911
+ const decimals = Number(rawDecimals);
912
+ const sharePrice = normalizedSharePrice(totalAssets, totalSupply, decimals);
913
+ return json.price * sharePrice;
914
+ }
915
+ return json.price;
916
+ }
917
+ catch {
918
+ // Fallback to CoinGecko if primary source fails
919
+ const fallbackPrice = await (0, fetcher_1.fetchTokenPricesFromCoinGecko)(symbol, coinGeckoKey);
920
+ // CoinGecko resolves to `null` when it has no price series for the coin.
921
+ // Guard BEFORE the LP branch: `null * sharePrice` is `0`, which the caller
922
+ // would cache in PRICE_CACHE as a genuine $0 price for the next 30 s.
923
+ // Throwing instead lands in PRICE_ERROR_CACHE (5 s) and surfaces as a
924
+ // typed error the consumer can branch on.
925
+ if (!fallbackPrice) {
926
+ throw new errors_1.UpshiftPriceUnavailableError(`failed to fetch token price: no price available for "${symbol}" from the Upshift price server or CoinGecko`, { context: { symbol } });
927
+ }
928
+ if (foundVaultLpAsset && provider) {
929
+ const vaultContract = new ethers_2.Contract((0, ethers_1.getAddress)(foundVaultLpAsset.vault), abis_1.ABI_LENDING_POOL_V2, provider);
930
+ const [totalAssets, totalSupply, rawDecimals] = await Promise.all([
931
+ vaultContract.totalAssets(),
932
+ vaultContract.totalSupply(),
933
+ vaultContract.decimals(),
934
+ ]);
935
+ const decimals = Number(rawDecimals);
936
+ const sharePrice = normalizedSharePrice(totalAssets, totalSupply, decimals);
937
+ return fallbackPrice * sharePrice;
938
+ }
939
+ return fallbackPrice;
940
+ }
941
+ }
942
+ /**
943
+ * Fetch token price by contract address and chain ID from Upshift price server.
944
+ * @param address - Token contract address
945
+ * @param chainId - Network chain ID
946
+ * @param headers - Optional monitoring headers for request tracking
947
+ * @returns Token price in USD, or 0 if not found
948
+ */
949
+ async function fetchTokenPriceByAddress(address, chainId, headers) {
950
+ if (!address || !chainId) {
951
+ return 0;
952
+ }
953
+ try {
954
+ const url = new URL(`${core_2.PRICE_SERVER_URL}/price_by_address_chain`);
955
+ url.searchParams.set('address', address);
956
+ url.searchParams.set('chain', chainId.toString());
957
+ url.searchParams.set('method', 'contract');
958
+ const res = await fetch(url.toString(), {
959
+ headers: compactHeaders({
960
+ accept: 'application/json',
961
+ ...headers,
962
+ }),
963
+ });
964
+ if (res.status !== 200) {
965
+ throw new Error(`Failed to fetch price for ${address} on chain ${chainId}: ${res.statusText}`);
966
+ }
967
+ const json = (await res.json());
968
+ return json.price || 0;
969
+ }
970
+ catch (e) {
971
+ logger_1.Logger.log.warn('fetchTokenPriceByAddress', `Failed to fetch price for ${address} on chain ${chainId}: ${e}`);
972
+ return 0;
973
+ }
974
+ }
975
+ /**
976
+ * Fetch active loans for a specific vault from backend API.
977
+ * Results are cached per vault and chain to reduce API calls.
978
+ * @param pool - Vault address
979
+ * @param chainId - Network chain ID
980
+ * @param headers - Monitoring headers for request tracking
981
+ * @returns Array of active loan objects
982
+ */
983
+ async function fetchTokenizedVaultLoans(pool, chainId, headers) {
984
+ const key = `loans-${chainId}-${pool}`;
985
+ let loans;
986
+ const cached = await (0, cache_1.getSafeCache)(key);
987
+ if (cached) {
988
+ loans = cached;
989
+ }
990
+ else {
991
+ const tokenizedVaultsResponse = await fetchUpshiftPublic(core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.loans(pool, chainId, true), { headers: headers });
992
+ loans = (await tokenizedVaultsResponse.json()).loans;
993
+ // Short TTL: loan state is live data (see ACTIVE_LOANS_TTL_MS). The
994
+ // falsy guard mirrors `setSafeCache` so a missing `loans` field is not
995
+ // cached as a sticky empty result.
996
+ if (loans)
997
+ cache_1.CACHE.set(key, loans, { ttl: ACTIVE_LOANS_TTL_MS });
998
+ }
999
+ return loans?.filter((l) => l.state.toLowerCase() === 'active');
1000
+ }
1001
+ /**
1002
+ * Fetch subaccount loans for a specific tokenized vault (lending pool).
1003
+ * Retrieves all active subaccount loan data from the backend.
1004
+ * @param pool - Vault address
1005
+ * @param chainId - Network chain ID
1006
+ * @param headers - Monitoring headers for request tracking
1007
+ * @returns Array of active subaccount loan objects
1008
+ */
1009
+ async function fetchTokenizedVaultSubaccountLoans(pool, chainId, headers) {
1010
+ const key = `subaccount-loans-${chainId}-${pool}`;
1011
+ let loans;
1012
+ const cached = await (0, cache_1.getSafeCache)(key);
1013
+ if (cached) {
1014
+ loans = cached;
1015
+ }
1016
+ else {
1017
+ const tokenizedVaultsResponse = await fetchUpshiftPublic(core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.subaccountLoans(pool, chainId, true), { headers: headers });
1018
+ loans = (await tokenizedVaultsResponse.json()).loans;
1019
+ // Short TTL: see fetchTokenizedVaultLoans / ACTIVE_LOANS_TTL_MS.
1020
+ if (loans)
1021
+ cache_1.CACHE.set(key, loans, { ttl: ACTIVE_LOANS_TTL_MS });
1022
+ }
1023
+ return loans?.filter((l) => l.state.toLowerCase() === 'active');
1024
+ }
1025
+ /**
1026
+ * Fetch historical timeseries data for a specific vault.
1027
+ * Returns TVL, APY, PnL, and share price data over time.
1028
+ * @param vaultAddress - Vault contract address
1029
+ * @param nDays - Number of days of historical data to fetch (default 30, min 1)
1030
+ * @param headers - Monitoring headers for request tracking
1031
+ * @returns Historical timeseries data with date keys
1032
+ */
1033
+ async function fetchVaultHistoricalTimeseries(vaultAddress, nDays, headers) {
1034
+ const key = `vault-historical-timeseries-${vaultAddress}-${nDays}`;
1035
+ const cachedResponse = await (0, cache_1.getSafeCache)(key);
1036
+ if (cachedResponse) {
1037
+ return cachedResponse;
1038
+ }
1039
+ const response = await fetchUpshiftPublic(core_2.WEBSERVER_ENDPOINTS.public.tokenizedVault.historicalTimeseries(vaultAddress, nDays), { headers: headers });
1040
+ if (!response.ok) {
1041
+ throw new Error(`Failed to fetch historical timeseries data: ${response.statusText}`);
1042
+ }
1043
+ const json = (await response.json());
1044
+ cache_1.CACHE.set(key, json, { ttl: 1000 * 60 * 10 }); // Cache for 10 minutes
1045
+ return json;
1046
+ }
1047
+ /**
1048
+ * Settle a batch of async tasks, allowing partial failure.
1049
+ *
1050
+ * Unlike `Promise.all`, a failing task does not reject the batch: its slot in
1051
+ * the result array is `null`, so results stay index-aligned with the input.
1052
+ *
1053
+ * Retries only apply to **thunks** (`() => Promise<T>`): a thunk is invoked
1054
+ * again on each attempt via {@link withRetry} (exponential backoff from
1055
+ * `baseDelay`, retryable network errors only). A **bare promise** is already
1056
+ * in flight and cannot be re-executed — re-awaiting it just yields the same
1057
+ * rejection — so bare promises are settled exactly once, with no retry and
1058
+ * no backoff sleep. Pass thunks when a retry is actually wanted.
1059
+ *
1060
+ * @param tasks - Promises and/or thunks to settle. Mixed arrays are allowed.
1061
+ * An empty array resolves to `[]`.
1062
+ * @param maxRetries - Maximum retry attempts per **thunk** (ignored for bare
1063
+ * promises). Default `3`.
1064
+ * @param baseDelay - Initial backoff delay in milliseconds for thunk retries
1065
+ * (ignored for bare promises). Default `1000`.
1066
+ * @returns Results in input order; `null` in the slot of any task that
1067
+ * ultimately failed. Never rejects.
1068
+ * @example
1069
+ * ```ts
1070
+ * // Bare promises: settle once, failures become null.
1071
+ * const [a, b] = await promiseSettle([getA(), getB()]);
1072
+ * // Thunks: each failing call is retried up to 3 times with backoff.
1073
+ * const [c, d] = await promiseSettle([() => getC(), () => getD()]);
1074
+ * ```
1075
+ */
1076
+ async function promiseSettle(tasks, maxRetries = 3, baseDelay = 1000) {
1077
+ const settling = tasks.map((task, index) => {
1078
+ if (typeof task !== 'function') {
1079
+ // Already-created promise: nothing to re-run, so settle it as-is.
1080
+ return task;
1081
+ }
1082
+ return withRetry(async () => {
1083
+ try {
1084
+ return await task();
1085
+ }
1086
+ catch (error) {
1087
+ logger_1.Logger.log.warn('promiseSettle', `Task at index ${index} failed`, error);
1088
+ throw error;
1089
+ }
1090
+ }, maxRetries, baseDelay);
1091
+ });
1092
+ const results = await Promise.allSettled(settling);
1093
+ return results.map((result, index) => {
1094
+ if (result.status === 'fulfilled') {
1095
+ return result.value;
1096
+ }
1097
+ else {
1098
+ logger_1.Logger.log.warn('promiseSettle', `Promise at index ${index} failed after retries`, result.reason);
1099
+ return null;
1100
+ }
1101
+ });
1102
+ }
1103
+ //# sourceMappingURL=fetcher.js.map