@defisaver/positions-sdk 2.1.105 → 2.1.106-sgho-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.
- package/cjs/aaveV3/index.d.ts +3 -0
- package/cjs/aaveV3/index.js +7 -2
- package/cjs/aaveV3/sgho.d.ts +18 -0
- package/cjs/aaveV3/sgho.js +95 -0
- package/cjs/aaveV4/index.js +53 -20
- package/cjs/types/aaveV4.d.ts +9 -0
- package/esm/aaveV3/index.d.ts +3 -0
- package/esm/aaveV3/index.js +5 -1
- package/esm/aaveV3/sgho.d.ts +18 -0
- package/esm/aaveV3/sgho.js +88 -0
- package/esm/aaveV4/index.js +53 -20
- package/esm/types/aaveV4.d.ts +9 -0
- package/package.json +2 -2
- package/src/aaveV3/index.ts +7 -1
- package/src/aaveV3/sgho.ts +100 -0
- package/src/aaveV4/index.ts +48 -20
- package/src/types/aaveV4.ts +9 -0
package/cjs/aaveV3/index.d.ts
CHANGED
|
@@ -46,5 +46,8 @@ export declare const getStakeAaveData: (provider: Client, network: NetworkNumber
|
|
|
46
46
|
stkGhoBalance: string;
|
|
47
47
|
ghoMeritApy: string;
|
|
48
48
|
stkAaveApy: string;
|
|
49
|
+
sgho: import("./sgho").SghoData;
|
|
49
50
|
}>;
|
|
50
51
|
export { getMeritCampaigns, getMerkleCampaigns, };
|
|
52
|
+
export { getSghoData } from './sgho';
|
|
53
|
+
export type { SghoData, SghoUserData } from './sgho';
|
package/cjs/aaveV3/index.js
CHANGED
|
@@ -12,7 +12,7 @@ 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.getMerkleCampaigns = exports.getMeritCampaigns = exports.getStakeAaveData = exports.fetchYearlyMeritApyForStakingGho = exports.REWARDABLE_ASSETS = exports.getAaveV3FullPositionData = exports.getAaveV3AccountData = exports._getAaveV3AccountData = exports.getAaveV3AccountBalances = exports._getAaveV3AccountBalances = exports.EMPTY_AAVE_DATA = exports.aaveV3EmodeCategoriesMapping = void 0;
|
|
15
|
+
exports.getSghoData = exports.getMerkleCampaigns = exports.getMeritCampaigns = exports.getStakeAaveData = exports.fetchYearlyMeritApyForStakingGho = exports.REWARDABLE_ASSETS = exports.getAaveV3FullPositionData = exports.getAaveV3AccountData = exports._getAaveV3AccountData = exports.getAaveV3AccountBalances = exports._getAaveV3AccountBalances = exports.EMPTY_AAVE_DATA = exports.aaveV3EmodeCategoriesMapping = void 0;
|
|
16
16
|
exports._getAaveV3MarketData = _getAaveV3MarketData;
|
|
17
17
|
exports.getAaveV3MarketData = getAaveV3MarketData;
|
|
18
18
|
const tokens_1 = require("@defisaver/tokens");
|
|
@@ -29,6 +29,7 @@ const merit_1 = require("./merit");
|
|
|
29
29
|
Object.defineProperty(exports, "getMeritCampaigns", { enumerable: true, get: function () { return merit_1.getMeritCampaigns; } });
|
|
30
30
|
const merkl_1 = require("./merkl");
|
|
31
31
|
Object.defineProperty(exports, "getMerkleCampaigns", { enumerable: true, get: function () { return merkl_1.getMerkleCampaigns; } });
|
|
32
|
+
const sgho_1 = require("./sgho");
|
|
32
33
|
const constants_1 = require("../constants");
|
|
33
34
|
const aaveV3EmodeCategoriesMapping = (extractedState, usedAssets) => {
|
|
34
35
|
const { eModeCategoriesData } = extractedState;
|
|
@@ -519,13 +520,14 @@ const getStakeAaveData = (provider, network, address) => __awaiter(void 0, void
|
|
|
519
520
|
const AaveIncentivesController = (0, contracts_1.AaveIncentivesControllerViem)(provider, network);
|
|
520
521
|
const stkAAVE = (0, contracts_1.StkAAVEViem)(provider, network);
|
|
521
522
|
const stkGHO = (0, contracts_1.createViemContractFromConfigFunc)('Erc20', stkGhoAddress)(provider, network);
|
|
522
|
-
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy] = yield Promise.all([
|
|
523
|
+
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy, sgho] = yield Promise.all([
|
|
523
524
|
AaveIncentivesController.read.getRewardsBalance([exports.REWARDABLE_ASSETS, address]),
|
|
524
525
|
stkAAVE.read.assets([stkAaveAddress]),
|
|
525
526
|
stkAAVE.read.balanceOf([address]),
|
|
526
527
|
stkAAVE.read.totalSupply(),
|
|
527
528
|
stkGHO.read.balanceOf([address]),
|
|
528
529
|
(0, exports.fetchYearlyMeritApyForStakingGho)(),
|
|
530
|
+
(0, sgho_1.getSghoData)(network, address),
|
|
529
531
|
]);
|
|
530
532
|
const stkAaveApy = new decimal_js_1.default((0, tokens_1.assetAmountInEth)(emissionsPerSecond[0].toString(), 'GHO') || 0).mul(constants_1.SECONDS_PER_YEAR).mul(100).div((0, tokens_1.assetAmountInEth)(stkAAVETotalSupply.toString(), 'stkAAVE'))
|
|
531
533
|
.toString();
|
|
@@ -538,6 +540,9 @@ const getStakeAaveData = (provider, network, address) => __awaiter(void 0, void
|
|
|
538
540
|
stkGhoBalance: (0, tokens_1.assetAmountInEth)(stkGHOBalance.toString(), 'GHO'),
|
|
539
541
|
ghoMeritApy,
|
|
540
542
|
stkAaveApy,
|
|
543
|
+
sgho,
|
|
541
544
|
};
|
|
542
545
|
});
|
|
543
546
|
exports.getStakeAaveData = getStakeAaveData;
|
|
547
|
+
var sgho_2 = require("./sgho");
|
|
548
|
+
Object.defineProperty(exports, "getSghoData", { enumerable: true, get: function () { return sgho_2.getSghoData; } });
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EthAddress, NetworkNumber } from '../types/common';
|
|
2
|
+
export interface SghoUserData {
|
|
3
|
+
shares: string;
|
|
4
|
+
balance: string;
|
|
5
|
+
maxDeposit: string;
|
|
6
|
+
maxWithdraw: string;
|
|
7
|
+
underlyingBalance: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SghoData {
|
|
10
|
+
totalAssets: string;
|
|
11
|
+
totalSupply: string;
|
|
12
|
+
supplyCap: string;
|
|
13
|
+
/** Target savings rate as an APY percent (e.g. "4.25" for 4.25%). */
|
|
14
|
+
targetRate: string;
|
|
15
|
+
paused: boolean;
|
|
16
|
+
user: SghoUserData;
|
|
17
|
+
}
|
|
18
|
+
export declare const getSghoData: (network: NetworkNumber, address?: EthAddress) => Promise<SghoData>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.getSghoData = void 0;
|
|
16
|
+
const decimal_js_1 = __importDefault(require("decimal.js"));
|
|
17
|
+
const common_1 = require("../types/common");
|
|
18
|
+
const utils_1 = require("../services/utils");
|
|
19
|
+
const constants_1 = require("../constants");
|
|
20
|
+
const EMPTY_SGHO_DATA = {
|
|
21
|
+
totalAssets: '0',
|
|
22
|
+
totalSupply: '0',
|
|
23
|
+
supplyCap: '0',
|
|
24
|
+
targetRate: '0',
|
|
25
|
+
paused: false,
|
|
26
|
+
user: {
|
|
27
|
+
shares: '0',
|
|
28
|
+
balance: '0',
|
|
29
|
+
maxDeposit: '0',
|
|
30
|
+
maxWithdraw: '0',
|
|
31
|
+
underlyingBalance: '0',
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
const SGHO_VAULT_QUERY = `query SghoVault($request: SghoVaultRequest!) {
|
|
35
|
+
value: sghoVault(request: $request) {
|
|
36
|
+
totalAssets { amount { value } }
|
|
37
|
+
totalSupply { value }
|
|
38
|
+
supplyCap { amount { value } }
|
|
39
|
+
targetRate { value }
|
|
40
|
+
paused
|
|
41
|
+
user {
|
|
42
|
+
shares { amount { value } }
|
|
43
|
+
balance { amount { value } }
|
|
44
|
+
maxDeposit { amount { value } }
|
|
45
|
+
maxWithdraw { amount { value } }
|
|
46
|
+
underlyingBalance { amount { value } }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}`;
|
|
50
|
+
const tokenAmountValue = (entry) => { var _a, _b; return ((_b = (_a = entry === null || entry === void 0 ? void 0 : entry.amount) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.toString()) || '0'; };
|
|
51
|
+
const decimalValue = (entry) => { var _a; return ((_a = entry === null || entry === void 0 ? void 0 : entry.value) === null || _a === void 0 ? void 0 : _a.toString()) || '0'; };
|
|
52
|
+
// Aave returns the rate as a ratio (e.g. 0.0425); consumers display/compound it as a percent (4.25).
|
|
53
|
+
const percentValue = (entry) => ((entry === null || entry === void 0 ? void 0 : entry.value) != null ? new decimal_js_1.default(entry.value).mul(100).toString() : '0');
|
|
54
|
+
const getSghoData = (network_1, ...args_1) => __awaiter(void 0, [network_1, ...args_1], void 0, function* (network, address = constants_1.ZERO_ADDRESS) {
|
|
55
|
+
var _a, _b, _c, _d, _e, _f;
|
|
56
|
+
if (network !== common_1.NetworkNumber.Eth)
|
|
57
|
+
return EMPTY_SGHO_DATA;
|
|
58
|
+
try {
|
|
59
|
+
const res = yield fetch('https://api.v3.aave.com/graphql', {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: { 'Content-Type': 'application/json' },
|
|
62
|
+
body: JSON.stringify({
|
|
63
|
+
operationName: 'SghoVault',
|
|
64
|
+
query: SGHO_VAULT_QUERY,
|
|
65
|
+
variables: { request: { chainId: 1, user: address } },
|
|
66
|
+
}),
|
|
67
|
+
signal: AbortSignal.timeout(utils_1.DEFAULT_TIMEOUT),
|
|
68
|
+
});
|
|
69
|
+
if (!res.ok)
|
|
70
|
+
throw new Error(`Aave SghoVault request failed: ${res.status}`);
|
|
71
|
+
const body = yield res.json();
|
|
72
|
+
const data = (_a = body === null || body === void 0 ? void 0 : body.data) === null || _a === void 0 ? void 0 : _a.value;
|
|
73
|
+
if (!data)
|
|
74
|
+
throw new Error('Aave SghoVault response missing data');
|
|
75
|
+
return {
|
|
76
|
+
totalAssets: tokenAmountValue(data.totalAssets),
|
|
77
|
+
totalSupply: decimalValue(data.totalSupply),
|
|
78
|
+
supplyCap: tokenAmountValue(data.supplyCap),
|
|
79
|
+
targetRate: percentValue(data.targetRate),
|
|
80
|
+
paused: !!data.paused,
|
|
81
|
+
user: {
|
|
82
|
+
shares: tokenAmountValue((_b = data === null || data === void 0 ? void 0 : data.user) === null || _b === void 0 ? void 0 : _b.shares),
|
|
83
|
+
balance: tokenAmountValue((_c = data === null || data === void 0 ? void 0 : data.user) === null || _c === void 0 ? void 0 : _c.balance),
|
|
84
|
+
maxDeposit: tokenAmountValue((_d = data === null || data === void 0 ? void 0 : data.user) === null || _d === void 0 ? void 0 : _d.maxDeposit),
|
|
85
|
+
maxWithdraw: tokenAmountValue((_e = data === null || data === void 0 ? void 0 : data.user) === null || _e === void 0 ? void 0 : _e.maxWithdraw),
|
|
86
|
+
underlyingBalance: tokenAmountValue((_f = data === null || data === void 0 ? void 0 : data.user) === null || _f === void 0 ? void 0 : _f.underlyingBalance),
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
console.error('External API Failure: Failed to fetch Aave sGHO vault data', e);
|
|
92
|
+
return EMPTY_SGHO_DATA;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
exports.getSghoData = getSghoData;
|
package/cjs/aaveV4/index.js
CHANGED
|
@@ -86,6 +86,9 @@ const fetchHubData = (viewContract, hubAddress) => __awaiter(void 0, void 0, voi
|
|
|
86
86
|
const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, network) => __awaiter(void 0, void 0, void 0, function* () {
|
|
87
87
|
var _a, _b, _c, _d, _e, _f;
|
|
88
88
|
const assetInfo = (0, tokens_1.getAssetInfoByAddress)(reserveAsset.underlying, network);
|
|
89
|
+
// `@defisaver/tokens` returns a placeholder ('?', decimals NaN) when the underlying is not in the
|
|
90
|
+
// tokens package. Flag it so consumers can render it read-only instead of feeding NaN into amounts.
|
|
91
|
+
const isUnsupported = assetInfo.symbol === '?';
|
|
89
92
|
const symbol = (0, utils_1.wethToEth)(assetInfo.symbol);
|
|
90
93
|
const hubInfo = (0, aaveV4_1.getAaveV4HubByAddress)(network, reserveAsset.hub);
|
|
91
94
|
if (!hubInfo) {
|
|
@@ -132,10 +135,23 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
|
|
|
132
135
|
const premiumMultiplier = totalDrawnShares.isZero() ? new decimal_js_1.default(1) : totalDrawnShares.add(totalPremiumShares).div(totalDrawnShares);
|
|
133
136
|
const supplyApr = borrowApr.mul(hubUtilization).mul(premiumMultiplier).mul(new decimal_js_1.default(1).minus(liquidityFee));
|
|
134
137
|
const utilization = hubUtilization.times(100).toString();
|
|
138
|
+
// For unsupported assets `symbol` is '?' (decimals NaN in `@defisaver/tokens`), so the
|
|
139
|
+
// symbol-based conversion would produce NaN. Fall back to the on-chain `decimals` so the reserve
|
|
140
|
+
// still shows correct amounts (and feeds correct USD/ratio/liquidation math) in read-only mode.
|
|
141
|
+
const toEth = (raw) => {
|
|
142
|
+
const rawStr = raw.toString();
|
|
143
|
+
if ((0, utils_1.isMaxUint)(rawStr))
|
|
144
|
+
return rawStr;
|
|
145
|
+
if (isUnsupported)
|
|
146
|
+
return new decimal_js_1.default(rawStr || 0).div(new decimal_js_1.default(10).pow(reserveAsset.decimals)).toString();
|
|
147
|
+
return (0, tokens_1.assetAmountInEth)(rawStr, symbol);
|
|
148
|
+
};
|
|
135
149
|
const hubLiquidityRaw = hubAsset.liquidity;
|
|
136
|
-
const hubLiquidity = (
|
|
150
|
+
const hubLiquidity = toEth(hubLiquidityRaw.toString());
|
|
137
151
|
return ({
|
|
138
152
|
symbol,
|
|
153
|
+
decimals: reserveAsset.decimals,
|
|
154
|
+
isUnsupported,
|
|
139
155
|
underlying: reserveAsset.underlying,
|
|
140
156
|
hub: hubInfo.address,
|
|
141
157
|
hubName: hubInfo === null || hubInfo === void 0 ? void 0 : hubInfo.label,
|
|
@@ -149,12 +165,12 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
|
|
|
149
165
|
liquidationFee: new decimal_js_1.default(reserveAsset.liquidationFee).div(10000).toNumber(),
|
|
150
166
|
maxLiquidationBonus: new decimal_js_1.default(reserveAsset.maxLiquidationBonus).div(10000).toNumber(),
|
|
151
167
|
price: new decimal_js_1.default(reserveAsset.price).div(new decimal_js_1.default(10).pow(oracleDecimals)).toString(),
|
|
152
|
-
totalSupplied: (
|
|
153
|
-
totalDrawn: (
|
|
154
|
-
totalPremium: (
|
|
155
|
-
totalDebt: (
|
|
156
|
-
supplyCap: (
|
|
157
|
-
borrowCap: (
|
|
168
|
+
totalSupplied: toEth(totalSuppliedRaw.toString()),
|
|
169
|
+
totalDrawn: toEth(totalDrawnRaw.toString()),
|
|
170
|
+
totalPremium: toEth(totalPremiumRaw.toString()),
|
|
171
|
+
totalDebt: toEth(totalDebtRaw.toString()),
|
|
172
|
+
supplyCap: toEth(supplyCapRaw.toString()),
|
|
173
|
+
borrowCap: toEth(borrowCapRaw.toString()),
|
|
158
174
|
spokeActive: reserveAsset.spokeActive,
|
|
159
175
|
spokeHalted: reserveAsset.spokeHalted,
|
|
160
176
|
drawnRate: drawnRate.toString(),
|
|
@@ -162,10 +178,10 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
|
|
|
162
178
|
supplyRate: (0, moneymarket_1.aprToApy)(supplyApr.toString()),
|
|
163
179
|
supplyIncentives,
|
|
164
180
|
borrowIncentives,
|
|
165
|
-
canBeBorrowed: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
|
|
166
|
-
canBeSupplied: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
|
|
167
|
-
canBeWithdrawn: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
168
|
-
canBePayBacked: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
181
|
+
canBeBorrowed: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
|
|
182
|
+
canBeSupplied: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
|
|
183
|
+
canBeWithdrawn: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
184
|
+
canBePayBacked: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
169
185
|
utilization,
|
|
170
186
|
hubLiquidity,
|
|
171
187
|
premiumMultiplier: premiumMultiplier.toString(),
|
|
@@ -208,17 +224,33 @@ function _getAaveV4AccountData(provider_1, network_1, spokeData_1, address_1) {
|
|
|
208
224
|
const healthFactorFromContract = new decimal_js_1.default(loanData.healthFactor.toString());
|
|
209
225
|
const healthFactor = (0, utils_1.isMaxUint)(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
|
|
210
226
|
const usedAssets = loanData.reserves.reduce((acc, usedReserveAsset) => {
|
|
211
|
-
|
|
227
|
+
var _a, _b, _c, _d;
|
|
228
|
+
const assetInfo = (0, tokens_1.getAssetInfoByAddress)(usedReserveAsset.underlying, network);
|
|
229
|
+
const isUnsupported = assetInfo.symbol === '?';
|
|
230
|
+
const symbol = (0, utils_1.wethToEth)(assetInfo.symbol);
|
|
231
|
+
const identifier = `${symbol}-${+usedReserveAsset.reserveId.toString()}`;
|
|
212
232
|
const reserveData = spokeData.assetsData[identifier];
|
|
213
|
-
const price = reserveData.price;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const
|
|
233
|
+
const price = (_a = reserveData === null || reserveData === void 0 ? void 0 : reserveData.price) !== null && _a !== void 0 ? _a : '0';
|
|
234
|
+
// For unsupported assets the symbol-based conversion yields NaN, so use the on-chain decimals
|
|
235
|
+
// from the reserve data instead. If the reserve is missing entirely we can't convert, so fall
|
|
236
|
+
// back to '0' and keep the entry read-only.
|
|
237
|
+
const toEth = (raw) => {
|
|
238
|
+
if ((0, utils_1.isMaxUint)(raw))
|
|
239
|
+
return raw;
|
|
240
|
+
if (!reserveData)
|
|
241
|
+
return '0';
|
|
242
|
+
if (isUnsupported)
|
|
243
|
+
return new decimal_js_1.default(raw || 0).div(new decimal_js_1.default(10).pow(reserveData.decimals)).toString();
|
|
244
|
+
return (0, tokens_1.assetAmountInEth)(raw, reserveData.symbol);
|
|
245
|
+
};
|
|
246
|
+
const supplied = toEth(usedReserveAsset.supplied.toString());
|
|
247
|
+
const drawn = toEth(usedReserveAsset.drawn.toString());
|
|
248
|
+
const premium = toEth(usedReserveAsset.premium.toString());
|
|
249
|
+
const borrowed = toEth(usedReserveAsset.totalDebt.toString());
|
|
218
250
|
acc[identifier] = {
|
|
219
|
-
symbol: reserveData.symbol,
|
|
220
|
-
hubName: reserveData.hubName,
|
|
221
|
-
assetId: reserveData.assetId,
|
|
251
|
+
symbol: (_b = reserveData === null || reserveData === void 0 ? void 0 : reserveData.symbol) !== null && _b !== void 0 ? _b : symbol,
|
|
252
|
+
hubName: (_c = reserveData === null || reserveData === void 0 ? void 0 : reserveData.hubName) !== null && _c !== void 0 ? _c : '',
|
|
253
|
+
assetId: (_d = reserveData === null || reserveData === void 0 ? void 0 : reserveData.assetId) !== null && _d !== void 0 ? _d : 0,
|
|
222
254
|
reserveId: +usedReserveAsset.reserveId.toString(),
|
|
223
255
|
supplied,
|
|
224
256
|
suppliedUsd: new decimal_js_1.default(supplied).mul(price).toString(),
|
|
@@ -232,6 +264,7 @@ function _getAaveV4AccountData(provider_1, network_1, spokeData_1, address_1) {
|
|
|
232
264
|
isBorrowed: usedReserveAsset.isBorrowing,
|
|
233
265
|
collateral: usedReserveAsset.isUsingAsCollateral,
|
|
234
266
|
collateralFactor: new decimal_js_1.default(usedReserveAsset.collateralFactor).div(10000).toNumber(),
|
|
267
|
+
isUnsupported: isUnsupported || !reserveData,
|
|
235
268
|
};
|
|
236
269
|
return acc;
|
|
237
270
|
}, {});
|
package/cjs/types/aaveV4.d.ts
CHANGED
|
@@ -74,6 +74,8 @@ export interface AaveV4ReserveAssetOnChain {
|
|
|
74
74
|
}
|
|
75
75
|
export interface AaveV4ReserveAssetData {
|
|
76
76
|
symbol: string;
|
|
77
|
+
/** Underlying token decimals as reported on-chain (independent of `@defisaver/tokens`). */
|
|
78
|
+
decimals: number;
|
|
77
79
|
underlying: EthAddress;
|
|
78
80
|
hub: EthAddress;
|
|
79
81
|
hubName: string;
|
|
@@ -119,6 +121,11 @@ export interface AaveV4ReserveAssetData {
|
|
|
119
121
|
hubLiquidity: string;
|
|
120
122
|
premiumMultiplier: string;
|
|
121
123
|
liquidityFee: string;
|
|
124
|
+
/**
|
|
125
|
+
* True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset).
|
|
126
|
+
* The reserve is kept for read-only display, but amounts are zeroed and all actions are disabled.
|
|
127
|
+
*/
|
|
128
|
+
isUnsupported?: boolean;
|
|
122
129
|
}
|
|
123
130
|
export type AaveV4AssetsData = Record<string, AaveV4ReserveAssetData>;
|
|
124
131
|
export interface AaveV4UsedReserveAsset {
|
|
@@ -138,6 +145,8 @@ export interface AaveV4UsedReserveAsset {
|
|
|
138
145
|
isBorrowed: boolean;
|
|
139
146
|
collateral: boolean;
|
|
140
147
|
collateralFactor: number;
|
|
148
|
+
/** True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset). */
|
|
149
|
+
isUnsupported?: boolean;
|
|
141
150
|
}
|
|
142
151
|
export interface AaveV4AggregatedPositionData {
|
|
143
152
|
suppliedUsd: string;
|
package/esm/aaveV3/index.d.ts
CHANGED
|
@@ -46,5 +46,8 @@ export declare const getStakeAaveData: (provider: Client, network: NetworkNumber
|
|
|
46
46
|
stkGhoBalance: string;
|
|
47
47
|
ghoMeritApy: string;
|
|
48
48
|
stkAaveApy: string;
|
|
49
|
+
sgho: import("./sgho").SghoData;
|
|
49
50
|
}>;
|
|
50
51
|
export { getMeritCampaigns, getMerkleCampaigns, };
|
|
52
|
+
export { getSghoData } from './sgho';
|
|
53
|
+
export type { SghoData, SghoUserData } from './sgho';
|
package/esm/aaveV3/index.js
CHANGED
|
@@ -19,6 +19,7 @@ import { IncentiveKind, NetworkNumber, } from '../types/common';
|
|
|
19
19
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
20
20
|
import { getMeritCampaigns } from './merit';
|
|
21
21
|
import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './merkl';
|
|
22
|
+
import { getSghoData } from './sgho';
|
|
22
23
|
import { SECONDS_PER_YEAR } from '../constants';
|
|
23
24
|
export const aaveV3EmodeCategoriesMapping = (extractedState, usedAssets) => {
|
|
24
25
|
const { eModeCategoriesData } = extractedState;
|
|
@@ -502,13 +503,14 @@ export const getStakeAaveData = (provider, network, address) => __awaiter(void 0
|
|
|
502
503
|
const AaveIncentivesController = AaveIncentivesControllerViem(provider, network);
|
|
503
504
|
const stkAAVE = StkAAVEViem(provider, network);
|
|
504
505
|
const stkGHO = createViemContractFromConfigFunc('Erc20', stkGhoAddress)(provider, network);
|
|
505
|
-
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy] = yield Promise.all([
|
|
506
|
+
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy, sgho] = yield Promise.all([
|
|
506
507
|
AaveIncentivesController.read.getRewardsBalance([REWARDABLE_ASSETS, address]),
|
|
507
508
|
stkAAVE.read.assets([stkAaveAddress]),
|
|
508
509
|
stkAAVE.read.balanceOf([address]),
|
|
509
510
|
stkAAVE.read.totalSupply(),
|
|
510
511
|
stkGHO.read.balanceOf([address]),
|
|
511
512
|
fetchYearlyMeritApyForStakingGho(),
|
|
513
|
+
getSghoData(network, address),
|
|
512
514
|
]);
|
|
513
515
|
const stkAaveApy = new Dec(assetAmountInEth(emissionsPerSecond[0].toString(), 'GHO') || 0).mul(SECONDS_PER_YEAR).mul(100).div(assetAmountInEth(stkAAVETotalSupply.toString(), 'stkAAVE'))
|
|
514
516
|
.toString();
|
|
@@ -521,6 +523,8 @@ export const getStakeAaveData = (provider, network, address) => __awaiter(void 0
|
|
|
521
523
|
stkGhoBalance: assetAmountInEth(stkGHOBalance.toString(), 'GHO'),
|
|
522
524
|
ghoMeritApy,
|
|
523
525
|
stkAaveApy,
|
|
526
|
+
sgho,
|
|
524
527
|
};
|
|
525
528
|
});
|
|
526
529
|
export { getMeritCampaigns, getMerkleCampaigns, };
|
|
530
|
+
export { getSghoData } from './sgho';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { EthAddress, NetworkNumber } from '../types/common';
|
|
2
|
+
export interface SghoUserData {
|
|
3
|
+
shares: string;
|
|
4
|
+
balance: string;
|
|
5
|
+
maxDeposit: string;
|
|
6
|
+
maxWithdraw: string;
|
|
7
|
+
underlyingBalance: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SghoData {
|
|
10
|
+
totalAssets: string;
|
|
11
|
+
totalSupply: string;
|
|
12
|
+
supplyCap: string;
|
|
13
|
+
/** Target savings rate as an APY percent (e.g. "4.25" for 4.25%). */
|
|
14
|
+
targetRate: string;
|
|
15
|
+
paused: boolean;
|
|
16
|
+
user: SghoUserData;
|
|
17
|
+
}
|
|
18
|
+
export declare const getSghoData: (network: NetworkNumber, address?: EthAddress) => Promise<SghoData>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import Dec from 'decimal.js';
|
|
11
|
+
import { NetworkNumber } from '../types/common';
|
|
12
|
+
import { DEFAULT_TIMEOUT } from '../services/utils';
|
|
13
|
+
import { ZERO_ADDRESS } from '../constants';
|
|
14
|
+
const EMPTY_SGHO_DATA = {
|
|
15
|
+
totalAssets: '0',
|
|
16
|
+
totalSupply: '0',
|
|
17
|
+
supplyCap: '0',
|
|
18
|
+
targetRate: '0',
|
|
19
|
+
paused: false,
|
|
20
|
+
user: {
|
|
21
|
+
shares: '0',
|
|
22
|
+
balance: '0',
|
|
23
|
+
maxDeposit: '0',
|
|
24
|
+
maxWithdraw: '0',
|
|
25
|
+
underlyingBalance: '0',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
const SGHO_VAULT_QUERY = `query SghoVault($request: SghoVaultRequest!) {
|
|
29
|
+
value: sghoVault(request: $request) {
|
|
30
|
+
totalAssets { amount { value } }
|
|
31
|
+
totalSupply { value }
|
|
32
|
+
supplyCap { amount { value } }
|
|
33
|
+
targetRate { value }
|
|
34
|
+
paused
|
|
35
|
+
user {
|
|
36
|
+
shares { amount { value } }
|
|
37
|
+
balance { amount { value } }
|
|
38
|
+
maxDeposit { amount { value } }
|
|
39
|
+
maxWithdraw { amount { value } }
|
|
40
|
+
underlyingBalance { amount { value } }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}`;
|
|
44
|
+
const tokenAmountValue = (entry) => { var _a, _b; return ((_b = (_a = entry === null || entry === void 0 ? void 0 : entry.amount) === null || _a === void 0 ? void 0 : _a.value) === null || _b === void 0 ? void 0 : _b.toString()) || '0'; };
|
|
45
|
+
const decimalValue = (entry) => { var _a; return ((_a = entry === null || entry === void 0 ? void 0 : entry.value) === null || _a === void 0 ? void 0 : _a.toString()) || '0'; };
|
|
46
|
+
// Aave returns the rate as a ratio (e.g. 0.0425); consumers display/compound it as a percent (4.25).
|
|
47
|
+
const percentValue = (entry) => ((entry === null || entry === void 0 ? void 0 : entry.value) != null ? new Dec(entry.value).mul(100).toString() : '0');
|
|
48
|
+
export const getSghoData = (network_1, ...args_1) => __awaiter(void 0, [network_1, ...args_1], void 0, function* (network, address = ZERO_ADDRESS) {
|
|
49
|
+
var _a, _b, _c, _d, _e, _f;
|
|
50
|
+
if (network !== NetworkNumber.Eth)
|
|
51
|
+
return EMPTY_SGHO_DATA;
|
|
52
|
+
try {
|
|
53
|
+
const res = yield fetch('https://api.v3.aave.com/graphql', {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: { 'Content-Type': 'application/json' },
|
|
56
|
+
body: JSON.stringify({
|
|
57
|
+
operationName: 'SghoVault',
|
|
58
|
+
query: SGHO_VAULT_QUERY,
|
|
59
|
+
variables: { request: { chainId: 1, user: address } },
|
|
60
|
+
}),
|
|
61
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT),
|
|
62
|
+
});
|
|
63
|
+
if (!res.ok)
|
|
64
|
+
throw new Error(`Aave SghoVault request failed: ${res.status}`);
|
|
65
|
+
const body = yield res.json();
|
|
66
|
+
const data = (_a = body === null || body === void 0 ? void 0 : body.data) === null || _a === void 0 ? void 0 : _a.value;
|
|
67
|
+
if (!data)
|
|
68
|
+
throw new Error('Aave SghoVault response missing data');
|
|
69
|
+
return {
|
|
70
|
+
totalAssets: tokenAmountValue(data.totalAssets),
|
|
71
|
+
totalSupply: decimalValue(data.totalSupply),
|
|
72
|
+
supplyCap: tokenAmountValue(data.supplyCap),
|
|
73
|
+
targetRate: percentValue(data.targetRate),
|
|
74
|
+
paused: !!data.paused,
|
|
75
|
+
user: {
|
|
76
|
+
shares: tokenAmountValue((_b = data === null || data === void 0 ? void 0 : data.user) === null || _b === void 0 ? void 0 : _b.shares),
|
|
77
|
+
balance: tokenAmountValue((_c = data === null || data === void 0 ? void 0 : data.user) === null || _c === void 0 ? void 0 : _c.balance),
|
|
78
|
+
maxDeposit: tokenAmountValue((_d = data === null || data === void 0 ? void 0 : data.user) === null || _d === void 0 ? void 0 : _d.maxDeposit),
|
|
79
|
+
maxWithdraw: tokenAmountValue((_e = data === null || data === void 0 ? void 0 : data.user) === null || _e === void 0 ? void 0 : _e.maxWithdraw),
|
|
80
|
+
underlyingBalance: tokenAmountValue((_f = data === null || data === void 0 ? void 0 : data.user) === null || _f === void 0 ? void 0 : _f.underlyingBalance),
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
console.error('External API Failure: Failed to fetch Aave sGHO vault data', e);
|
|
86
|
+
return EMPTY_SGHO_DATA;
|
|
87
|
+
}
|
|
88
|
+
});
|
package/esm/aaveV4/index.js
CHANGED
|
@@ -41,6 +41,9 @@ const fetchHubData = (viewContract, hubAddress) => __awaiter(void 0, void 0, voi
|
|
|
41
41
|
const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, network) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
42
|
var _a, _b, _c, _d, _e, _f;
|
|
43
43
|
const assetInfo = getAssetInfoByAddress(reserveAsset.underlying, network);
|
|
44
|
+
// `@defisaver/tokens` returns a placeholder ('?', decimals NaN) when the underlying is not in the
|
|
45
|
+
// tokens package. Flag it so consumers can render it read-only instead of feeding NaN into amounts.
|
|
46
|
+
const isUnsupported = assetInfo.symbol === '?';
|
|
44
47
|
const symbol = wethToEth(assetInfo.symbol);
|
|
45
48
|
const hubInfo = getAaveV4HubByAddress(network, reserveAsset.hub);
|
|
46
49
|
if (!hubInfo) {
|
|
@@ -87,10 +90,23 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
|
|
|
87
90
|
const premiumMultiplier = totalDrawnShares.isZero() ? new Dec(1) : totalDrawnShares.add(totalPremiumShares).div(totalDrawnShares);
|
|
88
91
|
const supplyApr = borrowApr.mul(hubUtilization).mul(premiumMultiplier).mul(new Dec(1).minus(liquidityFee));
|
|
89
92
|
const utilization = hubUtilization.times(100).toString();
|
|
93
|
+
// For unsupported assets `symbol` is '?' (decimals NaN in `@defisaver/tokens`), so the
|
|
94
|
+
// symbol-based conversion would produce NaN. Fall back to the on-chain `decimals` so the reserve
|
|
95
|
+
// still shows correct amounts (and feeds correct USD/ratio/liquidation math) in read-only mode.
|
|
96
|
+
const toEth = (raw) => {
|
|
97
|
+
const rawStr = raw.toString();
|
|
98
|
+
if (isMaxUint(rawStr))
|
|
99
|
+
return rawStr;
|
|
100
|
+
if (isUnsupported)
|
|
101
|
+
return new Dec(rawStr || 0).div(new Dec(10).pow(reserveAsset.decimals)).toString();
|
|
102
|
+
return assetAmountInEth(rawStr, symbol);
|
|
103
|
+
};
|
|
90
104
|
const hubLiquidityRaw = hubAsset.liquidity;
|
|
91
|
-
const hubLiquidity =
|
|
105
|
+
const hubLiquidity = toEth(hubLiquidityRaw.toString());
|
|
92
106
|
return ({
|
|
93
107
|
symbol,
|
|
108
|
+
decimals: reserveAsset.decimals,
|
|
109
|
+
isUnsupported,
|
|
94
110
|
underlying: reserveAsset.underlying,
|
|
95
111
|
hub: hubInfo.address,
|
|
96
112
|
hubName: hubInfo === null || hubInfo === void 0 ? void 0 : hubInfo.label,
|
|
@@ -104,12 +120,12 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
|
|
|
104
120
|
liquidationFee: new Dec(reserveAsset.liquidationFee).div(10000).toNumber(),
|
|
105
121
|
maxLiquidationBonus: new Dec(reserveAsset.maxLiquidationBonus).div(10000).toNumber(),
|
|
106
122
|
price: new Dec(reserveAsset.price).div(new Dec(10).pow(oracleDecimals)).toString(),
|
|
107
|
-
totalSupplied:
|
|
108
|
-
totalDrawn:
|
|
109
|
-
totalPremium:
|
|
110
|
-
totalDebt:
|
|
111
|
-
supplyCap:
|
|
112
|
-
borrowCap:
|
|
123
|
+
totalSupplied: toEth(totalSuppliedRaw.toString()),
|
|
124
|
+
totalDrawn: toEth(totalDrawnRaw.toString()),
|
|
125
|
+
totalPremium: toEth(totalPremiumRaw.toString()),
|
|
126
|
+
totalDebt: toEth(totalDebtRaw.toString()),
|
|
127
|
+
supplyCap: toEth(supplyCapRaw.toString()),
|
|
128
|
+
borrowCap: toEth(borrowCapRaw.toString()),
|
|
113
129
|
spokeActive: reserveAsset.spokeActive,
|
|
114
130
|
spokeHalted: reserveAsset.spokeHalted,
|
|
115
131
|
drawnRate: drawnRate.toString(),
|
|
@@ -117,10 +133,10 @@ const formatReserveAsset = (reserveAsset, hubAsset, reserveId, oracleDecimals, n
|
|
|
117
133
|
supplyRate: aprToApy(supplyApr.toString()),
|
|
118
134
|
supplyIncentives,
|
|
119
135
|
borrowIncentives,
|
|
120
|
-
canBeBorrowed: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
|
|
121
|
-
canBeSupplied: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
|
|
122
|
-
canBeWithdrawn: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
123
|
-
canBePayBacked: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
136
|
+
canBeBorrowed: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
|
|
137
|
+
canBeSupplied: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
|
|
138
|
+
canBeWithdrawn: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
139
|
+
canBePayBacked: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
124
140
|
utilization,
|
|
125
141
|
hubLiquidity,
|
|
126
142
|
premiumMultiplier: premiumMultiplier.toString(),
|
|
@@ -163,17 +179,33 @@ export function _getAaveV4AccountData(provider_1, network_1, spokeData_1, addres
|
|
|
163
179
|
const healthFactorFromContract = new Dec(loanData.healthFactor.toString());
|
|
164
180
|
const healthFactor = isMaxUint(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
|
|
165
181
|
const usedAssets = loanData.reserves.reduce((acc, usedReserveAsset) => {
|
|
166
|
-
|
|
182
|
+
var _a, _b, _c, _d;
|
|
183
|
+
const assetInfo = getAssetInfoByAddress(usedReserveAsset.underlying, network);
|
|
184
|
+
const isUnsupported = assetInfo.symbol === '?';
|
|
185
|
+
const symbol = wethToEth(assetInfo.symbol);
|
|
186
|
+
const identifier = `${symbol}-${+usedReserveAsset.reserveId.toString()}`;
|
|
167
187
|
const reserveData = spokeData.assetsData[identifier];
|
|
168
|
-
const price = reserveData.price;
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
const
|
|
188
|
+
const price = (_a = reserveData === null || reserveData === void 0 ? void 0 : reserveData.price) !== null && _a !== void 0 ? _a : '0';
|
|
189
|
+
// For unsupported assets the symbol-based conversion yields NaN, so use the on-chain decimals
|
|
190
|
+
// from the reserve data instead. If the reserve is missing entirely we can't convert, so fall
|
|
191
|
+
// back to '0' and keep the entry read-only.
|
|
192
|
+
const toEth = (raw) => {
|
|
193
|
+
if (isMaxUint(raw))
|
|
194
|
+
return raw;
|
|
195
|
+
if (!reserveData)
|
|
196
|
+
return '0';
|
|
197
|
+
if (isUnsupported)
|
|
198
|
+
return new Dec(raw || 0).div(new Dec(10).pow(reserveData.decimals)).toString();
|
|
199
|
+
return assetAmountInEth(raw, reserveData.symbol);
|
|
200
|
+
};
|
|
201
|
+
const supplied = toEth(usedReserveAsset.supplied.toString());
|
|
202
|
+
const drawn = toEth(usedReserveAsset.drawn.toString());
|
|
203
|
+
const premium = toEth(usedReserveAsset.premium.toString());
|
|
204
|
+
const borrowed = toEth(usedReserveAsset.totalDebt.toString());
|
|
173
205
|
acc[identifier] = {
|
|
174
|
-
symbol: reserveData.symbol,
|
|
175
|
-
hubName: reserveData.hubName,
|
|
176
|
-
assetId: reserveData.assetId,
|
|
206
|
+
symbol: (_b = reserveData === null || reserveData === void 0 ? void 0 : reserveData.symbol) !== null && _b !== void 0 ? _b : symbol,
|
|
207
|
+
hubName: (_c = reserveData === null || reserveData === void 0 ? void 0 : reserveData.hubName) !== null && _c !== void 0 ? _c : '',
|
|
208
|
+
assetId: (_d = reserveData === null || reserveData === void 0 ? void 0 : reserveData.assetId) !== null && _d !== void 0 ? _d : 0,
|
|
177
209
|
reserveId: +usedReserveAsset.reserveId.toString(),
|
|
178
210
|
supplied,
|
|
179
211
|
suppliedUsd: new Dec(supplied).mul(price).toString(),
|
|
@@ -187,6 +219,7 @@ export function _getAaveV4AccountData(provider_1, network_1, spokeData_1, addres
|
|
|
187
219
|
isBorrowed: usedReserveAsset.isBorrowing,
|
|
188
220
|
collateral: usedReserveAsset.isUsingAsCollateral,
|
|
189
221
|
collateralFactor: new Dec(usedReserveAsset.collateralFactor).div(10000).toNumber(),
|
|
222
|
+
isUnsupported: isUnsupported || !reserveData,
|
|
190
223
|
};
|
|
191
224
|
return acc;
|
|
192
225
|
}, {});
|
package/esm/types/aaveV4.d.ts
CHANGED
|
@@ -74,6 +74,8 @@ export interface AaveV4ReserveAssetOnChain {
|
|
|
74
74
|
}
|
|
75
75
|
export interface AaveV4ReserveAssetData {
|
|
76
76
|
symbol: string;
|
|
77
|
+
/** Underlying token decimals as reported on-chain (independent of `@defisaver/tokens`). */
|
|
78
|
+
decimals: number;
|
|
77
79
|
underlying: EthAddress;
|
|
78
80
|
hub: EthAddress;
|
|
79
81
|
hubName: string;
|
|
@@ -119,6 +121,11 @@ export interface AaveV4ReserveAssetData {
|
|
|
119
121
|
hubLiquidity: string;
|
|
120
122
|
premiumMultiplier: string;
|
|
121
123
|
liquidityFee: string;
|
|
124
|
+
/**
|
|
125
|
+
* True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset).
|
|
126
|
+
* The reserve is kept for read-only display, but amounts are zeroed and all actions are disabled.
|
|
127
|
+
*/
|
|
128
|
+
isUnsupported?: boolean;
|
|
122
129
|
}
|
|
123
130
|
export type AaveV4AssetsData = Record<string, AaveV4ReserveAssetData>;
|
|
124
131
|
export interface AaveV4UsedReserveAsset {
|
|
@@ -138,6 +145,8 @@ export interface AaveV4UsedReserveAsset {
|
|
|
138
145
|
isBorrowed: boolean;
|
|
139
146
|
collateral: boolean;
|
|
140
147
|
collateralFactor: number;
|
|
148
|
+
/** True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset). */
|
|
149
|
+
isUnsupported?: boolean;
|
|
141
150
|
}
|
|
142
151
|
export interface AaveV4AggregatedPositionData {
|
|
143
152
|
suppliedUsd: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defisaver/positions-sdk",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.106-sgho-dev",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./cjs/index.js",
|
|
6
6
|
"module": "./esm/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"author": "",
|
|
22
22
|
"license": "ISC",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@defisaver/tokens": "
|
|
24
|
+
"@defisaver/tokens": "1.7.35-sgho-dev",
|
|
25
25
|
"@types/lodash": "^4.17.15",
|
|
26
26
|
"@types/memoizee": "^0.4.12",
|
|
27
27
|
"decimal.js": "^10.6.0",
|
package/src/aaveV3/index.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
import { getViemProvider, setViemBlockNumber } from '../services/viem';
|
|
45
45
|
import { getMeritCampaigns } from './merit';
|
|
46
46
|
import { getAaveUnderlyingSymbol, getMerkleCampaigns } from './merkl';
|
|
47
|
+
import { getSghoData } from './sgho';
|
|
47
48
|
import { SECONDS_PER_YEAR } from '../constants';
|
|
48
49
|
|
|
49
50
|
export const aaveV3EmodeCategoriesMapping = (extractedState: any, usedAssets: AaveV3UsedAssets) => {
|
|
@@ -604,13 +605,14 @@ export const getStakeAaveData = async (provider: Client, network: NetworkNumber,
|
|
|
604
605
|
const stkGHO = createViemContractFromConfigFunc('Erc20', stkGhoAddress as HexString)(provider, network);
|
|
605
606
|
|
|
606
607
|
|
|
607
|
-
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy] = await Promise.all([
|
|
608
|
+
const [aaveRewardsBalance, emissionsPerSecond, stkAAVEBalance, stkAAVETotalSupply, stkGHOBalance, ghoMeritApy, sgho] = await Promise.all([
|
|
608
609
|
AaveIncentivesController.read.getRewardsBalance([REWARDABLE_ASSETS, address]),
|
|
609
610
|
stkAAVE.read.assets([stkAaveAddress]),
|
|
610
611
|
stkAAVE.read.balanceOf([address]),
|
|
611
612
|
stkAAVE.read.totalSupply(),
|
|
612
613
|
stkGHO.read.balanceOf([address]),
|
|
613
614
|
fetchYearlyMeritApyForStakingGho(),
|
|
615
|
+
getSghoData(network, address),
|
|
614
616
|
]);
|
|
615
617
|
|
|
616
618
|
|
|
@@ -625,6 +627,7 @@ export const getStakeAaveData = async (provider: Client, network: NetworkNumber,
|
|
|
625
627
|
stkGhoBalance: assetAmountInEth(stkGHOBalance.toString(), 'GHO'),
|
|
626
628
|
ghoMeritApy,
|
|
627
629
|
stkAaveApy,
|
|
630
|
+
sgho,
|
|
628
631
|
};
|
|
629
632
|
};
|
|
630
633
|
|
|
@@ -632,3 +635,6 @@ export {
|
|
|
632
635
|
getMeritCampaigns,
|
|
633
636
|
getMerkleCampaigns,
|
|
634
637
|
};
|
|
638
|
+
|
|
639
|
+
export { getSghoData } from './sgho';
|
|
640
|
+
export type { SghoData, SghoUserData } from './sgho';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import Dec from 'decimal.js';
|
|
2
|
+
import { EthAddress, NetworkNumber } from '../types/common';
|
|
3
|
+
import { DEFAULT_TIMEOUT } from '../services/utils';
|
|
4
|
+
import { ZERO_ADDRESS } from '../constants';
|
|
5
|
+
|
|
6
|
+
export interface SghoUserData {
|
|
7
|
+
shares: string;
|
|
8
|
+
balance: string;
|
|
9
|
+
maxDeposit: string;
|
|
10
|
+
maxWithdraw: string;
|
|
11
|
+
underlyingBalance: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface SghoData {
|
|
15
|
+
totalAssets: string;
|
|
16
|
+
totalSupply: string;
|
|
17
|
+
supplyCap: string;
|
|
18
|
+
/** Target savings rate as an APY percent (e.g. "4.25" for 4.25%). */
|
|
19
|
+
targetRate: string;
|
|
20
|
+
paused: boolean;
|
|
21
|
+
user: SghoUserData;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const EMPTY_SGHO_DATA: SghoData = {
|
|
25
|
+
totalAssets: '0',
|
|
26
|
+
totalSupply: '0',
|
|
27
|
+
supplyCap: '0',
|
|
28
|
+
targetRate: '0',
|
|
29
|
+
paused: false,
|
|
30
|
+
user: {
|
|
31
|
+
shares: '0',
|
|
32
|
+
balance: '0',
|
|
33
|
+
maxDeposit: '0',
|
|
34
|
+
maxWithdraw: '0',
|
|
35
|
+
underlyingBalance: '0',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const SGHO_VAULT_QUERY = `query SghoVault($request: SghoVaultRequest!) {
|
|
40
|
+
value: sghoVault(request: $request) {
|
|
41
|
+
totalAssets { amount { value } }
|
|
42
|
+
totalSupply { value }
|
|
43
|
+
supplyCap { amount { value } }
|
|
44
|
+
targetRate { value }
|
|
45
|
+
paused
|
|
46
|
+
user {
|
|
47
|
+
shares { amount { value } }
|
|
48
|
+
balance { amount { value } }
|
|
49
|
+
maxDeposit { amount { value } }
|
|
50
|
+
maxWithdraw { amount { value } }
|
|
51
|
+
underlyingBalance { amount { value } }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}`;
|
|
55
|
+
|
|
56
|
+
const tokenAmountValue = (entry: any): string => entry?.amount?.value?.toString() || '0';
|
|
57
|
+
const decimalValue = (entry: any): string => entry?.value?.toString() || '0';
|
|
58
|
+
// Aave returns the rate as a ratio (e.g. 0.0425); consumers display/compound it as a percent (4.25).
|
|
59
|
+
const percentValue = (entry: any): string => (entry?.value != null ? new Dec(entry.value).mul(100).toString() : '0');
|
|
60
|
+
|
|
61
|
+
export const getSghoData = async (
|
|
62
|
+
network: NetworkNumber,
|
|
63
|
+
address: EthAddress = ZERO_ADDRESS,
|
|
64
|
+
): Promise<SghoData> => {
|
|
65
|
+
if (network !== NetworkNumber.Eth) return EMPTY_SGHO_DATA;
|
|
66
|
+
try {
|
|
67
|
+
const res = await fetch('https://api.v3.aave.com/graphql', {
|
|
68
|
+
method: 'POST',
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
body: JSON.stringify({
|
|
71
|
+
operationName: 'SghoVault',
|
|
72
|
+
query: SGHO_VAULT_QUERY,
|
|
73
|
+
variables: { request: { chainId: 1, user: address } },
|
|
74
|
+
}),
|
|
75
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT),
|
|
76
|
+
});
|
|
77
|
+
if (!res.ok) throw new Error(`Aave SghoVault request failed: ${res.status}`);
|
|
78
|
+
const body = await res.json();
|
|
79
|
+
const data = body?.data?.value;
|
|
80
|
+
if (!data) throw new Error('Aave SghoVault response missing data');
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
totalAssets: tokenAmountValue(data.totalAssets),
|
|
84
|
+
totalSupply: decimalValue(data.totalSupply),
|
|
85
|
+
supplyCap: tokenAmountValue(data.supplyCap),
|
|
86
|
+
targetRate: percentValue(data.targetRate),
|
|
87
|
+
paused: !!data.paused,
|
|
88
|
+
user: {
|
|
89
|
+
shares: tokenAmountValue(data?.user?.shares),
|
|
90
|
+
balance: tokenAmountValue(data?.user?.balance),
|
|
91
|
+
maxDeposit: tokenAmountValue(data?.user?.maxDeposit),
|
|
92
|
+
maxWithdraw: tokenAmountValue(data?.user?.maxWithdraw),
|
|
93
|
+
underlyingBalance: tokenAmountValue(data?.user?.underlyingBalance),
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
} catch (e) {
|
|
97
|
+
console.error('External API Failure: Failed to fetch Aave sGHO vault data', e);
|
|
98
|
+
return EMPTY_SGHO_DATA;
|
|
99
|
+
}
|
|
100
|
+
};
|
package/src/aaveV4/index.ts
CHANGED
|
@@ -50,6 +50,9 @@ const fetchHubData = async (viewContract: ReturnType<typeof AaveV4ViewContractVi
|
|
|
50
50
|
|
|
51
51
|
const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAsset: AaveV4HubAssetOnChainData, reserveId: number, oracleDecimals: number, network: NetworkNumber): Promise<AaveV4ReserveAssetData> => {
|
|
52
52
|
const assetInfo = getAssetInfoByAddress(reserveAsset.underlying, network);
|
|
53
|
+
// `@defisaver/tokens` returns a placeholder ('?', decimals NaN) when the underlying is not in the
|
|
54
|
+
// tokens package. Flag it so consumers can render it read-only instead of feeding NaN into amounts.
|
|
55
|
+
const isUnsupported = assetInfo.symbol === '?';
|
|
53
56
|
const symbol = wethToEth(assetInfo.symbol);
|
|
54
57
|
const hubInfo = getAaveV4HubByAddress(network, reserveAsset.hub);
|
|
55
58
|
if (!hubInfo) {
|
|
@@ -101,11 +104,23 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
|
|
|
101
104
|
const supplyApr = borrowApr.mul(hubUtilization).mul(premiumMultiplier).mul(new Dec(1).minus(liquidityFee));
|
|
102
105
|
const utilization = hubUtilization.times(100).toString();
|
|
103
106
|
|
|
107
|
+
// For unsupported assets `symbol` is '?' (decimals NaN in `@defisaver/tokens`), so the
|
|
108
|
+
// symbol-based conversion would produce NaN. Fall back to the on-chain `decimals` so the reserve
|
|
109
|
+
// still shows correct amounts (and feeds correct USD/ratio/liquidation math) in read-only mode.
|
|
110
|
+
const toEth = (raw: string | number | bigint) => {
|
|
111
|
+
const rawStr = raw.toString();
|
|
112
|
+
if (isMaxUint(rawStr)) return rawStr;
|
|
113
|
+
if (isUnsupported) return new Dec(rawStr || 0).div(new Dec(10).pow(reserveAsset.decimals)).toString();
|
|
114
|
+
return assetAmountInEth(rawStr, symbol);
|
|
115
|
+
};
|
|
116
|
+
|
|
104
117
|
const hubLiquidityRaw = hubAsset.liquidity;
|
|
105
|
-
const hubLiquidity =
|
|
118
|
+
const hubLiquidity = toEth(hubLiquidityRaw.toString());
|
|
106
119
|
|
|
107
120
|
return ({
|
|
108
121
|
symbol,
|
|
122
|
+
decimals: reserveAsset.decimals,
|
|
123
|
+
isUnsupported,
|
|
109
124
|
underlying: reserveAsset.underlying,
|
|
110
125
|
hub: hubInfo.address,
|
|
111
126
|
hubName: hubInfo?.label,
|
|
@@ -119,12 +134,12 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
|
|
|
119
134
|
liquidationFee: new Dec(reserveAsset.liquidationFee).div(10000).toNumber(),
|
|
120
135
|
maxLiquidationBonus: new Dec(reserveAsset.maxLiquidationBonus).div(10000).toNumber(),
|
|
121
136
|
price: new Dec(reserveAsset.price).div(new Dec(10).pow(oracleDecimals)).toString(),
|
|
122
|
-
totalSupplied:
|
|
123
|
-
totalDrawn:
|
|
124
|
-
totalPremium:
|
|
125
|
-
totalDebt:
|
|
126
|
-
supplyCap:
|
|
127
|
-
borrowCap:
|
|
137
|
+
totalSupplied: toEth(totalSuppliedRaw.toString()),
|
|
138
|
+
totalDrawn: toEth(totalDrawnRaw.toString()),
|
|
139
|
+
totalPremium: toEth(totalPremiumRaw.toString()),
|
|
140
|
+
totalDebt: toEth(totalDebtRaw.toString()),
|
|
141
|
+
supplyCap: toEth(supplyCapRaw.toString()),
|
|
142
|
+
borrowCap: toEth(borrowCapRaw.toString()),
|
|
128
143
|
spokeActive: reserveAsset.spokeActive,
|
|
129
144
|
spokeHalted: reserveAsset.spokeHalted,
|
|
130
145
|
drawnRate: drawnRate.toString(),
|
|
@@ -132,10 +147,10 @@ const formatReserveAsset = async (reserveAsset: AaveV4ReserveAssetOnChain, hubAs
|
|
|
132
147
|
supplyRate: aprToApy(supplyApr.toString()),
|
|
133
148
|
supplyIncentives,
|
|
134
149
|
borrowIncentives,
|
|
135
|
-
canBeBorrowed: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
|
|
136
|
-
canBeSupplied: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
|
|
137
|
-
canBeWithdrawn: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
138
|
-
canBePayBacked: reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
150
|
+
canBeBorrowed: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen && reserveAsset.borrowable,
|
|
151
|
+
canBeSupplied: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused && !reserveAsset.frozen,
|
|
152
|
+
canBeWithdrawn: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
153
|
+
canBePayBacked: !isUnsupported && reserveAsset.spokeActive && !reserveAsset.spokeHalted && !reserveAsset.paused,
|
|
139
154
|
utilization,
|
|
140
155
|
hubLiquidity,
|
|
141
156
|
premiumMultiplier: premiumMultiplier.toString(),
|
|
@@ -182,17 +197,29 @@ export async function _getAaveV4AccountData(provider: Client, network: NetworkNu
|
|
|
182
197
|
const healthFactorFromContract = new Dec(loanData.healthFactor.toString());
|
|
183
198
|
const healthFactor = isMaxUint(healthFactorFromContract.toString()) ? 'Infinity' : healthFactorFromContract.div(1e18).toString();
|
|
184
199
|
const usedAssets = loanData.reserves.reduce((acc: AaveV4UsedReserveAssets, usedReserveAsset) => {
|
|
185
|
-
const
|
|
200
|
+
const assetInfo = getAssetInfoByAddress(usedReserveAsset.underlying, network);
|
|
201
|
+
const isUnsupported = assetInfo.symbol === '?';
|
|
202
|
+
const symbol = wethToEth(assetInfo.symbol);
|
|
203
|
+
const identifier = `${symbol}-${+usedReserveAsset.reserveId.toString()}`;
|
|
186
204
|
const reserveData = spokeData.assetsData[identifier];
|
|
187
|
-
const price = reserveData
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
205
|
+
const price = reserveData?.price ?? '0';
|
|
206
|
+
// For unsupported assets the symbol-based conversion yields NaN, so use the on-chain decimals
|
|
207
|
+
// from the reserve data instead. If the reserve is missing entirely we can't convert, so fall
|
|
208
|
+
// back to '0' and keep the entry read-only.
|
|
209
|
+
const toEth = (raw: string) => {
|
|
210
|
+
if (isMaxUint(raw)) return raw;
|
|
211
|
+
if (!reserveData) return '0';
|
|
212
|
+
if (isUnsupported) return new Dec(raw || 0).div(new Dec(10).pow(reserveData.decimals)).toString();
|
|
213
|
+
return assetAmountInEth(raw, reserveData.symbol);
|
|
214
|
+
};
|
|
215
|
+
const supplied = toEth(usedReserveAsset.supplied.toString());
|
|
216
|
+
const drawn = toEth(usedReserveAsset.drawn.toString());
|
|
217
|
+
const premium = toEth(usedReserveAsset.premium.toString());
|
|
218
|
+
const borrowed = toEth(usedReserveAsset.totalDebt.toString());
|
|
192
219
|
acc[identifier] = {
|
|
193
|
-
symbol: reserveData
|
|
194
|
-
hubName: reserveData
|
|
195
|
-
assetId: reserveData
|
|
220
|
+
symbol: reserveData?.symbol ?? symbol,
|
|
221
|
+
hubName: reserveData?.hubName ?? '',
|
|
222
|
+
assetId: reserveData?.assetId ?? 0,
|
|
196
223
|
reserveId: +usedReserveAsset.reserveId.toString(),
|
|
197
224
|
supplied,
|
|
198
225
|
suppliedUsd: new Dec(supplied).mul(price).toString(),
|
|
@@ -206,6 +233,7 @@ export async function _getAaveV4AccountData(provider: Client, network: NetworkNu
|
|
|
206
233
|
isBorrowed: usedReserveAsset.isBorrowing,
|
|
207
234
|
collateral: usedReserveAsset.isUsingAsCollateral,
|
|
208
235
|
collateralFactor: new Dec(usedReserveAsset.collateralFactor).div(10000).toNumber(),
|
|
236
|
+
isUnsupported: isUnsupported || !reserveData,
|
|
209
237
|
};
|
|
210
238
|
return acc;
|
|
211
239
|
}, {});
|
package/src/types/aaveV4.ts
CHANGED
|
@@ -85,6 +85,8 @@ export interface AaveV4ReserveAssetOnChain {
|
|
|
85
85
|
|
|
86
86
|
export interface AaveV4ReserveAssetData {
|
|
87
87
|
symbol: string,
|
|
88
|
+
/** Underlying token decimals as reported on-chain (independent of `@defisaver/tokens`). */
|
|
89
|
+
decimals: number,
|
|
88
90
|
underlying: EthAddress,
|
|
89
91
|
hub: EthAddress,
|
|
90
92
|
hubName: string,
|
|
@@ -130,6 +132,11 @@ export interface AaveV4ReserveAssetData {
|
|
|
130
132
|
hubLiquidity: string,
|
|
131
133
|
premiumMultiplier: string;
|
|
132
134
|
liquidityFee: string;
|
|
135
|
+
/**
|
|
136
|
+
* True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset).
|
|
137
|
+
* The reserve is kept for read-only display, but amounts are zeroed and all actions are disabled.
|
|
138
|
+
*/
|
|
139
|
+
isUnsupported?: boolean;
|
|
133
140
|
}
|
|
134
141
|
|
|
135
142
|
export type AaveV4AssetsData = Record<string, AaveV4ReserveAssetData>;
|
|
@@ -151,6 +158,8 @@ export interface AaveV4UsedReserveAsset {
|
|
|
151
158
|
isBorrowed: boolean,
|
|
152
159
|
collateral: boolean,
|
|
153
160
|
collateralFactor: number,
|
|
161
|
+
/** True when the underlying token is missing from `@defisaver/tokens` (placeholder `?` asset). */
|
|
162
|
+
isUnsupported?: boolean,
|
|
154
163
|
}
|
|
155
164
|
|
|
156
165
|
export interface AaveV4AggregatedPositionData {
|