@gearbox-protocol/sdk 8.9.0 → 8.10.1

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.
@@ -44,6 +44,7 @@ class AccountOpener extends import_sdk.SDKConstruct {
44
44
  #borrower;
45
45
  #faucet;
46
46
  #poolDepositMultiplier;
47
+ #minDebtMultiplier;
47
48
  constructor(service, options = {}) {
48
49
  super(service.sdk);
49
50
  this.#service = service;
@@ -59,6 +60,7 @@ class AccountOpener extends import_sdk.SDKConstruct {
59
60
  }
60
61
  this.#borrower = options.borrower;
61
62
  this.#poolDepositMultiplier = options.poolDepositMultiplier ?? 11000n;
63
+ this.#minDebtMultiplier = options.minDebtMultiplier ?? 10100n;
62
64
  }
63
65
  get borrower() {
64
66
  if (!this.#borrower) {
@@ -117,6 +119,12 @@ class AccountOpener extends import_sdk.SDKConstruct {
117
119
  }
118
120
  }
119
121
  this.#logger?.info(`opened ${success}/${targets.length} accounts`);
122
+ try {
123
+ await this.#directlyDistributeTokens(results);
124
+ this.#logger?.info("distributed direct transfer tokens");
125
+ } catch (e) {
126
+ this.#logger?.error(`failed to distribute tokens: ${e}`);
127
+ }
120
128
  return results;
121
129
  }
122
130
  async #openAccount(input, index, total) {
@@ -190,7 +198,8 @@ class AccountOpener extends import_sdk.SDKConstruct {
190
198
  target: symbol
191
199
  });
192
200
  const leverage = this.#getLeverage(input);
193
- const { minDebt, underlying } = cm.creditFacade;
201
+ const { underlying } = cm.creditFacade;
202
+ const minDebt = this.#minDebtMultiplier * cm.creditFacade.minDebt / import_sdk.PERCENTAGE_FACTOR;
194
203
  const expectedUnderlyingBalance = minDebt * leverage / import_sdk.PERCENTAGE_FACTOR;
195
204
  const expectedBalances = [];
196
205
  const leftoverBalances = [];
