@gearbox-protocol/sdk 0.0.99 → 0.0.102

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 (86) hide show
  1. package/lib/apy/convexAPY.d.ts +8 -0
  2. package/lib/apy/convexAPY.js +202 -0
  3. package/lib/apy/lidoAPY.d.ts +4 -0
  4. package/lib/apy/lidoAPY.js +104 -0
  5. package/lib/config.d.ts +1 -0
  6. package/lib/config.js +2 -1
  7. package/lib/contracts/contracts.d.ts +6 -1
  8. package/lib/contracts/contracts.js +52 -14
  9. package/lib/contracts/contractsRegister.js +16 -4
  10. package/lib/core/constants.d.ts +6 -0
  11. package/lib/core/constants.js +10 -4
  12. package/lib/core/creditAccount.d.ts +3 -1
  13. package/lib/core/creditAccount.js +31 -31
  14. package/lib/core/creditManager.d.ts +13 -2
  15. package/lib/core/creditManager.js +79 -29
  16. package/lib/core/errors.d.ts +10 -0
  17. package/lib/core/errors.js +16 -1
  18. package/lib/core/events.js +9 -9
  19. package/lib/core/multicall.d.ts +1 -1
  20. package/lib/core/pool.d.ts +1 -1
  21. package/lib/core/pool.js +7 -5
  22. package/lib/core/price.d.ts +2 -0
  23. package/lib/core/price.js +9 -0
  24. package/lib/core/strategy.d.ts +38 -0
  25. package/lib/core/strategy.js +56 -0
  26. package/lib/index.d.ts +7 -1
  27. package/lib/index.js +8 -3
  28. package/lib/pathfinder/path.js +1 -1
  29. package/lib/pathfinder/yVault.js +5 -5
  30. package/lib/payload/creditAccount.d.ts +4 -26
  31. package/lib/payload/creditManager.d.ts +3 -25
  32. package/lib/payload/pool.d.ts +2 -17
  33. package/lib/payload/pool.js +0 -1
  34. package/lib/tokens/token.js +8 -8
  35. package/lib/utils/formatter.d.ts +1 -0
  36. package/lib/utils/formatter.js +6 -1
  37. package/lib/utils/mappers.d.ts +2 -1
  38. package/lib/utils/mappers.js +13 -5
  39. package/lib/utils/multicall.js +4 -3
  40. package/lib/utils/types.d.ts +1 -0
  41. package/package.json +1 -1
  42. package/src/apy/convexAPY.ts +250 -0
  43. package/src/apy/lidoAPY.ts +88 -0
  44. package/src/config.ts +2 -1
  45. package/src/contracts/contracts.ts +69 -16
  46. package/src/contracts/contractsRegister.ts +19 -4
  47. package/src/core/constants.ts +10 -3
  48. package/src/core/creditAccount.ts +46 -37
  49. package/src/core/creditManager.ts +231 -148
  50. package/src/core/errors.ts +24 -0
  51. package/src/core/events.ts +921 -915
  52. package/src/core/multicall.ts +1 -1
  53. package/src/core/pool.ts +56 -51
  54. package/src/core/price.ts +9 -0
  55. package/src/core/strategy.ts +130 -0
  56. package/src/index.ts +8 -1
  57. package/src/pathfinder/path.ts +154 -154
  58. package/src/pathfinder/yVault.ts +63 -62
  59. package/src/payload/creditAccount.ts +4 -26
  60. package/src/payload/creditManager.ts +4 -26
  61. package/src/payload/pool.ts +2 -19
  62. package/src/tokens/token.ts +14 -9
  63. package/src/utils/formatter.ts +5 -1
  64. package/src/utils/mappers.ts +12 -5
  65. package/src/utils/multicall.ts +4 -9
  66. package/src/utils/types.ts +6 -2
  67. package/lib/core/adapters.d.ts +0 -15
  68. package/lib/core/adapters.js +0 -19
  69. package/lib/core/contracts.d.ts +0 -67
  70. package/lib/core/contracts.js +0 -254
  71. package/lib/core/contractsRegister.d.ts +0 -2
  72. package/lib/core/contractsRegister.js +0 -58
  73. package/lib/core/creditCard.d.ts +0 -13
  74. package/lib/core/creditCard.js +0 -2
  75. package/lib/core/oracles.d.ts +0 -38
  76. package/lib/core/oracles.js +0 -12
  77. package/lib/core/priceFeeds.d.ts +0 -3
  78. package/lib/core/priceFeeds.js +0 -492
  79. package/lib/core/protocols.d.ts +0 -13
  80. package/lib/core/protocols.js +0 -39
  81. package/lib/core/swap.d.ts +0 -4
  82. package/lib/core/swap.js +0 -8
  83. package/lib/core/trade.d.ts +0 -35
  84. package/lib/core/trade.js +0 -62
  85. package/lib/core/tradeTypes.d.ts +0 -79
  86. package/lib/core/tradeTypes.js +0 -21
