@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,611 @@
1
+ import type { Address, Hash, PrivateKeyAccount } from "viem";
2
+ import { isAddress, parseEther, parseEventLogs } from "viem";
3
+ import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
4
+
5
+ import { ierc20Abi } from "../abi/iERC20";
6
+ import { iCreditFacadeV300Abi, iPoolV300Abi } from "../abi/v300";
7
+ import type {
8
+ Asset,
9
+ CreditAccountData,
10
+ CreditAccountsService,
11
+ CreditSuite,
12
+ ILogger,
13
+ PoolContract,
14
+ RawTx,
15
+ } from "../sdk";
16
+ import {
17
+ ADDRESS_0X0,
18
+ AddressMap,
19
+ childLogger,
20
+ formatBN,
21
+ MAX_UINT256,
22
+ PERCENTAGE_FACTOR,
23
+ SDKConstruct,
24
+ sendRawTx,
25
+ } from "../sdk";
26
+ import { iDegenNftv2Abi } from "./abi";
27
+ import { type AnvilClient, createAnvilClient } from "./createAnvilClient";
28
+
29
+ const DEFAULT_LEVERAGE = 4;
30
+
31
+ export interface AccountOpenerOptions {
32
+ faucet?: Address;
33
+ borrower?: PrivateKeyAccount;
34
+ poolDepositMultiplier?: bigint;
35
+ }
36
+
37
+ export interface TargetAccount {
38
+ creditManager: Address;
39
+ collateral: Address;
40
+ leverage?: number;
41
+ slippage?: number;
42
+ }
43
+
44
+ export interface OpenAccountResult {
45
+ input: TargetAccount;
46
+ error?: string;
47
+ txHash?: string;
48
+ rawTx?: RawTx;
49
+ account?: CreditAccountData;
50
+ }
51
+
52
+ export class AccountOpener extends SDKConstruct {
53
+ #service: CreditAccountsService;
54
+ #anvil: AnvilClient;
55
+ #logger?: ILogger;
56
+ #borrower?: PrivateKeyAccount;
57
+ #faucet: Address;
58
+ #poolDepositMultiplier: bigint;
59
+
60
+ constructor(
61
+ service: CreditAccountsService,
62
+ options: AccountOpenerOptions = {},
63
+ ) {
64
+ super(service.sdk);
65
+ this.#service = service;
66
+ this.#logger = childLogger("AccountOpener", service.sdk.logger);
67
+ this.#anvil = createAnvilClient({
68
+ chain: service.sdk.provider.chain,
69
+ transport: service.sdk.provider.transport,
70
+ });
71
+ this.#faucet =
72
+ options.faucet ?? service.sdk.addressProvider.getAddress("FAUCET");
73
+ this.#borrower = options.borrower;
74
+ this.#poolDepositMultiplier = options.poolDepositMultiplier ?? 110_00n;
75
+ }
76
+
77
+ public get borrower(): Address {
78
+ if (!this.#borrower) {
79
+ throw new Error("borrower can be used only after openCreditAccounts");
80
+ }
81
+ return this.#borrower.address;
82
+ }
83
+
84
+ /**
85
+ * Tries to open account with underlying only in each CM
86
+ */
87
+ public async openCreditAccounts(
88
+ targets: TargetAccount[],
89
+ depositIntoPools = true,
90
+ ): Promise<OpenAccountResult[]> {
91
+ if (depositIntoPools) {
92
+ try {
93
+ await this.#depositIntoPools(targets);
94
+ } catch (e) {
95
+ this.#logger?.warn(`failed to deposit into pools: ${e}`);
96
+ }
97
+ }
98
+
99
+ await this.#prepareBorrower(targets);
100
+
101
+ const toApprove = new AddressMap<Set<Address>>();
102
+ for (const c of targets) {
103
+ const cm = this.sdk.marketRegister.findCreditManager(c.creditManager);
104
+ const toApproveOnCM = toApprove.get(c.creditManager) ?? new Set();
105
+ toApproveOnCM.add(cm.underlying);
106
+ toApprove.upsert(c.creditManager, toApproveOnCM);
107
+ }
108
+ for (const [cmAddr, tokens] of toApprove.entries()) {
109
+ const cm = this.sdk.marketRegister.findCreditManager(cmAddr);
110
+ for (const token of tokens) {
111
+ await this.#approve(token, cm);
112
+ }
113
+ }
114
+
115
+ const results: OpenAccountResult[] = [];
116
+ let success = 0;
117
+ for (let i = 0; i < targets.length; i++) {
118
+ const target = targets[i];
119
+ try {
120
+ const result = await this.#openAccount(target, i + 1, targets.length);
121
+ results.push(result);
122
+ success += result.account ? 1 : 0;
123
+ } catch (e) {
124
+ results.push({
125
+ input: target,
126
+ error: `${e}`,
127
+ });
128
+ }
129
+ }
130
+ this.#logger?.info(`opened ${success}/${targets.length} accounts`);
131
+ return results;
132
+ }
133
+
134
+ async #openAccount(
135
+ input: TargetAccount,
136
+ index: number,
137
+ total: number,
138
+ ): Promise<OpenAccountResult> {
139
+ const {
140
+ creditManager,
141
+ collateral,
142
+ leverage = DEFAULT_LEVERAGE,
143
+ slippage = 50,
144
+ } = input;
145
+ const borrower = await this.#getBorrower();
146
+ const cm = this.sdk.marketRegister.findCreditManager(creditManager);
147
+ const symbol = this.sdk.tokensMeta.symbol(collateral);
148
+ const logger = this.#logger?.child?.({
149
+ creditManager: cm.name,
150
+ collateral: symbol,
151
+ });
152
+ logger?.debug(`opening account #${index}/${total}`);
153
+ const { minDebt, underlying } = cm.creditFacade;
154
+
155
+ const expectedBalances: Asset[] = [];
156
+ const leftoverBalances: Asset[] = [];
157
+ for (const t of cm.creditManager.collateralTokens) {
158
+ const token = t as Address;
159
+ expectedBalances.push({
160
+ token,
161
+ balance: token === underlying ? BigInt(leverage) * minDebt : 1n,
162
+ });
163
+ leftoverBalances.push({
164
+ token,
165
+ balance: 1n,
166
+ });
167
+ }
168
+ logger?.debug("looking for open strategy");
169
+ const strategy = await this.sdk.router.findOpenStrategyPath({
170
+ creditManager: cm.creditManager,
171
+ expectedBalances,
172
+ leftoverBalances,
173
+ slippage,
174
+ target: collateral,
175
+ });
176
+ logger?.debug(strategy, "found open strategy");
177
+ const debt = minDebt * BigInt(leverage - 1);
178
+ const averageQuota = this.#getCollateralQuota(
179
+ cm,
180
+ collateral,
181
+ strategy.amount,
182
+ debt,
183
+ );
184
+ const minQuota = this.#getCollateralQuota(
185
+ cm,
186
+ collateral,
187
+ strategy.minAmount,
188
+ debt,
189
+ );
190
+ logger?.debug({ averageQuota, minQuota }, "calculated quotas");
191
+ const { tx, calls } = await this.#service.openCA({
192
+ creditManager: cm.creditManager.address,
193
+ averageQuota,
194
+ minQuota,
195
+ collateral: [{ token: underlying, balance: minDebt }],
196
+ debt,
197
+ calls: strategy.calls,
198
+ ethAmount: 0n,
199
+ permits: {},
200
+ to: borrower.address,
201
+ referralCode: 0n,
202
+ });
203
+ for (let i = 0; i < calls.length; i++) {
204
+ const call = calls[i];
205
+ logger?.debug(
206
+ `call #${i + 1}: ${this.sdk.parseFunctionData(call.target, call.callData)}`,
207
+ );
208
+ }
209
+ logger?.debug("prepared open account transaction");
210
+ let hash: Hash;
211
+ try {
212
+ hash = await sendRawTx(this.#anvil, {
213
+ tx,
214
+ account: borrower,
215
+ });
216
+ logger?.debug(`send transaction ${hash}`);
217
+ } catch (e) {
218
+ return {
219
+ input,
220
+ error: `${e}`,
221
+ rawTx: tx,
222
+ };
223
+ }
224
+ const receipt = await this.#anvil.waitForTransactionReceipt({ hash });
225
+ if (receipt.status === "reverted") {
226
+ return {
227
+ input,
228
+ error: `open credit account tx reverted`,
229
+ txHash: hash,
230
+ rawTx: tx,
231
+ };
232
+ }
233
+ logger?.info(`opened credit account ${index}/${total}`);
234
+ const logs = parseEventLogs({
235
+ abi: iCreditFacadeV300Abi,
236
+ logs: receipt.logs,
237
+ eventName: "OpenCreditAccount",
238
+ });
239
+ logger?.info(`found ${logs.length} logs`);
240
+ let account: CreditAccountData | undefined;
241
+ if (logs.length > 0) {
242
+ try {
243
+ logger?.debug(
244
+ `getting credit account data for ${logs[0].args.creditAccount}`,
245
+ );
246
+ account = await this.#service.getCreditAccountData(
247
+ logs[0].args.creditAccount,
248
+ );
249
+ } catch (e) {
250
+ logger?.error(`failed to get credit account data: ${e}`);
251
+ }
252
+ }
253
+ return {
254
+ input,
255
+ txHash: hash,
256
+ rawTx: tx,
257
+ account,
258
+ };
259
+ }
260
+
261
+ public async getOpenedAccounts(): Promise<CreditAccountData[]> {
262
+ return await this.#service.getCreditAccounts({
263
+ owner: this.borrower,
264
+ });
265
+ }
266
+
267
+ async #depositIntoPools(targets: TargetAccount[]): Promise<void> {
268
+ this.#logger?.debug("checking and topping up pools if necessary");
269
+
270
+ const minAvailableByPool: Record<Address, bigint> = {};
271
+ for (const { leverage = DEFAULT_LEVERAGE, creditManager } of targets) {
272
+ const cm = this.sdk.marketRegister.findCreditManager(creditManager);
273
+ const { minDebt } = cm.creditFacade;
274
+ minAvailableByPool[cm.pool] =
275
+ (minAvailableByPool[cm.pool] ?? 0n) +
276
+ (minDebt * BigInt(leverage - 1) * this.#poolDepositMultiplier) /
277
+ PERCENTAGE_FACTOR;
278
+ }
279
+
280
+ let totalUSD = 0n;
281
+ let deposits: [PoolContract, bigint][] = [];
282
+ for (const [p, minAvailable] of Object.entries(minAvailableByPool)) {
283
+ const market = this.sdk.marketRegister.findByPool(p as Address);
284
+ const pool = market.pool.pool;
285
+ let diff = minAvailable - pool.availableLiquidity;
286
+ diff = diff < 0n ? 0n : diff;
287
+ const [minS, availableS, diffS] = [
288
+ minAvailable,
289
+ pool.availableLiquidity,
290
+ diff,
291
+ ].map(v => this.sdk.tokensMeta.formatBN(pool.underlying, v));
292
+ this.#logger?.debug(
293
+ `Pool ${this.labelAddress(pool.address)} has ${availableS} liquidity, needs ${diffS} more for the minimum of ${minS} ${this.sdk.tokensMeta.symbol(pool.underlying)}`,
294
+ );
295
+ if (diff > 0n) {
296
+ deposits.push([pool, diff]);
297
+ totalUSD += market.priceOracle.convertToUSD(pool.underlying, diff);
298
+ }
299
+ }
300
+ totalUSD = (totalUSD * 105n) / 100n; // 5% more to be safe
301
+ this.#logger?.debug(
302
+ `total USD to claim from faucet: ${formatBN(totalUSD, 8)}`,
303
+ );
304
+
305
+ const depositor = await this.#createAccount();
306
+ this.#logger?.debug(`created depositor ${depositor.address}`);
307
+
308
+ await this.#claimFromFaucet(depositor, totalUSD);
309
+
310
+ for (const [pool, amount] of deposits) {
311
+ try {
312
+ await this.#depositToPool(pool, depositor, amount);
313
+ } catch (e) {
314
+ this.#logger?.warn(`failed to deposit into ${pool.name}: ${e}`);
315
+ }
316
+ }
317
+ }
318
+
319
+ async #depositToPool(
320
+ pool: PoolContract,
321
+ depositor: PrivateKeyAccount,
322
+ amount: bigint,
323
+ ): Promise<void> {
324
+ const { underlying, address } = pool;
325
+ const poolName = this.sdk.provider.addressLabels.get(address);
326
+ const amnt =
327
+ this.sdk.tokensMeta.formatBN(pool.underlying, amount) +
328
+ " " +
329
+ this.sdk.tokensMeta.symbol(pool.underlying);
330
+ this.#logger?.debug(`depositing ${amnt} into pool ${poolName}`);
331
+
332
+ const allowance = await this.#anvil.readContract({
333
+ address: underlying,
334
+ abi: ierc20Abi,
335
+ functionName: "balanceOf",
336
+ args: [depositor.address],
337
+ });
338
+ this.#logger?.debug(
339
+ `depositor balance in underlying: ${this.sdk.tokensMeta.formatBN(pool.underlying, allowance)}`,
340
+ );
341
+ let hash = await this.#anvil.writeContract({
342
+ account: depositor,
343
+ address: underlying,
344
+ abi: ierc20Abi,
345
+ functionName: "approve",
346
+ args: [address, allowance],
347
+ chain: this.#anvil.chain,
348
+ });
349
+ let receipt = await this.#anvil.waitForTransactionReceipt({ hash });
350
+ if (receipt.status === "reverted") {
351
+ throw new Error(
352
+ `tx ${hash} that approves underlying from depositor for pool ${poolName} reverted`,
353
+ );
354
+ }
355
+ this.#logger?.debug(
356
+ `depositor approved underlying for pool ${poolName}: ${hash}`,
357
+ );
358
+ hash = await this.#anvil.writeContract({
359
+ account: depositor,
360
+ address: address,
361
+ abi: iPoolV300Abi,
362
+ functionName: "deposit",
363
+ args: [amount, depositor.address],
364
+ chain: this.#anvil.chain,
365
+ });
366
+ receipt = await this.#anvil.waitForTransactionReceipt({ hash });
367
+ if (receipt.status === "reverted") {
368
+ throw new Error(`tx ${hash} that deposits to pool ${poolName} reverted`);
369
+ }
370
+ this.#logger?.debug(`deposited ${amnt} into ${poolName}`);
371
+ }
372
+
373
+ /**
374
+ * Creates borrower wallet,
375
+ * Sets ETH balance,
376
+ * Gets tokens from faucet,
377
+ * Approves collateral tokens to credit manager,
378
+ * Gets DEGEN_NFT,
379
+ */
380
+ async #prepareBorrower(targets: TargetAccount[]): Promise<PrivateKeyAccount> {
381
+ const borrower = await this.#getBorrower();
382
+
383
+ // each account will have minDebt in USD, see how much we need to claim from faucet
384
+ let claimUSD = 0n;
385
+ // collect all degen nfts
386
+ let degenNFTS: Record<Address, number> = {};
387
+ for (const target of targets) {
388
+ const cm = this.sdk.marketRegister.findCreditManager(
389
+ target.creditManager,
390
+ );
391
+ const market = this.sdk.marketRegister.findByCreditManager(
392
+ target.creditManager,
393
+ );
394
+ const { minDebt, degenNFT } = cm.creditFacade;
395
+
396
+ claimUSD += market.priceOracle.convertToUSD(cm.underlying, minDebt);
397
+
398
+ if (isAddress(degenNFT) && degenNFT !== ADDRESS_0X0) {
399
+ degenNFTS[degenNFT] = (degenNFTS[degenNFT] ?? 0) + 1;
400
+ }
401
+ }
402
+ claimUSD = (claimUSD * 11n) / 10n; // 10% more to be safe
403
+
404
+ await this.#claimFromFaucet(borrower, claimUSD);
405
+
406
+ for (const [degenNFT, amount] of Object.entries(degenNFTS)) {
407
+ await this.#mintDegenNft(degenNFT as Address, borrower.address, amount);
408
+ }
409
+ this.#logger?.debug("prepared borrower");
410
+ return borrower;
411
+ }
412
+
413
+ async #claimFromFaucet(
414
+ claimer: PrivateKeyAccount,
415
+ amountUSD: bigint,
416
+ ): Promise<void> {
417
+ const [usr, amnt] = [claimer.address, formatBN(amountUSD, 8)];
418
+
419
+ this.#logger?.debug(`account ${usr} claiming ${amnt} USD from faucet`);
420
+ const hash = await this.#anvil.writeContract({
421
+ account: claimer,
422
+ address: this.#faucet,
423
+ abi: [
424
+ {
425
+ type: "function",
426
+ inputs: [
427
+ { name: "amountUSD", internalType: "uint256", type: "uint256" },
428
+ ],
429
+ name: "claim",
430
+ outputs: [],
431
+ stateMutability: "nonpayable",
432
+ },
433
+ ],
434
+ functionName: "claim",
435
+ args: [amountUSD],
436
+ chain: this.#anvil.chain,
437
+ });
438
+ const receipt = await this.#anvil.waitForTransactionReceipt({
439
+ hash,
440
+ });
441
+ if (receipt.status === "reverted") {
442
+ throw new Error(
443
+ `account ${usr} failed to claimed equivalent of ${amnt} USD from faucet, tx: ${hash}`,
444
+ );
445
+ }
446
+ this.#logger?.debug(
447
+ `account ${usr} claimed equivalent of ${amnt} USD from faucet, tx: ${hash}`,
448
+ );
449
+ }
450
+
451
+ async #approve(token: Address, cm: CreditSuite): Promise<void> {
452
+ const borrower = await this.#getBorrower();
453
+ const symbol = this.#service.sdk.tokensMeta.symbol(token);
454
+ try {
455
+ if (symbol === "USDT") {
456
+ const hash = await this.#anvil.writeContract({
457
+ account: borrower,
458
+ address: token,
459
+ abi: ierc20Abi,
460
+ functionName: "approve",
461
+ args: [cm.creditManager.address, 0n],
462
+ chain: this.#anvil.chain,
463
+ });
464
+ await this.#anvil.waitForTransactionReceipt({
465
+ hash,
466
+ });
467
+ }
468
+
469
+ const hash = await this.#anvil.writeContract({
470
+ account: borrower,
471
+ address: token,
472
+ abi: ierc20Abi,
473
+ functionName: "approve",
474
+ args: [cm.creditManager.address, MAX_UINT256],
475
+ chain: this.#anvil.chain,
476
+ });
477
+ const receipt = await this.#anvil.waitForTransactionReceipt({
478
+ hash,
479
+ });
480
+
481
+ if (receipt.status === "reverted") {
482
+ this.#logger?.error(
483
+ `failed to allowed credit manager ${cm.creditManager.name} to spend ${symbol} (${token}), tx reverted: ${hash}`,
484
+ );
485
+ } else {
486
+ this.#logger?.debug(
487
+ `allowed credit manager ${cm.creditManager.name} to spend ${symbol} (${token}), tx: ${hash}`,
488
+ );
489
+ }
490
+ } catch (e) {
491
+ this.#logger?.error(
492
+ `failed to allowed credit manager ${cm.creditManager.name} to spend ${symbol} (${token}): ${e}`,
493
+ );
494
+ }
495
+ }
496
+
497
+ async #mintDegenNft(
498
+ degenNFT: Address,
499
+ to: Address,
500
+ amount: number,
501
+ ): Promise<void> {
502
+ if (amount <= 0) {
503
+ return;
504
+ }
505
+ let minter: Address | undefined;
506
+ try {
507
+ minter = await this.#anvil.readContract({
508
+ address: degenNFT,
509
+ abi: iDegenNftv2Abi,
510
+ functionName: "minter",
511
+ });
512
+ } catch (e) {
513
+ this.#logger?.error(`failed to get minter of degenNFT ${degenNFT}: ${e}`);
514
+ return;
515
+ }
516
+
517
+ try {
518
+ await this.#anvil.impersonateAccount({ address: minter });
519
+ await this.#anvil.setBalance({
520
+ address: minter,
521
+ value: parseEther("100"),
522
+ });
523
+ const hash = await this.#anvil.writeContract({
524
+ account: minter,
525
+ address: degenNFT,
526
+ abi: iDegenNftv2Abi,
527
+ functionName: "mint",
528
+ args: [to, BigInt(amount)],
529
+ chain: this.#anvil.chain,
530
+ });
531
+ const receipt = await this.#anvil.waitForTransactionReceipt({
532
+ hash,
533
+ });
534
+ if (receipt.status === "reverted") {
535
+ this.#logger?.error(
536
+ `failed to mint ${amount} degenNFT ${degenNFT} to borrower ${to}, tx reverted: ${hash}`,
537
+ );
538
+ }
539
+ this.#logger?.debug(
540
+ `minted ${amount} degenNFT ${degenNFT} to borrower ${to}, tx: ${hash}`,
541
+ );
542
+ } catch (e) {
543
+ this.#logger?.error(
544
+ `failed to mint ${amount} degenNFT ${degenNFT} to borrower ${to}: ${e}`,
545
+ );
546
+ } finally {
547
+ await this.#anvil.stopImpersonatingAccount({ address: minter });
548
+ }
549
+ }
550
+
551
+ async #getBorrower(): Promise<PrivateKeyAccount> {
552
+ if (!this.#borrower) {
553
+ this.#borrower = await this.#createAccount();
554
+ this.#logger?.info(`created borrower ${this.#borrower.address}`);
555
+ }
556
+ return this.#borrower;
557
+ }
558
+
559
+ async #createAccount(): Promise<PrivateKeyAccount> {
560
+ const acc = privateKeyToAccount(generatePrivateKey());
561
+ await this.#anvil.setBalance({
562
+ address: acc.address,
563
+ value: parseEther("100"),
564
+ });
565
+ return acc;
566
+ }
567
+
568
+ #getCollateralQuota(
569
+ cm: CreditSuite,
570
+ collateral: Address,
571
+ amount: bigint,
572
+ debt: bigint,
573
+ ): Asset[] {
574
+ const {
575
+ underlying,
576
+ creditManager: { liquidationThresholds },
577
+ } = cm;
578
+ const inUnderlying = collateral.toLowerCase() === underlying.toLowerCase();
579
+ if (inUnderlying) {
580
+ return [];
581
+ }
582
+ const collateralLT = BigInt(liquidationThresholds.mustGet(collateral));
583
+ const market = this.sdk.marketRegister.findByCreditManager(
584
+ cm.creditManager.address,
585
+ );
586
+ const quotaInfo = market.pool.pqk.quotas.mustGet(collateral);
587
+ const availableQuota = quotaInfo.limit - quotaInfo.totalQuoted;
588
+ if (availableQuota <= 0n) {
589
+ throw new Error(
590
+ `quota exceeded for asset ${this.labelAddress(collateral)} in ${cm.name}`,
591
+ );
592
+ }
593
+ const desiredQuota = this.#calcQuota(amount, debt, collateralLT);
594
+
595
+ return [
596
+ {
597
+ token: collateral,
598
+ balance: desiredQuota < availableQuota ? desiredQuota : availableQuota,
599
+ },
600
+ ];
601
+ }
602
+
603
+ #calcQuota(amount: bigint, debt: bigint, lt: bigint): bigint {
604
+ let quota = (amount * lt) / PERCENTAGE_FACTOR;
605
+ quota = debt < quota ? debt : quota;
606
+
607
+ quota = (quota * (PERCENTAGE_FACTOR + 500n)) / PERCENTAGE_FACTOR;
608
+
609
+ return (quota / PERCENTAGE_FACTOR) * PERCENTAGE_FACTOR;
610
+ }
611
+ }
@@ -0,0 +1,95 @@
1
+ import type {
2
+ AbiParametersToPrimitiveTypes,
3
+ ExtractAbiFunction,
4
+ } from "abitype";
5
+ import type { Address } from "viem";
6
+
7
+ import { iPriceFeedCompressorAbi } from "../abi/compressors";
8
+ import { iPriceFeedStoreAbi } from "../abi/iPriceFeedStore";
9
+ import type { GearboxSDK, ILogger, PriceFeedTreeNode, Unarray } from "../sdk";
10
+ import {
11
+ AddressMap,
12
+ AP_PRICE_FEED_COMPRESSOR,
13
+ rawTxToMulticallPriceUpdate,
14
+ SDKConstruct,
15
+ } from "../sdk";
16
+
17
+ export type ConnectedPriceFeed = Unarray<
18
+ AbiParametersToPrimitiveTypes<
19
+ ExtractAbiFunction<
20
+ typeof iPriceFeedStoreAbi,
21
+ "getTokenPriceFeedsMap"
22
+ >["outputs"]
23
+ >[0]
24
+ >;
25
+
26
+ export class PriceFeedStore extends SDKConstruct {
27
+ readonly #store: Address;
28
+ readonly #compressor: Address;
29
+ readonly #logger?: ILogger;
30
+
31
+ constructor(sdk: GearboxSDK) {
32
+ super(sdk);
33
+ this.#store = this.sdk.addressProvider.getAddress("PRICE_FEED_STORE");
34
+ this.#compressor = this.sdk.addressProvider.getLatestVersion(
35
+ AP_PRICE_FEED_COMPRESSOR,
36
+ );
37
+ this.#logger = sdk.logger?.child?.({
38
+ module: "PriceFeedStore",
39
+ });
40
+ }
41
+
42
+ public async load(update = true): Promise<AddressMap<PriceFeedTreeNode[]>> {
43
+ const pfMap = await this.provider.publicClient.readContract({
44
+ address: this.#store,
45
+ abi: iPriceFeedStoreAbi,
46
+ functionName: "getTokenPriceFeedsMap",
47
+ });
48
+ const addresses = pfMap.flatMap(f => f.priceFeeds);
49
+ const nodes = await this.#loadFromCompressor(addresses, update);
50
+ const result = new AddressMap<PriceFeedTreeNode[]>();
51
+ for (const { token, priceFeeds } of pfMap) {
52
+ result.upsert(
53
+ token,
54
+ priceFeeds
55
+ .map(pf => nodes.find(n => n.baseParams.addr === pf)!)
56
+ .filter(Boolean),
57
+ );
58
+ }
59
+ return result;
60
+ }
61
+
62
+ async #loadFromCompressor(
63
+ priceFeeds: Address[],
64
+ update = true,
65
+ ): Promise<PriceFeedTreeNode[]> {
66
+ let result = await this.provider.publicClient.readContract({
67
+ address: this.#compressor,
68
+ abi: iPriceFeedCompressorAbi,
69
+ functionName: "loadPriceFeedTree",
70
+ args: [priceFeeds],
71
+ });
72
+ if (update) {
73
+ const feeds = result.map(f => this.sdk.priceFeeds.create(f));
74
+ const { txs } =
75
+ await this.sdk.priceFeeds.generatePriceFeedsUpdateTxs(feeds);
76
+ const resp = await this.provider.publicClient.multicall({
77
+ contracts: [
78
+ ...txs.map(rawTxToMulticallPriceUpdate),
79
+ {
80
+ address: this.#compressor,
81
+ abi: iPriceFeedCompressorAbi,
82
+ functionName: "loadPriceFeedTree",
83
+ args: [priceFeeds],
84
+ },
85
+ ],
86
+ allowFailure: false,
87
+ });
88
+ result = resp.pop() as PriceFeedTreeNode[];
89
+ }
90
+ this.#logger?.debug(
91
+ `loaded ${result.length} price feed nodes from compressor`,
92
+ );
93
+ return [...result];
94
+ }
95
+ }