@@ -272,7 +281,7 @@ class AccountOpener extends import_sdk.SDKConstruct {
272
281
  for (const t of targets) {
273
282
  const leverage = this.#getLeverage(t);
274
283
  const cm = this.sdk.marketRegister.findCreditManager(t.creditManager);
275
- const { minDebt } = cm.creditFacade;
284
+ const minDebt = this.#minDebtMultiplier * cm.creditFacade.minDebt / import_sdk.PERCENTAGE_FACTOR;
276
285
  minAvailableByPool[cm.pool] = (minAvailableByPool[cm.pool] ?? 0n) + minDebt * (leverage - import_sdk.PERCENTAGE_FACTOR) / import_sdk.PERCENTAGE_FACTOR * this.#poolDepositMultiplier / import_sdk.PERCENTAGE_FACTOR;
277
286
  }
278
287
  let totalUSD = 0n;
@@ -372,7 +381,8 @@ class AccountOpener extends import_sdk.SDKConstruct {
372
381
  const market = this.sdk.marketRegister.findByCreditManager(
373
382
  target.creditManager
374
383
  );
375
- const { minDebt, degenNFT } = cm.creditFacade;
384
+ const { degenNFT } = cm.creditFacade;
385
+ const minDebt = this.#minDebtMultiplier * cm.creditFacade.minDebt / import_sdk.PERCENTAGE_FACTOR;
376
386
  claimUSD += market.priceOracle.convertToUSD(cm.underlying, minDebt);
377
387
  if ((0, import_viem.isAddress)(degenNFT) && degenNFT !== import_sdk.ADDRESS_0X0) {
378
388
  degenNFTS[degenNFT] = (degenNFTS[degenNFT] ?? 0) + 1;
@@ -503,6 +513,87 @@ class AccountOpener extends import_sdk.SDKConstruct {
503
513
  });
504
514
  return acc;
505
515
  }
516
+ /**
517
+ * Claims tokens from faucet, uniformly distributes them to accounts
518
+ * @param targets
519
+ * @returns
520
+ */
521
+ async #directlyDistributeTokens(targets) {
522
+ const tokens = new import_sdk.AddressSet(
523
+ targets.flatMap((t) => t.input.directTransfer ?? [])
524
+ );
525
+ if (tokens.size === 0) {
526
+ return;
527
+ }
528
+ const distributorKey = (0, import_accounts.generatePrivateKey)();
529
+ const distributor = (0, import_accounts.privateKeyToAccount)(distributorKey);
530
+ await this.#anvil.setBalance({
531
+ address: distributor.address,
532
+ value: (0, import_viem.parseEther)("100")
533
+ });
534
+ await (0, import_claimFromFaucet.claimFromFaucet)({
535
+ publicClient: this.#anvil,
536
+ wallet: this.#anvil,
537
+ faucet: this.faucet,
538
+ amountUSD: (minAmountUSD) => minAmountUSD * BigInt(targets.length),
539
+ claimer: distributor,
540
+ role: "reward token distributor",
541
+ logger: this.#logger
542
+ });
543
+ const actualBalances = await this.#anvil.multicall({
544
+ contracts: tokens.map(
545
+ (token) => ({
546
+ address: token,
547
+ abi: import_viem.erc20Abi,
548
+ functionName: "balanceOf",
549
+ args: [distributor.address]
550
+ })
551
+ ),
552
+ allowFailure: false
553
+ });
554
+ const tokensArr = tokens.asArray();
555
+ for (let i = 0; i < tokensArr.length; i++) {
556
+ const token = tokensArr[i];
557
+ const balance = actualBalances[i];
558
+ this.#logger?.debug(`${token} balance: ${balance}`);
559
+ }
560
+ for (const { account, input } of targets) {
561
+ if (!account) {
562
+ continue;
563
+ }
564
+ const directTransfer = new import_sdk.AddressSet(input.directTransfer);
565
+ for (let i = 0; i < tokensArr.length; i++) {
566
+ const token = tokensArr[i];
567
+ if (!directTransfer.has(token)) {
568
+ continue;
569
+ }
570
+ const balance = actualBalances[i] / BigInt(targets.length);
571
+ this.#logger?.debug(
572
+ `sending ${balance} ${token} to ${account.creditAccount}`
573
+ );
574
+ const hash = await this.#anvil.writeContract({
575
+ account: distributor,
576
+ address: token,
577
+ abi: import_viem.erc20Abi,
578
+ functionName: "transfer",
579
+ args: [account.creditAccount, balance],
580
+ chain: this.#anvil.chain
581
+ });
582
+ const receipt = await this.#anvil.waitForTransactionReceipt({
583
+ hash
584
+ });
585
+ if (receipt.status === "reverted") {
586
+ this.#logger?.error(
587
+ `failed to send ${token} to ${account.creditAccount}, tx ${hash} reverted`
588
+ );
589
+ } else {
590
+ this.#logger?.debug(
591
+ `sent ${token} to ${account.creditAccount}, tx: ${hash}`
592
+ );
593
+ }
594
+ }
595
+ }
596
+ }
506
597
  #getCollateralQuota(cm, collateral, collateralAmount, debt, logger) {
