@defisaver/positions-sdk 0.0.181 → 0.0.183-dev-allocator
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.
- package/cjs/aaveV3/index.js +7 -3
- package/cjs/config/contracts.d.ts +3 -0
- package/cjs/config/contracts.js +3 -0
- package/cjs/helpers/aaveHelpers/index.js +0 -1
- package/cjs/helpers/morphoBlueHelpers/index.d.ts +5 -0
- package/cjs/helpers/morphoBlueHelpers/index.js +127 -1
- package/cjs/staking/staking.d.ts +2 -3
- package/cjs/staking/staking.js +2 -2
- package/cjs/types/aave.d.ts +1 -0
- package/cjs/types/morphoBlue.d.ts +25 -0
- package/esm/aaveV3/index.js +8 -4
- package/esm/config/contracts.d.ts +3 -0
- package/esm/config/contracts.js +3 -0
- package/esm/helpers/aaveHelpers/index.js +0 -1
- package/esm/helpers/morphoBlueHelpers/index.d.ts +5 -0
- package/esm/helpers/morphoBlueHelpers/index.js +124 -0
- package/esm/staking/staking.d.ts +2 -3
- package/esm/staking/staking.js +2 -2
- package/esm/types/aave.d.ts +1 -0
- package/esm/types/morphoBlue.d.ts +25 -0
- package/package.json +1 -1
- package/src/aaveV3/index.ts +8 -8
- package/src/config/contracts.js +3 -0
- package/src/helpers/aaveHelpers/index.ts +0 -1
- package/src/helpers/morphoBlueHelpers/index.ts +142 -1
- package/src/staking/staking.ts +2 -4
- package/src/types/aave.ts +1 -0
- package/src/types/morphoBlue.ts +23 -0
package/cjs/aaveV3/index.js
CHANGED
|
@@ -104,7 +104,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
104
104
|
params: [],
|
|
105
105
|
},
|
|
106
106
|
{
|
|
107
|
-
target: (0, tokens_1.getAssetInfo)('GHO').address,
|
|
107
|
+
target: (0, tokens_1.getAssetInfo)('GHO', network).address,
|
|
108
108
|
abiItem: (0, utils_1.getAbiItem)(GhoTokenAbi, 'getFacilitatorsList'),
|
|
109
109
|
params: [],
|
|
110
110
|
},
|
|
@@ -148,7 +148,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
148
148
|
const assetsData = yield Promise.all(loanInfo
|
|
149
149
|
.map((tokenMarket, i) => __awaiter(this, void 0, void 0, function* () {
|
|
150
150
|
const symbol = market.assets[i];
|
|
151
|
-
const nativeAsset = symbol === 'GHO';
|
|
151
|
+
const nativeAsset = symbol === 'GHO' && network === common_1.NetworkNumber.Eth;
|
|
152
152
|
// eslint-disable-next-line guard-for-in
|
|
153
153
|
for (const eModeIndex in eModeCategoriesData) {
|
|
154
154
|
if ((0, utils_1.isEnabledOnBitmap)(Number(eModeCategoriesData[eModeIndex].collateralBitmap), Number(tokenMarket.assetId)))
|
|
@@ -198,6 +198,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
198
198
|
_market.supplyIncentives.push({
|
|
199
199
|
apy: _market.incentiveSupplyApy || '0',
|
|
200
200
|
token: _market.symbol,
|
|
201
|
+
incentiveKind: 'staking',
|
|
201
202
|
});
|
|
202
203
|
}
|
|
203
204
|
if (_market.canBeBorrowed && _market.incentiveSupplyApy) {
|
|
@@ -209,6 +210,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
209
210
|
_market.borrowIncentives.push({
|
|
210
211
|
apy: _market.incentiveBorrowApy,
|
|
211
212
|
token: _market.incentiveBorrowToken,
|
|
213
|
+
incentiveKind: 'reward',
|
|
212
214
|
});
|
|
213
215
|
}
|
|
214
216
|
if (!rewardForMarket)
|
|
@@ -238,6 +240,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
238
240
|
_market.supplyIncentives.push({
|
|
239
241
|
token: supplyRewardData.rewardTokenSymbol,
|
|
240
242
|
apy: rewardApy,
|
|
243
|
+
incentiveKind: 'reward',
|
|
241
244
|
});
|
|
242
245
|
}
|
|
243
246
|
});
|
|
@@ -265,6 +268,7 @@ function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
265
268
|
_market.borrowIncentives.push({
|
|
266
269
|
token: borrowRewardData.rewardTokenSymbol,
|
|
267
270
|
apy: rewardApy,
|
|
271
|
+
incentiveKind: 'reward',
|
|
268
272
|
});
|
|
269
273
|
}
|
|
270
274
|
});
|
|
@@ -419,7 +423,7 @@ const getAaveV3AccountData = (web3, network, address, extractedState) => __await
|
|
|
419
423
|
}
|
|
420
424
|
if (!usedAssets[asset])
|
|
421
425
|
usedAssets[asset] = {};
|
|
422
|
-
const nativeAsset = asset === 'GHO';
|
|
426
|
+
const nativeAsset = asset === 'GHO' && network === common_1.NetworkNumber.Eth;
|
|
423
427
|
let discountRateOnBorrow = '0';
|
|
424
428
|
const borrowed = new decimal_js_1.default(borrowedStable).add(borrowedVariable).toString();
|
|
425
429
|
if (nativeAsset && new decimal_js_1.default(borrowed).gt(0) && new decimal_js_1.default(stkAaveBalance).gt(0)) {
|
package/cjs/config/contracts.js
CHANGED
|
@@ -12,3 +12,8 @@ export declare const getApyAfterValuesEstimation: (selectedMarket: MorphoBlueMar
|
|
|
12
12
|
borrowRate: string;
|
|
13
13
|
supplyRate: string;
|
|
14
14
|
}>;
|
|
15
|
+
export declare const getReallocatableLiquidity: (marketId: string, network?: NetworkNumber) => Promise<string>;
|
|
16
|
+
export declare const getReallocation: (marketId: string, liquidityToAllocate: string, network?: NetworkNumber) => Promise<{
|
|
17
|
+
vaults: string[];
|
|
18
|
+
withdrawals: [string[], string][][];
|
|
19
|
+
}>;
|
|
@@ -12,13 +12,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.getApyAfterValuesEstimation = exports.getBorrowRate = exports.getSupplyRate = exports.getMorphoBlueAggregatedPositionData = void 0;
|
|
15
|
+
exports.getReallocation = exports.getReallocatableLiquidity = exports.getApyAfterValuesEstimation = exports.getBorrowRate = exports.getSupplyRate = exports.getMorphoBlueAggregatedPositionData = void 0;
|
|
16
16
|
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
17
17
|
const tokens_1 = require("@defisaver/tokens");
|
|
18
18
|
const moneymarket_1 = require("../../moneymarket");
|
|
19
19
|
const staking_1 = require("../../staking");
|
|
20
|
+
const common_1 = require("../../types/common");
|
|
20
21
|
const constants_1 = require("../../constants");
|
|
21
22
|
const contracts_1 = require("../../contracts");
|
|
23
|
+
const utils_1 = require("../../services/utils");
|
|
22
24
|
const getMorphoBlueAggregatedPositionData = ({ usedAssets, assetsData, marketInfo }) => {
|
|
23
25
|
var _a, _b, _c, _d, _e, _f;
|
|
24
26
|
const payload = {};
|
|
@@ -110,3 +112,127 @@ const getApyAfterValuesEstimation = (selectedMarket, action, amount, asset, web3
|
|
|
110
112
|
return { borrowRate, supplyRate };
|
|
111
113
|
});
|
|
112
114
|
exports.getApyAfterValuesEstimation = getApyAfterValuesEstimation;
|
|
115
|
+
const API_URL = 'https://blue-api.morpho.org/graphql';
|
|
116
|
+
const MARKET_QUERY = `
|
|
117
|
+
query MarketByUniqueKey($uniqueKey: String!, $chainId: Int!) {
|
|
118
|
+
marketByUniqueKey(uniqueKey: $uniqueKey, chainId: $chainId) {
|
|
119
|
+
reallocatableLiquidityAssets
|
|
120
|
+
loanAsset {
|
|
121
|
+
address
|
|
122
|
+
decimals
|
|
123
|
+
priceUsd
|
|
124
|
+
}
|
|
125
|
+
state {
|
|
126
|
+
liquidityAssets
|
|
127
|
+
}
|
|
128
|
+
publicAllocatorSharedLiquidity {
|
|
129
|
+
assets
|
|
130
|
+
vault {
|
|
131
|
+
address
|
|
132
|
+
name
|
|
133
|
+
}
|
|
134
|
+
allocationMarket {
|
|
135
|
+
uniqueKey
|
|
136
|
+
loanAsset {
|
|
137
|
+
address
|
|
138
|
+
}
|
|
139
|
+
collateralAsset {
|
|
140
|
+
address
|
|
141
|
+
}
|
|
142
|
+
irmAddress
|
|
143
|
+
oracle {
|
|
144
|
+
address
|
|
145
|
+
}
|
|
146
|
+
lltv
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
loanAsset {
|
|
150
|
+
address
|
|
151
|
+
}
|
|
152
|
+
collateralAsset {
|
|
153
|
+
address
|
|
154
|
+
}
|
|
155
|
+
oracle {
|
|
156
|
+
address
|
|
157
|
+
}
|
|
158
|
+
irmAddress
|
|
159
|
+
lltv
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
`;
|
|
163
|
+
const getReallocatableLiquidity = (marketId, network = common_1.NetworkNumber.Eth) => __awaiter(void 0, void 0, void 0, function* () {
|
|
164
|
+
var _a;
|
|
165
|
+
const response = yield fetch(API_URL, {
|
|
166
|
+
method: 'POST',
|
|
167
|
+
headers: { 'Content-Type': 'application/json' },
|
|
168
|
+
body: JSON.stringify({
|
|
169
|
+
query: MARKET_QUERY,
|
|
170
|
+
variables: { uniqueKey: marketId, chainId: network },
|
|
171
|
+
}),
|
|
172
|
+
});
|
|
173
|
+
const data = yield response.json();
|
|
174
|
+
const marketData = (_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.marketByUniqueKey;
|
|
175
|
+
if (!marketData)
|
|
176
|
+
throw new Error('Market data not found');
|
|
177
|
+
return marketData.reallocatableLiquidityAssets;
|
|
178
|
+
});
|
|
179
|
+
exports.getReallocatableLiquidity = getReallocatableLiquidity;
|
|
180
|
+
const getReallocation = (marketId, liquidityToAllocate, network = common_1.NetworkNumber.Eth) => __awaiter(void 0, void 0, void 0, function* () {
|
|
181
|
+
var _b, _c, _d;
|
|
182
|
+
const response = yield fetch(API_URL, {
|
|
183
|
+
method: 'POST',
|
|
184
|
+
headers: { 'Content-Type': 'application/json' },
|
|
185
|
+
body: JSON.stringify({
|
|
186
|
+
query: MARKET_QUERY,
|
|
187
|
+
variables: { uniqueKey: marketId, chainId: network },
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
190
|
+
const data = yield response.json();
|
|
191
|
+
const marketData = (_b = data === null || data === void 0 ? void 0 : data.data) === null || _b === void 0 ? void 0 : _b.marketByUniqueKey;
|
|
192
|
+
if (!marketData)
|
|
193
|
+
throw new Error('Market data not found');
|
|
194
|
+
if (new decimal_js_1.default(marketData.reallocatableLiquidityAssets).lt(liquidityToAllocate))
|
|
195
|
+
throw new Error('Not enough liquidity available to allocate');
|
|
196
|
+
const vaultTotalAssets = marketData.publicAllocatorSharedLiquidity.reduce((acc, item) => {
|
|
197
|
+
const vaultAddress = item.vault.address;
|
|
198
|
+
acc[vaultAddress] = new decimal_js_1.default(acc[vaultAddress] || '0').add(item.assets).toString();
|
|
199
|
+
return acc;
|
|
200
|
+
}, {});
|
|
201
|
+
const sortedVaults = Object.entries(vaultTotalAssets).sort(([, a], [, b]) => new decimal_js_1.default(b || '0').sub(a || '0').toNumber());
|
|
202
|
+
const withdrawalsPerVault = {};
|
|
203
|
+
let totalReallocated = '0';
|
|
204
|
+
for (const [vaultAddress] of sortedVaults) {
|
|
205
|
+
if (new decimal_js_1.default(totalReallocated).gte(liquidityToAllocate))
|
|
206
|
+
break;
|
|
207
|
+
const vaultAllocations = marketData.publicAllocatorSharedLiquidity.filter((item) => (0, utils_1.compareAddresses)(item.vault.address, vaultAddress));
|
|
208
|
+
for (const item of vaultAllocations) {
|
|
209
|
+
if (new decimal_js_1.default(totalReallocated).gte(liquidityToAllocate))
|
|
210
|
+
break;
|
|
211
|
+
const itemAmount = item.assets;
|
|
212
|
+
const leftToAllocate = new decimal_js_1.default(liquidityToAllocate).sub(totalReallocated).toString();
|
|
213
|
+
const amountToTake = new decimal_js_1.default(itemAmount).lt(leftToAllocate) ? itemAmount : leftToAllocate;
|
|
214
|
+
totalReallocated = new decimal_js_1.default(totalReallocated).add(amountToTake).toString();
|
|
215
|
+
const withdrawal = [
|
|
216
|
+
[
|
|
217
|
+
item.allocationMarket.loanAsset.address,
|
|
218
|
+
(_c = item.allocationMarket.collateralAsset) === null || _c === void 0 ? void 0 : _c.address,
|
|
219
|
+
(_d = item.allocationMarket.oracle) === null || _d === void 0 ? void 0 : _d.address,
|
|
220
|
+
item.allocationMarket.irmAddress,
|
|
221
|
+
item.allocationMarket.lltv,
|
|
222
|
+
],
|
|
223
|
+
amountToTake.toString(),
|
|
224
|
+
];
|
|
225
|
+
if (!withdrawalsPerVault[vaultAddress]) {
|
|
226
|
+
withdrawalsPerVault[vaultAddress] = [];
|
|
227
|
+
}
|
|
228
|
+
withdrawalsPerVault[vaultAddress].push(withdrawal);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const vaults = Object.keys(withdrawalsPerVault);
|
|
232
|
+
const withdrawals = vaults.map((vaultAddress) => withdrawalsPerVault[vaultAddress]);
|
|
233
|
+
return {
|
|
234
|
+
vaults,
|
|
235
|
+
withdrawals,
|
|
236
|
+
};
|
|
237
|
+
});
|
|
238
|
+
exports.getReallocation = getReallocation;
|
package/cjs/staking/staking.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Web3 from 'web3';
|
|
2
|
-
import { MMAssetsData, MMUsedAssets
|
|
2
|
+
import { MMAssetsData, MMUsedAssets } from '../types/common';
|
|
3
3
|
export declare const getStETHApy: (web3: Web3, fromBlock?: number, blockNumber?: 'latest' | number) => Promise<string>;
|
|
4
4
|
export declare const getCbETHApy: (web3: Web3, blockNumber?: 'latest' | number) => Promise<string>;
|
|
5
5
|
export declare const getREthApy: (web3: Web3, blockNumber?: 'latest' | number) => Promise<string>;
|
|
@@ -8,11 +8,10 @@ export declare const getSsrApy: () => Promise<string>;
|
|
|
8
8
|
export declare const STAKING_ASSETS: string[];
|
|
9
9
|
export declare const getStakingApy: (asset: string, web3: Web3, blockNumber?: 'latest' | number, fromBlock?: number | undefined) => "0" | Promise<any> | undefined;
|
|
10
10
|
export declare const calculateInterestEarned: (principal: string, interest: string, type: string, apy?: boolean) => number;
|
|
11
|
-
export declare const calculateNetApy: ({ usedAssets, assetsData, isMorpho
|
|
11
|
+
export declare const calculateNetApy: ({ usedAssets, assetsData, isMorpho }: {
|
|
12
12
|
usedAssets: MMUsedAssets;
|
|
13
13
|
assetsData: MMAssetsData;
|
|
14
14
|
isMorpho?: boolean | undefined;
|
|
15
|
-
network?: NetworkNumber | undefined;
|
|
16
15
|
}) => {
|
|
17
16
|
netApy: string;
|
|
18
17
|
totalInterestUsd: string;
|
package/cjs/staking/staking.js
CHANGED
|
@@ -170,7 +170,7 @@ const calculateInterestEarned = (principal, interest, type, apy = false) => {
|
|
|
170
170
|
return (+principal * (Math.pow(((1 + (+interest / 100) / constants_1.BLOCKS_IN_A_YEAR)), (constants_1.BLOCKS_IN_A_YEAR * interval)))) - +principal; // eslint-disable-line
|
|
171
171
|
};
|
|
172
172
|
exports.calculateInterestEarned = calculateInterestEarned;
|
|
173
|
-
const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false
|
|
173
|
+
const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }) => {
|
|
174
174
|
const sumValues = Object.values(usedAssets).reduce((_acc, usedAsset) => {
|
|
175
175
|
const acc = Object.assign({}, _acc);
|
|
176
176
|
const assetData = assetsData[usedAsset.symbol];
|
|
@@ -193,7 +193,7 @@ const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false, network = 1
|
|
|
193
193
|
acc.borrowedUsd = new decimal_js_1.default(acc.borrowedUsd).add(amount).toString();
|
|
194
194
|
const rate = isMorpho
|
|
195
195
|
? usedAsset.borrowRate === '0' ? assetData.borrowRateP2P : usedAsset.borrowRate
|
|
196
|
-
: (usedAsset.symbol === 'GHO' &&
|
|
196
|
+
: (usedAsset.symbol === 'GHO' && assetsData.nativeAsset)
|
|
197
197
|
? usedAsset.discountedBorrowRate
|
|
198
198
|
: ((usedAsset === null || usedAsset === void 0 ? void 0 : usedAsset.interestMode) === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
|
|
199
199
|
const borrowInterest = (0, exports.calculateInterestEarned)(amount, rate, 'year', true);
|
package/cjs/types/aave.d.ts
CHANGED
|
@@ -76,6 +76,7 @@ export interface MorphoAaveV2AssetData extends AaveV2AssetData {
|
|
|
76
76
|
export interface IncentiveData {
|
|
77
77
|
token: string;
|
|
78
78
|
apy: string;
|
|
79
|
+
incentiveKind?: 'staking' | 'reward';
|
|
79
80
|
}
|
|
80
81
|
export interface AaveV3AssetData extends AaveAssetData {
|
|
81
82
|
isIsolated: boolean;
|
|
@@ -137,3 +137,28 @@ export interface MorphoBluePositionData {
|
|
|
137
137
|
supplyShares: string;
|
|
138
138
|
borrowShares: string;
|
|
139
139
|
}
|
|
140
|
+
export interface MorphoBlueVault {
|
|
141
|
+
address: string;
|
|
142
|
+
}
|
|
143
|
+
export interface MorphoBlueAllocationMarket {
|
|
144
|
+
loanAsset: {
|
|
145
|
+
address: string;
|
|
146
|
+
};
|
|
147
|
+
collateralAsset: {
|
|
148
|
+
address: string;
|
|
149
|
+
};
|
|
150
|
+
oracle: {
|
|
151
|
+
address: string;
|
|
152
|
+
};
|
|
153
|
+
irmAddress: string;
|
|
154
|
+
lltv: string;
|
|
155
|
+
}
|
|
156
|
+
export interface MorphoBluePublicAllocatorItem {
|
|
157
|
+
vault: MorphoBlueVault;
|
|
158
|
+
assets: string;
|
|
159
|
+
allocationMarket: MorphoBlueAllocationMarket;
|
|
160
|
+
}
|
|
161
|
+
export interface MorphoBlueRealloactionMarketData {
|
|
162
|
+
reallocatableLiquidityAssets: string;
|
|
163
|
+
publicAllocatorSharedLiquidity: MorphoBluePublicAllocatorItem[];
|
|
164
|
+
}
|
package/esm/aaveV3/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { getStakingApy, STAKING_ASSETS } from '../staking';
|
|
|
16
16
|
import { multicall } from '../multicall';
|
|
17
17
|
import { getAssetsBalances } from '../assets';
|
|
18
18
|
import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
|
|
19
|
-
import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode
|
|
19
|
+
import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
|
|
20
20
|
import { AAVE_V3 } from '../markets/aave';
|
|
21
21
|
export const test = (web3, network) => {
|
|
22
22
|
const contract = AaveV3ViewContract(web3, 1);
|
|
@@ -95,7 +95,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
95
95
|
params: [],
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
|
-
target: getAssetInfo('GHO').address,
|
|
98
|
+
target: getAssetInfo('GHO', network).address,
|
|
99
99
|
abiItem: getAbiItem(GhoTokenAbi, 'getFacilitatorsList'),
|
|
100
100
|
params: [],
|
|
101
101
|
},
|
|
@@ -139,7 +139,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
139
139
|
const assetsData = yield Promise.all(loanInfo
|
|
140
140
|
.map((tokenMarket, i) => __awaiter(this, void 0, void 0, function* () {
|
|
141
141
|
const symbol = market.assets[i];
|
|
142
|
-
const nativeAsset = symbol === 'GHO';
|
|
142
|
+
const nativeAsset = symbol === 'GHO' && network === NetworkNumber.Eth;
|
|
143
143
|
// eslint-disable-next-line guard-for-in
|
|
144
144
|
for (const eModeIndex in eModeCategoriesData) {
|
|
145
145
|
if (isEnabledOnBitmap(Number(eModeCategoriesData[eModeIndex].collateralBitmap), Number(tokenMarket.assetId)))
|
|
@@ -189,6 +189,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
189
189
|
_market.supplyIncentives.push({
|
|
190
190
|
apy: _market.incentiveSupplyApy || '0',
|
|
191
191
|
token: _market.symbol,
|
|
192
|
+
incentiveKind: 'staking',
|
|
192
193
|
});
|
|
193
194
|
}
|
|
194
195
|
if (_market.canBeBorrowed && _market.incentiveSupplyApy) {
|
|
@@ -200,6 +201,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
200
201
|
_market.borrowIncentives.push({
|
|
201
202
|
apy: _market.incentiveBorrowApy,
|
|
202
203
|
token: _market.incentiveBorrowToken,
|
|
204
|
+
incentiveKind: 'reward',
|
|
203
205
|
});
|
|
204
206
|
}
|
|
205
207
|
if (!rewardForMarket)
|
|
@@ -229,6 +231,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
229
231
|
_market.supplyIncentives.push({
|
|
230
232
|
token: supplyRewardData.rewardTokenSymbol,
|
|
231
233
|
apy: rewardApy,
|
|
234
|
+
incentiveKind: 'reward',
|
|
232
235
|
});
|
|
233
236
|
}
|
|
234
237
|
});
|
|
@@ -256,6 +259,7 @@ export function getAaveV3MarketData(web3, network, market, defaultWeb3) {
|
|
|
256
259
|
_market.borrowIncentives.push({
|
|
257
260
|
token: borrowRewardData.rewardTokenSymbol,
|
|
258
261
|
apy: rewardApy,
|
|
262
|
+
incentiveKind: 'reward',
|
|
259
263
|
});
|
|
260
264
|
}
|
|
261
265
|
});
|
|
@@ -408,7 +412,7 @@ export const getAaveV3AccountData = (web3, network, address, extractedState) =>
|
|
|
408
412
|
}
|
|
409
413
|
if (!usedAssets[asset])
|
|
410
414
|
usedAssets[asset] = {};
|
|
411
|
-
const nativeAsset = asset === 'GHO';
|
|
415
|
+
const nativeAsset = asset === 'GHO' && network === NetworkNumber.Eth;
|
|
412
416
|
let discountRateOnBorrow = '0';
|
|
413
417
|
const borrowed = new Dec(borrowedStable).add(borrowedVariable).toString();
|
|
414
418
|
if (nativeAsset && new Dec(borrowed).gt(0) && new Dec(stkAaveBalance).gt(0)) {
|
package/esm/config/contracts.js
CHANGED
|
@@ -12,3 +12,8 @@ export declare const getApyAfterValuesEstimation: (selectedMarket: MorphoBlueMar
|
|
|
12
12
|
borrowRate: string;
|
|
13
13
|
supplyRate: string;
|
|
14
14
|
}>;
|
|
15
|
+
export declare const getReallocatableLiquidity: (marketId: string, network?: NetworkNumber) => Promise<string>;
|
|
16
|
+
export declare const getReallocation: (marketId: string, liquidityToAllocate: string, network?: NetworkNumber) => Promise<{
|
|
17
|
+
vaults: string[];
|
|
18
|
+
withdrawals: [string[], string][][];
|
|
19
|
+
}>;
|
|
@@ -11,8 +11,10 @@ import Dec from 'decimal.js';
|
|
|
11
11
|
import { assetAmountInWei } from '@defisaver/tokens';
|
|
12
12
|
import { calcLeverageLiqPrice, getAssetsTotal, isLeveragedPos } from '../../moneymarket';
|
|
13
13
|
import { calculateNetApy } from '../../staking';
|
|
14
|
+
import { NetworkNumber } from '../../types/common';
|
|
14
15
|
import { borrowOperations, SECONDS_PER_YEAR, WAD } from '../../constants';
|
|
15
16
|
import { MorphoBlueViewContract } from '../../contracts';
|
|
17
|
+
import { compareAddresses } from '../../services/utils';
|
|
16
18
|
export const getMorphoBlueAggregatedPositionData = ({ usedAssets, assetsData, marketInfo }) => {
|
|
17
19
|
var _a, _b, _c, _d, _e, _f;
|
|
18
20
|
const payload = {};
|
|
@@ -100,3 +102,125 @@ export const getApyAfterValuesEstimation = (selectedMarket, action, amount, asse
|
|
|
100
102
|
const supplyRate = getSupplyRate(data.market.totalSupplyAssets, data.market.totalBorrowAssets, data.borrowRate, data.market.fee);
|
|
101
103
|
return { borrowRate, supplyRate };
|
|
102
104
|
});
|
|
105
|
+
const API_URL = 'https://blue-api.morpho.org/graphql';
|
|
106
|
+
const MARKET_QUERY = `
|
|
107
|
+
query MarketByUniqueKey($uniqueKey: String!, $chainId: Int!) {
|
|
108
|
+
marketByUniqueKey(uniqueKey: $uniqueKey, chainId: $chainId) {
|
|
109
|
+
reallocatableLiquidityAssets
|
|
110
|
+
loanAsset {
|
|
111
|
+
address
|
|
112
|
+
decimals
|
|
113
|
+
priceUsd
|
|
114
|
+
}
|
|
115
|
+
state {
|
|
116
|
+
liquidityAssets
|
|
117
|
+
}
|
|
118
|
+
publicAllocatorSharedLiquidity {
|
|
119
|
+
assets
|
|
120
|
+
vault {
|
|
121
|
+
address
|
|
122
|
+
name
|
|
123
|
+
}
|
|
124
|
+
allocationMarket {
|
|
125
|
+
uniqueKey
|
|
126
|
+
loanAsset {
|
|
127
|
+
address
|
|
128
|
+
}
|
|
129
|
+
collateralAsset {
|
|
130
|
+
address
|
|
131
|
+
}
|
|
132
|
+
irmAddress
|
|
133
|
+
oracle {
|
|
134
|
+
address
|
|
135
|
+
}
|
|
136
|
+
lltv
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
loanAsset {
|
|
140
|
+
address
|
|
141
|
+
}
|
|
142
|
+
collateralAsset {
|
|
143
|
+
address
|
|
144
|
+
}
|
|
145
|
+
oracle {
|
|
146
|
+
address
|
|
147
|
+
}
|
|
148
|
+
irmAddress
|
|
149
|
+
lltv
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
`;
|
|
153
|
+
export const getReallocatableLiquidity = (marketId, network = NetworkNumber.Eth) => __awaiter(void 0, void 0, void 0, function* () {
|
|
154
|
+
var _a;
|
|
155
|
+
const response = yield fetch(API_URL, {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers: { 'Content-Type': 'application/json' },
|
|
158
|
+
body: JSON.stringify({
|
|
159
|
+
query: MARKET_QUERY,
|
|
160
|
+
variables: { uniqueKey: marketId, chainId: network },
|
|
161
|
+
}),
|
|
162
|
+
});
|
|
163
|
+
const data = yield response.json();
|
|
164
|
+
const marketData = (_a = data === null || data === void 0 ? void 0 : data.data) === null || _a === void 0 ? void 0 : _a.marketByUniqueKey;
|
|
165
|
+
if (!marketData)
|
|
166
|
+
throw new Error('Market data not found');
|
|
167
|
+
return marketData.reallocatableLiquidityAssets;
|
|
168
|
+
});
|
|
169
|
+
export const getReallocation = (marketId, liquidityToAllocate, network = NetworkNumber.Eth) => __awaiter(void 0, void 0, void 0, function* () {
|
|
170
|
+
var _b, _c, _d;
|
|
171
|
+
const response = yield fetch(API_URL, {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: { 'Content-Type': 'application/json' },
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
query: MARKET_QUERY,
|
|
176
|
+
variables: { uniqueKey: marketId, chainId: network },
|
|
177
|
+
}),
|
|
178
|
+
});
|
|
179
|
+
const data = yield response.json();
|
|
180
|
+
const marketData = (_b = data === null || data === void 0 ? void 0 : data.data) === null || _b === void 0 ? void 0 : _b.marketByUniqueKey;
|
|
181
|
+
if (!marketData)
|
|
182
|
+
throw new Error('Market data not found');
|
|
183
|
+
if (new Dec(marketData.reallocatableLiquidityAssets).lt(liquidityToAllocate))
|
|
184
|
+
throw new Error('Not enough liquidity available to allocate');
|
|
185
|
+
const vaultTotalAssets = marketData.publicAllocatorSharedLiquidity.reduce((acc, item) => {
|
|
186
|
+
const vaultAddress = item.vault.address;
|
|
187
|
+
acc[vaultAddress] = new Dec(acc[vaultAddress] || '0').add(item.assets).toString();
|
|
188
|
+
return acc;
|
|
189
|
+
}, {});
|
|
190
|
+
const sortedVaults = Object.entries(vaultTotalAssets).sort(([, a], [, b]) => new Dec(b || '0').sub(a || '0').toNumber());
|
|
191
|
+
const withdrawalsPerVault = {};
|
|
192
|
+
let totalReallocated = '0';
|
|
193
|
+
for (const [vaultAddress] of sortedVaults) {
|
|
194
|
+
if (new Dec(totalReallocated).gte(liquidityToAllocate))
|
|
195
|
+
break;
|
|
196
|
+
const vaultAllocations = marketData.publicAllocatorSharedLiquidity.filter((item) => compareAddresses(item.vault.address, vaultAddress));
|
|
197
|
+
for (const item of vaultAllocations) {
|
|
198
|
+
if (new Dec(totalReallocated).gte(liquidityToAllocate))
|
|
199
|
+
break;
|
|
200
|
+
const itemAmount = item.assets;
|
|
201
|
+
const leftToAllocate = new Dec(liquidityToAllocate).sub(totalReallocated).toString();
|
|
202
|
+
const amountToTake = new Dec(itemAmount).lt(leftToAllocate) ? itemAmount : leftToAllocate;
|
|
203
|
+
totalReallocated = new Dec(totalReallocated).add(amountToTake).toString();
|
|
204
|
+
const withdrawal = [
|
|
205
|
+
[
|
|
206
|
+
item.allocationMarket.loanAsset.address,
|
|
207
|
+
(_c = item.allocationMarket.collateralAsset) === null || _c === void 0 ? void 0 : _c.address,
|
|
208
|
+
(_d = item.allocationMarket.oracle) === null || _d === void 0 ? void 0 : _d.address,
|
|
209
|
+
item.allocationMarket.irmAddress,
|
|
210
|
+
item.allocationMarket.lltv,
|
|
211
|
+
],
|
|
212
|
+
amountToTake.toString(),
|
|
213
|
+
];
|
|
214
|
+
if (!withdrawalsPerVault[vaultAddress]) {
|
|
215
|
+
withdrawalsPerVault[vaultAddress] = [];
|
|
216
|
+
}
|
|
217
|
+
withdrawalsPerVault[vaultAddress].push(withdrawal);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
const vaults = Object.keys(withdrawalsPerVault);
|
|
221
|
+
const withdrawals = vaults.map((vaultAddress) => withdrawalsPerVault[vaultAddress]);
|
|
222
|
+
return {
|
|
223
|
+
vaults,
|
|
224
|
+
withdrawals,
|
|
225
|
+
};
|
|
226
|
+
});
|
package/esm/staking/staking.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Web3 from 'web3';
|
|
2
|
-
import { MMAssetsData, MMUsedAssets
|
|
2
|
+
import { MMAssetsData, MMUsedAssets } from '../types/common';
|
|
3
3
|
export declare const getStETHApy: (web3: Web3, fromBlock?: number, blockNumber?: 'latest' | number) => Promise<string>;
|
|
4
4
|
export declare const getCbETHApy: (web3: Web3, blockNumber?: 'latest' | number) => Promise<string>;
|
|
5
5
|
export declare const getREthApy: (web3: Web3, blockNumber?: 'latest' | number) => Promise<string>;
|
|
@@ -8,11 +8,10 @@ export declare const getSsrApy: () => Promise<string>;
|
|
|
8
8
|
export declare const STAKING_ASSETS: string[];
|
|
9
9
|
export declare const getStakingApy: (asset: string, web3: Web3, blockNumber?: 'latest' | number, fromBlock?: number | undefined) => "0" | Promise<any> | undefined;
|
|
10
10
|
export declare const calculateInterestEarned: (principal: string, interest: string, type: string, apy?: boolean) => number;
|
|
11
|
-
export declare const calculateNetApy: ({ usedAssets, assetsData, isMorpho
|
|
11
|
+
export declare const calculateNetApy: ({ usedAssets, assetsData, isMorpho }: {
|
|
12
12
|
usedAssets: MMUsedAssets;
|
|
13
13
|
assetsData: MMAssetsData;
|
|
14
14
|
isMorpho?: boolean | undefined;
|
|
15
|
-
network?: NetworkNumber | undefined;
|
|
16
15
|
}) => {
|
|
17
16
|
netApy: string;
|
|
18
17
|
totalInterestUsd: string;
|
package/esm/staking/staking.js
CHANGED
|
@@ -157,7 +157,7 @@ export const calculateInterestEarned = (principal, interest, type, apy = false)
|
|
|
157
157
|
}
|
|
158
158
|
return (+principal * (Math.pow(((1 + (+interest / 100) / BLOCKS_IN_A_YEAR)), (BLOCKS_IN_A_YEAR * interval)))) - +principal; // eslint-disable-line
|
|
159
159
|
};
|
|
160
|
-
export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false
|
|
160
|
+
export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }) => {
|
|
161
161
|
const sumValues = Object.values(usedAssets).reduce((_acc, usedAsset) => {
|
|
162
162
|
const acc = Object.assign({}, _acc);
|
|
163
163
|
const assetData = assetsData[usedAsset.symbol];
|
|
@@ -180,7 +180,7 @@ export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false, netw
|
|
|
180
180
|
acc.borrowedUsd = new Dec(acc.borrowedUsd).add(amount).toString();
|
|
181
181
|
const rate = isMorpho
|
|
182
182
|
? usedAsset.borrowRate === '0' ? assetData.borrowRateP2P : usedAsset.borrowRate
|
|
183
|
-
: (usedAsset.symbol === 'GHO' &&
|
|
183
|
+
: (usedAsset.symbol === 'GHO' && assetsData.nativeAsset)
|
|
184
184
|
? usedAsset.discountedBorrowRate
|
|
185
185
|
: ((usedAsset === null || usedAsset === void 0 ? void 0 : usedAsset.interestMode) === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
|
|
186
186
|
const borrowInterest = calculateInterestEarned(amount, rate, 'year', true);
|
package/esm/types/aave.d.ts
CHANGED
|
@@ -76,6 +76,7 @@ export interface MorphoAaveV2AssetData extends AaveV2AssetData {
|
|
|
76
76
|
export interface IncentiveData {
|
|
77
77
|
token: string;
|
|
78
78
|
apy: string;
|
|
79
|
+
incentiveKind?: 'staking' | 'reward';
|
|
79
80
|
}
|
|
80
81
|
export interface AaveV3AssetData extends AaveAssetData {
|
|
81
82
|
isIsolated: boolean;
|
|
@@ -137,3 +137,28 @@ export interface MorphoBluePositionData {
|
|
|
137
137
|
supplyShares: string;
|
|
138
138
|
borrowShares: string;
|
|
139
139
|
}
|
|
140
|
+
export interface MorphoBlueVault {
|
|
141
|
+
address: string;
|
|
142
|
+
}
|
|
143
|
+
export interface MorphoBlueAllocationMarket {
|
|
144
|
+
loanAsset: {
|
|
145
|
+
address: string;
|
|
146
|
+
};
|
|
147
|
+
collateralAsset: {
|
|
148
|
+
address: string;
|
|
149
|
+
};
|
|
150
|
+
oracle: {
|
|
151
|
+
address: string;
|
|
152
|
+
};
|
|
153
|
+
irmAddress: string;
|
|
154
|
+
lltv: string;
|
|
155
|
+
}
|
|
156
|
+
export interface MorphoBluePublicAllocatorItem {
|
|
157
|
+
vault: MorphoBlueVault;
|
|
158
|
+
assets: string;
|
|
159
|
+
allocationMarket: MorphoBlueAllocationMarket;
|
|
160
|
+
}
|
|
161
|
+
export interface MorphoBlueRealloactionMarketData {
|
|
162
|
+
reallocatableLiquidityAssets: string;
|
|
163
|
+
publicAllocatorSharedLiquidity: MorphoBluePublicAllocatorItem[];
|
|
164
|
+
}
|
package/package.json
CHANGED
package/src/aaveV3/index.ts
CHANGED
|
@@ -34,11 +34,7 @@ import { multicall } from '../multicall';
|
|
|
34
34
|
import { IUiIncentiveDataProviderV3 } from '../types/contracts/generated/AaveUiIncentiveDataProviderV3';
|
|
35
35
|
import { getAssetsBalances } from '../assets';
|
|
36
36
|
import { aprToApy, calculateBorrowingAssetLimit } from '../moneymarket';
|
|
37
|
-
import {
|
|
38
|
-
aaveAnyGetAggregatedPositionData,
|
|
39
|
-
aaveV3IsInIsolationMode,
|
|
40
|
-
aaveV3IsInSiloedMode,
|
|
41
|
-
} from '../helpers/aaveHelpers';
|
|
37
|
+
import { aaveAnyGetAggregatedPositionData, aaveV3IsInIsolationMode, aaveV3IsInSiloedMode } from '../helpers/aaveHelpers';
|
|
42
38
|
import { AAVE_V3 } from '../markets/aave';
|
|
43
39
|
|
|
44
40
|
export const test = (web3: Web3, network: NetworkNumber) => {
|
|
@@ -137,7 +133,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
|
|
|
137
133
|
params: [],
|
|
138
134
|
},
|
|
139
135
|
{
|
|
140
|
-
target: getAssetInfo('GHO').address,
|
|
136
|
+
target: getAssetInfo('GHO', network).address,
|
|
141
137
|
abiItem: getAbiItem(GhoTokenAbi, 'getFacilitatorsList'),
|
|
142
138
|
params: [],
|
|
143
139
|
},
|
|
@@ -191,7 +187,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
|
|
|
191
187
|
const assetsData: AaveV3AssetData[] = await Promise.all(loanInfo
|
|
192
188
|
.map(async (tokenMarket, i) => {
|
|
193
189
|
const symbol = market.assets[i];
|
|
194
|
-
const nativeAsset = symbol === 'GHO';
|
|
190
|
+
const nativeAsset = symbol === 'GHO' && network === NetworkNumber.Eth;
|
|
195
191
|
|
|
196
192
|
// eslint-disable-next-line guard-for-in
|
|
197
193
|
for (const eModeIndex in eModeCategoriesData) {
|
|
@@ -290,6 +286,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
|
|
|
290
286
|
_market.supplyIncentives.push({
|
|
291
287
|
apy: _market.incentiveSupplyApy || '0',
|
|
292
288
|
token: _market.symbol,
|
|
289
|
+
incentiveKind: 'staking',
|
|
293
290
|
});
|
|
294
291
|
}
|
|
295
292
|
|
|
@@ -302,6 +299,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
|
|
|
302
299
|
_market.borrowIncentives.push({
|
|
303
300
|
apy: _market.incentiveBorrowApy,
|
|
304
301
|
token: _market.incentiveBorrowToken!!,
|
|
302
|
+
incentiveKind: 'reward',
|
|
305
303
|
});
|
|
306
304
|
}
|
|
307
305
|
|
|
@@ -330,6 +328,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
|
|
|
330
328
|
_market.supplyIncentives.push({
|
|
331
329
|
token: supplyRewardData.rewardTokenSymbol,
|
|
332
330
|
apy: rewardApy,
|
|
331
|
+
incentiveKind: 'reward',
|
|
333
332
|
});
|
|
334
333
|
}
|
|
335
334
|
});
|
|
@@ -356,6 +355,7 @@ export async function getAaveV3MarketData(web3: Web3, network: NetworkNumber, ma
|
|
|
356
355
|
_market.borrowIncentives.push({
|
|
357
356
|
token: borrowRewardData.rewardTokenSymbol,
|
|
358
357
|
apy: rewardApy,
|
|
358
|
+
incentiveKind: 'reward',
|
|
359
359
|
});
|
|
360
360
|
}
|
|
361
361
|
});
|
|
@@ -543,7 +543,7 @@ export const getAaveV3AccountData = async (web3: Web3, network: NetworkNumber, a
|
|
|
543
543
|
interestMode = 'both';
|
|
544
544
|
}
|
|
545
545
|
if (!usedAssets[asset]) usedAssets[asset] = {} as AaveV3UsedAsset;
|
|
546
|
-
const nativeAsset = asset === 'GHO';
|
|
546
|
+
const nativeAsset = asset === 'GHO' && network === NetworkNumber.Eth;
|
|
547
547
|
|
|
548
548
|
let discountRateOnBorrow = '0';
|
|
549
549
|
const borrowed = new Dec(borrowedStable).add(borrowedVariable).toString();
|
package/src/config/contracts.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import Dec from 'decimal.js';
|
|
2
|
-
import { assetAmountInWei } from '@defisaver/tokens';
|
|
2
|
+
import { assetAmountInWei, getAssetInfoByAddress } from '@defisaver/tokens';
|
|
3
3
|
import Web3 from 'web3';
|
|
4
4
|
import { calcLeverageLiqPrice, getAssetsTotal, isLeveragedPos } from '../../moneymarket';
|
|
5
5
|
import { calculateNetApy } from '../../staking';
|
|
6
6
|
import { MMAssetsData, MMUsedAssets, NetworkNumber } from '../../types/common';
|
|
7
7
|
import {
|
|
8
8
|
MorphoBlueAggregatedPositionData, MorphoBlueAssetsData, MorphoBlueMarketData, MorphoBlueMarketInfo,
|
|
9
|
+
MorphoBluePublicAllocatorItem,
|
|
10
|
+
MorphoBlueRealloactionMarketData,
|
|
9
11
|
} from '../../types';
|
|
10
12
|
import { borrowOperations, SECONDS_PER_YEAR, WAD } from '../../constants';
|
|
11
13
|
import { MorphoBlueViewContract } from '../../contracts';
|
|
12
14
|
import { MarketParamsStruct } from '../../types/contracts/generated/MorphoBlueView';
|
|
15
|
+
import { compareAddresses } from '../../services/utils';
|
|
13
16
|
|
|
14
17
|
export const getMorphoBlueAggregatedPositionData = ({ usedAssets, assetsData, marketInfo }: { usedAssets: MMUsedAssets, assetsData: MorphoBlueAssetsData, marketInfo: MorphoBlueMarketInfo }): MorphoBlueAggregatedPositionData => {
|
|
15
18
|
const payload = {} as MorphoBlueAggregatedPositionData;
|
|
@@ -113,4 +116,142 @@ export const getApyAfterValuesEstimation = async (selectedMarket: MorphoBlueMark
|
|
|
113
116
|
const borrowRate = getBorrowRate(data.borrowRate, data.market.totalBorrowShares);
|
|
114
117
|
const supplyRate = getSupplyRate(data.market.totalSupplyAssets, data.market.totalBorrowAssets, data.borrowRate, data.market.fee);
|
|
115
118
|
return { borrowRate, supplyRate };
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const API_URL = 'https://blue-api.morpho.org/graphql';
|
|
122
|
+
const MARKET_QUERY = `
|
|
123
|
+
query MarketByUniqueKey($uniqueKey: String!, $chainId: Int!) {
|
|
124
|
+
marketByUniqueKey(uniqueKey: $uniqueKey, chainId: $chainId) {
|
|
125
|
+
reallocatableLiquidityAssets
|
|
126
|
+
loanAsset {
|
|
127
|
+
address
|
|
128
|
+
decimals
|
|
129
|
+
priceUsd
|
|
130
|
+
}
|
|
131
|
+
state {
|
|
132
|
+
liquidityAssets
|
|
133
|
+
}
|
|
134
|
+
publicAllocatorSharedLiquidity {
|
|
135
|
+
assets
|
|
136
|
+
vault {
|
|
137
|
+
address
|
|
138
|
+
name
|
|
139
|
+
}
|
|
140
|
+
allocationMarket {
|
|
141
|
+
uniqueKey
|
|
142
|
+
loanAsset {
|
|
143
|
+
address
|
|
144
|
+
}
|
|
145
|
+
collateralAsset {
|
|
146
|
+
address
|
|
147
|
+
}
|
|
148
|
+
irmAddress
|
|
149
|
+
oracle {
|
|
150
|
+
address
|
|
151
|
+
}
|
|
152
|
+
lltv
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
loanAsset {
|
|
156
|
+
address
|
|
157
|
+
}
|
|
158
|
+
collateralAsset {
|
|
159
|
+
address
|
|
160
|
+
}
|
|
161
|
+
oracle {
|
|
162
|
+
address
|
|
163
|
+
}
|
|
164
|
+
irmAddress
|
|
165
|
+
lltv
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
`;
|
|
169
|
+
|
|
170
|
+
export const getReallocatableLiquidity = async (marketId: string, network: NetworkNumber = NetworkNumber.Eth): Promise<string> => {
|
|
171
|
+
const response = await fetch(API_URL, {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: { 'Content-Type': 'application/json' },
|
|
174
|
+
body: JSON.stringify({
|
|
175
|
+
query: MARKET_QUERY,
|
|
176
|
+
variables: { uniqueKey: marketId, chainId: network },
|
|
177
|
+
}),
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const data: { data: { marketByUniqueKey: MorphoBlueRealloactionMarketData } } = await response.json();
|
|
181
|
+
const marketData: MorphoBlueRealloactionMarketData = data?.data?.marketByUniqueKey;
|
|
182
|
+
|
|
183
|
+
if (!marketData) throw new Error('Market data not found');
|
|
184
|
+
|
|
185
|
+
return marketData.reallocatableLiquidityAssets;
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
export const getReallocation = async (marketId: string, liquidityToAllocate: string, network: NetworkNumber = NetworkNumber.Eth) => {
|
|
189
|
+
const response = await fetch(API_URL, {
|
|
190
|
+
method: 'POST',
|
|
191
|
+
headers: { 'Content-Type': 'application/json' },
|
|
192
|
+
body: JSON.stringify({
|
|
193
|
+
query: MARKET_QUERY,
|
|
194
|
+
variables: { uniqueKey: marketId, chainId: network },
|
|
195
|
+
}),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const data: { data: { marketByUniqueKey: MorphoBlueRealloactionMarketData } } = await response.json();
|
|
199
|
+
const marketData: MorphoBlueRealloactionMarketData = data?.data?.marketByUniqueKey;
|
|
200
|
+
|
|
201
|
+
if (!marketData) throw new Error('Market data not found');
|
|
202
|
+
|
|
203
|
+
if (new Dec(marketData.reallocatableLiquidityAssets).lt(liquidityToAllocate)) throw new Error('Not enough liquidity available to allocate');
|
|
204
|
+
|
|
205
|
+
const vaultTotalAssets = marketData.publicAllocatorSharedLiquidity.reduce(
|
|
206
|
+
(acc: Record<string, string>, item: MorphoBluePublicAllocatorItem) => {
|
|
207
|
+
const vaultAddress = item.vault.address;
|
|
208
|
+
acc[vaultAddress] = new Dec(acc[vaultAddress] || '0').add(item.assets).toString();
|
|
209
|
+
return acc;
|
|
210
|
+
},
|
|
211
|
+
{},
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
const sortedVaults = Object.entries(vaultTotalAssets).sort(
|
|
215
|
+
([, a]: [string, string], [, b]: [string, string]) => new Dec(b || '0').sub(a || '0').toNumber(),
|
|
216
|
+
);
|
|
217
|
+
|
|
218
|
+
const withdrawalsPerVault: Record<string, [string[], string][]> = {};
|
|
219
|
+
let totalReallocated = '0';
|
|
220
|
+
for (const [vaultAddress] of sortedVaults) {
|
|
221
|
+
if (new Dec(totalReallocated).gte(liquidityToAllocate)) break;
|
|
222
|
+
|
|
223
|
+
const vaultAllocations = marketData.publicAllocatorSharedLiquidity.filter(
|
|
224
|
+
(item: MorphoBluePublicAllocatorItem) => compareAddresses(item.vault.address, vaultAddress),
|
|
225
|
+
);
|
|
226
|
+
for (const item of vaultAllocations) {
|
|
227
|
+
if (new Dec(totalReallocated).gte(liquidityToAllocate)) break;
|
|
228
|
+
const itemAmount = item.assets;
|
|
229
|
+
const leftToAllocate = new Dec(liquidityToAllocate).sub(totalReallocated).toString();
|
|
230
|
+
const amountToTake = new Dec(itemAmount).lt(leftToAllocate) ? itemAmount : leftToAllocate;
|
|
231
|
+
totalReallocated = new Dec(totalReallocated).add(amountToTake).toString();
|
|
232
|
+
const withdrawal: [string[], string] = [
|
|
233
|
+
[
|
|
234
|
+
item.allocationMarket.loanAsset.address,
|
|
235
|
+
item.allocationMarket.collateralAsset?.address,
|
|
236
|
+
item.allocationMarket.oracle?.address,
|
|
237
|
+
item.allocationMarket.irmAddress,
|
|
238
|
+
item.allocationMarket.lltv,
|
|
239
|
+
],
|
|
240
|
+
amountToTake.toString(),
|
|
241
|
+
];
|
|
242
|
+
if (!withdrawalsPerVault[vaultAddress]) {
|
|
243
|
+
withdrawalsPerVault[vaultAddress] = [];
|
|
244
|
+
}
|
|
245
|
+
withdrawalsPerVault[vaultAddress].push(withdrawal);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const vaults = Object.keys(withdrawalsPerVault);
|
|
250
|
+
const withdrawals = vaults.map(
|
|
251
|
+
(vaultAddress) => withdrawalsPerVault[vaultAddress],
|
|
252
|
+
);
|
|
253
|
+
return {
|
|
254
|
+
vaults,
|
|
255
|
+
withdrawals,
|
|
256
|
+
};
|
|
116
257
|
};
|
package/src/staking/staking.ts
CHANGED
|
@@ -151,9 +151,7 @@ export const calculateInterestEarned = (principal: string, interest: string, typ
|
|
|
151
151
|
return (+principal * (((1 + (+interest / 100) / BLOCKS_IN_A_YEAR)) ** (BLOCKS_IN_A_YEAR * interval))) - +principal; // eslint-disable-line
|
|
152
152
|
};
|
|
153
153
|
|
|
154
|
-
export const calculateNetApy = ({
|
|
155
|
-
usedAssets, assetsData, isMorpho = false, network = 1,
|
|
156
|
-
}: { usedAssets: MMUsedAssets, assetsData: MMAssetsData, isMorpho?: boolean, network?: NetworkNumber }) => {
|
|
154
|
+
export const calculateNetApy = ({ usedAssets, assetsData, isMorpho = false }: { usedAssets: MMUsedAssets, assetsData: MMAssetsData, isMorpho?: boolean }) => {
|
|
157
155
|
const sumValues = Object.values(usedAssets).reduce((_acc, usedAsset) => {
|
|
158
156
|
const acc = { ..._acc };
|
|
159
157
|
const assetData = assetsData[usedAsset.symbol];
|
|
@@ -178,7 +176,7 @@ export const calculateNetApy = ({
|
|
|
178
176
|
acc.borrowedUsd = new Dec(acc.borrowedUsd).add(amount).toString();
|
|
179
177
|
const rate = isMorpho
|
|
180
178
|
? usedAsset.borrowRate === '0' ? assetData.borrowRateP2P : usedAsset.borrowRate
|
|
181
|
-
: (usedAsset.symbol === 'GHO' &&
|
|
179
|
+
: (usedAsset.symbol === 'GHO' && assetsData.nativeAsset)
|
|
182
180
|
? usedAsset.discountedBorrowRate
|
|
183
181
|
: (usedAsset?.interestMode === '1' ? usedAsset.stableBorrowRate : assetData.borrowRate);
|
|
184
182
|
const borrowInterest = calculateInterestEarned(amount, rate as string, 'year', true);
|
package/src/types/aave.ts
CHANGED
package/src/types/morphoBlue.ts
CHANGED
|
@@ -152,3 +152,26 @@ export interface MorphoBluePositionData {
|
|
|
152
152
|
supplyShares: string,
|
|
153
153
|
borrowShares: string,
|
|
154
154
|
}
|
|
155
|
+
|
|
156
|
+
export interface MorphoBlueVault {
|
|
157
|
+
address: string,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface MorphoBlueAllocationMarket {
|
|
161
|
+
loanAsset: { address: string },
|
|
162
|
+
collateralAsset: { address: string },
|
|
163
|
+
oracle: { address: string },
|
|
164
|
+
irmAddress: string,
|
|
165
|
+
lltv: string,
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export interface MorphoBluePublicAllocatorItem {
|
|
169
|
+
vault: MorphoBlueVault,
|
|
170
|
+
assets: string,
|
|
171
|
+
allocationMarket: MorphoBlueAllocationMarket,
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export interface MorphoBlueRealloactionMarketData {
|
|
175
|
+
reallocatableLiquidityAssets: string,
|
|
176
|
+
publicAllocatorSharedLiquidity: MorphoBluePublicAllocatorItem[],
|
|
177
|
+
}
|