@gearbox-protocol/sdk 3.0.0-vfourabi.1 → 3.0.0-vfourabi.3

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 (275) hide show
  1. package/.eslintignore +3 -0
  2. package/.github/workflows/lint_pr.yml +18 -0
  3. package/.github/workflows/pr.yml +39 -0
  4. package/.github/workflows/release.yml +47 -0
  5. package/.gitignore +19 -0
  6. package/.husky/commit-msg +1 -0
  7. package/.husky/pre-commit +1 -0
  8. package/.nvmrc +1 -0
  9. package/.releaserc.json +34 -0
  10. package/.vscode/extensions.json +7 -0
  11. package/.vscode/settings.json +16 -0
  12. package/.yarn/install-state.gz +0 -0
  13. package/.yarnrc.yml +1 -0
  14. package/ContributionAgreement +72 -0
  15. package/dist/cjs/abi/iZapper.cjs +85 -0
  16. package/dist/cjs/abi/iZapper.d.ts +123 -0
  17. package/dist/cjs/sdk/index.cjs +19830 -19764
  18. package/dist/cjs/sdk/index.d.ts +3746 -3061
  19. package/dist/esm/abi/iZapper.d.mts +123 -0
  20. package/dist/esm/abi/iZapper.mjs +83 -0
  21. package/dist/esm/sdk/index.d.mts +3746 -3061
  22. package/dist/esm/sdk/index.mjs +19807 -19765
  23. package/jest.config.js +7 -0
  24. package/package.json +32 -2
  25. package/scripts/example.ts +30 -0
  26. package/src/abi/compressors.ts +3962 -0
  27. package/src/abi/errors.ts +196 -0
  28. package/src/abi/iERC20.ts +122 -0
  29. package/src/abi/iPausable.ts +35 -0
  30. package/src/abi/iPriceFeedStore.ts +227 -0
  31. package/src/abi/iUpdatablePriceFeed.ts +16 -0
  32. package/src/abi/iVersion.ts +28 -0
  33. package/src/abi/iZapper.ts +84 -0
  34. package/src/abi/routerV300.ts +378 -0
  35. package/src/abi/v300.ts +4151 -0
  36. package/src/abi/v310.ts +5179 -0
  37. package/src/adapters/AbstractAdapter.ts +28 -0
  38. package/src/adapters/BalancerV2VaultAdapterContract.ts +19 -0
  39. package/src/adapters/BalancerV3RouterAdapterContract.ts +19 -0
  40. package/src/adapters/CamelotV3AdapterContract.ts +20 -0
  41. package/src/adapters/ConvexV1BaseRewardPoolAdapterContract.ts +20 -0
  42. package/src/adapters/ConvexV1BoosterAdapterContract.ts +20 -0
  43. package/src/adapters/Curve2AssetsAdapterContract.ts +20 -0
  44. package/src/adapters/Curve3AssetsAdapterContract.ts +20 -0
  45. package/src/adapters/Curve4AssetsAdapterContract.ts +20 -0
  46. package/src/adapters/CurveV1AdapterStETHContract.ts +20 -0
  47. package/src/adapters/CurveV1StableNGAdapterContract.ts +20 -0
  48. package/src/adapters/DaiUsdsAdapterContract.ts +21 -0
  49. package/src/adapters/ERC4626AdapterContract.ts +20 -0
  50. package/src/adapters/MellowERC4626VaultAdapterContract.ts +20 -0
  51. package/src/adapters/MellowVaultAdapterContract.ts +20 -0
  52. package/src/adapters/PendleRouterAdapterContract.ts +21 -0
  53. package/src/adapters/StakingRewardsAdapterContract.ts +21 -0
  54. package/src/adapters/UniswapV2AdapterContract.ts +20 -0
  55. package/src/adapters/UniswapV3AdapterContract.ts +170 -0
  56. package/src/adapters/VelodromeV2AdapterContract.ts +20 -0
  57. package/src/adapters/WstETHV1AdapterContract.ts +20 -0
  58. package/src/adapters/YearnV2AdapterContract.ts +20 -0
  59. package/src/adapters/abi/adapters.ts +4325 -0
  60. package/src/adapters/abi/iBalancerV3RouterAdapter.ts +126 -0
  61. package/src/adapters/abi/index.ts +2 -0
  62. package/src/adapters/index.ts +2 -0
  63. package/src/adapters/plugin.ts +90 -0
  64. package/src/adapters/types.ts +62 -0
  65. package/src/dev/AccountOpener.ts +611 -0
  66. package/src/dev/PriceFeedStore.ts +95 -0
  67. package/src/dev/SDKExample.ts +167 -0
  68. package/src/dev/abi.ts +14 -0
  69. package/src/dev/calcLiquidatableLTs.ts +77 -0
  70. package/src/dev/createAnvilClient.ts +155 -0
  71. package/src/dev/index.ts +7 -0
  72. package/src/dev/setLTZero.ts +127 -0
  73. package/src/dev/setLTs.ts +68 -0
  74. package/src/sdk/GearboxSDK.ts +488 -0
  75. package/src/sdk/abi/index.ts +1 -0
  76. package/src/sdk/abi/oracles.ts +4614 -0
  77. package/src/sdk/accounts/CreditAccountsService.ts +1123 -0
  78. package/src/sdk/accounts/index.ts +1 -0
  79. package/src/sdk/base/AddressLabeller.ts +35 -0
  80. package/src/sdk/base/BaseContract.ts +237 -0
  81. package/src/sdk/base/IAddressLabeller.ts +13 -0
  82. package/src/sdk/base/PlaceholderContract.ts +12 -0
  83. package/src/sdk/base/SDKConstruct.ts +35 -0
  84. package/src/sdk/base/TokensMeta.ts +45 -0
  85. package/src/sdk/base/index.ts +6 -0
  86. package/src/sdk/base/types.ts +102 -0
  87. package/src/sdk/bots/BotsService.ts +92 -0
  88. package/src/sdk/bots/index.ts +2 -0
  89. package/src/sdk/bots/utils.ts +19 -0
  90. package/src/sdk/chain/Provider.ts +99 -0
  91. package/src/sdk/chain/chains.ts +41 -0
  92. package/src/sdk/chain/detectChain.ts +21 -0
  93. package/src/sdk/chain/index.ts +3 -0
  94. package/src/sdk/constants/address-provider.ts +47 -0
  95. package/src/sdk/constants/addresses.ts +82 -0
  96. package/src/sdk/constants/bot-permissions.ts +36 -0
  97. package/src/sdk/constants/index.ts +6 -0
  98. package/src/sdk/constants/math.ts +23 -0
  99. package/src/sdk/constants/networks.ts +38 -0
  100. package/src/sdk/constants/periphery.ts +7 -0
  101. package/src/sdk/core/BotListV3Contract.ts +103 -0
  102. package/src/sdk/core/GearStakingV3Contract.ts +84 -0
  103. package/src/sdk/core/address-provider/AbstractAddressProviderContract.ts +101 -0
  104. package/src/sdk/core/address-provider/AddressProviderV3Contract.ts +105 -0
  105. package/src/sdk/core/address-provider/AddressProviderV3_1Contract.ts +92 -0
  106. package/src/sdk/core/address-provider/getAddressProvider.ts +45 -0
  107. package/src/sdk/core/address-provider/index.ts +4 -0
  108. package/src/sdk/core/address-provider/types.ts +17 -0
  109. package/src/sdk/core/index.ts +3 -0
  110. package/src/sdk/gauges/GaugeStakingService.ts +100 -0
  111. package/src/sdk/gauges/index.ts +2 -0
  112. package/src/sdk/gauges/utils.ts +25 -0
  113. package/src/sdk/index.ts +17 -0
  114. package/src/sdk/market/MarketConfiguratorContract.ts +78 -0
  115. package/src/sdk/market/MarketRegister.ts +330 -0
  116. package/src/sdk/market/MarketSuite.ts +83 -0
  117. package/src/sdk/market/adapters/PlaceholderAdapterContracts.ts +18 -0
  118. package/src/sdk/market/adapters/factory.ts +34 -0
  119. package/src/sdk/market/adapters/index.ts +3 -0
  120. package/src/sdk/market/adapters/types.ts +7 -0
  121. package/src/sdk/market/credit/CreditConfiguratorV300Contract.ts +164 -0
  122. package/src/sdk/market/credit/CreditConfiguratorV310Contract.ts +139 -0
  123. package/src/sdk/market/credit/CreditFacadeV300Contract.ts +206 -0
  124. package/src/sdk/market/credit/CreditFacadeV310Contract.ts +190 -0
  125. package/src/sdk/market/credit/CreditManagerV300Contract.ts +122 -0
  126. package/src/sdk/market/credit/CreditManagerV310Contract.ts +122 -0
  127. package/src/sdk/market/credit/CreditSuite.ts +65 -0
  128. package/src/sdk/market/credit/createCreditConfigurator.ts +18 -0
  129. package/src/sdk/market/credit/createCreditFacade.ts +18 -0
  130. package/src/sdk/market/credit/createCreditManager.ts +18 -0
  131. package/src/sdk/market/credit/index.ts +8 -0
  132. package/src/sdk/market/credit/types.ts +42 -0
  133. package/src/sdk/market/index.ts +7 -0
  134. package/src/sdk/market/oracle/PriceOracleBaseContract.ts +376 -0
  135. package/src/sdk/market/oracle/PriceOracleV300Contract.ts +71 -0
  136. package/src/sdk/market/oracle/PriceOracleV310Contract.ts +43 -0
  137. package/src/sdk/market/oracle/createPriceOracle.ts +22 -0
  138. package/src/sdk/market/oracle/index.ts +4 -0
  139. package/src/sdk/market/oracle/types.ts +48 -0
  140. package/src/sdk/market/pool/GaugeContract.ts +120 -0
  141. package/src/sdk/market/pool/LinearInterestRateModelContract.ts +75 -0
  142. package/src/sdk/market/pool/PoolQuotaKeeperV300Contract.ts +89 -0
  143. package/src/sdk/market/pool/PoolQuotaKeeperV310Contract.ts +89 -0
  144. package/src/sdk/market/pool/PoolSuite.ts +76 -0
  145. package/src/sdk/market/pool/PoolV300Contract.ts +144 -0
  146. package/src/sdk/market/pool/PoolV310Contract.ts +144 -0
  147. package/src/sdk/market/pool/TumblerContract.ts +73 -0
  148. package/src/sdk/market/pool/createInterestRateModel.ts +33 -0
  149. package/src/sdk/market/pool/createPool.ts +19 -0
  150. package/src/sdk/market/pool/createPoolQuotaKeeper.ts +20 -0
  151. package/src/sdk/market/pool/createRateKeeper.ts +25 -0
  152. package/src/sdk/market/pool/index.ts +6 -0
  153. package/src/sdk/market/pool/types.ts +28 -0
  154. package/src/sdk/market/pricefeeds/AbstractLPPriceFeed.ts +71 -0
  155. package/src/sdk/market/pricefeeds/AbstractPriceFeed.ts +137 -0
  156. package/src/sdk/market/pricefeeds/BalancerStablePriceFeed.ts +24 -0
  157. package/src/sdk/market/pricefeeds/BalancerWeightedPriceFeed.ts +70 -0
  158. package/src/sdk/market/pricefeeds/BoundedPriceFeed.ts +34 -0
  159. package/src/sdk/market/pricefeeds/ChainlinkPriceFeed.ts +16 -0
  160. package/src/sdk/market/pricefeeds/CompositePriceFeed.ts +25 -0
  161. package/src/sdk/market/pricefeeds/CurveCryptoPriceFeed.ts +24 -0
  162. package/src/sdk/market/pricefeeds/CurveStablePriceFeed.ts +24 -0
  163. package/src/sdk/market/pricefeeds/CurveUSDPriceFeed.ts +24 -0
  164. package/src/sdk/market/pricefeeds/Erc4626PriceFeed.ts +36 -0
  165. package/src/sdk/market/pricefeeds/MellowLRTPriceFeed.ts +26 -0
  166. package/src/sdk/market/pricefeeds/PendleTWAPPTPriceFeed.ts +44 -0
  167. package/src/sdk/market/pricefeeds/PriceFeedRef.ts +34 -0
  168. package/src/sdk/market/pricefeeds/PriceFeedsRegister.ts +293 -0
  169. package/src/sdk/market/pricefeeds/RedstonePriceFeed.ts +65 -0
  170. package/src/sdk/market/pricefeeds/RedstoneUpdater.ts +304 -0
  171. package/src/sdk/market/pricefeeds/WstETHPriceFeed.ts +24 -0
  172. package/src/sdk/market/pricefeeds/YearnPriceFeed.ts +24 -0
  173. package/src/sdk/market/pricefeeds/ZeroPriceFeed.ts +17 -0
  174. package/src/sdk/market/pricefeeds/index.ts +20 -0
  175. package/src/sdk/market/pricefeeds/types.ts +82 -0
  176. package/src/sdk/market/pricefeeds/utils.ts +24 -0
  177. package/src/sdk/plugins/index.ts +10 -0
  178. package/src/sdk/router/PathOptionFactory.ts +147 -0
  179. package/src/sdk/router/RouterV3Contract.ts +558 -0
  180. package/src/sdk/router/index.ts +2 -0
  181. package/src/sdk/router/types.ts +48 -0
  182. package/src/sdk/sdk-gov-legacy/contracts/adapters.ts +39 -0
  183. package/src/sdk/sdk-gov-legacy/contracts/contracts.ts +647 -0
  184. package/src/sdk/sdk-gov-legacy/contracts/index.ts +2 -0
  185. package/src/sdk/sdk-gov-legacy/core/constants.ts +11 -0
  186. package/src/sdk/sdk-gov-legacy/index.ts +4 -0
  187. package/src/sdk/sdk-gov-legacy/oracles/PriceFeedType.ts +24 -0
  188. package/src/sdk/sdk-gov-legacy/oracles/index.ts +1 -0
  189. package/src/sdk/sdk-gov-legacy/tokens/aave.ts +101 -0
  190. package/src/sdk/sdk-gov-legacy/tokens/aura.ts +284 -0
  191. package/src/sdk/sdk-gov-legacy/tokens/balancer.ts +421 -0
  192. package/src/sdk/sdk-gov-legacy/tokens/compound.ts +79 -0
  193. package/src/sdk/sdk-gov-legacy/tokens/convex.ts +561 -0
  194. package/src/sdk/sdk-gov-legacy/tokens/curveLP.ts +480 -0
  195. package/src/sdk/sdk-gov-legacy/tokens/decimals.ts +301 -0
  196. package/src/sdk/sdk-gov-legacy/tokens/erc4626.ts +75 -0
  197. package/src/sdk/sdk-gov-legacy/tokens/gear.ts +273 -0
  198. package/src/sdk/sdk-gov-legacy/tokens/index.ts +18 -0
  199. package/src/sdk/sdk-gov-legacy/tokens/normal.ts +613 -0
  200. package/src/sdk/sdk-gov-legacy/tokens/quoted.ts +10 -0
  201. package/src/sdk/sdk-gov-legacy/tokens/stakingRewards.ts +41 -0
  202. package/src/sdk/sdk-gov-legacy/tokens/token.ts +2354 -0
  203. package/src/sdk/sdk-gov-legacy/tokens/tokenData.ts +44 -0
  204. package/src/sdk/sdk-gov-legacy/tokens/tokenType.ts +33 -0
  205. package/src/sdk/sdk-gov-legacy/tokens/wrapped.ts +28 -0
  206. package/src/sdk/sdk-gov-legacy/tokens/yearn.ts +122 -0
  207. package/src/sdk/sdk-gov-legacy/tokens/zircuit.ts +44 -0
  208. package/src/sdk/sdk-legacy/apy/index.ts +149 -0
  209. package/src/sdk/sdk-legacy/core/assets.ts +200 -0
  210. package/src/sdk/sdk-legacy/core/creditAccount.spec.ts +1966 -0
  211. package/src/sdk/sdk-legacy/core/creditAccount.ts +816 -0
  212. package/src/sdk/sdk-legacy/core/creditManager.ts +316 -0
  213. package/src/sdk/sdk-legacy/core/creditSession.ts +352 -0
  214. package/src/sdk/sdk-legacy/core/endpoint.ts +131 -0
  215. package/src/sdk/sdk-legacy/core/eventOrTx.ts +101 -0
  216. package/src/sdk/sdk-legacy/core/pool.ts +439 -0
  217. package/src/sdk/sdk-legacy/core/strategy.ts +82 -0
  218. package/src/sdk/sdk-legacy/core/transactions.ts +865 -0
  219. package/src/sdk/sdk-legacy/gearboxRewards/api.ts +704 -0
  220. package/src/sdk/sdk-legacy/gearboxRewards/apy.ts +267 -0
  221. package/src/sdk/sdk-legacy/gearboxRewards/extraAPY.ts +165 -0
  222. package/src/sdk/sdk-legacy/gearboxRewards/index.ts +3 -0
  223. package/src/sdk/sdk-legacy/gearboxRewards/merklAPI.ts +151 -0
  224. package/src/sdk/sdk-legacy/index.ts +21 -0
  225. package/src/sdk/sdk-legacy/pathfinder/core.ts +18 -0
  226. package/src/sdk/sdk-legacy/pathfinder/index.ts +1 -0
  227. package/src/sdk/sdk-legacy/payload/creditAccount.ts +48 -0
  228. package/src/sdk/sdk-legacy/payload/creditManager.ts +133 -0
  229. package/src/sdk/sdk-legacy/payload/creditSession.ts +143 -0
  230. package/src/sdk/sdk-legacy/payload/graphPayload.ts +10 -0
  231. package/src/sdk/sdk-legacy/payload/pool.ts +198 -0
  232. package/src/sdk/sdk-legacy/payload/token.ts +13 -0
  233. package/src/sdk/sdk-legacy/tokens/tokenData.ts +57 -0
  234. package/src/sdk/sdk-legacy/types/IAirdropDistributor.ts +103 -0
  235. package/src/sdk/sdk-legacy/types/IBaseRewardPool.ts +249 -0
  236. package/src/sdk/sdk-legacy/types/IDataCompressorV3.ts +957 -0
  237. package/src/sdk/sdk-legacy/types/IDegenDistributor.ts +70 -0
  238. package/src/sdk/sdk-legacy/types/IERC20Permit.ts +35 -0
  239. package/src/sdk/sdk-legacy/types/IERC20ZapperDeposits.ts +99 -0
  240. package/src/sdk/sdk-legacy/types/IETHZapperDeposits.ts +27 -0
  241. package/src/sdk/sdk-legacy/types/IFarmingPool.ts +229 -0
  242. package/src/sdk/sdk-legacy/types/IInterestRateModel.ts +23 -0
  243. package/src/sdk/sdk-legacy/types/IMulticall3.ts +242 -0
  244. package/src/sdk/sdk-legacy/types/IOffchainOracle.ts +31 -0
  245. package/src/sdk/sdk-legacy/types/index.ts +11 -0
  246. package/src/sdk/sdk-legacy/utils/formatter.ts +46 -0
  247. package/src/sdk/sdk-legacy/utils/index.ts +3 -0
  248. package/src/sdk/sdk-legacy/utils/math.ts +6 -0
  249. package/src/sdk/sdk-legacy/utils/price.ts +27 -0
  250. package/src/sdk/types/index.ts +5 -0
  251. package/src/sdk/types/logger.ts +13 -0
  252. package/src/sdk/types/state-human.ts +224 -0
  253. package/src/sdk/types/state.ts +8 -0
  254. package/src/sdk/types/transactions.ts +22 -0
  255. package/src/sdk/types/tvl.ts +4 -0
  256. package/src/sdk/utils/AddressMap.ts +111 -0
  257. package/src/sdk/utils/bytes32ToString.ts +6 -0
  258. package/src/sdk/utils/childLogger.ts +8 -0
  259. package/src/sdk/utils/createRawTx.ts +86 -0
  260. package/src/sdk/utils/etherscan.ts +42 -0
  261. package/src/sdk/utils/filterDust.ts +20 -0
  262. package/src/sdk/utils/formatter.ts +124 -0
  263. package/src/sdk/utils/index.ts +10 -0
  264. package/src/sdk/utils/internal/Hooks.ts +51 -0
  265. package/src/sdk/utils/internal/index.ts +1 -0
  266. package/src/sdk/utils/json.ts +27 -0
  267. package/src/sdk/utils/mappers.ts +38 -0
  268. package/src/sdk/utils/retry.ts +24 -0
  269. package/src/sdk/utils/viem/detectNetwork.ts +27 -0
  270. package/src/sdk/utils/viem/index.ts +3 -0
  271. package/src/sdk/utils/viem/sendRawTx.ts +36 -0
  272. package/src/sdk/utils/viem/simulateMulticall.ts +262 -0
  273. package/tsconfig.build.json +4 -0
  274. package/tsconfig.json +16 -0
  275. package/tsup.config.ts +77 -0