507
598
  const {
508
599
  underlying,
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var AddressSet_exports = {};
20
+ __export(AddressSet_exports, {
21
+ AddressSet: () => AddressSet
22
+ });
23
+ module.exports = __toCommonJS(AddressSet_exports);
24
+ var import_viem = require("viem");
25
+ class AddressSet extends Set {
26
+ constructor(entries) {
27
+ super(Array.from(entries ?? []).map((a) => (0, import_viem.getAddress)(a)));
28
+ }
29
+ add(value) {
30
+ return super.add((0, import_viem.getAddress)(value));
31
+ }
32
+ delete(value) {
33
+ return super.delete((0, import_viem.getAddress)(value));
34
+ }
35
+ has(value) {
36
+ return super.has((0, import_viem.getAddress)(value));
37
+ }
38
+ asArray() {
39
+ return Array.from(this);
40
+ }
41
+ map(fn) {
42
+ return this.asArray().map(fn);
43
+ }
44
+ }
45
+ // Annotate the CommonJS export names for ESM import in node:
46
+ 0 && (module.exports = {
47
+ AddressSet
48
+ });
@@ -16,6 +16,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
16
16
  var utils_exports = {};
17
17
  module.exports = __toCommonJS(utils_exports);
18
18
  __reExport(utils_exports, require("./AddressMap.js"), module.exports);
19
+ __reExport(utils_exports, require("./AddressSet.js"), module.exports);
19
20
  __reExport(utils_exports, require("./bytes32ToString.js"), module.exports);
20
21
  __reExport(utils_exports, require("./childLogger.js"), module.exports);
21
22
  __reExport(utils_exports, require("./createRawTx.js"), module.exports);
@@ -32,6 +33,7 @@ __reExport(utils_exports, require("./zod.js"), module.exports);
32
33
  // Annotate the CommonJS export names for ESM import in node:
33
34
  0 && (module.exports = {
34
35
  ...require("./AddressMap.js"),
36
+ ...require("./AddressSet.js"),
35
37
  ...require("./bytes32ToString.js"),
36
38
  ...require("./childLogger.js"),
37
39
  ...require("./createRawTx.js"),
@@ -1,10 +1,17 @@
1
- import { BaseError, isAddress, parseEther, parseEventLogs } from "viem";
1
+ import {
2
+ BaseError,
3
+ erc20Abi,
4
+ isAddress,
5
+ parseEther,
6
+ parseEventLogs
7
+ } from "viem";
2
8
  import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
3
9
  import { ierc20Abi } from "../abi/iERC20.js";
4
10
  import { iCreditFacadeV300Abi, iPoolV300Abi } from "../abi/v300.js";
5
11
  import {
6
12
  ADDRESS_0X0,
7
13
  AddressMap,
14
+ AddressSet,
8
15
  childLogger,
9
16
  formatBN,
10
17
  MAX_UINT256,
@@ -29,6 +36,7 @@ class AccountOpener extends SDKConstruct {
29
36
  #borrower;
30
37
  #faucet;
31
38
  #poolDepositMultiplier;
39
+ #minDebtMultiplier;
32
40
  constructor(service, options = {}) {
33
41
  super(service.sdk);
34
42
  this.#service = service;
@@ -44,6 +52,7 @@ class AccountOpener extends SDKConstruct {
44
52
  }
45
53
  this.#borrower = options.borrower;
46
54
  this.#poolDepositMultiplier = options.poolDepositMultiplier ?? 11000n;
55
+ this.#minDebtMultiplier = options.minDebtMultiplier ?? 10100n;
47
56
  }
48
57
  get borrower() {
49
58
  if (!this.#borrower) {
@@ -102,6 +111,12 @@ class AccountOpener extends SDKConstruct {
102
111
  }
103
112
  }
104
113
  this.#logger?.info(`opened ${success}/${targets.length} accounts`);
114
+ try {
115
+ await this.#directlyDistributeTokens(results);
116
+ this.#logger?.info("distributed direct transfer tokens");
117
+ } catch (e) {
118
+ this.#logger?.error(`failed to distribute tokens: ${e}`);
119
+ }
105
120
  return results;
106
121
  }
107
122
  async #openAccount(input, index, total) {
@@ -175,7 +190,8 @@ class AccountOpener extends SDKConstruct {
175
190
  target: symbol
176
191
  });
177
192
  const leverage = this.#getLeverage(input);
178
- const { minDebt, underlying } = cm.creditFacade;
193
+ const { underlying } = cm.creditFacade;
194
+ const minDebt = this.#minDebtMultiplier * cm.creditFacade.minDebt / PERCENTAGE_FACTOR;
179
195
  const expectedUnderlyingBalance = minDebt * leverage / PERCENTAGE_FACTOR;
180
196
  const expectedBalances = [];
181
197
  const leftoverBalances = [];
@@ -257,7 +273,7 @@ class AccountOpener extends SDKConstruct {
257
273
  for (const t of targets) {
258
274
  const leverage = this.#getLeverage(t);
259
275
  const cm = this.sdk.marketRegister.findCreditManager(t.creditManager);
260
- const { minDebt } = cm.creditFacade;
276
+ const minDebt = this.#minDebtMultiplier * cm.creditFacade.minDebt / PERCENTAGE_FACTOR;
261
277
  minAvailableByPool[cm.pool] = (minAvailableByPool[cm.pool] ?? 0n) + minDebt * (leverage - PERCENTAGE_FACTOR) / PERCENTAGE_FACTOR * this.#poolDepositMultiplier / PERCENTAGE_FACTOR;
262
278
  }
263
279
  let totalUSD = 0n;
@@ -357,7 +373,8 @@ class AccountOpener extends SDKConstruct {
357
373
  const market = this.sdk.marketRegister.findByCreditManager(
358
374
  target.creditManager
359
375
  );
360
- const { minDebt, degenNFT } = cm.creditFacade;
376
+ const { degenNFT } = cm.creditFacade;
377
+ const minDebt = this.#minDebtMultiplier * cm.creditFacade.minDebt / PERCENTAGE_FACTOR;
361
378
  claimUSD += market.priceOracle.convertToUSD(cm.underlying, minDebt);
362
379
  if (isAddress(degenNFT) && degenNFT !== ADDRESS_0X0) {
363
380
  degenNFTS[degenNFT] = (degenNFTS[degenNFT] ?? 0) + 1;
@@ -488,6 +505,87 @@ class AccountOpener extends SDKConstruct {
488
505
  });
489
506
  return acc;
490
507
  }
508
+ /**
509
+ * Claims tokens from faucet, uniformly distributes them to accounts
510
+ * @param targets
511
+ * @returns
512
+ */
513
+ async #directlyDistributeTokens(targets) {
514
+ const tokens = new AddressSet(
515
+ targets.flatMap((t) => t.input.directTransfer ?? [])
516
+ );
517
+ if (tokens.size === 0) {
518
+ return;
519
+ }
520
+ const distributorKey = generatePrivateKey();
521
+ const distributor = privateKeyToAccount(distributorKey);
522
+ await this.#anvil.setBalance({
523
+ address: distributor.address,
524
+ value: parseEther("100")
525
+ });
526
+ await claimFromFaucet({
527
+ publicClient: this.#anvil,
528
+ wallet: this.#anvil,
529
+ faucet: this.faucet,
530
+ amountUSD: (minAmountUSD) => minAmountUSD * BigInt(targets.length),
531
+ claimer: distributor,
532
+ role: "reward token distributor",
533
+ logger: this.#logger
534
+ });
535
+ const actualBalances = await this.#anvil.multicall({
536
+ contracts: tokens.map(
537
+ (token) => ({
538
+ address: token,
539
+ abi: erc20Abi,
540
+ functionName: "balanceOf",
541
+ args: [distributor.address]
542
+ })
543
+ ),
544
+ allowFailure: false
545
+ });
546
+ const tokensArr = tokens.asArray();
547
+ for (let i = 0; i < tokensArr.length; i++) {
548
+ const token = tokensArr[i];
549
+ const balance = actualBalances[i];
550
+ this.#logger?.debug(`${token} balance: ${balance}`);
551
+ }
552
+ for (const { account, input } of targets) {
553
+ if (!account) {
554
+ continue;
555
+ }
556
+ const directTransfer = new AddressSet(input.directTransfer);
557
+ for (let i = 0; i < tokensArr.length; i++) {
558
+ const token = tokensArr[i];
559
+ if (!directTransfer.has(token)) {
560
+ continue;
561
+ }
562
+ const balance = actualBalances[i] / BigInt(targets.length);
563
+ this.#logger?.debug(
564
+ `sending ${balance} ${token} to ${account.creditAccount}`
565
+ );
566
+ const hash = await this.#anvil.writeContract({
567
+ account: distributor,
568
+ address: token,
569
+ abi: erc20Abi,
570
+ functionName: "transfer",
571
+ args: [account.creditAccount, balance],
572
+ chain: this.#anvil.chain
573
+ });
574
+ const receipt = await this.#anvil.waitForTransactionReceipt({
575
+ hash
576
+ });
577
+ if (receipt.status === "reverted") {
578
+ this.#logger?.error(
579
+ `failed to send ${token} to ${account.creditAccount}, tx ${hash} reverted`
580
+ );
581
+ } else {
582
+ this.#logger?.debug(
583
+ `sent ${token} to ${account.creditAccount}, tx: ${hash}`
584
+ );
585
+ }
586
+ }
587
+ }
588
+ }
491
589
  #getCollateralQuota(cm, collateral, collateralAmount, debt, logger) {
