@defisaver/positions-sdk 0.0.199 → 0.0.201-fluid-dev

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 (100) hide show
  1. package/cjs/config/contracts.d.ts +169 -4
  2. package/cjs/config/contracts.js +20 -0
  3. package/cjs/contracts.d.ts +2 -0
  4. package/cjs/contracts.js +3 -1
  5. package/cjs/fluid/index.d.ts +38 -0
  6. package/cjs/fluid/index.js +163 -0
  7. package/cjs/helpers/fluidHelpers/index.d.ts +6 -0
  8. package/cjs/helpers/fluidHelpers/index.js +40 -0
  9. package/cjs/helpers/index.d.ts +2 -0
  10. package/cjs/helpers/index.js +3 -1
  11. package/cjs/helpers/liquityV2Helpers/index.d.ts +12 -0
  12. package/cjs/helpers/liquityV2Helpers/index.js +63 -0
  13. package/cjs/index.d.ts +3 -1
  14. package/cjs/index.js +5 -1
  15. package/cjs/liquityV2/index.d.ts +18 -0
  16. package/cjs/liquityV2/index.js +194 -0
  17. package/cjs/markets/aave/marketAssets.js +1 -1
  18. package/cjs/markets/fluid/index.d.ts +174 -0
  19. package/cjs/markets/fluid/index.js +1286 -0
  20. package/cjs/markets/index.d.ts +2 -0
  21. package/cjs/markets/index.js +5 -1
  22. package/cjs/markets/liquityV2/index.d.ts +10 -0
  23. package/cjs/markets/liquityV2/index.js +47 -0
  24. package/cjs/moneymarket/moneymarketCommonService.js +1 -1
  25. package/cjs/types/contracts/generated/FluidView.d.ts +318 -0
  26. package/cjs/types/contracts/generated/FluidView.js +5 -0
  27. package/cjs/types/contracts/generated/LiquityV2CollSurplusPool.d.ts +64 -0
  28. package/cjs/types/contracts/generated/LiquityV2CollSurplusPool.js +5 -0
  29. package/cjs/types/contracts/generated/LiquityV2TroveNFT.d.ts +73 -0
  30. package/cjs/types/contracts/generated/LiquityV2TroveNFT.js +5 -0
  31. package/cjs/types/contracts/generated/LiquityV2View.d.ts +244 -0
  32. package/cjs/types/contracts/generated/LiquityV2View.js +5 -0
  33. package/cjs/types/contracts/generated/index.d.ts +4 -0
  34. package/cjs/types/fluid.d.ts +225 -0
  35. package/cjs/types/fluid.js +129 -0
  36. package/cjs/types/index.d.ts +2 -0
  37. package/cjs/types/index.js +2 -0
  38. package/cjs/types/liquityV2.d.ts +111 -0
  39. package/cjs/types/liquityV2.js +24 -0
  40. package/esm/config/contracts.d.ts +169 -4
  41. package/esm/config/contracts.js +20 -0
  42. package/esm/contracts.d.ts +2 -0
  43. package/esm/contracts.js +2 -0
  44. package/esm/fluid/index.d.ts +38 -0
  45. package/esm/fluid/index.js +153 -0
  46. package/esm/helpers/fluidHelpers/index.d.ts +6 -0
  47. package/esm/helpers/fluidHelpers/index.js +33 -0
  48. package/esm/helpers/index.d.ts +2 -0
  49. package/esm/helpers/index.js +2 -0
  50. package/esm/helpers/liquityV2Helpers/index.d.ts +12 -0
  51. package/esm/helpers/liquityV2Helpers/index.js +55 -0
  52. package/esm/index.d.ts +3 -1
  53. package/esm/index.js +3 -1
  54. package/esm/liquityV2/index.d.ts +18 -0
  55. package/esm/liquityV2/index.js +183 -0
  56. package/esm/markets/aave/marketAssets.js +1 -1
  57. package/esm/markets/fluid/index.d.ts +174 -0
  58. package/esm/markets/fluid/index.js +1196 -0
  59. package/esm/markets/index.d.ts +2 -0
  60. package/esm/markets/index.js +2 -0
  61. package/esm/markets/liquityV2/index.d.ts +10 -0
  62. package/esm/markets/liquityV2/index.js +40 -0
  63. package/esm/moneymarket/moneymarketCommonService.js +1 -1
  64. package/esm/types/contracts/generated/FluidView.d.ts +318 -0
  65. package/esm/types/contracts/generated/FluidView.js +4 -0
  66. package/esm/types/contracts/generated/LiquityV2CollSurplusPool.d.ts +64 -0
  67. package/esm/types/contracts/generated/LiquityV2CollSurplusPool.js +4 -0
  68. package/esm/types/contracts/generated/LiquityV2TroveNFT.d.ts +73 -0
  69. package/esm/types/contracts/generated/LiquityV2TroveNFT.js +4 -0
  70. package/esm/types/contracts/generated/LiquityV2View.d.ts +244 -0
  71. package/esm/types/contracts/generated/LiquityV2View.js +4 -0
  72. package/esm/types/contracts/generated/index.d.ts +4 -0
  73. package/esm/types/fluid.d.ts +225 -0
  74. package/esm/types/fluid.js +126 -0
  75. package/esm/types/index.d.ts +2 -0
  76. package/esm/types/index.js +2 -0
  77. package/esm/types/liquityV2.d.ts +111 -0
  78. package/esm/types/liquityV2.js +21 -0
  79. package/package.json +2 -2
  80. package/src/config/contracts.js +20 -0
  81. package/src/contracts.ts +2 -0
  82. package/src/fluid/index.ts +220 -0
  83. package/src/helpers/fluidHelpers/index.ts +54 -0
  84. package/src/helpers/index.ts +3 -1
  85. package/src/helpers/liquityV2Helpers/index.ts +80 -0
  86. package/src/index.ts +4 -0
  87. package/src/liquityV2/index.ts +228 -0
  88. package/src/markets/aave/marketAssets.ts +1 -1
  89. package/src/markets/fluid/index.ts +1290 -0
  90. package/src/markets/index.ts +3 -2
  91. package/src/markets/liquityV2/index.ts +44 -0
  92. package/src/moneymarket/moneymarketCommonService.ts +1 -1
  93. package/src/types/contracts/generated/FluidView.ts +399 -0
  94. package/src/types/contracts/generated/LiquityV2CollSurplusPool.ts +130 -0
  95. package/src/types/contracts/generated/LiquityV2TroveNFT.ts +150 -0
  96. package/src/types/contracts/generated/LiquityV2View.ts +315 -0
  97. package/src/types/contracts/generated/index.ts +4 -0
  98. package/src/types/fluid.ts +240 -0
  99. package/src/types/index.ts +3 -1
  100. package/src/types/liquityV2.ts +119 -0