@@ -1,26 +1,4 @@
1
- import { BigNumberish } from "ethers";
2
- export interface TokenBalancePayload {
3
- token: string;
4
- balance: BigNumberish;
5
- isAllowed: boolean;
6
- }
7
- export interface CreditAccountDataPayload {
8
- addr: string;
9
- borrower: string;
10
- inUse: boolean;
11
- creditManager: string;
12
- underlyingToken: string;
13
- borrowedAmountPlusInterest: BigNumberish;
14
- totalValue: BigNumberish;
15
- healthFactor: BigNumberish;
16
- borrowRate: BigNumberish;
17
- balances?: Array<TokenBalancePayload>;
18
- }
19
- export interface CreditAccountDataExtendedPayload extends CreditAccountDataPayload {
20
- repayAmount: BigNumberish;
21
- liquidationAmount: BigNumberish;
22
- canBeClosed?: boolean;
23
- borrowedAmount: BigNumberish;
24
- cumulativeIndexAtOpen: BigNumberish;
25
- since: BigNumberish;
26
- }
1
+ import { CreditAccountDataStruct } from "../types/contracts/core/DataCompressor";
2
+ export declare type TokenBalancePayload = CreditAccountDataStruct["balances"];
3
+ export declare type CreditAccountDataPayload = CreditAccountDataStruct;
4
+ export declare type CreditAccountDataExtendedPayload = CreditAccountDataStruct;
@@ -1,33 +1,11 @@
1
1
  import { BigNumberish } from "ethers";
2
+ import { CreditManagerDataStruct } from "../types/contracts/interfaces/IDataCompressor.sol/IDataCompressor";
2
3
  export interface AdapterPayload {
3
4
  allowedContract: string;
4
5
  adapter: string;
5
6
  }