@@ -0,0 +1,1123 @@
1
+ import type { Address, ContractFunctionArgs } from "viem";
2
+ import { encodeFunctionData } from "viem";
3
+
4
+ import {
5
+ iCreditAccountCompressorAbi,
6
+ iPeripheryCompressorAbi,
7
+ iRewardsCompressorAbi,
8
+ } from "../../abi/compressors";
9
+ import { iCreditFacadeV300MulticallAbi } from "../../abi/v300";
10
+ import type { CreditAccountData } from "../base";
11
+ import { SDKConstruct } from "../base";
12
+ import {
13
+ ADDRESS_0X0,
14
+ AP_CREDIT_ACCOUNT_COMPRESSOR,
15
+ AP_PERIPHERY_COMPRESSOR,
16
+ AP_REWARDS_COMPRESSOR,
17
+ MAX_UINT256,
18
+ MIN_INT96,
19
+ } from "../constants";
20
+ import type { GearboxSDK } from "../GearboxSDK";
21
+ import type {
22
+ CreditSuite,
23
+ IPriceFeedContract,
24
+ IPriceOracleContract,
25
+ OnDemandPriceUpdate,
26
+ UpdatePriceFeedsResult,
27
+ } from "../market";
28
+ import { rawTxToMulticallPriceUpdate } from "../market";
29
+ import {
30
+ type Asset,
31
+ assetsMap,
32
+ type CreditAccountDataSlice,
33
+ type RouterCloseResult,
34
+ } from "../router";
35
+ import { iBaseRewardPoolAbi } from "../sdk-legacy";
36
+ import type { ILogger, MultiCall, RawTx } from "../types";
37
+ import { childLogger } from "../utils";
38
+ import { simulateMulticall } from "../utils/viem";
39
+
40
+ type CompressorAbi = typeof iCreditAccountCompressorAbi;
41
+
42
+ type GetCreditAccountsArgs = ContractFunctionArgs<
43
+ typeof iCreditAccountCompressorAbi,
44
+ "pure" | "view",
45
+ "getCreditAccounts"
46
+ >;
47
+
48
+ export interface CreditAccountServiceOptions {
49
+ batchSize?: number;
50
+ }
51
+
52
+ interface ReadContractOptions {
53
+ blockNumber?: bigint;
54
+ }
55
+
56
+ export interface CreditAccountFilter {
57
+ creditManager?: Address;
58
+ owner?: Address;
59
+ includeZeroDebt?: boolean;
60
+ minHealthFactor?: number;
61
+ maxHealthFactor?: number;
62
+ }
63
+
64
+ export interface CloseCreditAccountResult extends CommonResult {
65
+ routerCloseResult: RouterCloseResult;
66
+ }
67
+
68
+ export interface CommonResult {
69
+ tx: RawTx;
70
+ calls: Array<MultiCall>;
71
+ creditFacade: CreditSuite["creditFacade"];
72
+ }
73
+
74
+ type CloseOptions = "close" | "zeroDebt";
75
+
76
+ interface CloseCreditAccountProps {
77
+ operation: CloseOptions;
78
+ creditAccount: CreditAccountDataSlice;
79
+ assetsToWithdraw: Array<Address>;
80
+ to: Address;
81
+ slippage?: bigint;
82
+ closePath?: RouterCloseResult;
83
+ }
84
+
85
+ interface RepayCreditAccountProps extends RepayAndLiquidateCreditAccountProps {
86
+ operation: CloseOptions;
87
+ }
88
+
89
+ interface RepayAndLiquidateCreditAccountProps {
90
+ collateralAssets: Array<Asset>;
91
+ assetsToWithdraw: Array<Address>;
92
+ creditAccount: CreditAccountDataSlice;
93
+ to: Address;
94
+ permits: Record<string, PermitResult>;
95
+ }
96
+
97
+ interface PrepareUpdateQuotasProps {
98
+ minQuota: Array<Asset>;
99
+ averageQuota: Array<Asset>;
100
+ }
101
+
102
+ interface UpdateQuotasProps extends PrepareUpdateQuotasProps {
103
+ creditAccount: CreditAccountDataSlice;
104
+ }
105
+
106
+ interface AddCollateralProps extends PrepareUpdateQuotasProps {
107
+ asset: Asset;
108
+ ethAmount: bigint;
109
+ permit: PermitResult | undefined;
110
+ creditAccount: CreditAccountDataSlice;
111
+ }
112
+
113
+ interface WithdrawCollateralProps extends PrepareUpdateQuotasProps {
114
+ assetsToWithdraw: Array<Asset>;
115
+ to: Address;
116
+ creditAccount: CreditAccountDataSlice;
117
+ }
118
+
119
+ interface ExecuteSwapProps extends PrepareUpdateQuotasProps {
120
+ calls: Array<MultiCall>;
121
+ creditAccount: CreditAccountDataSlice;
122
+ }
123
+
124
+ export interface ClaimFarmRewardsProps extends PrepareUpdateQuotasProps {
125
+ tokensToDisable: Array<Asset>;
126
+ calls: Array<MultiCall>;
127
+ creditAccount: CreditAccountDataSlice;
128
+ }
129
+
130
+ export interface OpenCAProps extends PrepareUpdateQuotasProps {
131
+ ethAmount: bigint;
132
+ collateral: Array<Asset>;
133
+ debt: bigint;
134
+ withdrawDebt?: boolean;
135
+ permits: Record<string, PermitResult>;
136
+ calls: Array<MultiCall>;
137
+
138
+ creditManager: Address;
139
+
140
+ to: Address;
141
+ referralCode: bigint;
142
+ }
143
+
144
+ interface ChangeDeptProps {
145
+ creditAccount: CreditAccountDataSlice;
146
+ amount: bigint;
147
+ }
148
+
149
+ export interface PermitResult {
150
+ r: Address;
151
+ s: Address;
152
+ v: number;
153
+
154
+ token: Address;
155
+ owner: Address;
156
+ spender: Address;
157
+ value: bigint;
158
+
159
+ deadline: bigint;
160
+ nonce: bigint;
161
+ }
162
+
163
+ export interface Rewards {
164
+ adapter: Address;
165
+ stakedPhantomToken: Address;
166
+ calls: Array<MultiCall>;
167
+
168
+ rewards: Array<Asset>;
169
+ }
170
+
171
+ export class CreditAccountsService extends SDKConstruct {
172
+ #compressor: Address;
173
+ #batchSize?: number;
174
+ #logger?: ILogger;
175
+
176
+ constructor(sdk: GearboxSDK, options?: CreditAccountServiceOptions) {
177
+ super(sdk);
178
+ this.#compressor = sdk.addressProvider.getLatestVersion(
179
+ AP_CREDIT_ACCOUNT_COMPRESSOR,
180
+ );
181
+ this.#batchSize = options?.batchSize;
182
+ this.#logger = childLogger("CreditAccountsService", sdk.logger);
183
+ }
184
+
185
+ /**
186
+ * Returns single credit account data, or undefined if it's not found
187
+ * Performs all necessary price feed updates under the hood
188
+ * @param account
189
+ * @param options
190
+ * @returns
191
+ */
192
+ public async getCreditAccountData(
193
+ account: Address,
194
+ options?: ReadContractOptions,
195
+ ): Promise<CreditAccountData | undefined> {
196
+ const blockNumber = options?.blockNumber;
197
+ let raw: CreditAccountData;
198
+ try {
199
+ raw = await this.provider.publicClient.readContract({
200
+ abi: iCreditAccountCompressorAbi,
201
+ address: this.#compressor,
202
+ functionName: "getCreditAccountData",
203
+ args: [account],
204
+ blockNumber,
205
+ });
206
+ } catch (e) {
207
+ // TODO: reverts if account is not found, how to handle other revert reasons?
208
+ return undefined;
209
+ }
210
+ if (raw.success) {
211
+ return raw;
212
+ }
213
+ const { txs: priceUpdateTxs, timestamp: _ } =
214
+ await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(undefined, {
215
+ account,
216
+ });
217
+ const resp = await simulateMulticall(this.provider.publicClient, {
218
+ contracts: [
219
+ ...priceUpdateTxs.map(rawTxToMulticallPriceUpdate),
220
+ {
221
+ abi: iCreditAccountCompressorAbi,
222
+ address: this.#compressor,
223
+ functionName: "getCreditAccountData",
224
+ args: [account],
225
+ },
226
+ ],
227
+ allowFailure: false,
228
+ // gas: 550_000_000n,
229
+ batchSize: 0, // we cannot have price updates and compressor request in different batches
230
+ blockNumber,
231
+ });
232
+ const cad = resp.pop() as CreditAccountData;
233
+ return cad;
234
+ }
235
+
236
+ /**
237
+ * Methods to get all credit accounts with some optional filtering
238
+ * Performs all necessary price feed updates under the hood
239
+ *
240
+ * TODO: do we want to expose pagination?
241
+ * TODO: do we want to expose "reverting"?
242
+ * TODO: do we want to expose MarketFilter in any way? If so, we need to check that the MarketFilter is compatibled with attached markets?
243
+ * @param args
244
+ * @param options
245
+ * @returns returned credit accounts are sorted by health factor in ascending order
246
+ */
247
+ public async getCreditAccounts(
248
+ args?: CreditAccountFilter,
249
+ options?: ReadContractOptions,
250
+ ): Promise<Array<CreditAccountData>> {
251
+ const {
252
+ creditManager,
253
+ includeZeroDebt = false,
254
+ maxHealthFactor = 65_535, // TODO: this will change to bigint
255
+ minHealthFactor = 0,
256
+ owner = ADDRESS_0X0,
257
+ } = args ?? {};
258
+ // either credit manager or all attached markets
259
+ const arg0 = creditManager ?? {
260
+ configurators: this.marketConfigurators,
261
+ pools: [],
262
+ underlying: ADDRESS_0X0,
263
+ };
264
+ const caFilter = {
265
+ owner,
266
+ includeZeroDebt,
267
+ minHealthFactor,
268
+ maxHealthFactor,
269
+ };
270
+
271
+ const { txs: priceUpdateTxs, timestamp: _ } =
272
+ await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs();
273
+
274
+ const allCAs: Array<CreditAccountData> = [];
275
+ // reverting filter is exclusive, we need both options to get all accounts
276
+ for (const reverting of [false, true]) {
277
+ let offset = 0n;
278
+ do {
279
+ const [accounts, newOffset] = await this.#getCreditAccounts(
280
+ this.#batchSize
281
+ ? [
282
+ arg0,
283
+ { ...caFilter, reverting },
284
+ offset,
285
+ BigInt(this.#batchSize), // limit
286
+ ]
287
+ : [arg0, { ...caFilter, reverting }, offset],
288
+ priceUpdateTxs,
289
+ options,
290
+ );
291
+ allCAs.push(...accounts);
292
+ offset = newOffset;
293
+ } while (offset !== 0n);
294
+ }
295
+
296
+ // sort by health factor ascending
297
+ return allCAs.sort((a, b) => Number(a.healthFactor - b.healthFactor));
298
+ }
299
+
300
+ async getRewards(creditAccount: Address): Promise<Array<Rewards>> {
301
+ const rewards = await this.provider.publicClient.readContract({
302
+ abi: iRewardsCompressorAbi,
303
+ address: this.rewardCompressor,
304
+ functionName: "getRewards",
305
+ args: [creditAccount],
306
+ });
307
+
308
+ const r = rewards.reduce<Record<string, Rewards>>((acc, r) => {
309
+ const adapter = r.adapter.toLowerCase() as Address;
310
+ const stakedPhantomToken = r.stakedPhantomToken.toLowerCase() as Address;
311
+ const rewardToken = r.rewardToken.toLowerCase() as Address;
312
+
313
+ const key = [adapter, stakedPhantomToken].join("-");
314
+
315
+ if (!acc[key]) {
316
+ const callData = encodeFunctionData({
317
+ abi: iBaseRewardPoolAbi,
318
+ functionName: "getReward",
319
+ args: [],
320
+ });
321
+
322
+ acc[adapter] = {
323
+ adapter,
324
+ stakedPhantomToken,
325
+ calls: [
326
+ {
327
+ target: adapter,
328
+ callData,
329
+ },
330
+ ],
331
+ rewards: [],
332
+ };
333
+ }
334
+
335
+ acc[adapter].rewards.push({
336
+ token: rewardToken,
337
+ balance: r.amount,
338
+ });
339
+
340
+ return acc;
341
+ }, {});
342
+
343
+ return Object.values(r);
344
+ }
345
+
346
+ async getConnectedBots(
347
+ accountsToCheck: Array<{ creditAccount: Address; creditManager: Address }>,
348
+ ) {
349
+ const resp = await this.provider.publicClient.multicall({
350
+ contracts: accountsToCheck.map(o => {
351
+ const pool = this.sdk.marketRegister.findByCreditManager(
352
+ o.creditManager,
353
+ );
354
+
355
+ return {
356
+ abi: iPeripheryCompressorAbi,
357
+ address: this.peripheryCompressor,
358
+ functionName: "getConnectedBots",
359
+ args: [pool.configurator.address, o.creditAccount],
360
+ } as const;
361
+ }),
362
+ allowFailure: true,
363
+ });
364
+
365
+ return resp;
366
+ }
367
+
368
+ /**
369
+ * Generates transaction to liquidate credit account
370
+ * @param account
371
+ * @param to Address to transfer underlying left after liquidation
372
+ * @param slippage
373
+ * @returns
374
+ */
375
+ public async fullyLiquidate(
376
+ account: CreditAccountDataSlice,
377
+ to: Address,
378
+ slippage = 50n,
379
+ ): Promise<CloseCreditAccountResult> {
380
+ const cm = this.sdk.marketRegister.findCreditManager(account.creditManager);
381
+ const routerCloseResult = await this.sdk.router.findBestClosePath({
382
+ creditAccount: account,
383
+ creditManager: cm.creditManager,
384
+ slippage,
385
+ });
386
+ const priceUpdates = await this.getPriceUpdatesForFacade(
387
+ account.creditManager,
388
+ account,
389
+ undefined,
390
+ );
391
+ const calls = [...priceUpdates, ...routerCloseResult.calls];
392
+ const tx = cm.creditFacade.liquidateCreditAccount(
393
+ account.creditAccount,
394
+ to,
395
+ calls,
396
+ );
397
+ return { tx, calls, routerCloseResult, creditFacade: cm.creditFacade };
398
+ }
399
+
400
+ /**
401
+ * Closes credit account or sets debt to zero (but keep account)
402
+ * @param operation
403
+ * @param creditAccount
404
+ * @param assetsToWithdraw Tokens to withdraw from credit account
405
+ * @param to Address to withdraw underlying to
406
+ * @param slippage
407
+ * @param closePath
408
+ * @returns
409
+ */
410
+ async closeCreditAccount({
411
+ operation,
412
+ assetsToWithdraw,
413
+ creditAccount: ca,
414
+ to,
415
+ slippage = 50n,
416
+ closePath,
417
+ }: CloseCreditAccountProps): Promise<CloseCreditAccountResult> {
418
+ const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
419
+
420
+ const routerCloseResult =
421
+ closePath ||
422
+ (await this.sdk.router.findBestClosePath({
423
+ creditAccount: ca,
424
+ creditManager: cm.creditManager,
425
+ slippage,
426
+ }));
427
+
428
+ const calls: Array<MultiCall> = [
429
+ ...routerCloseResult.calls,
430
+ ...this.#prepareDisableQuotas(ca),
431
+ ...this.#prepareDecreaseDebt(ca),
432
+ ...this.#prepareDisableTokens(ca),
433
+ ...assetsToWithdraw.map(t =>
434
+ this.#prepareWithdrawToken(ca.creditFacade, t, MAX_UINT256, to),
435
+ ),
436
+ ];
437
+
438
+ const tx =
439
+ operation === "close"
440
+ ? cm.creditFacade.closeCreditAccount(ca.creditAccount, calls)
441
+ : cm.creditFacade.multicall(ca.creditAccount, calls);
442
+ return { tx, calls, routerCloseResult, creditFacade: cm.creditFacade };
443
+ }
444
+
445
+ /**
446
+ * Repays credit account or sets debt to zero (but keep account)
447
+ * @param operation
448
+ * @param creditAccount
449
+ * @param assetsToWithdraw Tokens to withdraw from credit account
450
+ * @param collateralAssets Tokens to pay for
451
+ * @param to Address to withdraw underlying to
452
+ * @param slippage
453
+ * @param permits
454
+ * @returns
455
+ */
456
+ async repayCreditAccount({
457
+ operation,
458
+ collateralAssets,
459
+ assetsToWithdraw,
460
+ creditAccount: ca,
461
+ permits,
462
+ to,
463
+ }: RepayCreditAccountProps): Promise<CommonResult> {
464
+ const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
465
+ const addCollateral = collateralAssets.filter(a => a.balance > 0);
466
+
467
+ const calls: Array<MultiCall> = [
468
+ ...this.#prepareAddCollateral(ca.creditFacade, addCollateral, permits),
469
+ ...this.#prepareDisableQuotas(ca),
470
+ ...this.#prepareDecreaseDebt(ca),
471
+ ...this.#prepareDisableTokens(ca),
472
+ // TODO: probably needs a better way to handle reward tokens
473
+ ...assetsToWithdraw.map(t =>
474
+ this.#prepareWithdrawToken(ca.creditFacade, t, MAX_UINT256, to),
475
+ ),
476
+ ];
477
+
478
+ const tx =
479
+ operation === "close"
480
+ ? cm.creditFacade.closeCreditAccount(ca.creditAccount, calls)
481
+ : cm.creditFacade.multicall(ca.creditAccount, calls);
482
+ return { tx, calls, creditFacade: cm.creditFacade };
483
+ }
484
+
485
+ /**
486
+ * Repays liquidatable credit account
487
+ * @param creditAccount
488
+ * @param assetsToWithdraw Tokens to withdraw from credit account
489
+ * @param collateralAssets Tokens to pay for
490
+ * @param to Address to withdraw underlying to
491
+ * @param slippage
492
+ * @returns
493
+ */
494
+ async repayAndLiquidateCreditAccount({
495
+ collateralAssets,
496
+ assetsToWithdraw,
497
+ creditAccount: ca,
498
+ permits,
499
+ to,
500
+ }: RepayAndLiquidateCreditAccountProps): Promise<CommonResult> {
501
+ const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
502
+
503
+ const priceUpdates = await this.getPriceUpdatesForFacade(
504
+ ca.creditManager,
505
+ ca,
506
+ undefined,
507
+ );
508
+
509
+ const addCollateral = collateralAssets.filter(a => a.balance > 0);
510
+
511
+ const calls: Array<MultiCall> = [
512
+ ...priceUpdates,
513
+ ...this.#prepareAddCollateral(ca.creditFacade, addCollateral, permits),
514
+ ...assetsToWithdraw.map(t =>
515
+ this.#prepareWithdrawToken(ca.creditFacade, t, MAX_UINT256, to),
516
+ ),
517
+ ];
518
+
519
+ const tx = cm.creditFacade.liquidateCreditAccount(
520
+ ca.creditAccount,
521
+ to,
522
+ calls,
523
+ );
524
+ return { tx, calls, creditFacade: cm.creditFacade };
525
+ }
526
+
527
+ public async updateQuotas(props: UpdateQuotasProps): Promise<CommonResult> {
528
+ const { creditAccount } = props;
529
+ const cm = this.sdk.marketRegister.findCreditManager(
530
+ creditAccount.creditManager,
531
+ );
532
+ const priceUpdates = await this.getPriceUpdatesForFacade(
533
+ creditAccount.creditManager,
534
+ creditAccount,
535
+ undefined,
536
+ );
537
+
538
+ const calls: Array<MultiCall> = [
539
+ ...priceUpdates,
540
+ ...this.#prepareUpdateQuotas(props.creditAccount.creditFacade, props),
541
+ ];
542
+
543
+ const tx = cm.creditFacade.multicall(creditAccount.creditAccount, [
544
+ ...priceUpdates,
545
+ ...this.#prepareUpdateQuotas(props.creditAccount.creditFacade, props),
546
+ ]);
547
+
548
+ return { tx, calls, creditFacade: cm.creditFacade };
549
+ }
550
+
551
+ public async addCollateral(props: AddCollateralProps): Promise<CommonResult> {
552
+ const { creditAccount, asset, permit, ethAmount } = props;
553
+ const cm = this.sdk.marketRegister.findCreditManager(
554
+ creditAccount.creditManager,
555
+ );
556
+
557
+ const priceUpdatesCalls = await this.getPriceUpdatesForFacade(
558
+ creditAccount.creditManager,
559
+ creditAccount,
560
+ props.averageQuota,
561
+ );
562
+
563
+ const calls: Array<MultiCall> = [
564
+ ...priceUpdatesCalls,
565
+ ...this.#prepareAddCollateral(
566
+ creditAccount.creditFacade,
567
+ [asset],
568
+ permit ? { [asset.token]: permit } : {},
569
+ ),
570
+ ...this.#prepareUpdateQuotas(creditAccount.creditFacade, props),
571
+ ];
572
+
573
+ const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
574
+ tx.value = ethAmount.toString(10);
575
+
576
+ return { tx, calls, creditFacade: cm.creditFacade };
577
+ }
578
+
579
+ public async changeDebt({
580
+ creditAccount,
581
+ amount,
582
+ }: ChangeDeptProps): Promise<CommonResult> {
583
+ if (amount === 0n) {
584
+ throw new Error("debt increase or decrease must be non-zero");
585
+ }
586
+ const isDecrease = amount < 0n;
587
+ const change = isDecrease ? -amount : amount;
588
+
589
+ const cm = this.sdk.marketRegister.findCreditManager(
590
+ creditAccount.creditManager,
591
+ );
592
+
593
+ const priceUpdatesCalls = await this.getPriceUpdatesForFacade(
594
+ creditAccount.creditManager,
595
+ creditAccount,
596
+ undefined,
597
+ );
598
+
599
+ const underlyingEnabled = (creditAccount.enabledTokensMask & 1n) === 1n;
600
+ const shouldEnable = !isDecrease && !underlyingEnabled;
601
+
602
+ const calls: Array<MultiCall> = [
603
+ ...priceUpdatesCalls,
604
+ ...(shouldEnable
605
+ ? this.#prepareEnableTokens(creditAccount.creditFacade, [
606
+ creditAccount.underlying,
607
+ ])
608
+ : []),
609
+ this.#prepareChangeDebt(creditAccount.creditFacade, change, isDecrease),
610
+ ];
611
+
612
+ const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
613
+
614
+ return { tx, calls, creditFacade: cm.creditFacade };
615
+ }
616
+
617
+ public async withdrawCollateral(
618
+ props: WithdrawCollateralProps,
619
+ ): Promise<CommonResult> {
620
+ const { creditAccount, assetsToWithdraw, to } = props;
621
+
622
+ const cm = this.sdk.marketRegister.findCreditManager(
623
+ creditAccount.creditManager,
624
+ );
625
+
626
+ const priceUpdatesCalls = await this.getPriceUpdatesForFacade(
627
+ creditAccount.creditManager,
628
+ creditAccount,
629
+ undefined,
630
+ );
631
+
632
+ const calls: Array<MultiCall> = [
633
+ ...priceUpdatesCalls,
634
+ ...assetsToWithdraw.map(a =>
635
+ this.#prepareWithdrawToken(
636
+ creditAccount.creditFacade,
637
+ a.token,
638
+ a.balance,
639
+ to,
640
+ ),
641
+ ),
642
+ ...this.#prepareUpdateQuotas(creditAccount.creditFacade, props),
643
+ ];
644
+
645
+ const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
646
+
647
+ return { tx, calls, creditFacade: cm.creditFacade };
648
+ }
649
+
650
+ public async executeSwap(props: ExecuteSwapProps): Promise<CommonResult> {
651
+ const { creditAccount, calls: swapCalls } = props;
652
+ if (swapCalls.length === 0) throw new Error("No path to execute");
653
+
654
+ const cm = this.sdk.marketRegister.findCreditManager(
655
+ creditAccount.creditManager,
656
+ );
657
+
658
+ const priceUpdatesCalls = await this.getPriceUpdatesForFacade(
659
+ creditAccount.creditManager,
660
+ creditAccount,
661
+ props.averageQuota,
662
+ );
663
+
664
+ const calls: Array<MultiCall> = [
665
+ ...priceUpdatesCalls,
666
+ ...swapCalls,
667
+ ...this.#prepareUpdateQuotas(creditAccount.creditFacade, props),
668
+ ];
669
+
670
+ const tx = cm.creditFacade.multicall(creditAccount.creditAccount, calls);
671
+
672
+ return { tx, calls, creditFacade: cm.creditFacade };
673
+ }
674
+
675
+ public async claimFarmRewards(
676
+ props: ClaimFarmRewardsProps,
677
+ ): Promise<CommonResult> {
678
+ const { tokensToDisable, calls: claimCalls, creditAccount: ca } = props;
679
+ if (claimCalls.length === 0) throw new Error("No path to execute");
680
+
681
+ const cm = this.sdk.marketRegister.findCreditManager(ca.creditManager);
682
+
683
+ const priceUpdatesCalls = await this.getPriceUpdatesForFacade(
684
+ ca.creditManager,
685
+ ca,
686
+ props.averageQuota,
687
+ );
688
+
689
+ // TODO: probably needs a better way to handle reward tokens
690
+ const calls = [
691
+ ...priceUpdatesCalls,
692
+ ...claimCalls,
693
+ ...tokensToDisable.map(a =>
694
+ this.#prepareDisableToken(ca.creditFacade, a.token),
695
+ ),
696
+ ...this.#prepareUpdateQuotas(ca.creditFacade, props),
697
+ ];
698
+
699
+ const tx = cm.creditFacade.multicall(ca.creditAccount, calls);
700
+
701
+ return { tx, calls, creditFacade: cm.creditFacade };
702
+ }
703
+
704
+ public async openCA(props: OpenCAProps): Promise<CommonResult> {
705
+ const {
706
+ ethAmount,
707
+ creditManager,
708
+ collateral,
709
+ permits,
710
+ debt,
711
+ withdrawDebt,
712
+ referralCode,
713
+ to,
714
+ calls: openPathCalls,
715
+ } = props;
716
+
717
+ const cmSuite = this.sdk.marketRegister.findCreditManager(creditManager);
718
+ const cm = cmSuite.creditManager;
719
+
720
+ const priceUpdatesCalls = await this.getPriceUpdatesForFacade(
721
+ cm.address,
722
+ undefined,
723
+ props.averageQuota,
724
+ );
725
+
726
+ const calls = [
727
+ ...priceUpdatesCalls,
728
+ this.#prepareIncreaseDebt(cm.creditFacade, debt),
729
+ ...this.#prepareAddCollateral(cm.creditFacade, collateral, permits),
730
+ ...this.#prepareUpdateQuotas(cm.creditFacade, props),
731
+ ...openPathCalls,
732
+ ...(withdrawDebt
733
+ ? [this.#prepareWithdrawToken(cm.creditFacade, cm.underlying, debt, to)]
734
+ : []),
735
+ ];
736
+
737
+ const tx = cmSuite.creditFacade.openCreditAccount(to, calls, referralCode);
738
+ tx.value = ethAmount.toString(10);
739
+
740
+ return { calls, tx, creditFacade: cmSuite.creditFacade };
741
+ }
742
+
743
+ /**
744
+ * Internal wrapper for CreditAccountCompressor.getCreditAccounts + price updates wrapped into multicall
745
+ * @param args
746
+ * @param priceUpdateTxs
747
+ * @param options
748
+ * @returns
749
+ */
750
+ async #getCreditAccounts(
751
+ args: GetCreditAccountsArgs,
752
+ priceUpdateTxs?: Array<RawTx>,
753
+ options?: ReadContractOptions,
754
+ ): Promise<[accounts: Array<CreditAccountData>, newOffset: bigint]> {
755
+ const blockNumber = options?.blockNumber;
756
+ if (priceUpdateTxs?.length) {
757
+ const resp = await simulateMulticall(this.provider.publicClient, {
758
+ contracts: [
759
+ ...priceUpdateTxs.map(rawTxToMulticallPriceUpdate),
760
+ {
761
+ abi: iCreditAccountCompressorAbi,
762
+ address: this.#compressor,
763
+ functionName: "getCreditAccounts",
764
+ args,
765
+ },
766
+ ],
767
+ allowFailure: false,
768
+ // gas: 550_000_000n,
769
+ batchSize: 0, // we cannot have price updates and compressor request in different batches
770
+ blockNumber,
771
+ });
772
+ const getCreditAccountsResp = resp.pop() as any as [
773
+ Array<CreditAccountData>,
774
+ bigint,
775
+ ];
776
+ return getCreditAccountsResp;
777
+ }
778
+
779
+ return this.provider.publicClient.readContract<
780
+ CompressorAbi,
781
+ "getCreditAccounts",
782
+ GetCreditAccountsArgs
783
+ >({
784
+ abi: iCreditAccountCompressorAbi,
785
+ address: this.#compressor,
786
+ functionName: "getCreditAccounts",
787
+ args,
788
+ blockNumber,
789
+ });
790
+ }
791
+
792
+ /**
793
+ * Returns raw txs that are needed to update all price feeds so that all credit accounts (possibly from different markets) compute
794
+ * @param accounts
795
+ * @returns
796
+ */
797
+ public async getUpdateForAccounts(
798
+ accounts: Array<CreditAccountDataSlice>,
799
+ ): Promise<UpdatePriceFeedsResult> {
800
+ // for each market, using pool address as key, gather tokens to update and find PriceFeedFactories
801
+ const tokensByPool = new Map<Address, Set<Address>>();
802
+ const oracleByPool = new Map<Address, IPriceOracleContract>();
803
+
804
+ for (const acc of accounts) {
805
+ const market = this.sdk.marketRegister.findByCreditManager(
806
+ acc.creditManager,
807
+ );
808
+ const pool = market.pool.pool.address;
809
+ oracleByPool.set(pool, market.priceOracle);
810
+
811
+ for (const t of acc.tokens) {
812
+ if (t.balance > 10n) {
813
+ const tokens = tokensByPool.get(pool) ?? new Set<Address>();
814
+ tokens.add(t.token);
815
+ tokensByPool.set(pool, tokens);
816
+ }
817
+ }
818
+ }
819
+ // priceFeeds can contain PriceFeeds from different markets
820
+ const priceFeeds: Array<IPriceFeedContract> = [];
821
+ for (const [pool, oracle] of oracleByPool.entries()) {
822
+ const tokens = Array.from(tokensByPool.get(pool) ?? []);
823
+ priceFeeds.push(...oracle.priceFeedsForTokens(tokens));
824
+ }
825
+ return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(priceFeeds);
826
+ }
827
+
828
+ public async getUpdateForAccount(
829
+ creditManager: Address,
830
+ creditAccount: CreditAccountDataSlice | undefined,
831
+ desiredQuotas: Array<Asset> | undefined,
832
+ ): Promise<UpdatePriceFeedsResult> {
833
+ // for each market, using pool address as key, gather tokens to update and find PriceFeedFactories
834
+ const tokensByPool = new Map<Address, Set<Address>>();
835
+ const oracleByPool = new Map<Address, IPriceOracleContract>();
836
+ const quotaRecord = desiredQuotas
837
+ ? assetsMap(desiredQuotas)
838
+ : desiredQuotas;
839
+ const caBalancesRecord = creditAccount
840
+ ? assetsMap(creditAccount.tokens)
841
+ : creditAccount;
842
+
843
+ const market = this.sdk.marketRegister.findByCreditManager(creditManager);
844
+ const cm =
845
+ this.sdk.marketRegister.findCreditManager(creditManager).creditManager;
846
+ const pool = market.pool.pool.address;
847
+
848
+ oracleByPool.set(pool, market.priceOracle);
849
+
850
+ const insertToken = (p: Address, t: Address) => {
851
+ const tokens = tokensByPool.get(p) ?? new Set<Address>();
852
+ tokens.add(t);
853
+ tokensByPool.set(pool, tokens);
854
+ };
855
+
856
+ for (const t of cm.collateralTokens) {
857
+ if (creditAccount && caBalancesRecord && quotaRecord) {
858
+ const balanceAsset = caBalancesRecord.get(t);
859
+ const balance = balanceAsset?.balance || 0n;
860
+ const mask = balanceAsset?.mask || 0n;
861
+ const isEnabled = (mask & creditAccount.enabledTokensMask) !== 0n;
862
+
863
+ const quotaAsset = quotaRecord.get(t);
864
+ const quotaBalance = quotaAsset?.balance || 0n;
865
+
866
+ if ((balance > 10n && isEnabled) || quotaBalance > 0)
867
+ insertToken(pool, t);
868
+ } else if (creditAccount && caBalancesRecord) {
869
+ const balanceAsset = caBalancesRecord.get(t);
870
+ const balance = balanceAsset?.balance || 0n;
871
+ const mask = balanceAsset?.mask || 0n;
872
+ const isEnabled = (mask & creditAccount.enabledTokensMask) !== 0n;
873
+
874
+ if (balance > 10n && isEnabled) insertToken(pool, t);
875
+ } else if (quotaRecord) {
876
+ const quotaAsset = quotaRecord.get(t);
877
+ const quotaBalance = quotaAsset?.balance || 0n;
878
+
879
+ if (quotaBalance > 0) insertToken(pool, t);
880
+ }
881
+ }
882
+
883
+ // priceFeeds can contain PriceFeeds from different markets
884
+ const priceFeeds: Array<IPriceFeedContract> = [];
885
+ for (const [pool, oracle] of oracleByPool.entries()) {
886
+ const tokens = Array.from(tokensByPool.get(pool) ?? []);
887
+ priceFeeds.push(...oracle.priceFeedsForTokens(tokens));
888
+ }
889
+ this.#logger?.debug(
890
+ { account: creditAccount?.creditAccount, manager: cm.name },
891
+ `generating price feed updates for ${priceFeeds.length} price feeds`,
892
+ );
893
+ return this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(
894
+ priceFeeds,
895
+ creditAccount ? { account: creditAccount.creditAccount } : undefined,
896
+ );
897
+ }
898
+
899
+ /**
900
+ * Returns account price updates in a non-encoded format
901
+ * @param acc
902
+ * @returns
903
+ */
904
+ public async getOnDemandPriceUpdates(
905
+ creditManager: Address,
906
+ creditAccount: CreditAccountDataSlice | undefined,
907
+ desiredQuotas: Array<Asset> | undefined,
908
+ ): Promise<Array<OnDemandPriceUpdate>> {
909
+ const market = this.sdk.marketRegister.findByCreditManager(creditManager);
910
+ const cm = this.sdk.marketRegister.findCreditManager(creditManager);
911
+ const update = await this.getUpdateForAccount(
912
+ creditManager,
913
+ creditAccount,
914
+ desiredQuotas,
915
+ );
916
+ this.#logger?.debug(
917
+ { account: creditAccount?.creditAccount, manager: cm.name },
918
+ `getting on demand price updates from ${update.txs.length} txs`,
919
+ );
920
+ return market.priceOracle.onDemandPriceUpdates(update);
921
+ }
922
+
923
+ /**
924
+ * Returns price updates in format that is accepted by various credit facade methods (multicall, close/liquidate, etc...)
925
+ * @param acc
926
+ * @returns
927
+ */
928
+ public async getPriceUpdatesForFacade(
929
+ creditManager: Address,
930
+ creditAccount: CreditAccountDataSlice | undefined,
931
+ desiredQuotas: Array<Asset> | undefined,
932
+ ): Promise<Array<MultiCall>> {
933
+ const cm = this.sdk.marketRegister.findCreditManager(creditManager);
934
+ const updates = await this.getOnDemandPriceUpdates(
935
+ creditManager,
936
+ creditAccount,
937
+ desiredQuotas,
938
+ );
939
+ return cm.creditFacade.encodeOnDemandPriceUpdates(updates);
940
+ }
941
+
942
+ #prepareDisableQuotas(ca: CreditAccountDataSlice): Array<MultiCall> {
943
+ const calls: Array<MultiCall> = [];
944
+ for (const { token, quota } of ca.tokens) {
945
+ if (quota > 0n) {
946
+ calls.push({
947
+ target: ca.creditFacade,
948
+ callData: encodeFunctionData({
949
+ abi: iCreditFacadeV300MulticallAbi,
950
+ functionName: "updateQuota",
951
+ args: [token, MIN_INT96, 0n],
952
+ }),
953
+ });
954
+ }
955
+ }
956
+ return calls;
957
+ }
958
+
959
+ #prepareUpdateQuotas(
960
+ creditFacade: Address,
961
+ { averageQuota, minQuota }: PrepareUpdateQuotasProps,
962
+ ): Array<MultiCall> {
963
+ const minRecord = assetsMap(minQuota);
964
+
965
+ const calls: Array<MultiCall> = averageQuota.map(q => {
966
+ const minAsset = minRecord.get(q.token);
967
+ const min = minAsset && minAsset?.balance > 0 ? minAsset.balance : 0n;
968
+
969
+ return {
970
+ target: creditFacade,
971
+ callData: encodeFunctionData({
972
+ abi: iCreditFacadeV300MulticallAbi,
973
+ functionName: "updateQuota",
974
+ args: [q.token, q.balance, min],
975
+ }),
976
+ };
977
+ });
978
+
979
+ return calls;
980
+ }
981
+
982
+ #prepareDecreaseDebt(ca: CreditAccountDataSlice): Array<MultiCall> {
983
+ if (ca.debt > 0n) {
984
+ return [
985
+ {
986
+ target: ca.creditFacade,
987
+ callData: encodeFunctionData({
988
+ abi: iCreditFacadeV300MulticallAbi,
989
+ functionName: "decreaseDebt",
990
+ args: [MAX_UINT256],
991
+ }),
992
+ },
993
+ ];
994
+ }
995
+ return [];
996
+ }
997
+
998
+ #prepareDisableTokens(ca: CreditAccountDataSlice): Array<MultiCall> {
999
+ const calls: Array<MultiCall> = [];
1000
+ for (const t of ca.tokens) {
1001
+ if (
1002
+ t.token !== ca.underlying &&
1003
+ (t.mask & ca.enabledTokensMask) !== 0n &&
1004
+ t.quota === 0n
1005
+ ) {
1006
+ calls.push(this.#prepareDisableToken(ca.creditFacade, t.token));
1007
+ }
1008
+ }
1009
+ return calls;
1010
+ }
1011
+ #prepareDisableToken(creditFacade: Address, token: Address): MultiCall {
1012
+ return {
1013
+ target: creditFacade,
1014
+ callData: encodeFunctionData({
1015
+ abi: iCreditFacadeV300MulticallAbi,
1016
+ functionName: "disableToken",
1017
+ args: [token],
1018
+ }),
1019
+ };
1020
+ }
1021
+
1022
+ #prepareEnableTokens(
1023
+ creditFacade: Address,
1024
+ tokens: Array<Address>,
1025
+ ): Array<MultiCall> {
1026
+ return tokens.map(t => ({
1027
+ target: creditFacade,
1028
+ callData: encodeFunctionData({
1029
+ abi: iCreditFacadeV300MulticallAbi,
1030
+ functionName: "enableToken",
1031
+ args: [t],
1032
+ }),
1033
+ }));
1034
+ }
1035
+
1036
+ #prepareWithdrawToken(
1037
+ creditFacade: Address,
1038
+ token: Address,
1039
+ amount: bigint,
1040
+ to: Address,
1041
+ ): MultiCall {
1042
+ return {
1043
+ target: creditFacade,
1044
+ callData: encodeFunctionData({
1045
+ abi: iCreditFacadeV300MulticallAbi,
1046
+ functionName: "withdrawCollateral",
1047
+ args: [token, amount, to],
1048
+ }),
1049
+ };
1050
+ }
1051
+
1052
+ #prepareIncreaseDebt(creditFacade: Address, debt: bigint): MultiCall {
1053
+ return {
1054
+ target: creditFacade,
1055
+ callData: encodeFunctionData({
1056
+ abi: iCreditFacadeV300MulticallAbi,
1057
+ functionName: "increaseDebt",
1058
+ args: [debt],
1059
+ }),
1060
+ };
1061
+ }
1062
+ #prepareChangeDebt(
1063
+ creditFacade: Address,
1064
+ change: bigint,
1065
+ isDecrease: boolean,
1066
+ ): MultiCall {
1067
+ return {
1068
+ target: creditFacade,
1069
+ callData: encodeFunctionData({
1070
+ abi: iCreditFacadeV300MulticallAbi,
1071
+ functionName: isDecrease ? "decreaseDebt" : "increaseDebt",
1072
+ args: [change],
1073
+ }),
1074
+ };
1075
+ }
1076
+
1077
+ #prepareAddCollateral(
1078
+ creditFacade: Address,
1079
+ assets: Array<Asset>,
1080
+ permits: Record<string, PermitResult>,
1081
+ ): Array<MultiCall> {
1082
+ const calls = assets.map(({ token, balance }) => {
1083
+ const p = permits[token];
1084
+
1085
+ if (p) {
1086
+ return {
1087
+ target: creditFacade,
1088
+ callData: encodeFunctionData({
1089
+ abi: iCreditFacadeV300MulticallAbi,
1090
+ functionName: "addCollateralWithPermit",
1091
+ args: [token, balance, p.deadline, p.v, p.r, p.s],
1092
+ }),
1093
+ };
1094
+ }
1095
+
1096
+ return {
1097
+ target: creditFacade,
1098
+ callData: encodeFunctionData({
1099
+ abi: iCreditFacadeV300MulticallAbi,
1100
+ functionName: "addCollateral",
1101
+ args: [token, balance],
1102
+ }),
1103
+ };
1104
+ });
1105
+
1106
+ return calls;
1107
+ }
1108
+
1109
+ /**
1110
+ * Returns addresses of market configurators
1111
+ */
1112
+ private get marketConfigurators(): Array<Address> {
1113
+ return this.sdk.marketRegister.marketConfigurators.map(mc => mc.address);
1114
+ }
1115
+
1116
+ private get rewardCompressor(): Address {
1117
+ return this.sdk.addressProvider.getLatestVersion(AP_REWARDS_COMPRESSOR);
1118
+ }
1119
+
1120
+ private get peripheryCompressor(): Address {
1121
+ return this.sdk.addressProvider.getLatestVersion(AP_PERIPHERY_COMPRESSOR);
1122
+ }
1123
+ }