@@ -0,0 +1,220 @@
1
+ import Web3 from 'web3';
2
+ import Dec from 'decimal.js';
3
+ import { getAssetInfo, getAssetInfoByAddress } from '@defisaver/tokens';
4
+ import { EthAddress, NetworkNumber } from '../types/common';
5
+ import {
6
+ FluidAggregatedVaultData,
7
+ FluidAssetData, FluidAssetsData,
8
+ FluidMarketData,
9
+ FluidMarketInfo,
10
+ FluidUsedAsset,
11
+ FluidUsedAssets,
12
+ FluidVaultData,
13
+ FluidVaultType, InnerFluidMarketData,
14
+ } from '../types';
15
+ import { FluidViewContract } from '../contracts';
16
+ import { getEthAmountForDecimals } from '../services/utils';
17
+ import { getFluidAggregatedData } from '../helpers/fluidHelpers';
18
+ import { FluidView } from '../types/contracts/generated';
19
+
20
+ export const EMPTY_USED_ASSET = {
21
+ isSupplied: false,
22
+ isBorrowed: false,
23
+ supplied: '0',
24
+ suppliedUsd: '0',
25
+ borrowed: '0',
26
+ borrowedUsd: '0',
27
+ symbol: '',
28
+ collateral: false,
29
+ };
30
+
31
+ const parseVaultType = (vaultType: number) => {
32
+ switch (vaultType) {
33
+ case 10000: return FluidVaultType.T1;
34
+ case 20000: return FluidVaultType.T2;
35
+ case 30000: return FluidVaultType.T3;
36
+ case 40000: return FluidVaultType.T4;
37
+ default: return FluidVaultType.Unknown;
38
+ }
39
+ };
40
+
41
+ const parseMarketData = (data: FluidView.VaultDataStructOutputStruct) => {
42
+ const collAsset = getAssetInfoByAddress(data.supplyToken0);
43
+ const debtAsset = getAssetInfoByAddress(data.borrowToken0);
44
+
45
+ const collAssetData: FluidAssetData = {
46
+ symbol: collAsset.symbol,
47
+ address: collAsset.address,
48
+ price: getEthAmountForDecimals(data.priceOfSupplyToken0InUSD, 8),
49
+ totalSupply: data.totalSupplyVault,
50
+ totalBorrow: data.totalBorrowVault,
51
+ canBeSupplied: true,
52
+ canBeBorrowed: false,
53
+ supplyRate: new Dec(data.supplyRateVault).div(100).toString(),
54
+ borrowRate: '0',
55
+ };
56
+
57
+ const debtAssetData: FluidAssetData = {
58
+ symbol: debtAsset.symbol,
59
+ address: debtAsset.address,
60
+ price: getEthAmountForDecimals(data.priceOfBorrowToken0InUSD, 8),
61
+ totalSupply: data.totalSupplyVault,
62
+ totalBorrow: data.totalBorrowVault,
63
+ canBeSupplied: false,
64
+ canBeBorrowed: true,
65
+ supplyRate: '0',
66
+ borrowRate: new Dec(data.borrowRateVault).div(100).toString(),
67
+ };
68
+
69
+ const assetsData = {
70
+ [collAsset.symbol]: collAssetData,
71
+ [debtAsset.symbol]: debtAssetData,
72
+ };
73
+
74
+ const marketData = {
75
+ vaultId: +data.vaultId,
76
+ isSmartColl: data.isSmartColl,
77
+ isSmartDebt: data.isSmartDebt,
78
+ marketAddress: data.vault,
79
+ vaultType: parseVaultType(+data.vaultType),
80
+ oracle: data.oracle,
81
+ liquidationPenaltyPercent: new Dec(data.liquidationPenalty).div(100).toString(),
82
+ collFactor: new Dec(data.collateralFactor).div(10000).toString(), // we want actual factor, not in %, so we divide by 10000 instead of 100
83
+ liquidationRatio: new Dec(data.liquidationThreshold).div(100).toString(),
84
+ collAsset0: collAsset.symbol,
85
+ debtAsset0: debtAsset.symbol,
86
+ totalPositions: data.totalPositions,
87
+ totalSupplyVault: getEthAmountForDecimals(data.totalSupplyVault, collAsset.decimals),
88
+ totalBorrowVault: getEthAmountForDecimals(data.totalBorrowVault, debtAsset.decimals),
89
+ withdrawalLimit: getEthAmountForDecimals(data.withdrawalLimit, collAsset.decimals),
90
+ withdrawableUntilLimit: getEthAmountForDecimals(data.withdrawableUntilLimit, collAsset.decimals),
91
+ withdrawable: getEthAmountForDecimals(data.withdrawable, collAsset.decimals),
92
+ borrowLimit: getEthAmountForDecimals(data.borrowLimit, debtAsset.decimals),
93
+ borrowableUntilLimit: getEthAmountForDecimals(data.borrowableUntilLimit, debtAsset.decimals),
94
+ borrowable: getEthAmountForDecimals(data.borrowable, debtAsset.decimals),
95
+ borrowLimitUtilization: getEthAmountForDecimals(data.borrowLimitUtilization, debtAsset.decimals),
96
+ maxBorrowLimit: getEthAmountForDecimals(data.maxBorrowLimit, debtAsset.decimals),
97
+ baseBorrowLimit: getEthAmountForDecimals(data.baseBorrowLimit, debtAsset.decimals),
98
+ minimumBorrowing: getEthAmountForDecimals(data.minimumBorrowing, debtAsset.decimals),
99
+ };
100
+
101
+ return {
102
+ assetsData,
103
+ marketData,
104
+ } as FluidMarketData;
105
+ };
106
+
107
+ export const EMPTY_FLUID_DATA = {
108
+ usedAssets: {},
109
+ suppliedUsd: '0',
110
+ borrowedUsd: '0',
111
+ borrowLimitUsd: '0',
112
+ leftToBorrowUsd: '0',
113
+ ratio: '0',
114
+ minRatio: '0',
115
+ netApy: '0',
116
+ incentiveUsd: '0',
117
+ totalInterestUsd: '0',
118
+ isSubscribedToAutomation: false,
119
+ automationResubscribeRequired: false,
120
+ lastUpdated: Date.now(),
121
+ };
122
+
123
+ const parseUserData = (userPositionData: FluidView.UserPositionStructOutputStruct, vaultData: FluidMarketData): FluidVaultData => {
124
+ const {
125
+ assetsData,
126
+ marketData,
127
+ } = vaultData;
128
+
129
+ const payload = {
130
+ owner: userPositionData.owner,
131
+ vaultId: marketData.vaultId,
132
+ ...EMPTY_FLUID_DATA,
133
+ lastUpdated: Date.now(),
134
+ };
135
+ const collAsset = getAssetInfo(marketData.collAsset0);
136
+ const debtAsset = getAssetInfo(marketData.debtAsset0);
137
+
138
+ const supplied = getEthAmountForDecimals(userPositionData.supply, collAsset.decimals);
139
+ const borrowed = getEthAmountForDecimals(userPositionData.borrow, debtAsset.decimals);
140
+
141
+ const collUsedAsset: FluidUsedAsset = {
142
+ ...EMPTY_USED_ASSET,
143
+ symbol: collAsset.symbol,
144
+ collateral: true,
145
+ supplied,
146
+ suppliedUsd: new Dec(supplied).mul(assetsData[collAsset.symbol].price).toString(),
147
+ isSupplied: new Dec(supplied).gt(0),
148
+ };
149
+
150
+ const debtUsedAsset: FluidUsedAsset = {
151
+ ...EMPTY_USED_ASSET,
152
+ symbol: debtAsset.symbol,
153
+ collateral: false,
154
+ borrowed,
155
+ borrowedUsd: new Dec(borrowed).mul(assetsData[debtAsset.symbol].price).toString(),
156
+ isBorrowed: new Dec(borrowed).gt(0),
157
+ };
158
+
159
+ const usedAssets: FluidUsedAssets = {
160
+ [collAsset.symbol]: collUsedAsset,
161
+ [debtAsset.symbol]: debtUsedAsset,
162
+ };
163
+
164
+ return {
165
+ ...payload,
166
+ usedAssets,
167
+ ...(getFluidAggregatedData({
168
+ usedAssets,
169
+ assetsData,
170
+ marketData,
171
+ }) as FluidAggregatedVaultData),
172
+ };
173
+ };
174
+
175
+ export const getFluidMarketData = async (web3: Web3, network: NetworkNumber, market: FluidMarketInfo) => {
176
+ const view = FluidViewContract(web3, network);
177
+
178
+ const data = await view.methods.getVaultData(market.marketAddress).call();
179
+
180
+ return parseMarketData(data);
181
+ };
182
+
183
+ export const getFluidVaultIdsForUser = async (web3: Web3,
184
+ network:NetworkNumber,
185
+ user: EthAddress): Promise<string[]> => {
186
+ const view = FluidViewContract(web3, network);
187
+
188
+ return view.methods.getUserNftIds(user).call();
189
+ };
190
+
191
+
192
+ export const getFluidPosition = async (
193
+ web3: Web3,
194
+ network: NetworkNumber,
195
+ vaultId: string,
196
+ extractedState: {
197
+ assetsData: FluidAssetsData
198
+ marketData: InnerFluidMarketData,
199
+ },
200
+ ): Promise<FluidVaultData> => {
201
+ const view = FluidViewContract(web3, network);
202
+
203
+ const data = await view.methods.getPositionByNftId(vaultId).call();
204
+
205
+ const userPositionData = data[0];
206
+
207
+ return parseUserData(userPositionData, extractedState);
208
+ };
209
+
210
+ export const getFluidPositionWithMarket = async (web3: Web3, network: NetworkNumber, vaultId: string) => {
211
+ const view = FluidViewContract(web3, network);
212
+ const data = await view.methods.getPositionByNftId(vaultId).call();
213
+ const marketData = parseMarketData(data.vault);
214
+ const userData = parseUserData(data.position, marketData);
215
+
216
+ return {
217
+ userData,
218
+ marketData,
219
+ };
220
+ };
@@ -0,0 +1,54 @@
1
+ import Dec from 'decimal.js';
2
+ import {
3
+ FluidAggregatedVaultData,
4
+ FluidAssetsData,
5
+ FluidUsedAssets,
6
+ InnerFluidMarketData,
7
+ } from '../../types';
8
+ import { calcLeverageLiqPrice, getAssetsTotal, isLeveragedPos } from '../../moneymarket';
9
+ import { calculateNetApy } from '../../staking';
10
+ import { MMAssetsData } from '../../types/common';
11
+
12
+ export const getFluidAggregatedData = ({
13
+ usedAssets,
14
+ assetsData,
15
+ marketData,
16
+ }: {
17
+ usedAssets: FluidUsedAssets,
18
+ marketData: InnerFluidMarketData,
19
+ assetsData: FluidAssetsData
20
+ }): FluidAggregatedVaultData => {
21
+ const payload = {} as FluidAggregatedVaultData;
22
+ payload.suppliedUsd = getAssetsTotal(usedAssets, ({ isSupplied }: { isSupplied: boolean }) => isSupplied, ({ suppliedUsd }: { suppliedUsd: string }) => suppliedUsd);
23
+ payload.borrowedUsd = getAssetsTotal(usedAssets, ({ isBorrowed }: { isBorrowed: boolean }) => isBorrowed, ({ borrowedUsd }: { borrowedUsd: string }) => borrowedUsd);
24
+
25
+ const { netApy, incentiveUsd, totalInterestUsd } = calculateNetApy({ usedAssets, assetsData: assetsData as unknown as MMAssetsData });
26
+ payload.netApy = netApy;
27
+ payload.incentiveUsd = incentiveUsd;
28
+ payload.totalInterestUsd = totalInterestUsd;
29
+ const collFactor = marketData.collFactor;
30
+ const liqRatio = marketData.liquidationRatio;
31
+
32
+ payload.borrowLimitUsd = new Dec(payload.suppliedUsd).mul(collFactor).toString();
33
+ payload.liquidationLimitUsd = new Dec(payload.suppliedUsd).mul(liqRatio).div(100).toString();
34
+ const leftToBorrowUsd = new Dec(payload.borrowLimitUsd).sub(payload.borrowedUsd);
35
+ payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
36
+ payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
37
+ payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
38
+
39
+ const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
40
+
41
+ payload.leveragedType = leveragedType;
42
+ if (leveragedType !== '') {
43
+ payload.leveragedAsset = leveragedAsset;
44
+ let assetPrice = assetsData[leveragedAsset].price;
45
+ if (leveragedType === 'lsd-leverage') {
46
+ // Treat ETH like a stablecoin in a long stETH position
47
+ payload.leveragedLsdAssetRatio = new Dec(assetsData[leveragedAsset].price).div(assetsData.ETH.price).toDP(18).toString();
48
+ assetPrice = new Dec(assetPrice).div(assetsData.ETH.price).toString();
49
+ }
50
+ payload.liquidationPrice = calcLeverageLiqPrice(leveragedType, assetPrice, payload.borrowedUsd, payload.liquidationLimitUsd);
51
+ }
52
+
53
+ return payload;
54
+ };
@@ -6,4 +6,6 @@ export * as makerHelpers from './makerHelpers';
6
6
  export * as chickenBondsHelpers from './chickenBondsHelpers';