492
590
  const {
493
591
  underlying,
@@ -0,0 +1,24 @@
1
+ import { getAddress } from "viem";
2
+ class AddressSet extends Set {
3
+ constructor(entries) {
4
+ super(Array.from(entries ?? []).map((a) => getAddress(a)));
5
+ }
6
+ add(value) {
7
+ return super.add(getAddress(value));
8
+ }
9
+ delete(value) {
10
+ return super.delete(getAddress(value));
11
+ }
12
+ has(value) {
13
+ return super.has(getAddress(value));
14
+ }
15
+ asArray() {
16
+ return Array.from(this);
17
+ }
18
+ map(fn) {
19
+ return this.asArray().map(fn);
20
+ }
21
+ }
22
+ export {
23
+ AddressSet
24
+ };
@@ -1,4 +1,5 @@
1
1
  export * from "./AddressMap.js";
2
+ export * from "./AddressSet.js";
2
3
  export * from "./bytes32ToString.js";
3
4
  export * from "./childLogger.js";
4
5
  export * from "./createRawTx.js";
@@ -10,6 +10,7 @@ export interface AccountOpenerOptions {
10
10
  faucet?: Address;
11
11
  borrower?: PrivateKeyAccount;
12
12
  poolDepositMultiplier?: bigint;
13
+ minDebtMultiplier?: bigint;
13
14
  }
14
15
  export interface TargetAccount {
15
16
  creditManager: Address;
@@ -25,6 +26,10 @@ export interface TargetAccount {
25
26
  * TODO: not implemented
26
27
  */
27
28
  collateral?: Address;
29
+ /**
30
+ * These tokens will be transferred directly from faucet to credit account
31
+ */
32
+ directTransfer?: Address[];
28
33
  leverage?: number;
29
34
  slippage?: number;
30
35
  }
@@ -0,0 +1,9 @@
1
+ import { type Address } from "viem";
2
+ export declare class AddressSet extends Set<Address> {
3
+ constructor(entries?: Iterable<Address>);
4
+ add(value: Address): this;
5
+ delete(value: Address): boolean;
6
+ has(value: Address): boolean;
7
+ asArray(): Address[];
8
+ map<T>(fn: (address: Address) => T): T[];
9
+ }
@@ -1,4 +1,5 @@
1
1
  export * from "./AddressMap.js";
2
+ export * from "./AddressSet.js";
2
3
  export * from "./bytes32ToString.js";
3
4
  export * from "./childLogger.js";
4
5
  export * from "./createRawTx.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "8.9.0",
3
+ "version": "8.10.1",
4
4
  "description": "Gearbox SDK",
5
5
  "license": "MIT",
6
6
  "main": "./dist/cjs/sdk/index.js",