6
- export interface CreditManagerDataPayload {
7
- addr: string;
8
- hasAccount?: boolean;
9
- underlyingToken?: string;
10
- isWETH?: boolean;
11
- canBorrow?: boolean;
12
- borrowRate?: BigNumberish;
13
- minAmount?: BigNumberish;
14
- maxAmount?: BigNumberish;
15
- maxLeverageFactor?: BigNumberish;
16
- availableLiquidity?: BigNumberish;
17
- allowedTokens?: Array<string>;
18
- adapters?: Array<AdapterPayload>;
19
- }
20
- export interface CreditManagerStatPayload {
21
- addr: string;
22
- underlyingToken?: string;
23
- isWETH?: boolean;
24
- canBorrow?: boolean;
25
- borrowRate?: BigNumberish;
26
- minAmount?: BigNumberish;
27
- maxAmount?: BigNumberish;
28
- maxLeverageFactor?: BigNumberish;
29
- availableLiquidity?: BigNumberish;
30
- allowedTokens?: Array<string>;
7
+ export declare type CreditManagerDataPayload = CreditManagerDataStruct;
8
+ export interface CreditManagerStatPayload extends CreditManagerDataPayload {
31
9
  allowedContracts?: Array<string>;
32
10
  uniqueUsers: number;
33
11
  openedAccountsCount?: number;
@@ -1,17 +1,2 @@
1
- import { BigNumberish } from "ethers";
2
- export interface PoolDataPayload {
3
- addr: string;
4
- underlyingToken: string;
5
- dieselToken: string;
6
- isWETH: boolean;
7
- expectedLiquidity: BigNumberish;
8
- expectedLiquidityLimit?: BigNumberish;
9
- availableLiquidity: BigNumberish;
10
- totalBorrowed: BigNumberish;
11
- depositAPY_RAY: BigNumberish;
12
- borrowAPY_RAY: BigNumberish;
13
- dieselRate_RAY: BigNumberish;
14
- withdrawFee: BigNumberish;
15
- timestampLU?: BigNumberish;
16
- cumulativeIndex_RAY?: BigNumberish;
17
- }
1
+ import { PoolDataStruct } from "../types/contracts/interfaces/IDataCompressor.sol/IDataCompressor";
2
+ export declare type PoolDataPayload = PoolDataStruct;
@@ -1,3 +1,2 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- //
@@ -141,24 +141,24 @@ exports.tokenDataByNetwork = {
141
141
  cvxsteCRV: "0xb22c2015327cfbeD480eF45B6382d4bC963a4595",
142
142
  cvxcrvPlain3andSUSD: "0xBBeAdEA3C648cF4026d0422EAF2463050202700b",
143
143
  cvxFRAX3CRV: "0xBC523005975D86de9226785DD83e4f8d2A87fA73",
144
- cvxLUSD3CRV: "0xF1128521595A6CAee02af9DBdb15857954cC2cA0",
144
+ cvxLUSD3CRV: "0xF90d9a96985a80e6c2cA9952cd2C6Db5B720408F",
145
145
  cvxgusd3CRV: "0xa3aDFDf18d166e26bF1Bc0ee63D26d0d1064b056",
146
146
  // CONVEX PHANTOM TOKEN ADDRESSES
147
147
  stkcvx3Crv: "0xf4FC4Aa052346fEa87f1e864f10de0f7383e9502",
148
148
  stkcvxFRAX3CRV: "0xd726f9684245065B120E1ac18de389f6b05351Ba",
149
- stkcvxLUSD3CRV: "0x028b65EE7B3B70307d653Ed9cC93ae30e05e4026",
149
+ stkcvxLUSD3CRV: "0x5c355c46413B45Cc58aB61AcaF5BB72E7c2d1465",
150
150
  stkcvxgusd3CRV: "0x9A74e8106f6c28b21b1B6a0F985cf1227BE05F04",
151
151
  stkcvxsteCRV: "0xd8bAbB7EfBF7F931a69B209f71b27421F8b18516",
152
152
  stkcvxcrvPlain3andSUSD: "0x6b45Cab756B41a7204973b71362ef5F73E67F6DA",
153
153
  //GEARBOX
154
- dDAI: "0x0d06D2e31781A0585feE334F63beF43543496e5d",
155
- dUSDC: "0xcCc83353856A79c94EaDa39Df76B9c7C4c762dBF",
156
- dWBTC: "0x4cCb374472C8c73b067c8c40b9420a221Ef014ca",
157
- dWETH: "0x3B1e0Db6C960b32beEDf82af9db2da63F15Ba01E",
154
+ dDAI: "0x077a3Ce0D572b72436F6644793Fc7721353aF1f4",
155
+ dUSDC: "0x8147e00456c8A3128182730bFFdFd9D1E6bbC048",
156
+ dWBTC: "0x34D9B3c13B25632879B2DaabBde702F612902238",
157
+ dWETH: "0x19e4F905749D3b487CA4927b54e55b64625a1143",
158
158
  GEAR: "0xe01c5d0297c56e992dab3886057a1441485ff7c7"
159
159
  }
160
160
  };
161
- exports.tokenSymbolByAddress = (0, mappers_1.objectEntries)(exports.tokenDataByNetwork).reduce(function (sum, _a) {
161
+ exports.tokenSymbolByAddress = (0, mappers_1.objectEntries)(exports.tokenDataByNetwork).reduce(function (acc, _a) {
162
162
  var _ = _a[0], tokens = _a[1];
163
- return __assign(__assign({}, sum), (0, mappers_1.keyToLowercase)((0, mappers_1.swapKeyValue)(tokens)));
163
+ return __assign(__assign({}, acc), (0, mappers_1.filterEmptyKeys)((0, mappers_1.keyToLowercase)((0, mappers_1.swapKeyValue)(tokens))));
164
164
  }, {});
@@ -11,3 +11,4 @@ export declare function shortHash(address?: string): string;
11
11
  export declare const formatRate: (rate: BigNumberish | undefined) => string;
12
12
  export declare function formatDate(date: Date): string;
13
13
  export declare function formatHf(healthFactor: number): string;
14
+ export declare function formatLeverage(leverage: number, decimals?: number): string;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.formatHf = exports.formatDate = exports.formatRate = exports.shortHash = exports.shortAddress = exports.toBN = exports.toSignificant = exports.toHumanFormat = exports.formatBn4dig = exports.formatBN = exports.formatRAY = exports.rayToNumber = void 0;
6
+ exports.formatLeverage = exports.formatHf = exports.formatDate = exports.formatRate = exports.shortHash = exports.shortAddress = exports.toBN = exports.toSignificant = exports.toHumanFormat = exports.formatBn4dig = exports.formatBN = exports.formatRAY = exports.rayToNumber = void 0;
7
7
  var ethers_1 = require("ethers");
8
8
  var constants_1 = require("../core/constants");
9
9
  var decimal_js_light_1 = __importDefault(require("decimal.js-light"));
@@ -123,3 +123,8 @@ function formatHf(healthFactor) {
123
123
  return (healthFactor / 10000).toFixed(2);
124
124
  }
125
125
  exports.formatHf = formatHf;
126
+ function formatLeverage(leverage, decimals) {
127
+ if (decimals === void 0) { decimals = 2; }
128
+ return (leverage / constants_1.LEVERAGE_DECIMALS).toFixed(decimals);
129
+ }
130
+ exports.formatLeverage = formatLeverage;
@@ -2,5 +2,6 @@ declare type SupportedValue = string | number;
2
2
  declare const objectEntries: <K extends SupportedValue, T>(o: Record<K, T>) => [K, T][];
3
3
  declare const swapKeyValue: <K extends SupportedValue, T extends SupportedValue>(o: Record<K, T>) => Record<T, K>;
4
4
  declare const keyToLowercase: <K extends SupportedValue, T extends SupportedValue>(o: Record<K, T>) => Record<K, T>;
5
+ declare const filterEmptyKeys: <K extends SupportedValue, T extends SupportedValue>(o: Record<K, T>) => Record<K, T>;
5
6
  export type { SupportedValue };
6
- export { objectEntries, swapKeyValue, keyToLowercase };
7
+ export { objectEntries, swapKeyValue, keyToLowercase, filterEmptyKeys };
@@ -11,23 +11,31 @@ var __assign = (this && this.__assign) || function () {
11
11
  return __assign.apply(this, arguments);
12
12
  };
13
13
  Object.defineProperty(exports, "__esModule", { value: true });
14
- exports.keyToLowercase = exports.swapKeyValue = exports.objectEntries = void 0;
14
+ exports.filterEmptyKeys = exports.keyToLowercase = exports.swapKeyValue = exports.objectEntries = void 0;
15
15
  var objectEntries = function (o) { return Object.entries(o); };
16
16
  exports.objectEntries = objectEntries;
17
17
  var swapKeyValue = function (o) {
18
- return objectEntries(o).reduce(function (sum, _a) {
18
+ return objectEntries(o).reduce(function (acc, _a) {
19
19
  var _b;
20
20
  var key = _a[0], value = _a[1];
21
- return __assign(__assign({}, sum), (_b = {}, _b[value] = key, _b));
21
+ return __assign(__assign({}, acc), (_b = {}, _b[value] = key, _b));
22
22
  }, {});
23
23
  };
24
24
  exports.swapKeyValue = swapKeyValue;
25
25
  var keyToLowercase = function (o) {
26
- return objectEntries(o).reduce(function (sum, _a) {
26
+ return objectEntries(o).reduce(function (acc, _a) {
27
27
  var _b;
28
28
  var key = _a[0], value = _a[1];
29
29
  var keyTransformed = typeof key === "string" ? key.toLowerCase() : key;
30
- return __assign(__assign({}, sum), (_b = {}, _b[keyTransformed] = value, _b));
30
+ return __assign(__assign({}, acc), (_b = {}, _b[keyTransformed] = value, _b));
31
31
  }, {});
32
32
  };
33
33
  exports.keyToLowercase = keyToLowercase;
34
+ var filterEmptyKeys = function (o) {
35
+ return objectEntries(o).reduce(function (acc, _a) {
36
+ var _b;
37
+ var key = _a[0], value = _a[1];
38
+ return !!key ? __assign(__assign({}, acc), (_b = {}, _b[key] = value, _b)) : acc;
39
+ }, {});
40
+ };
41
+ exports.filterEmptyKeys = filterEmptyKeys;
@@ -37,6 +37,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
39
  exports.MultiCallContract = exports.multicall = void 0;
40
+ var config_1 = require("../config");
40
41
  var types_1 = require("../types");
41
42
  function multicall(calls, p) {
42
43
  return __awaiter(this, void 0, void 0, function () {
@@ -44,7 +45,7 @@ function multicall(calls, p) {
44
45
  return __generator(this, function (_a) {
45
46
  switch (_a.label) {
46
47
  case 0:
47
- multiCallContract = types_1.Multicall2__factory.connect("0x5ba1e12693dc8f9c48aad8770482f4739beed696", p);
48
+ multiCallContract = types_1.Multicall2__factory.connect(config_1.MULTICALL_ADDRESS, p);
48
49
  return [4 /*yield*/, multiCallContract.callStatic.aggregate(calls.map(function (c) { return ({
49
50
  target: c.address,
50
51
  callData: c.interface.encodeFunctionData(c.method, c.params)
@@ -55,7 +56,7 @@ function multicall(calls, p) {
55
56
  .map(function (d, num) {
56
57
  return calls[num].interface.decodeFunctionResult(calls[num].method, d);
57
58
  })
58
- .map(function (r) { return r[0]; })];
59
+ .map(function (r) { return (Array.isArray(r) && r.length <= 1 ? r[0] : r); })];
59
60
  }
60
61
  });
61
62
  });
@@ -65,7 +66,7 @@ var MultiCallContract = /** @class */ (function () {
65
66
  function MultiCallContract(address, intrerface, provider) {
66
67
  this._address = address;
67
68
  this._interface = intrerface;
68
- this._multiCall = types_1.Multicall2__factory.connect("0x5ba1e12693dc8f9c48aad8770482f4739beed696", provider);
69
+ this._multiCall = types_1.Multicall2__factory.connect(config_1.MULTICALL_ADDRESS, provider);
69
70
  }
70
71
  MultiCallContract.prototype.call = function (data) {
71
72
  return __awaiter(this, void 0, void 0, function () {
@@ -1,3 +1,4 @@
1
1
  export declare type PartialRecord<K extends keyof any, T> = {
2
2
  [P in K]?: T;
3
3
  };
4
+ export declare type AwaitedRes<T extends (...args: any) => any> = Awaited<ReturnType<T>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gearbox-protocol/sdk",
3
- "version": "0.0.99",
3
+ "version": "0.0.102",
4
4
  "description": "Gearbox SDK",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -0,0 +1,250 @@
1
+ import { BigNumber, providers } from "ethers";
2
+ import axios from "axios";
3
+ import {
4
+ ConvexPoolContract,
5
+ ConvexPoolParams,
6
+ contractsByNetwork,
7
+ contractParams,
8
+ CurvePoolContract
9
+ } from "../contracts/contracts";
10
+
11
+ import { tokenDataByNetwork, supportedTokens } from "../tokens/token";
12
+ import { CurveLPToken } from "../tokens/curveLP";
13
+ import { ConvexPhantomTokenData } from "../tokens/convex";
14
+
15
+ import {
16
+ IBaseRewardPool__factory,
17
+ IBaseRewardPool,
18
+ IConvexToken__factory,
19
+ IConvexToken,
20
+ CurveV1AdapterStETH,
21
+ CurveV1AdapterStETH__factory
22
+ } from "../types";
23
+
24
+ import { multicall, MCall } from "../utils/multicall";
25
+ import { toBN } from "../utils/formatter";
26
+ import { AwaitedRes } from "../utils/types";
27
+
28
+ import {
29
+ SECONDS_PER_YEAR,
30
+ WAD,
31
+ WAD_DECIMALS_POW,
32
+ NetworkType,
33
+ PRICE_DECIMALS
34
+ } from "../core/constants";
35
+
36
+ type SupportedPools = Extract<
37
+ ConvexPoolContract,
38
+ | "CONVEX_3CRV_POOL"
39
+ | "CONVEX_FRAX3CRV_POOL"
40
+ | "CONVEX_LUSD3CRV_POOL"
41
+ | "CONVEX_GUSD_POOL"
42
+ | "CONVEX_SUSD_POOL"
43
+ >;
44
+
45
+ type SupportedConvex = Extract<
46
+ CurvePoolContract,
47
+ | "CURVE_3CRV_POOL"
48
+ | "CURVE_FRAX_POOL"
49
+ | "CURVE_LUSD_POOL"
50
+ | "CURVE_GUSD_POOL"
51
+ | "CURVE_SUSD_POOL"
52
+ >;
53
+
54
+ const curveSwapByPool: Record<SupportedPools, SupportedConvex> = {
55
+ CONVEX_3CRV_POOL: "CURVE_3CRV_POOL",
56
+ CONVEX_FRAX3CRV_POOL: "CURVE_FRAX_POOL",
57
+ CONVEX_LUSD3CRV_POOL: "CURVE_LUSD_POOL",
58
+ CONVEX_GUSD_POOL: "CURVE_GUSD_POOL",
59
+ CONVEX_SUSD_POOL: "CURVE_SUSD_POOL"
60
+ };
61
+
62
+ export async function getConvexApy(
63
+ pool: SupportedPools,
64
+ provider: providers.Provider,
65
+ networkType: NetworkType,
66
+ getTokenPrice: (tokenAddress: string) => BigNumber
67
+ ) {
68
+ const tokenList = tokenDataByNetwork[networkType];
69
+ const contractsList = contractsByNetwork[networkType];
70
+
71
+ const poolParams = contractParams[pool] as ConvexPoolParams;
72
+ const stakedTokenParams = supportedTokens[
73
+ poolParams.stakedToken
74
+ ] as ConvexPhantomTokenData;
75
+
76
+ const underlying = stakedTokenParams.underlying;
77
+ const basePoolAddress = contractsList[pool];
78
+ const swapPoolAddress = contractsList[curveSwapByPool[pool]];
79
+ const cvxAddress = tokenList.CVX;
80
+
81
+ const extraPoolAddresses = poolParams.extraRewards.map(d => {
82
+ return d.poolAddress[networkType];
83
+ });
84
+
85
+ const [basePoolRate, basePoolSupply, vPrice, cvxSupply, ...extra] =
86
+ await getPoolData(
87
+ basePoolAddress,
88
+ swapPoolAddress,
89
+ cvxAddress,
90
+ extraPoolAddresses,
91
+ provider
92
+ );
93
+
94
+ const cvxPrice = getTokenPrice(tokenList["CVX"]);
95
+ const crvPrice = getTokenPrice(tokenList["CRV"]);
96
+
97
+ const crvPerSecond = basePoolRate;
98
+ const virtualSupply = basePoolSupply.mul(vPrice).div(WAD);
99
+ const crvPerUnderlying = crvPerSecond.mul(WAD).div(virtualSupply);
100
+
101
+ const crvPerYear = crvPerUnderlying.mul(SECONDS_PER_YEAR);
102
+ const cvxPerYear = getCVXMintAmount(crvPerYear, cvxSupply);
103
+
104
+ const crvAPY = crvPerYear.mul(cvxPrice).div(PRICE_DECIMALS);
105
+ const cvxAPY = cvxPerYear.mul(crvPrice).div(PRICE_DECIMALS);
106
+
107
+ const extraAPRs = await Promise.all(
108
+ extraPoolAddresses.map(async (_, index) => {
109
+ const extraRewardSymbol = poolParams.extraRewards[index].rewardToken;
110
+ const extraPoolRate = extra[index];
111
+
112
+ const perUnderlying = extraPoolRate.mul(WAD).div(virtualSupply);
113
+ const perYear = perUnderlying.mul(SECONDS_PER_YEAR);
114
+
115
+ const extraPrise = getTokenPrice(tokenList[extraRewardSymbol]);
116
+
117
+ const extraAPY = perYear.mul(extraPrise).div(PRICE_DECIMALS);
118
+
119
+ return extraAPY;
120
+ })
121
+ );
122
+
123
+ const extraAPYTotal = extraAPRs.reduce(
124
+ (acc, apy) => acc.add(apy),
125
+ BigNumber.from(0)
126
+ );
127
+
128
+ const baseApyRAY = await getCurveBaseApy(underlying);
129
+
130
+ return baseApyRAY.add(crvAPY).add(cvxAPY).add(extraAPYTotal);
131
+ }
132
+
133
+ const CVX_MAX_SUPPLY = WAD.mul(100000000);
134
+ const CVX_REDUCTION_PER_CLIFF = BigNumber.from(100000);
135
+ const CVX_TOTAL_CLIFFS = WAD.mul(1000);
136
+
137
+ function getCVXMintAmount(crvAmount: BigNumber, cvxSupply: BigNumber) {
138
+ const currentCliff = cvxSupply.div(CVX_REDUCTION_PER_CLIFF);
139
+
140
+ if (currentCliff.lt(CVX_TOTAL_CLIFFS)) {
141
+ const remainingCliffs = CVX_TOTAL_CLIFFS.sub(currentCliff);
142
+
143
+ const mintedAmount = crvAmount.mul(remainingCliffs).div(CVX_TOTAL_CLIFFS);
144
+
145
+ const amountTillMax = CVX_MAX_SUPPLY.sub(cvxSupply);
146
+
147
+ return mintedAmount.gt(amountTillMax) ? amountTillMax : mintedAmount;
148
+ }
149
+
150
+ return BigNumber.from(0);
151
+ }
152
+
153
+ type IBaseRewardPoolInterface = IBaseRewardPool["interface"];
154
+ type IConvexTokenInterface = IConvexToken["interface"];
155
+ type CurveV1AdapterStETHInterface = CurveV1AdapterStETH["interface"];
156
+
157
+ async function getPoolData(
158
+ basePoolAddress: string,
159
+ underlying: string,
160
+ cvxAddress: string,
161
+ extraPoolAddresses: string[],
162
+ provider: providers.Provider
163
+ ) {
164
+ const calls: [
165
+ MCall<IBaseRewardPoolInterface>,
166
+ MCall<IBaseRewardPoolInterface>,
167
+ MCall<CurveV1AdapterStETHInterface>,
168
+ MCall<IConvexTokenInterface>,
169
+ ...Array<MCall<IBaseRewardPoolInterface>>
170
+ ] = [
171
+ {
172
+ address: basePoolAddress,
173
+ interface: IBaseRewardPool__factory.createInterface(),
174
+ method: "rewardRate()"
175
+ },
176
+ {
177
+ address: basePoolAddress,
178
+ interface: IBaseRewardPool__factory.createInterface(),
179
+ method: "totalSupply()"
180
+ },
181
+ {
182
+ address: underlying,
183
+ interface: CurveV1AdapterStETH__factory.createInterface(),
184
+ method: "get_virtual_price()"
185
+ },
186
+ {
187
+ address: cvxAddress,
188
+ interface: IConvexToken__factory.createInterface(),
189
+ method: "totalSupply()"
190
+ },
191
+ ...extraPoolAddresses.map(
192
+ (extraPoolAddress): MCall<IBaseRewardPoolInterface> => ({
193
+ address: extraPoolAddress,
194
+ interface: IBaseRewardPool__factory.createInterface(),
195
+ method: "rewardRate()"
196
+ })
197
+ )
198
+ ];
199
+
200
+ return multicall<
201
+ [
202
+ AwaitedRes<IBaseRewardPool["rewardRate"]>,
203
+ AwaitedRes<IBaseRewardPool["totalSupply"]>,
204
+ AwaitedRes<CurveV1AdapterStETH["get_virtual_price"]>,
205
+ AwaitedRes<IConvexToken["totalSupply"]>,
206
+ ...Array<AwaitedRes<IBaseRewardPool["rewardRate"]>>
207
+ ]
208
+ >(calls, provider);
209
+ }
210
+
211
+ interface CurveAPRData {
212
+ baseApy: number;
213
+ crvApy: number;
214
+ crvBoost: number;
215
+ crvPrice: number;
216
+ }
217
+
218
+ interface APYResponse {
219
+ apys: Record<string, CurveAPRData>;
220
+ }
221
+
222
+ const curveLPTokenToPoolName: Record<CurveLPToken, string> = {
223
+ "3Crv": "3pool",
224
+ FRAX3CRV: "frax",
225
+ gusd3CRV: "gusd",
226
+ LUSD3CRV: "lusd",
227
+ crvPlain3andSUSD: "susdv2",
228
+ steCRV: "steth"
229
+ };
230
+
231
+ const RESPONSE_DECIMALS = 100;
232
+
233
+ // https://www.convexfinance.com/api/curve-apys
234
+
235
+ export async function getCurveBaseApy(
236
+ curveLPToken: CurveLPToken
237
+ ): Promise<BigNumber> {
238
+ const poolName = curveLPTokenToPoolName[curveLPToken];
239
+
240
+ try {
241
+ const url = "https://www.convexfinance.com/api/curve-apys";
242
+ const result = await axios.get<APYResponse>(url);
243
+
244
+ const { baseApy = 0 } = result.data.apys[poolName] || {};
245
+
246
+ return toBN((baseApy / RESPONSE_DECIMALS).toString(), WAD_DECIMALS_POW);
247
+ } catch (e) {
248
+ return BigNumber.from(0);
249
+ }
250
+ }
@@ -0,0 +1,88 @@
1
+ import { providers } from "ethers";
2
+
3
+ import { multicall, MCall } from "../utils/multicall";
4
+ import { contractParams, LidoParams } from "../contracts/contracts";
5
+ import { tokenDataByNetwork } from "../tokens/token";
6
+
7
+ import { WAD, SECONDS_PER_YEAR, NetworkType } from "../core/constants";
8
+
9
+ import {
10
+ ILidoOracle__factory,
11
+ ILidoOracle,
12
+ IstETH__factory,
13
+ IstETH
14
+ } from "../types";
15
+
16
+ type ILidoOracleInterface = ILidoOracle["interface"];
17
+
18
+ type IstETHInterface = IstETH["interface"];
19
+
20
+ const lidoOracleAddress = (contractParams.LIDO_STETH_GATEWAY as LidoParams)
21
+ .oracle;
22
+
23
+ const lidoStEthAddress: Record<NetworkType, string> = {
24
+ Mainnet: tokenDataByNetwork.Mainnet.STETH,
25
+ Kovan: tokenDataByNetwork.Kovan.STETH
26
+ };
27
+
28
+ export async function getLidoApy(
29
+ provider: providers.Provider,
30
+ networkType: NetworkType
31
+ ) {
32
+ if (!lidoOracleAddress[networkType]) {
33
+ throw `No Lido APR oracle found on current network: ${networkType}`;
34
+ }
35
+ if (!lidoStEthAddress[networkType]) {
36
+ throw `No Lido stETH found on current network: ${networkType}`;
37
+ }
38
+
39
+ const [{ postTotalPooledEther, preTotalPooledEther, timeElapsed }, fee] =
40
+ await geLidoData(
41
+ lidoOracleAddress[networkType],
42
+ lidoStEthAddress[networkType],
43
+ provider,
44
+ networkType
45
+ );
46
+
47
+ const lidoAPRRay = postTotalPooledEther
48
+ .sub(preTotalPooledEther)
49
+ .mul(SECONDS_PER_YEAR)
50
+ .mul(WAD)
51
+ .div(preTotalPooledEther.mul(timeElapsed));
52
+
53
+ return [lidoAPRRay, fee] as const;
54
+ }
55
+
56
+ async function geLidoData(
57
+ lidoOracleAddress: string,
58
+ stETHAddress: string,
59
+ provider: providers.Provider,
60
+ network: NetworkType
61
+ ) {
62
+ const calls: [MCall<ILidoOracleInterface>, ...Array<MCall<IstETHInterface>>] =
63
+ [
64
+ {
65
+ address: lidoOracleAddress,
66
+ interface: ILidoOracle__factory.createInterface(),
67
+ method: "getLastCompletedReportDelta()"
68
+ }
69
+ ];
70
+
71
+ if (network !== "Kovan")
72
+ calls.push({
73
+ address: stETHAddress,
74
+ interface: IstETH__factory.createInterface(),
75
+ method: "getFee()"
76
+ });
77
+
78
+ const [stats, fee = Math.floor(LIDO_FEE_DECIMALS / 10)] = await multicall<
79
+ [
80
+ Awaited<ReturnType<ILidoOracle["getLastCompletedReportDelta"]>>,
81
+ Awaited<ReturnType<IstETH["getFee"]>>
82
+ ]
83
+ >(calls, provider);
84
+
85
+ return [stats, fee] as const;
86
+ }
87
+
88
+ export const LIDO_FEE_DECIMALS = 10000;
package/src/config.ts CHANGED
@@ -1 +1,2 @@
1
- export const STATIC_TOKEN = "https://static.gearbox.fi/tokens/"
1
+ export const STATIC_TOKEN = "https://static.gearbox.fi/tokens/";
2
+ export const MULTICALL_ADDRESS = "0x5ba1e12693dc8f9c48aad8770482f4739beed696";