7
7
  export * as morphoBlueHelpers from './morphoBlueHelpers';
8
8
  export * as llamaLendHelpers from './llamaLendHelpers';
9
- export * as eulerV2Helpers from './eulerHelpers';
9
+ export * as liquityV2Helpers from './liquityV2Helpers';
10
+ export * as eulerV2Helpers from './eulerHelpers';
11
+ export * as fluidHelpers from './fluidHelpers';
@@ -0,0 +1,80 @@
1
+ import Dec from 'decimal.js';
2
+ import { calcLeverageLiqPrice, getAssetsTotal, isLeveragedPos } from '../../moneymarket';
3
+ import {
4
+ LiquityV2AggregatedTroveData, LiquityV2AssetsData, LiquityV2UsedAsset, LiquityV2UsedAssets,
5
+ } from '../../types';
6
+ import { calculateInterestEarned } from '../../staking';
7
+
8
+ export const calculateNetApyLiquityV2 = (usedAssets: LiquityV2UsedAssets, assetsData: LiquityV2AssetsData, interestRate: string) => {
9
+ const sumValues = Object.values(usedAssets).reduce((_acc, usedAsset) => {
10
+ const acc = { ..._acc };
11
+ const assetData = assetsData[usedAsset.symbol];
12
+
13
+ if (usedAsset.suppliedUsd) {
14
+ const amount = usedAsset.suppliedUsd;
15
+ acc.suppliedUsd = new Dec(acc.suppliedUsd).add(amount).toString();
16
+ if (assetData.incentiveSupplyApy) {
17
+ const incentiveInterest = calculateInterestEarned(amount, assetData.incentiveSupplyApy, 'year', true);
18
+ acc.incentiveUsd = new Dec(acc.incentiveUsd).add(incentiveInterest).toString();
19
+ }
20
+ }
21
+
22
+ if (usedAsset.borrowedUsd) {
23
+ const amount = usedAsset.borrowedUsd;
24
+ acc.borrowedUsd = new Dec(acc.borrowedUsd).add(amount).toString();
25
+ const rate = interestRate;
26
+ const borrowInterest = calculateInterestEarned(amount, rate as string, 'year', true);
27
+ acc.borrowInterest = new Dec(acc.borrowInterest).sub(borrowInterest.toString()).toString();
28
+ }
29
+
30
+ return acc;
31
+ }, {
32
+ borrowInterest: '0', supplyInterest: '0', incentiveUsd: '0', borrowedUsd: '0', suppliedUsd: '0',
33
+ });
34
+
35
+ const {
36
+ borrowedUsd, suppliedUsd, borrowInterest, supplyInterest, incentiveUsd,
37
+ } = sumValues;
38
+
39
+ const totalInterestUsd = new Dec(borrowInterest).add(supplyInterest).add(incentiveUsd).toString();
40
+ const balance = new Dec(suppliedUsd).sub(borrowedUsd);
41
+ const netApy = new Dec(totalInterestUsd).div(balance).times(100).toString();
42
+
43
+ return { netApy, totalInterestUsd, incentiveUsd };
44
+ };
45
+
46
+ export const getLiquityV2AggregatedPositionData = ({
47
+ usedAssets,
48
+ assetsData,
49
+ minCollRatio,
50
+ interestRate,
51
+ }: {
52
+ usedAssets: LiquityV2UsedAssets
53
+ assetsData: LiquityV2AssetsData
54
+ minCollRatio: string
55
+ interestRate: string
56
+ }): LiquityV2AggregatedTroveData => {
57
+ const payload = {} as LiquityV2AggregatedTroveData;
58
+ payload.suppliedUsd = getAssetsTotal(usedAssets, (usedAsset: LiquityV2UsedAsset) => usedAsset, ({ suppliedUsd }: { suppliedUsd: string }) => suppliedUsd);
59
+ payload.borrowedUsd = getAssetsTotal(usedAssets, (usedAsset: LiquityV2UsedAsset) => usedAsset, ({ borrowedUsd }: { borrowedUsd: string }) => borrowedUsd);
60
+ payload.borrowLimitUsd = new Dec(payload.suppliedUsd).div(minCollRatio).mul(100).toString();
61
+ const leftToBorrowUsd = new Dec(payload.borrowLimitUsd).sub(payload.borrowedUsd);
62
+ payload.leftToBorrowUsd = leftToBorrowUsd.lte('0') ? '0' : leftToBorrowUsd.toString();
63
+ payload.ratio = +payload.suppliedUsd ? new Dec(payload.borrowLimitUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
64
+ payload.collRatio = +payload.suppliedUsd ? new Dec(payload.suppliedUsd).div(payload.borrowedUsd).mul(100).toString() : '0';
65
+ const { netApy, incentiveUsd, totalInterestUsd } = calculateNetApyLiquityV2(usedAssets, assetsData, interestRate);
66
+ payload.netApy = netApy;
67
+ payload.incentiveUsd = incentiveUsd;
68
+ payload.totalInterestUsd = totalInterestUsd;
69
+
70
+ const { leveragedType, leveragedAsset } = isLeveragedPos(usedAssets);
71
+ payload.leveragedType = leveragedType;
72
+ payload.leveragedAsset = leveragedAsset;
73
+ payload.liquidationPrice = '';
74
+ if (leveragedType !== '') {
75
+ const assetPrice = assetsData[leveragedAsset].price;
76
+ payload.liquidationPrice = calcLeverageLiqPrice(leveragedType, assetPrice, payload.borrowedUsd, payload.borrowLimitUsd);
77
+ }
78
+
79
+ return payload;
80
+ };
package/src/index.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import './setup';
2
2
 
3
+ import * as fluid from './fluid';
3
4
  import * as aaveV3 from './aaveV3';
4
5
  import * as morphoAaveV3 from './morphoAaveV3';
5
6
  import * as aaveV2 from './aaveV2';
@@ -9,6 +10,7 @@ import * as compoundV2 from './compoundV2';
9
10
  import * as spark from './spark';
10
11
  import * as curveUsd from './curveUsd';
11
12
  import * as liquity from './liquity';
13
+ import * as liquityV2 from './liquityV2';
12
14
  import * as maker from './maker';
13
15
  import * as staking from './staking';
14
16
  import * as multicall from './multicall';
@@ -34,6 +36,7 @@ export {
34
36
  spark,
35
37
  curveUsd,
36
38
  liquity,
39
+ liquityV2,
37
40
  maker,
38
41
  chickenBonds,
39
42
  exchange,
@@ -45,4 +48,5 @@ export {
45
48
  morphoBlue,
46
49
  llamaLend,
47
50
  eulerV2,
51
+ fluid,
48
52
  };
@@ -0,0 +1,228 @@
1
+ import Web3 from 'web3';
2
+ import Dec from 'decimal.js';
3
+ import { assetAmountInEth, getAssetInfo } from '@defisaver/tokens';
4
+ import { createContractWrapper, LiquityV2ViewContract } from '../contracts';
5
+ import { EthAddress, NetworkNumber } from '../types/common';
6
+ import {
7
+ InnerLiquityV2MarketData,
8
+ LIQUITY_V2_TROVE_STATUS_ENUM,
9
+ LiquityV2AssetsData, LiquityV2MarketData, LiquityV2MarketInfo, LiquityV2TroveData, LiquityV2UsedAssets,
10
+ } from '../types';
11
+ import { getStakingApy, STAKING_ASSETS } from '../staking';
12
+ import { getLiquityV2AggregatedPositionData } from '../helpers/liquityV2Helpers';
13
+ import { addToObjectIf, compareAddresses, ethToWeth } from '../services/utils';
14
+ import { LiquityV2View } from '../types/contracts/generated';
15
+ import { ZERO_ADDRESS } from '../constants';
16
+
17
+
18
+ export const getLiquityV2MarketData = async (web3: Web3, network: NetworkNumber, selectedMarket: LiquityV2MarketInfo, mainnetWeb3: Web3): Promise<LiquityV2MarketData> => {
19
+ const viewContract = LiquityV2ViewContract(web3, network);
20
+ const { marketAddress, debtToken, collateralToken } = selectedMarket;
21
+ const data = await viewContract.methods.getMarketData(marketAddress).call();
22
+ const hintHelperAddress = data.hintHelpers;
23
+ const troveNFTAddress = data.troveNFT;
24
+ const borrowerOperationsAddress = data.borrowerOperations;
25
+ const troveManagerAddress = data.troveManager;
26
+ const stabilityPoolAddress = data.stabilityPool;
27
+ const collSurplusPoolAddress = data.collSurplusPool;
28
+ const activePoolAddress = data.activePool;
29
+
30
+ const minCollRatio = new Dec(data.MCR).div(1e16).toString();
31
+ const criticalCollRatio = new Dec(data.CCR).div(1e18).toString();
32
+
33
+ const totalMarketBorrow = assetAmountInEth(data.entireSystemDebt);
34
+ const totalMarketSupply = assetAmountInEth(data.entireSystemColl);
35
+ const collPrice = assetAmountInEth(data.collPrice);
36
+
37
+ const totalCollRatio = new Dec(totalMarketSupply).mul(collPrice).div(totalMarketBorrow).toString();
38
+ const leftToBorrowGlobal = new Dec(totalMarketSupply).mul(collPrice).div(criticalCollRatio).sub(totalMarketBorrow)
39
+ .toString();
40
+ const minCollAmountForCurrentBorrow = new Dec(totalMarketBorrow).mul(criticalCollRatio).div(collPrice).toString();
41
+ const leftToWithdrawGlobal = new Dec(totalMarketSupply).sub(minCollAmountForCurrentBorrow).toString();
42
+
43
+ const assetsData: LiquityV2AssetsData = {};
44
+ assetsData[debtToken] = {
45
+ symbol: debtToken,
46
+ address: getAssetInfo(debtToken, network).address,
47
+ price: '1',
48
+ totalSupply: '0',
49
+ totalBorrow: totalMarketBorrow,
50
+ canBeSupplied: false,
51
+ canBeBorrowed: true,
52
+ leftToBorrowGlobal,
53
+ leftToWithdrawGlobal: '0',
54
+ };
55
+ assetsData[collateralToken] = {
56
+ symbol: collateralToken,
57
+ address: getAssetInfo(ethToWeth(collateralToken), network).address,
58
+ price: collPrice,
59
+ totalSupply: totalMarketSupply,
60
+ totalBorrow: '0',
61
+ canBeSupplied: true,
62
+ canBeBorrowed: false,
63
+ leftToBorrowGlobal: '0',
64
+ leftToWithdrawGlobal,
65
+ };
66
+ if (STAKING_ASSETS.includes(collateralToken)) {
67
+ assetsData[collateralToken].incentiveSupplyApy = await getStakingApy(collateralToken, mainnetWeb3);
68
+ assetsData[collateralToken].incentiveSupplyToken = collateralToken;
69
+ }
70
+
71
+ return {
72
+ assetsData,
73
+ marketData: {
74
+ minCollRatio,
75
+ totalCollRatio: new Dec(totalCollRatio).mul(100).toString(),
76
+ criticalCollRatio: new Dec(criticalCollRatio).mul(100).toString(),
77
+ isUnderCollateralized: new Dec(totalCollRatio).lt(criticalCollRatio),
78
+ hintHelperAddress,
79
+ troveNFTAddress,
80
+ borrowerOperationsAddress,
81
+ troveManagerAddress,
82
+ stabilityPoolAddress,
83
+ collSurplusPoolAddress,
84
+ activePoolAddress,
85
+ },
86
+ };
87
+ };
88
+
89
+ const _getUserTroves = async (viewContract: any, account: EthAddress, marketAddress: EthAddress, startIndex = 0, endIndex = 100) => viewContract.methods.getUserTroves(account, marketAddress, startIndex, endIndex).call();
90
+
91
+ const getUserTroves = async (viewContract: any, account: EthAddress, marketAddress: EthAddress, startIndex = 0, endIndex = 100, troves: LiquityV2View.ExistingTroveStructOutput[] = []): Promise<{ troves: LiquityV2View.ExistingTroveStructOutput[], nextFreeTroveIndex: string }> => {
92
+ const result = await _getUserTroves(viewContract, account, marketAddress, startIndex, endIndex);
93
+ const newStartIndex = endIndex + 1;
94
+ const nextFreeTroveIndex = result.nextFreeTroveIndex;
95
+ const existingTroves = [...troves, ...result.troves];
96
+ if (nextFreeTroveIndex !== '-1') return { troves: existingTroves.filter((trove) => trove.ownedByUser), nextFreeTroveIndex };
97
+ return getUserTroves(viewContract, account, marketAddress, newStartIndex, newStartIndex + 100, existingTroves);
98
+ };
99
+
100
+ const TransferEventSig = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef';
101
+
102
+ const nftContractCreationBlockMapping = {
103
+ ETH: 21686215,
104
+ wstETH: 21686238,
105
+ rETH: 21686257,
106
+ };
107
+
108
+ const getTransferredTroves = async (web3: Web3, network: NetworkNumber, troveNFTAddress: EthAddress, limitBlocksForEventFetching: boolean, collAsset: string, account: EthAddress): Promise<{ troveId: string }[]> => {
109
+ const nftContract = createContractWrapper(web3, network, 'LiquityV2TroveNFT', troveNFTAddress);
110
+ // @ts-ignore
111
+ const nftContractCreationBlock = nftContractCreationBlockMapping[collAsset];
112
+ const currentBlock = await web3.eth.getBlockNumber();
113
+ const events = await nftContract.getPastEvents(
114
+ TransferEventSig,
115
+ {
116
+ filter: { to: account },
117
+ fromBlock: limitBlocksForEventFetching ? (currentBlock - 1000) : nftContractCreationBlock,
118
+ },
119
+ );
120
+ const userTransferredTroves = events.filter((event) => !compareAddresses(event.returnValues.from, ZERO_ADDRESS) && compareAddresses(event.returnValues.to, account));
121
+
122
+ // check if the last know transfer address is the user
123
+ userTransferredTroves.forEach((event, index) => {
124
+ const otherTransfers = events.filter((e) => event.blockNumber < e.blockNumber && e.returnValues.tokenId === event.returnValues.tokenId);
125
+ // @ts-ignore
126
+ userTransferredTroves[index].invalid = !!otherTransfers.length;
127
+ });
128
+ // @ts-ignore
129
+ return userTransferredTroves.filter((event) => !event.invalid).map((event) => ({ troveId: event.returnValues.tokenId }));
130
+ };
131
+
132
+ export const getLiquityV2UserTroveIds = async (web3: Web3, network: NetworkNumber, selectedMarket: LiquityV2MarketInfo, troveNFTAddress: EthAddress, limitBlocksForEventFetching: boolean, account: EthAddress): Promise<{ troves: { troveId: string }[], nextFreeTroveIndex: string }> => {
133
+ const viewContract = LiquityV2ViewContract(web3, network);
134
+ const [{ troves: userTroves, nextFreeTroveIndex }, userTransferredTroves] = await Promise.all([
135
+ getUserTroves(viewContract, account, selectedMarket.marketAddress),
136
+ getTransferredTroves(web3, network, troveNFTAddress, limitBlocksForEventFetching, selectedMarket.collateralToken, account),
137
+ ]);
138
+ const troves = [...userTroves.map(({ troveId }) => ({ troveId })), ...userTransferredTroves];
139
+ const filteredTroves = troves.filter((value, index, self) => index === self.findIndex((t) => (
140
+ t.troveId === value.troveId
141
+ )),
142
+ );
143
+ return { troves: filteredTroves, nextFreeTroveIndex };
144
+ };
145
+
146
+ const _getDebtInFront = async (viewContract: any, marketAddress: EthAddress, troveId: string, accumulatedSum = '0', iterations = 2000) => viewContract.methods.getDebtInFront(marketAddress, troveId, accumulatedSum, iterations).call();
147
+
148
+ export const getDebtInFrontLiquityV2 = async (viewContract: any, marketAddress: EthAddress, troveId: string, accumulatedSum = '0', iterations = 2000): Promise<string> => {
149
+ const { debt, next } = await _getDebtInFront(viewContract, marketAddress, troveId, accumulatedSum, iterations);
150
+ if (next === '0') return assetAmountInEth(debt);
151
+ return getDebtInFrontLiquityV2(viewContract, marketAddress, next, debt, iterations);
152
+ };
153
+
154
+ export const getLiquityV2TroveData = async (
155
+ web3: Web3,
156
+ network: NetworkNumber,
157
+ {
158
+ selectedMarket,
159
+ assetsData,
160
+ marketData,
161
+ troveId,
162
+ }:
163
+ {
164
+ selectedMarket: LiquityV2MarketInfo,
165
+ assetsData: LiquityV2AssetsData,
166
+ marketData: InnerLiquityV2MarketData,
167
+ troveId: string
168
+ },
169
+ ): Promise<LiquityV2TroveData> => {
170
+ const viewContract = LiquityV2ViewContract(web3, network);
171
+ const { minCollRatio } = marketData;
172
+ const { collateralToken, marketAddress, debtToken } = selectedMarket;
173
+ const [data, debtInFront] = await Promise.all([
174
+ viewContract.methods.getTroveInfo(marketAddress, troveId).call(),
175
+ getDebtInFrontLiquityV2(viewContract, marketAddress, troveId),
176
+ ]);
177
+ const usedAssets: LiquityV2UsedAssets = {};
178
+
179
+ const debtAssetData = assetsData[debtToken];
180
+ const borrowed = assetAmountInEth(data.debtAmount);
181
+ usedAssets[debtToken] = {
182
+ symbol: debtToken,
183
+ supplied: '0',
184
+ suppliedUsd: '0',
185
+ borrowed,
186
+ borrowedUsd: new Dec(borrowed).mul(debtAssetData.price).toString(),
187
+ isBorrowed: true,
188
+ isSupplied: false,
189
+ };
190
+
191
+ const collAssetData = assetsData[collateralToken];
192
+ const suppliedColl = assetAmountInEth(data.collAmount);
193
+ usedAssets[collateralToken] = {
194
+ symbol: collateralToken,
195
+ supplied: suppliedColl,
196
+ suppliedUsd: new Dec(suppliedColl).mul(collAssetData.price).toString(),
197
+ borrowed: '0',
198
+ borrowedUsd: '0',
199
+ isBorrowed: false,
200
+ isSupplied: true,
201
+ collateral: true,
202
+ };
203
+
204
+ const collRatio = new Dec(data.TCRatio).div(1e16).toString();
205
+ const interestRate = new Dec(data.annualInterestRate).div(1e16).toString();
206
+ const interestBatchManager = data.interestBatchManager;
207
+
208
+ const payload: LiquityV2TroveData = {
209
+ usedAssets,
210
+ troveId,
211
+ interestRate,
212
+ interestBatchManager,
213
+ debtInFront,
214
+ troveStatus: LIQUITY_V2_TROVE_STATUS_ENUM[parseInt(data.status, 10)],
215
+ ...getLiquityV2AggregatedPositionData({
216
+ usedAssets, assetsData, minCollRatio, interestRate,
217
+ }),
218
+ collRatio,
219
+ };
220
+
221
+ return payload;
222
+ };
223
+
224
+ export const getLiquityV2ClaimableCollateral = async (collSurplusPoolAddress: EthAddress, account: EthAddress, web3: Web3, network: NetworkNumber): Promise<string> => {
225
+ const collSurplusPoolContract = createContractWrapper(web3, network, 'LiquityV2CollSurplusPool', collSurplusPoolAddress);
226
+ const claimableCollateral = await collSurplusPoolContract.methods.getCollateral(account).call();
227
+ return claimableCollateral;
228
+ };
@@ -11,7 +11,7 @@ export const morphoAaveV2AssetDefaultMarket = ['DAI', 'ETH', 'USDC', 'USDT', 'WB
11
11
 
12
12
  export const morphoAaveV3AssetEthMarket = ['ETH', 'wstETH', 'DAI', 'USDC', 'WBTC', 'rETH', 'cbETH', 'sDAI', 'USDT'];
13
13
 
14
- export const aaveV3AssetsDefaultMarketEth = ['ETH', 'wstETH', 'WBTC', 'USDC', 'DAI', 'LINK', 'AAVE', 'cbETH', 'USDT', 'rETH', 'LUSD', 'CRV', 'MKR', 'SNX', 'BAL', 'UNI', 'LDO', 'ENS', '1INCH', 'FRAX', 'GHO', 'RPL', 'sDAI', 'STG', 'KNC', 'FXS', 'crvUSD', 'PYUSD', 'weETH', 'osETH', 'USDe', 'ETHx', 'sUSDe', 'tBTC', 'cbBTC', 'USDS', 'rsETH'];
14
+ export const aaveV3AssetsDefaultMarketEth = ['ETH', 'wstETH', 'WBTC', 'USDC', 'DAI', 'LINK', 'AAVE', 'cbETH', 'USDT', 'rETH', 'LUSD', 'CRV', 'MKR', 'SNX', 'BAL', 'UNI', 'LDO', 'ENS', '1INCH', 'FRAX', 'GHO', 'RPL', 'sDAI', 'STG', 'KNC', 'FXS', 'crvUSD', 'PYUSD', 'weETH', 'osETH', 'USDe', 'ETHx', 'sUSDe', 'tBTC', 'cbBTC', 'USDS', 'rsETH', 'LBTC'];
15
15
  export const aaveV3AssetsDefaultMarketOpt = [
16
16
  'DAI', 'USDC.e', 'USDT', 'SUSD', 'AAVE', 'LINK', 'WBTC', 'ETH', 'OP', 'wstETH', 'LUSD', 'MAI', 'rETH', 'USDC',
17
17
  ];