@agether/sdk 2.18.0 → 2.18.2
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/dist/cli.js +89 -7
- package/dist/index.d.mts +72 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +299 -7
- package/dist/index.mjs +299 -7
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -600,7 +600,7 @@ var init_MorphoClient = __esm({
|
|
|
600
600
|
init_retry();
|
|
601
601
|
init_types();
|
|
602
602
|
init_abis();
|
|
603
|
-
MORPHO_API_URL = "https://api.morpho.org/graphql";
|
|
603
|
+
MORPHO_API_URL = "https://blue-api.morpho.org/graphql";
|
|
604
604
|
morphoIface = new import_ethers2.ethers.Interface(MORPHO_BLUE_ABI);
|
|
605
605
|
erc20Iface = new import_ethers2.ethers.Interface(ERC20_ABI);
|
|
606
606
|
MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
@@ -648,7 +648,7 @@ var init_MorphoClient = __esm({
|
|
|
648
648
|
first: 500
|
|
649
649
|
orderBy: SupplyAssetsUsd
|
|
650
650
|
orderDirection: Desc
|
|
651
|
-
where: { chainId_in: [${chainId}] }
|
|
651
|
+
where: { chainId_in: [${chainId}], whitelisted: true }
|
|
652
652
|
) {
|
|
653
653
|
items {
|
|
654
654
|
uniqueKey
|
|
@@ -1057,7 +1057,7 @@ var init_MorphoClient = __esm({
|
|
|
1057
1057
|
first: 100
|
|
1058
1058
|
orderBy: SupplyAssetsUsd
|
|
1059
1059
|
orderDirection: Desc
|
|
1060
|
-
where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter}${searchClause} }
|
|
1060
|
+
where: { chainId_in: [${chainId}], whitelisted: true${loanFilter}${collateralFilter}${searchClause} }
|
|
1061
1061
|
) {
|
|
1062
1062
|
items {
|
|
1063
1063
|
uniqueKey
|
|
@@ -1067,6 +1067,8 @@ var init_MorphoClient = __esm({
|
|
|
1067
1067
|
state {
|
|
1068
1068
|
borrowAssets
|
|
1069
1069
|
supplyAssets
|
|
1070
|
+
supplyAssetsUsd
|
|
1071
|
+
borrowAssetsUsd
|
|
1070
1072
|
utilization
|
|
1071
1073
|
supplyApy
|
|
1072
1074
|
borrowApy
|
|
@@ -1097,8 +1099,8 @@ var init_MorphoClient = __esm({
|
|
|
1097
1099
|
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
1098
1100
|
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
1099
1101
|
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
1100
|
-
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
1101
|
-
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
1102
|
+
totalSupplyUsd: m.state?.supplyAssetsUsd ? Number(m.state.supplyAssetsUsd) : m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
1103
|
+
totalBorrowUsd: m.state?.borrowAssetsUsd ? Number(m.state.borrowAssetsUsd) : m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
1102
1104
|
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
1103
1105
|
marketId: m.uniqueKey
|
|
1104
1106
|
};
|
|
@@ -1136,6 +1138,8 @@ var init_MorphoClient = __esm({
|
|
|
1136
1138
|
state {
|
|
1137
1139
|
borrowAssets
|
|
1138
1140
|
supplyAssets
|
|
1141
|
+
supplyAssetsUsd
|
|
1142
|
+
borrowAssetsUsd
|
|
1139
1143
|
utilization
|
|
1140
1144
|
supplyApy
|
|
1141
1145
|
borrowApy
|
|
@@ -1338,7 +1342,7 @@ var init_MorphoClient = __esm({
|
|
|
1338
1342
|
} else {
|
|
1339
1343
|
try {
|
|
1340
1344
|
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
1341
|
-
const loanDecimals =
|
|
1345
|
+
const loanDecimals = market.loanDecimals;
|
|
1342
1346
|
const oracleContract = new import_ethers2.Contract(params.oracle, [
|
|
1343
1347
|
"function price() view returns (uint256)"
|
|
1344
1348
|
], this.provider);
|
|
@@ -1881,8 +1885,8 @@ var init_MorphoClient = __esm({
|
|
|
1881
1885
|
const { params: p } = await this._findActiveMarket();
|
|
1882
1886
|
params = p;
|
|
1883
1887
|
}
|
|
1884
|
-
const loanTokenAddr = params.loanToken;
|
|
1885
1888
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1889
|
+
const loanTokenAddr = params.loanToken;
|
|
1886
1890
|
let repayAssets;
|
|
1887
1891
|
let repayShares;
|
|
1888
1892
|
let approveAmount;
|
|
@@ -2260,6 +2264,84 @@ var init_MorphoClient = __esm({
|
|
|
2260
2264
|
// ────────────────────────────────────────────────────────────
|
|
2261
2265
|
// ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
|
|
2262
2266
|
// ────────────────────────────────────────────────────────────
|
|
2267
|
+
/**
|
|
2268
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
2269
|
+
* Full position exit: approve + repay(shares) + withdrawCollateral → 1 UserOp.
|
|
2270
|
+
*/
|
|
2271
|
+
async repayAndWithdraw(tokenSymbol, loanTokenSymbol, toEoa = true) {
|
|
2272
|
+
const acctAddr = await this.getAccountAddress();
|
|
2273
|
+
const morphoAddr = this.config.contracts.morphoBlue;
|
|
2274
|
+
let params;
|
|
2275
|
+
let colSymbol;
|
|
2276
|
+
if (tokenSymbol) {
|
|
2277
|
+
params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
2278
|
+
colSymbol = tokenSymbol;
|
|
2279
|
+
} else {
|
|
2280
|
+
const active = await this._findActiveMarket();
|
|
2281
|
+
params = active.params;
|
|
2282
|
+
colSymbol = active.symbol;
|
|
2283
|
+
}
|
|
2284
|
+
const colInfo = await this._resolveToken(colSymbol);
|
|
2285
|
+
const dest = toEoa ? await this.getSignerAddress() : acctAddr;
|
|
2286
|
+
const marketId = import_ethers2.ethers.keccak256(import_ethers2.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
2287
|
+
["address", "address", "address", "address", "uint256"],
|
|
2288
|
+
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2289
|
+
));
|
|
2290
|
+
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
2291
|
+
const borrowShares = BigInt(pos.borrowShares);
|
|
2292
|
+
const collateralAmount = BigInt(pos.collateral);
|
|
2293
|
+
if (collateralAmount === 0n) {
|
|
2294
|
+
throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
2295
|
+
}
|
|
2296
|
+
const targets = [];
|
|
2297
|
+
const values = [];
|
|
2298
|
+
const datas = [];
|
|
2299
|
+
if (borrowShares > 0n) {
|
|
2300
|
+
const onChainMkt = await this.morphoBlue.market(marketId);
|
|
2301
|
+
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2302
|
+
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2303
|
+
const estimatedDebt = totalBorrowShares > 0n ? borrowShares * totalBorrowAssets / totalBorrowShares + 100n : 0n;
|
|
2304
|
+
const loanContract = new import_ethers2.Contract(params.loanToken, ERC20_ABI, this._signer);
|
|
2305
|
+
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2306
|
+
if (acctBalance < estimatedDebt) {
|
|
2307
|
+
const shortfall = estimatedDebt - acctBalance;
|
|
2308
|
+
const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
|
|
2309
|
+
if (eoaBalance >= shortfall) {
|
|
2310
|
+
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
2311
|
+
await transferTx.wait();
|
|
2312
|
+
this._refreshSigner();
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
targets.push(params.loanToken);
|
|
2316
|
+
values.push(0n);
|
|
2317
|
+
datas.push(erc20Iface.encodeFunctionData("approve", [morphoAddr, estimatedDebt]));
|
|
2318
|
+
targets.push(morphoAddr);
|
|
2319
|
+
values.push(0n);
|
|
2320
|
+
datas.push(morphoIface.encodeFunctionData("repay", [
|
|
2321
|
+
this._toTuple(params),
|
|
2322
|
+
0n,
|
|
2323
|
+
borrowShares,
|
|
2324
|
+
acctAddr,
|
|
2325
|
+
"0x"
|
|
2326
|
+
]));
|
|
2327
|
+
}
|
|
2328
|
+
targets.push(morphoAddr);
|
|
2329
|
+
values.push(0n);
|
|
2330
|
+
datas.push(morphoIface.encodeFunctionData("withdrawCollateral", [
|
|
2331
|
+
this._toTuple(params),
|
|
2332
|
+
collateralAmount,
|
|
2333
|
+
acctAddr,
|
|
2334
|
+
dest
|
|
2335
|
+
]));
|
|
2336
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2337
|
+
return {
|
|
2338
|
+
tx: receipt.hash,
|
|
2339
|
+
repaid: borrowShares > 0n ? "all" : "0",
|
|
2340
|
+
withdrawn: import_ethers2.ethers.formatUnits(collateralAmount, colInfo.decimals),
|
|
2341
|
+
collateralToken: colSymbol,
|
|
2342
|
+
loanToken: this._tokenCache.get(params.loanToken.toLowerCase())?.symbol ?? "unknown"
|
|
2343
|
+
};
|
|
2344
|
+
}
|
|
2263
2345
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
2264
2346
|
_toTuple(p) {
|
|
2265
2347
|
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
package/dist/index.d.mts
CHANGED
|
@@ -1002,6 +1002,17 @@ declare class MorphoClient extends AgentAccountClient {
|
|
|
1002
1002
|
* responsibility.
|
|
1003
1003
|
*/
|
|
1004
1004
|
private _refreshSigner;
|
|
1005
|
+
/**
|
|
1006
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
1007
|
+
* Full position exit: approve + repay(shares) + withdrawCollateral → 1 UserOp.
|
|
1008
|
+
*/
|
|
1009
|
+
repayAndWithdraw(tokenSymbol?: string, loanTokenSymbol?: string, toEoa?: boolean): Promise<{
|
|
1010
|
+
tx: string;
|
|
1011
|
+
repaid: string;
|
|
1012
|
+
withdrawn: string;
|
|
1013
|
+
collateralToken: string;
|
|
1014
|
+
loanToken: string;
|
|
1015
|
+
}>;
|
|
1005
1016
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
1006
1017
|
private _toTuple;
|
|
1007
1018
|
/** Find the first market where the agent has collateral deposited. */
|
|
@@ -1128,6 +1139,67 @@ declare class AaveClient extends AgentAccountClient {
|
|
|
1128
1139
|
* Supply an asset and borrow in one atomic batch operation.
|
|
1129
1140
|
*/
|
|
1130
1141
|
supplyAndBorrow(supplyAsset: string, supplyAmount: string, borrowAsset: string, borrowAmount: string): Promise<ethers.TransactionReceipt>;
|
|
1142
|
+
/**
|
|
1143
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
1144
|
+
* Full position exit: approve + repay + withdraw → 1 UserOp.
|
|
1145
|
+
*/
|
|
1146
|
+
repayAndWithdraw(repayAsset: string, withdrawAsset: string, to?: string): Promise<ethers.TransactionReceipt>;
|
|
1147
|
+
/**
|
|
1148
|
+
* Search reserves by token symbol (case-insensitive partial match).
|
|
1149
|
+
*/
|
|
1150
|
+
searchReserves(query: string): Promise<AaveReserveInfo[]>;
|
|
1151
|
+
/**
|
|
1152
|
+
* Get borrowing options: which tokens can be borrowed, with what collateral.
|
|
1153
|
+
* If collateral symbol given, shows what you can borrow using that as collateral.
|
|
1154
|
+
*/
|
|
1155
|
+
getBorrowingOptions(collateral?: string): Promise<Array<{
|
|
1156
|
+
collateral: string;
|
|
1157
|
+
borrowable: AaveReserveInfo[];
|
|
1158
|
+
collateralBalance: number;
|
|
1159
|
+
collateralValueUsd: number;
|
|
1160
|
+
maxBorrowUsd: number;
|
|
1161
|
+
}>>;
|
|
1162
|
+
/**
|
|
1163
|
+
* Calculate max additional borrowable in USD given current positions.
|
|
1164
|
+
*/
|
|
1165
|
+
getMaxBorrowable(): Promise<{
|
|
1166
|
+
availableBorrowUsd: number;
|
|
1167
|
+
currentLtv: number;
|
|
1168
|
+
liquidationThreshold: number;
|
|
1169
|
+
totalCollateralUsd: number;
|
|
1170
|
+
totalDebtUsd: number;
|
|
1171
|
+
}>;
|
|
1172
|
+
/**
|
|
1173
|
+
* Scan wallet for tokens that exist as Aave reserves.
|
|
1174
|
+
*/
|
|
1175
|
+
getWalletTokens(): Promise<Array<{
|
|
1176
|
+
symbol: string;
|
|
1177
|
+
address: string;
|
|
1178
|
+
eoaBalance: number;
|
|
1179
|
+
safeBalance: number;
|
|
1180
|
+
priceUsd: number;
|
|
1181
|
+
valueUsd: number;
|
|
1182
|
+
canSupply: boolean;
|
|
1183
|
+
canBorrow: boolean;
|
|
1184
|
+
}>>;
|
|
1185
|
+
/**
|
|
1186
|
+
* Get yield spread for LST carry trades on Aave.
|
|
1187
|
+
* Compares LST native yield vs Aave borrow rates.
|
|
1188
|
+
*/
|
|
1189
|
+
getYieldSpread(_minLiquidity?: number): Promise<Array<{
|
|
1190
|
+
collateralToken: string;
|
|
1191
|
+
loanToken: string;
|
|
1192
|
+
collateralYield: number;
|
|
1193
|
+
borrowRate: number;
|
|
1194
|
+
netSpread: number;
|
|
1195
|
+
profitable: boolean;
|
|
1196
|
+
collateralLtv: number;
|
|
1197
|
+
maxSafeLeverage: number;
|
|
1198
|
+
}>>;
|
|
1199
|
+
private static readonly LST_PROJECT_MAP;
|
|
1200
|
+
private static _lstYieldCache;
|
|
1201
|
+
private static readonly LST_CACHE_TTL;
|
|
1202
|
+
private _getLstYields;
|
|
1131
1203
|
private _resolveReserve;
|
|
1132
1204
|
}
|
|
1133
1205
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1002,6 +1002,17 @@ declare class MorphoClient extends AgentAccountClient {
|
|
|
1002
1002
|
* responsibility.
|
|
1003
1003
|
*/
|
|
1004
1004
|
private _refreshSigner;
|
|
1005
|
+
/**
|
|
1006
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
1007
|
+
* Full position exit: approve + repay(shares) + withdrawCollateral → 1 UserOp.
|
|
1008
|
+
*/
|
|
1009
|
+
repayAndWithdraw(tokenSymbol?: string, loanTokenSymbol?: string, toEoa?: boolean): Promise<{
|
|
1010
|
+
tx: string;
|
|
1011
|
+
repaid: string;
|
|
1012
|
+
withdrawn: string;
|
|
1013
|
+
collateralToken: string;
|
|
1014
|
+
loanToken: string;
|
|
1015
|
+
}>;
|
|
1005
1016
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
1006
1017
|
private _toTuple;
|
|
1007
1018
|
/** Find the first market where the agent has collateral deposited. */
|
|
@@ -1128,6 +1139,67 @@ declare class AaveClient extends AgentAccountClient {
|
|
|
1128
1139
|
* Supply an asset and borrow in one atomic batch operation.
|
|
1129
1140
|
*/
|
|
1130
1141
|
supplyAndBorrow(supplyAsset: string, supplyAmount: string, borrowAsset: string, borrowAmount: string): Promise<ethers.TransactionReceipt>;
|
|
1142
|
+
/**
|
|
1143
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
1144
|
+
* Full position exit: approve + repay + withdraw → 1 UserOp.
|
|
1145
|
+
*/
|
|
1146
|
+
repayAndWithdraw(repayAsset: string, withdrawAsset: string, to?: string): Promise<ethers.TransactionReceipt>;
|
|
1147
|
+
/**
|
|
1148
|
+
* Search reserves by token symbol (case-insensitive partial match).
|
|
1149
|
+
*/
|
|
1150
|
+
searchReserves(query: string): Promise<AaveReserveInfo[]>;
|
|
1151
|
+
/**
|
|
1152
|
+
* Get borrowing options: which tokens can be borrowed, with what collateral.
|
|
1153
|
+
* If collateral symbol given, shows what you can borrow using that as collateral.
|
|
1154
|
+
*/
|
|
1155
|
+
getBorrowingOptions(collateral?: string): Promise<Array<{
|
|
1156
|
+
collateral: string;
|
|
1157
|
+
borrowable: AaveReserveInfo[];
|
|
1158
|
+
collateralBalance: number;
|
|
1159
|
+
collateralValueUsd: number;
|
|
1160
|
+
maxBorrowUsd: number;
|
|
1161
|
+
}>>;
|
|
1162
|
+
/**
|
|
1163
|
+
* Calculate max additional borrowable in USD given current positions.
|
|
1164
|
+
*/
|
|
1165
|
+
getMaxBorrowable(): Promise<{
|
|
1166
|
+
availableBorrowUsd: number;
|
|
1167
|
+
currentLtv: number;
|
|
1168
|
+
liquidationThreshold: number;
|
|
1169
|
+
totalCollateralUsd: number;
|
|
1170
|
+
totalDebtUsd: number;
|
|
1171
|
+
}>;
|
|
1172
|
+
/**
|
|
1173
|
+
* Scan wallet for tokens that exist as Aave reserves.
|
|
1174
|
+
*/
|
|
1175
|
+
getWalletTokens(): Promise<Array<{
|
|
1176
|
+
symbol: string;
|
|
1177
|
+
address: string;
|
|
1178
|
+
eoaBalance: number;
|
|
1179
|
+
safeBalance: number;
|
|
1180
|
+
priceUsd: number;
|
|
1181
|
+
valueUsd: number;
|
|
1182
|
+
canSupply: boolean;
|
|
1183
|
+
canBorrow: boolean;
|
|
1184
|
+
}>>;
|
|
1185
|
+
/**
|
|
1186
|
+
* Get yield spread for LST carry trades on Aave.
|
|
1187
|
+
* Compares LST native yield vs Aave borrow rates.
|
|
1188
|
+
*/
|
|
1189
|
+
getYieldSpread(_minLiquidity?: number): Promise<Array<{
|
|
1190
|
+
collateralToken: string;
|
|
1191
|
+
loanToken: string;
|
|
1192
|
+
collateralYield: number;
|
|
1193
|
+
borrowRate: number;
|
|
1194
|
+
netSpread: number;
|
|
1195
|
+
profitable: boolean;
|
|
1196
|
+
collateralLtv: number;
|
|
1197
|
+
maxSafeLeverage: number;
|
|
1198
|
+
}>>;
|
|
1199
|
+
private static readonly LST_PROJECT_MAP;
|
|
1200
|
+
private static _lstYieldCache;
|
|
1201
|
+
private static readonly LST_CACHE_TTL;
|
|
1202
|
+
private _getLstYields;
|
|
1131
1203
|
private _resolveReserve;
|
|
1132
1204
|
}
|
|
1133
1205
|
|
package/dist/index.js
CHANGED
|
@@ -1570,7 +1570,7 @@ async function withRetry(fn, options = {}) {
|
|
|
1570
1570
|
}
|
|
1571
1571
|
|
|
1572
1572
|
// src/clients/MorphoClient.ts
|
|
1573
|
-
var MORPHO_API_URL2 = "https://api.morpho.org/graphql";
|
|
1573
|
+
var MORPHO_API_URL2 = "https://blue-api.morpho.org/graphql";
|
|
1574
1574
|
var morphoIface = new import_ethers3.ethers.Interface(MORPHO_BLUE_ABI);
|
|
1575
1575
|
var erc20Iface2 = new import_ethers3.ethers.Interface(ERC20_ABI);
|
|
1576
1576
|
var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
@@ -1618,7 +1618,7 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
1618
1618
|
first: 500
|
|
1619
1619
|
orderBy: SupplyAssetsUsd
|
|
1620
1620
|
orderDirection: Desc
|
|
1621
|
-
where: { chainId_in: [${chainId}] }
|
|
1621
|
+
where: { chainId_in: [${chainId}], whitelisted: true }
|
|
1622
1622
|
) {
|
|
1623
1623
|
items {
|
|
1624
1624
|
uniqueKey
|
|
@@ -2027,7 +2027,7 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2027
2027
|
first: 100
|
|
2028
2028
|
orderBy: SupplyAssetsUsd
|
|
2029
2029
|
orderDirection: Desc
|
|
2030
|
-
where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter}${searchClause} }
|
|
2030
|
+
where: { chainId_in: [${chainId}], whitelisted: true${loanFilter}${collateralFilter}${searchClause} }
|
|
2031
2031
|
) {
|
|
2032
2032
|
items {
|
|
2033
2033
|
uniqueKey
|
|
@@ -2037,6 +2037,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2037
2037
|
state {
|
|
2038
2038
|
borrowAssets
|
|
2039
2039
|
supplyAssets
|
|
2040
|
+
supplyAssetsUsd
|
|
2041
|
+
borrowAssetsUsd
|
|
2040
2042
|
utilization
|
|
2041
2043
|
supplyApy
|
|
2042
2044
|
borrowApy
|
|
@@ -2067,8 +2069,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2067
2069
|
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
2068
2070
|
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
2069
2071
|
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
2070
|
-
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
2071
|
-
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
2072
|
+
totalSupplyUsd: m.state?.supplyAssetsUsd ? Number(m.state.supplyAssetsUsd) : m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
2073
|
+
totalBorrowUsd: m.state?.borrowAssetsUsd ? Number(m.state.borrowAssetsUsd) : m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
2072
2074
|
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
2073
2075
|
marketId: m.uniqueKey
|
|
2074
2076
|
};
|
|
@@ -2106,6 +2108,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2106
2108
|
state {
|
|
2107
2109
|
borrowAssets
|
|
2108
2110
|
supplyAssets
|
|
2111
|
+
supplyAssetsUsd
|
|
2112
|
+
borrowAssetsUsd
|
|
2109
2113
|
utilization
|
|
2110
2114
|
supplyApy
|
|
2111
2115
|
borrowApy
|
|
@@ -2308,7 +2312,7 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2308
2312
|
} else {
|
|
2309
2313
|
try {
|
|
2310
2314
|
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
2311
|
-
const loanDecimals =
|
|
2315
|
+
const loanDecimals = market.loanDecimals;
|
|
2312
2316
|
const oracleContract = new import_ethers3.Contract(params.oracle, [
|
|
2313
2317
|
"function price() view returns (uint256)"
|
|
2314
2318
|
], this.provider);
|
|
@@ -2851,8 +2855,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2851
2855
|
const { params: p } = await this._findActiveMarket();
|
|
2852
2856
|
params = p;
|
|
2853
2857
|
}
|
|
2854
|
-
const loanTokenAddr = params.loanToken;
|
|
2855
2858
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2859
|
+
const loanTokenAddr = params.loanToken;
|
|
2856
2860
|
let repayAssets;
|
|
2857
2861
|
let repayShares;
|
|
2858
2862
|
let approveAmount;
|
|
@@ -3200,6 +3204,84 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
3200
3204
|
// ────────────────────────────────────────────────────────────
|
|
3201
3205
|
// ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
|
|
3202
3206
|
// ────────────────────────────────────────────────────────────
|
|
3207
|
+
/**
|
|
3208
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
3209
|
+
* Full position exit: approve + repay(shares) + withdrawCollateral → 1 UserOp.
|
|
3210
|
+
*/
|
|
3211
|
+
async repayAndWithdraw(tokenSymbol, loanTokenSymbol, toEoa = true) {
|
|
3212
|
+
const acctAddr = await this.getAccountAddress();
|
|
3213
|
+
const morphoAddr = this.config.contracts.morphoBlue;
|
|
3214
|
+
let params;
|
|
3215
|
+
let colSymbol;
|
|
3216
|
+
if (tokenSymbol) {
|
|
3217
|
+
params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
3218
|
+
colSymbol = tokenSymbol;
|
|
3219
|
+
} else {
|
|
3220
|
+
const active = await this._findActiveMarket();
|
|
3221
|
+
params = active.params;
|
|
3222
|
+
colSymbol = active.symbol;
|
|
3223
|
+
}
|
|
3224
|
+
const colInfo = await this._resolveToken(colSymbol);
|
|
3225
|
+
const dest = toEoa ? await this.getSignerAddress() : acctAddr;
|
|
3226
|
+
const marketId = import_ethers3.ethers.keccak256(import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
3227
|
+
["address", "address", "address", "address", "uint256"],
|
|
3228
|
+
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
3229
|
+
));
|
|
3230
|
+
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
3231
|
+
const borrowShares = BigInt(pos.borrowShares);
|
|
3232
|
+
const collateralAmount = BigInt(pos.collateral);
|
|
3233
|
+
if (collateralAmount === 0n) {
|
|
3234
|
+
throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
3235
|
+
}
|
|
3236
|
+
const targets = [];
|
|
3237
|
+
const values = [];
|
|
3238
|
+
const datas = [];
|
|
3239
|
+
if (borrowShares > 0n) {
|
|
3240
|
+
const onChainMkt = await this.morphoBlue.market(marketId);
|
|
3241
|
+
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
3242
|
+
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
3243
|
+
const estimatedDebt = totalBorrowShares > 0n ? borrowShares * totalBorrowAssets / totalBorrowShares + 100n : 0n;
|
|
3244
|
+
const loanContract = new import_ethers3.Contract(params.loanToken, ERC20_ABI, this._signer);
|
|
3245
|
+
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
3246
|
+
if (acctBalance < estimatedDebt) {
|
|
3247
|
+
const shortfall = estimatedDebt - acctBalance;
|
|
3248
|
+
const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
|
|
3249
|
+
if (eoaBalance >= shortfall) {
|
|
3250
|
+
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
3251
|
+
await transferTx.wait();
|
|
3252
|
+
this._refreshSigner();
|
|
3253
|
+
}
|
|
3254
|
+
}
|
|
3255
|
+
targets.push(params.loanToken);
|
|
3256
|
+
values.push(0n);
|
|
3257
|
+
datas.push(erc20Iface2.encodeFunctionData("approve", [morphoAddr, estimatedDebt]));
|
|
3258
|
+
targets.push(morphoAddr);
|
|
3259
|
+
values.push(0n);
|
|
3260
|
+
datas.push(morphoIface.encodeFunctionData("repay", [
|
|
3261
|
+
this._toTuple(params),
|
|
3262
|
+
0n,
|
|
3263
|
+
borrowShares,
|
|
3264
|
+
acctAddr,
|
|
3265
|
+
"0x"
|
|
3266
|
+
]));
|
|
3267
|
+
}
|
|
3268
|
+
targets.push(morphoAddr);
|
|
3269
|
+
values.push(0n);
|
|
3270
|
+
datas.push(morphoIface.encodeFunctionData("withdrawCollateral", [
|
|
3271
|
+
this._toTuple(params),
|
|
3272
|
+
collateralAmount,
|
|
3273
|
+
acctAddr,
|
|
3274
|
+
dest
|
|
3275
|
+
]));
|
|
3276
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
3277
|
+
return {
|
|
3278
|
+
tx: receipt.hash,
|
|
3279
|
+
repaid: borrowShares > 0n ? "all" : "0",
|
|
3280
|
+
withdrawn: import_ethers3.ethers.formatUnits(collateralAmount, colInfo.decimals),
|
|
3281
|
+
collateralToken: colSymbol,
|
|
3282
|
+
loanToken: this._tokenCache.get(params.loanToken.toLowerCase())?.symbol ?? "unknown"
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3203
3285
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
3204
3286
|
_toTuple(p) {
|
|
3205
3287
|
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
|
@@ -3791,6 +3873,199 @@ var _AaveClient = class _AaveClient extends AgentAccountClient {
|
|
|
3791
3873
|
);
|
|
3792
3874
|
}
|
|
3793
3875
|
// ─── Helpers ──────────────────────────────────────────────────────────
|
|
3876
|
+
/**
|
|
3877
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
3878
|
+
* Full position exit: approve + repay + withdraw → 1 UserOp.
|
|
3879
|
+
*/
|
|
3880
|
+
async repayAndWithdraw(repayAsset, withdrawAsset, to) {
|
|
3881
|
+
const repayReserve = this._resolveReserve(repayAsset);
|
|
3882
|
+
const withdrawReserve = this._resolveReserve(withdrawAsset);
|
|
3883
|
+
const safeAddr = await this.getAccountAddress();
|
|
3884
|
+
const poolAddr = await this._pool.getAddress();
|
|
3885
|
+
const recipient = to ?? safeAddr;
|
|
3886
|
+
const targets = [];
|
|
3887
|
+
const values = [];
|
|
3888
|
+
const datas = [];
|
|
3889
|
+
targets.push(repayReserve.address);
|
|
3890
|
+
values.push(0n);
|
|
3891
|
+
datas.push(this._erc20Iface.encodeFunctionData("approve", [poolAddr, import_ethers4.ethers.MaxUint256]));
|
|
3892
|
+
targets.push(poolAddr);
|
|
3893
|
+
values.push(0n);
|
|
3894
|
+
datas.push(this._poolIface.encodeFunctionData("repay", [
|
|
3895
|
+
repayReserve.address,
|
|
3896
|
+
import_ethers4.ethers.MaxUint256,
|
|
3897
|
+
2,
|
|
3898
|
+
safeAddr
|
|
3899
|
+
]));
|
|
3900
|
+
targets.push(poolAddr);
|
|
3901
|
+
values.push(0n);
|
|
3902
|
+
datas.push(this._poolIface.encodeFunctionData("withdraw", [
|
|
3903
|
+
withdrawReserve.address,
|
|
3904
|
+
import_ethers4.ethers.MaxUint256,
|
|
3905
|
+
recipient
|
|
3906
|
+
]));
|
|
3907
|
+
return this.executeBatch(targets, values, datas);
|
|
3908
|
+
}
|
|
3909
|
+
// ─── Market Discovery ─────────────────────────────────────────────────
|
|
3910
|
+
/**
|
|
3911
|
+
* Search reserves by token symbol (case-insensitive partial match).
|
|
3912
|
+
*/
|
|
3913
|
+
async searchReserves(query) {
|
|
3914
|
+
const reserves = await this.getReserves();
|
|
3915
|
+
const q = query.toLowerCase();
|
|
3916
|
+
return reserves.filter(
|
|
3917
|
+
(r) => r.symbol.toLowerCase().includes(q) || r.address.toLowerCase() === q
|
|
3918
|
+
);
|
|
3919
|
+
}
|
|
3920
|
+
/**
|
|
3921
|
+
* Get borrowing options: which tokens can be borrowed, with what collateral.
|
|
3922
|
+
* If collateral symbol given, shows what you can borrow using that as collateral.
|
|
3923
|
+
*/
|
|
3924
|
+
async getBorrowingOptions(collateral) {
|
|
3925
|
+
const reserves = await this.getReserves();
|
|
3926
|
+
const safeAddr = await this.getAccountAddress();
|
|
3927
|
+
const results = [];
|
|
3928
|
+
const eoaAddr = this.getWalletAddress();
|
|
3929
|
+
for (const reserve of reserves) {
|
|
3930
|
+
if (!reserve.isActive || reserve.ltv === 0) continue;
|
|
3931
|
+
if (collateral && reserve.symbol.toLowerCase() !== collateral.toLowerCase()) continue;
|
|
3932
|
+
const token = new import_ethers4.Contract(reserve.address, [
|
|
3933
|
+
"function balanceOf(address) view returns (uint256)"
|
|
3934
|
+
], this.provider);
|
|
3935
|
+
const [eoaBal, safeBal] = await Promise.all([
|
|
3936
|
+
token.balanceOf(eoaAddr).catch(() => 0n),
|
|
3937
|
+
token.balanceOf(safeAddr).catch(() => 0n)
|
|
3938
|
+
]);
|
|
3939
|
+
const totalBal = Number(eoaBal + safeBal) / 10 ** reserve.decimals;
|
|
3940
|
+
if (totalBal <= 0 && !collateral) continue;
|
|
3941
|
+
const collateralValueUsd = totalBal * reserve.priceUsd;
|
|
3942
|
+
const maxBorrowUsd = collateralValueUsd * (reserve.ltv / 100);
|
|
3943
|
+
const borrowable = reserves.filter((r) => r.borrowingEnabled && r.isActive && r.symbol !== reserve.symbol);
|
|
3944
|
+
results.push({
|
|
3945
|
+
collateral: reserve.symbol,
|
|
3946
|
+
borrowable,
|
|
3947
|
+
collateralBalance: totalBal,
|
|
3948
|
+
collateralValueUsd,
|
|
3949
|
+
maxBorrowUsd
|
|
3950
|
+
});
|
|
3951
|
+
}
|
|
3952
|
+
return results;
|
|
3953
|
+
}
|
|
3954
|
+
/**
|
|
3955
|
+
* Calculate max additional borrowable in USD given current positions.
|
|
3956
|
+
*/
|
|
3957
|
+
async getMaxBorrowable() {
|
|
3958
|
+
const data = await this.getAccountData();
|
|
3959
|
+
return {
|
|
3960
|
+
availableBorrowUsd: data.availableBorrowUsd,
|
|
3961
|
+
currentLtv: data.currentLtv,
|
|
3962
|
+
liquidationThreshold: data.liquidationThreshold,
|
|
3963
|
+
totalCollateralUsd: data.totalCollateralUsd,
|
|
3964
|
+
totalDebtUsd: data.totalDebtUsd
|
|
3965
|
+
};
|
|
3966
|
+
}
|
|
3967
|
+
/**
|
|
3968
|
+
* Scan wallet for tokens that exist as Aave reserves.
|
|
3969
|
+
*/
|
|
3970
|
+
async getWalletTokens() {
|
|
3971
|
+
const reserves = await this.getReserves();
|
|
3972
|
+
const safeAddr = await this.getAccountAddress();
|
|
3973
|
+
const eoaAddr = this.getWalletAddress();
|
|
3974
|
+
const results = [];
|
|
3975
|
+
const promises = reserves.map(async (reserve) => {
|
|
3976
|
+
const token = new import_ethers4.Contract(reserve.address, [
|
|
3977
|
+
"function balanceOf(address) view returns (uint256)"
|
|
3978
|
+
], this.provider);
|
|
3979
|
+
const [eoaBal, safeBal] = await Promise.all([
|
|
3980
|
+
token.balanceOf(eoaAddr).catch(() => 0n),
|
|
3981
|
+
token.balanceOf(safeAddr).catch(() => 0n)
|
|
3982
|
+
]);
|
|
3983
|
+
const eoaBalance = Number(eoaBal) / 10 ** reserve.decimals;
|
|
3984
|
+
const safeBalance = Number(safeBal) / 10 ** reserve.decimals;
|
|
3985
|
+
if (eoaBalance > 0 || safeBalance > 0) {
|
|
3986
|
+
return {
|
|
3987
|
+
symbol: reserve.symbol,
|
|
3988
|
+
address: reserve.address,
|
|
3989
|
+
eoaBalance,
|
|
3990
|
+
safeBalance,
|
|
3991
|
+
priceUsd: reserve.priceUsd,
|
|
3992
|
+
valueUsd: (eoaBalance + safeBalance) * reserve.priceUsd,
|
|
3993
|
+
canSupply: reserve.isActive,
|
|
3994
|
+
canBorrow: reserve.borrowingEnabled
|
|
3995
|
+
};
|
|
3996
|
+
}
|
|
3997
|
+
return null;
|
|
3998
|
+
});
|
|
3999
|
+
const settled = await Promise.all(promises);
|
|
4000
|
+
for (const r of settled) {
|
|
4001
|
+
if (r) results.push(r);
|
|
4002
|
+
}
|
|
4003
|
+
return results;
|
|
4004
|
+
}
|
|
4005
|
+
/**
|
|
4006
|
+
* Get yield spread for LST carry trades on Aave.
|
|
4007
|
+
* Compares LST native yield vs Aave borrow rates.
|
|
4008
|
+
*/
|
|
4009
|
+
async getYieldSpread(_minLiquidity = 0) {
|
|
4010
|
+
const reserves = await this.getReserves();
|
|
4011
|
+
const lstYields = await this._getLstYields();
|
|
4012
|
+
if (Object.keys(lstYields).length === 0) return [];
|
|
4013
|
+
const results = [];
|
|
4014
|
+
for (const [symbol, yieldApy] of Object.entries(lstYields)) {
|
|
4015
|
+
const collateralReserve = reserves.find((r) => r.symbol.toLowerCase() === symbol.toLowerCase());
|
|
4016
|
+
if (!collateralReserve || !collateralReserve.isActive || collateralReserve.ltv === 0) continue;
|
|
4017
|
+
for (const loanReserve of reserves) {
|
|
4018
|
+
if (!loanReserve.borrowingEnabled || !loanReserve.isActive) continue;
|
|
4019
|
+
if (loanReserve.symbol === collateralReserve.symbol) continue;
|
|
4020
|
+
const netSpread = yieldApy - loanReserve.borrowApy;
|
|
4021
|
+
const safeLtv = collateralReserve.ltv / 100 * 0.8;
|
|
4022
|
+
const maxLeverage = 1 / (1 - safeLtv);
|
|
4023
|
+
results.push({
|
|
4024
|
+
collateralToken: collateralReserve.symbol,
|
|
4025
|
+
loanToken: loanReserve.symbol,
|
|
4026
|
+
collateralYield: yieldApy,
|
|
4027
|
+
borrowRate: loanReserve.borrowApy,
|
|
4028
|
+
netSpread,
|
|
4029
|
+
profitable: netSpread > 0,
|
|
4030
|
+
collateralLtv: collateralReserve.ltv,
|
|
4031
|
+
maxSafeLeverage: parseFloat(maxLeverage.toFixed(2))
|
|
4032
|
+
});
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
return results.sort((a, b) => b.netSpread - a.netSpread);
|
|
4036
|
+
}
|
|
4037
|
+
async _getLstYields() {
|
|
4038
|
+
if (_AaveClient._lstYieldCache && Date.now() - _AaveClient._lstYieldCache.ts < _AaveClient.LST_CACHE_TTL) {
|
|
4039
|
+
return _AaveClient._lstYieldCache.data;
|
|
4040
|
+
}
|
|
4041
|
+
const yields = {};
|
|
4042
|
+
try {
|
|
4043
|
+
const resp = await fetch("https://yields.llama.fi/pools", {
|
|
4044
|
+
headers: { "User-Agent": "agether-sdk/1.0" },
|
|
4045
|
+
signal: AbortSignal.timeout(1e4)
|
|
4046
|
+
});
|
|
4047
|
+
if (!resp.ok) return yields;
|
|
4048
|
+
const data = await resp.json();
|
|
4049
|
+
const pools = data?.data ?? [];
|
|
4050
|
+
for (const [morphoSymbol, mapping] of Object.entries(_AaveClient.LST_PROJECT_MAP)) {
|
|
4051
|
+
const matchingPools = pools.filter(
|
|
4052
|
+
(p) => p.project === mapping.project && p.symbol?.toUpperCase() === mapping.symbol && ["Ethereum", "Base"].includes(p.chain)
|
|
4053
|
+
);
|
|
4054
|
+
if (matchingPools.length > 0) {
|
|
4055
|
+
const best = matchingPools.reduce(
|
|
4056
|
+
(a, b) => (b.tvlUsd ?? 0) > (a.tvlUsd ?? 0) ? b : a
|
|
4057
|
+
);
|
|
4058
|
+
if (best.apy !== void 0 && best.apy > 0) {
|
|
4059
|
+
yields[morphoSymbol] = parseFloat(best.apy.toFixed(4));
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
}
|
|
4063
|
+
} catch (e) {
|
|
4064
|
+
console.warn("[aave] Failed to fetch LST yields:", e instanceof Error ? e.message : e);
|
|
4065
|
+
}
|
|
4066
|
+
_AaveClient._lstYieldCache = { data: yields, ts: Date.now() };
|
|
4067
|
+
return yields;
|
|
4068
|
+
}
|
|
3794
4069
|
_resolveReserve(symbolOrAddress) {
|
|
3795
4070
|
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3796
4071
|
const bySymbol = reserves.find((r) => r.symbol.toLowerCase() === symbolOrAddress.toLowerCase());
|
|
@@ -3804,6 +4079,23 @@ var _AaveClient = class _AaveClient extends AgentAccountClient {
|
|
|
3804
4079
|
}
|
|
3805
4080
|
};
|
|
3806
4081
|
_AaveClient.CACHE_TTL = 6e4;
|
|
4082
|
+
// ─── DeFi Llama LST Yields (shared logic) ─────────────────────────────
|
|
4083
|
+
_AaveClient.LST_PROJECT_MAP = {
|
|
4084
|
+
"wstETH": { project: "lido", symbol: "STETH" },
|
|
4085
|
+
"cbETH": { project: "coinbase-wrapped-staked-eth", symbol: "CBETH" },
|
|
4086
|
+
"rETH": { project: "rocket-pool", symbol: "RETH" },
|
|
4087
|
+
"weETH": { project: "ether.fi-stake", symbol: "WEETH" },
|
|
4088
|
+
"ezETH": { project: "renzo", symbol: "EZETH" },
|
|
4089
|
+
"rsETH": { project: "kelp", symbol: "RSETH" },
|
|
4090
|
+
"swETH": { project: "swell-liquid-staking", symbol: "SWETH" },
|
|
4091
|
+
"mETH": { project: "meth-protocol", symbol: "METH" },
|
|
4092
|
+
"sfrxETH": { project: "frax-ether", symbol: "SFRXETH" },
|
|
4093
|
+
"oETH": { project: "origin-ether", symbol: "OETH" },
|
|
4094
|
+
"ETHx": { project: "stader", symbol: "ETHX" },
|
|
4095
|
+
"wBETH": { project: "binance-staked-eth", symbol: "WBETH" }
|
|
4096
|
+
};
|
|
4097
|
+
_AaveClient._lstYieldCache = null;
|
|
4098
|
+
_AaveClient.LST_CACHE_TTL = 30 * 60 * 1e3;
|
|
3807
4099
|
var AaveClient = _AaveClient;
|
|
3808
4100
|
|
|
3809
4101
|
// src/clients/ScoringClient.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1492,7 +1492,7 @@ async function withRetry(fn, options = {}) {
|
|
|
1492
1492
|
}
|
|
1493
1493
|
|
|
1494
1494
|
// src/clients/MorphoClient.ts
|
|
1495
|
-
var MORPHO_API_URL2 = "https://api.morpho.org/graphql";
|
|
1495
|
+
var MORPHO_API_URL2 = "https://blue-api.morpho.org/graphql";
|
|
1496
1496
|
var morphoIface = new ethers3.Interface(MORPHO_BLUE_ABI);
|
|
1497
1497
|
var erc20Iface2 = new ethers3.Interface(ERC20_ABI);
|
|
1498
1498
|
var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
@@ -1540,7 +1540,7 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
1540
1540
|
first: 500
|
|
1541
1541
|
orderBy: SupplyAssetsUsd
|
|
1542
1542
|
orderDirection: Desc
|
|
1543
|
-
where: { chainId_in: [${chainId}] }
|
|
1543
|
+
where: { chainId_in: [${chainId}], whitelisted: true }
|
|
1544
1544
|
) {
|
|
1545
1545
|
items {
|
|
1546
1546
|
uniqueKey
|
|
@@ -1949,7 +1949,7 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
1949
1949
|
first: 100
|
|
1950
1950
|
orderBy: SupplyAssetsUsd
|
|
1951
1951
|
orderDirection: Desc
|
|
1952
|
-
where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter}${searchClause} }
|
|
1952
|
+
where: { chainId_in: [${chainId}], whitelisted: true${loanFilter}${collateralFilter}${searchClause} }
|
|
1953
1953
|
) {
|
|
1954
1954
|
items {
|
|
1955
1955
|
uniqueKey
|
|
@@ -1959,6 +1959,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
1959
1959
|
state {
|
|
1960
1960
|
borrowAssets
|
|
1961
1961
|
supplyAssets
|
|
1962
|
+
supplyAssetsUsd
|
|
1963
|
+
borrowAssetsUsd
|
|
1962
1964
|
utilization
|
|
1963
1965
|
supplyApy
|
|
1964
1966
|
borrowApy
|
|
@@ -1989,8 +1991,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
1989
1991
|
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
1990
1992
|
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
1991
1993
|
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
1992
|
-
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
1993
|
-
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
1994
|
+
totalSupplyUsd: m.state?.supplyAssetsUsd ? Number(m.state.supplyAssetsUsd) : m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
1995
|
+
totalBorrowUsd: m.state?.borrowAssetsUsd ? Number(m.state.borrowAssetsUsd) : m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
1994
1996
|
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
1995
1997
|
marketId: m.uniqueKey
|
|
1996
1998
|
};
|
|
@@ -2028,6 +2030,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2028
2030
|
state {
|
|
2029
2031
|
borrowAssets
|
|
2030
2032
|
supplyAssets
|
|
2033
|
+
supplyAssetsUsd
|
|
2034
|
+
borrowAssetsUsd
|
|
2031
2035
|
utilization
|
|
2032
2036
|
supplyApy
|
|
2033
2037
|
borrowApy
|
|
@@ -2230,7 +2234,7 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2230
2234
|
} else {
|
|
2231
2235
|
try {
|
|
2232
2236
|
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
2233
|
-
const loanDecimals =
|
|
2237
|
+
const loanDecimals = market.loanDecimals;
|
|
2234
2238
|
const oracleContract = new Contract3(params.oracle, [
|
|
2235
2239
|
"function price() view returns (uint256)"
|
|
2236
2240
|
], this.provider);
|
|
@@ -2773,8 +2777,8 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
2773
2777
|
const { params: p } = await this._findActiveMarket();
|
|
2774
2778
|
params = p;
|
|
2775
2779
|
}
|
|
2776
|
-
const loanTokenAddr = params.loanToken;
|
|
2777
2780
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2781
|
+
const loanTokenAddr = params.loanToken;
|
|
2778
2782
|
let repayAssets;
|
|
2779
2783
|
let repayShares;
|
|
2780
2784
|
let approveAmount;
|
|
@@ -3122,6 +3126,84 @@ var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
|
3122
3126
|
// ────────────────────────────────────────────────────────────
|
|
3123
3127
|
// ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
|
|
3124
3128
|
// ────────────────────────────────────────────────────────────
|
|
3129
|
+
/**
|
|
3130
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
3131
|
+
* Full position exit: approve + repay(shares) + withdrawCollateral → 1 UserOp.
|
|
3132
|
+
*/
|
|
3133
|
+
async repayAndWithdraw(tokenSymbol, loanTokenSymbol, toEoa = true) {
|
|
3134
|
+
const acctAddr = await this.getAccountAddress();
|
|
3135
|
+
const morphoAddr = this.config.contracts.morphoBlue;
|
|
3136
|
+
let params;
|
|
3137
|
+
let colSymbol;
|
|
3138
|
+
if (tokenSymbol) {
|
|
3139
|
+
params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
3140
|
+
colSymbol = tokenSymbol;
|
|
3141
|
+
} else {
|
|
3142
|
+
const active = await this._findActiveMarket();
|
|
3143
|
+
params = active.params;
|
|
3144
|
+
colSymbol = active.symbol;
|
|
3145
|
+
}
|
|
3146
|
+
const colInfo = await this._resolveToken(colSymbol);
|
|
3147
|
+
const dest = toEoa ? await this.getSignerAddress() : acctAddr;
|
|
3148
|
+
const marketId = ethers3.keccak256(ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
3149
|
+
["address", "address", "address", "address", "uint256"],
|
|
3150
|
+
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
3151
|
+
));
|
|
3152
|
+
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
3153
|
+
const borrowShares = BigInt(pos.borrowShares);
|
|
3154
|
+
const collateralAmount = BigInt(pos.collateral);
|
|
3155
|
+
if (collateralAmount === 0n) {
|
|
3156
|
+
throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
3157
|
+
}
|
|
3158
|
+
const targets = [];
|
|
3159
|
+
const values = [];
|
|
3160
|
+
const datas = [];
|
|
3161
|
+
if (borrowShares > 0n) {
|
|
3162
|
+
const onChainMkt = await this.morphoBlue.market(marketId);
|
|
3163
|
+
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
3164
|
+
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
3165
|
+
const estimatedDebt = totalBorrowShares > 0n ? borrowShares * totalBorrowAssets / totalBorrowShares + 100n : 0n;
|
|
3166
|
+
const loanContract = new Contract3(params.loanToken, ERC20_ABI, this._signer);
|
|
3167
|
+
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
3168
|
+
if (acctBalance < estimatedDebt) {
|
|
3169
|
+
const shortfall = estimatedDebt - acctBalance;
|
|
3170
|
+
const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
|
|
3171
|
+
if (eoaBalance >= shortfall) {
|
|
3172
|
+
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
3173
|
+
await transferTx.wait();
|
|
3174
|
+
this._refreshSigner();
|
|
3175
|
+
}
|
|
3176
|
+
}
|
|
3177
|
+
targets.push(params.loanToken);
|
|
3178
|
+
values.push(0n);
|
|
3179
|
+
datas.push(erc20Iface2.encodeFunctionData("approve", [morphoAddr, estimatedDebt]));
|
|
3180
|
+
targets.push(morphoAddr);
|
|
3181
|
+
values.push(0n);
|
|
3182
|
+
datas.push(morphoIface.encodeFunctionData("repay", [
|
|
3183
|
+
this._toTuple(params),
|
|
3184
|
+
0n,
|
|
3185
|
+
borrowShares,
|
|
3186
|
+
acctAddr,
|
|
3187
|
+
"0x"
|
|
3188
|
+
]));
|
|
3189
|
+
}
|
|
3190
|
+
targets.push(morphoAddr);
|
|
3191
|
+
values.push(0n);
|
|
3192
|
+
datas.push(morphoIface.encodeFunctionData("withdrawCollateral", [
|
|
3193
|
+
this._toTuple(params),
|
|
3194
|
+
collateralAmount,
|
|
3195
|
+
acctAddr,
|
|
3196
|
+
dest
|
|
3197
|
+
]));
|
|
3198
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
3199
|
+
return {
|
|
3200
|
+
tx: receipt.hash,
|
|
3201
|
+
repaid: borrowShares > 0n ? "all" : "0",
|
|
3202
|
+
withdrawn: ethers3.formatUnits(collateralAmount, colInfo.decimals),
|
|
3203
|
+
collateralToken: colSymbol,
|
|
3204
|
+
loanToken: this._tokenCache.get(params.loanToken.toLowerCase())?.symbol ?? "unknown"
|
|
3205
|
+
};
|
|
3206
|
+
}
|
|
3125
3207
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
3126
3208
|
_toTuple(p) {
|
|
3127
3209
|
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
|
@@ -3713,6 +3795,199 @@ var _AaveClient = class _AaveClient extends AgentAccountClient {
|
|
|
3713
3795
|
);
|
|
3714
3796
|
}
|
|
3715
3797
|
// ─── Helpers ──────────────────────────────────────────────────────────
|
|
3798
|
+
/**
|
|
3799
|
+
* Repay all debt and withdraw all collateral in one atomic batch.
|
|
3800
|
+
* Full position exit: approve + repay + withdraw → 1 UserOp.
|
|
3801
|
+
*/
|
|
3802
|
+
async repayAndWithdraw(repayAsset, withdrawAsset, to) {
|
|
3803
|
+
const repayReserve = this._resolveReserve(repayAsset);
|
|
3804
|
+
const withdrawReserve = this._resolveReserve(withdrawAsset);
|
|
3805
|
+
const safeAddr = await this.getAccountAddress();
|
|
3806
|
+
const poolAddr = await this._pool.getAddress();
|
|
3807
|
+
const recipient = to ?? safeAddr;
|
|
3808
|
+
const targets = [];
|
|
3809
|
+
const values = [];
|
|
3810
|
+
const datas = [];
|
|
3811
|
+
targets.push(repayReserve.address);
|
|
3812
|
+
values.push(0n);
|
|
3813
|
+
datas.push(this._erc20Iface.encodeFunctionData("approve", [poolAddr, ethers4.MaxUint256]));
|
|
3814
|
+
targets.push(poolAddr);
|
|
3815
|
+
values.push(0n);
|
|
3816
|
+
datas.push(this._poolIface.encodeFunctionData("repay", [
|
|
3817
|
+
repayReserve.address,
|
|
3818
|
+
ethers4.MaxUint256,
|
|
3819
|
+
2,
|
|
3820
|
+
safeAddr
|
|
3821
|
+
]));
|
|
3822
|
+
targets.push(poolAddr);
|
|
3823
|
+
values.push(0n);
|
|
3824
|
+
datas.push(this._poolIface.encodeFunctionData("withdraw", [
|
|
3825
|
+
withdrawReserve.address,
|
|
3826
|
+
ethers4.MaxUint256,
|
|
3827
|
+
recipient
|
|
3828
|
+
]));
|
|
3829
|
+
return this.executeBatch(targets, values, datas);
|
|
3830
|
+
}
|
|
3831
|
+
// ─── Market Discovery ─────────────────────────────────────────────────
|
|
3832
|
+
/**
|
|
3833
|
+
* Search reserves by token symbol (case-insensitive partial match).
|
|
3834
|
+
*/
|
|
3835
|
+
async searchReserves(query) {
|
|
3836
|
+
const reserves = await this.getReserves();
|
|
3837
|
+
const q = query.toLowerCase();
|
|
3838
|
+
return reserves.filter(
|
|
3839
|
+
(r) => r.symbol.toLowerCase().includes(q) || r.address.toLowerCase() === q
|
|
3840
|
+
);
|
|
3841
|
+
}
|
|
3842
|
+
/**
|
|
3843
|
+
* Get borrowing options: which tokens can be borrowed, with what collateral.
|
|
3844
|
+
* If collateral symbol given, shows what you can borrow using that as collateral.
|
|
3845
|
+
*/
|
|
3846
|
+
async getBorrowingOptions(collateral) {
|
|
3847
|
+
const reserves = await this.getReserves();
|
|
3848
|
+
const safeAddr = await this.getAccountAddress();
|
|
3849
|
+
const results = [];
|
|
3850
|
+
const eoaAddr = this.getWalletAddress();
|
|
3851
|
+
for (const reserve of reserves) {
|
|
3852
|
+
if (!reserve.isActive || reserve.ltv === 0) continue;
|
|
3853
|
+
if (collateral && reserve.symbol.toLowerCase() !== collateral.toLowerCase()) continue;
|
|
3854
|
+
const token = new Contract4(reserve.address, [
|
|
3855
|
+
"function balanceOf(address) view returns (uint256)"
|
|
3856
|
+
], this.provider);
|
|
3857
|
+
const [eoaBal, safeBal] = await Promise.all([
|
|
3858
|
+
token.balanceOf(eoaAddr).catch(() => 0n),
|
|
3859
|
+
token.balanceOf(safeAddr).catch(() => 0n)
|
|
3860
|
+
]);
|
|
3861
|
+
const totalBal = Number(eoaBal + safeBal) / 10 ** reserve.decimals;
|
|
3862
|
+
if (totalBal <= 0 && !collateral) continue;
|
|
3863
|
+
const collateralValueUsd = totalBal * reserve.priceUsd;
|
|
3864
|
+
const maxBorrowUsd = collateralValueUsd * (reserve.ltv / 100);
|
|
3865
|
+
const borrowable = reserves.filter((r) => r.borrowingEnabled && r.isActive && r.symbol !== reserve.symbol);
|
|
3866
|
+
results.push({
|
|
3867
|
+
collateral: reserve.symbol,
|
|
3868
|
+
borrowable,
|
|
3869
|
+
collateralBalance: totalBal,
|
|
3870
|
+
collateralValueUsd,
|
|
3871
|
+
maxBorrowUsd
|
|
3872
|
+
});
|
|
3873
|
+
}
|
|
3874
|
+
return results;
|
|
3875
|
+
}
|
|
3876
|
+
/**
|
|
3877
|
+
* Calculate max additional borrowable in USD given current positions.
|
|
3878
|
+
*/
|
|
3879
|
+
async getMaxBorrowable() {
|
|
3880
|
+
const data = await this.getAccountData();
|
|
3881
|
+
return {
|
|
3882
|
+
availableBorrowUsd: data.availableBorrowUsd,
|
|
3883
|
+
currentLtv: data.currentLtv,
|
|
3884
|
+
liquidationThreshold: data.liquidationThreshold,
|
|
3885
|
+
totalCollateralUsd: data.totalCollateralUsd,
|
|
3886
|
+
totalDebtUsd: data.totalDebtUsd
|
|
3887
|
+
};
|
|
3888
|
+
}
|
|
3889
|
+
/**
|
|
3890
|
+
* Scan wallet for tokens that exist as Aave reserves.
|
|
3891
|
+
*/
|
|
3892
|
+
async getWalletTokens() {
|
|
3893
|
+
const reserves = await this.getReserves();
|
|
3894
|
+
const safeAddr = await this.getAccountAddress();
|
|
3895
|
+
const eoaAddr = this.getWalletAddress();
|
|
3896
|
+
const results = [];
|
|
3897
|
+
const promises = reserves.map(async (reserve) => {
|
|
3898
|
+
const token = new Contract4(reserve.address, [
|
|
3899
|
+
"function balanceOf(address) view returns (uint256)"
|
|
3900
|
+
], this.provider);
|
|
3901
|
+
const [eoaBal, safeBal] = await Promise.all([
|
|
3902
|
+
token.balanceOf(eoaAddr).catch(() => 0n),
|
|
3903
|
+
token.balanceOf(safeAddr).catch(() => 0n)
|
|
3904
|
+
]);
|
|
3905
|
+
const eoaBalance = Number(eoaBal) / 10 ** reserve.decimals;
|
|
3906
|
+
const safeBalance = Number(safeBal) / 10 ** reserve.decimals;
|
|
3907
|
+
if (eoaBalance > 0 || safeBalance > 0) {
|
|
3908
|
+
return {
|
|
3909
|
+
symbol: reserve.symbol,
|
|
3910
|
+
address: reserve.address,
|
|
3911
|
+
eoaBalance,
|
|
3912
|
+
safeBalance,
|
|
3913
|
+
priceUsd: reserve.priceUsd,
|
|
3914
|
+
valueUsd: (eoaBalance + safeBalance) * reserve.priceUsd,
|
|
3915
|
+
canSupply: reserve.isActive,
|
|
3916
|
+
canBorrow: reserve.borrowingEnabled
|
|
3917
|
+
};
|
|
3918
|
+
}
|
|
3919
|
+
return null;
|
|
3920
|
+
});
|
|
3921
|
+
const settled = await Promise.all(promises);
|
|
3922
|
+
for (const r of settled) {
|
|
3923
|
+
if (r) results.push(r);
|
|
3924
|
+
}
|
|
3925
|
+
return results;
|
|
3926
|
+
}
|
|
3927
|
+
/**
|
|
3928
|
+
* Get yield spread for LST carry trades on Aave.
|
|
3929
|
+
* Compares LST native yield vs Aave borrow rates.
|
|
3930
|
+
*/
|
|
3931
|
+
async getYieldSpread(_minLiquidity = 0) {
|
|
3932
|
+
const reserves = await this.getReserves();
|
|
3933
|
+
const lstYields = await this._getLstYields();
|
|
3934
|
+
if (Object.keys(lstYields).length === 0) return [];
|
|
3935
|
+
const results = [];
|
|
3936
|
+
for (const [symbol, yieldApy] of Object.entries(lstYields)) {
|
|
3937
|
+
const collateralReserve = reserves.find((r) => r.symbol.toLowerCase() === symbol.toLowerCase());
|
|
3938
|
+
if (!collateralReserve || !collateralReserve.isActive || collateralReserve.ltv === 0) continue;
|
|
3939
|
+
for (const loanReserve of reserves) {
|
|
3940
|
+
if (!loanReserve.borrowingEnabled || !loanReserve.isActive) continue;
|
|
3941
|
+
if (loanReserve.symbol === collateralReserve.symbol) continue;
|
|
3942
|
+
const netSpread = yieldApy - loanReserve.borrowApy;
|
|
3943
|
+
const safeLtv = collateralReserve.ltv / 100 * 0.8;
|
|
3944
|
+
const maxLeverage = 1 / (1 - safeLtv);
|
|
3945
|
+
results.push({
|
|
3946
|
+
collateralToken: collateralReserve.symbol,
|
|
3947
|
+
loanToken: loanReserve.symbol,
|
|
3948
|
+
collateralYield: yieldApy,
|
|
3949
|
+
borrowRate: loanReserve.borrowApy,
|
|
3950
|
+
netSpread,
|
|
3951
|
+
profitable: netSpread > 0,
|
|
3952
|
+
collateralLtv: collateralReserve.ltv,
|
|
3953
|
+
maxSafeLeverage: parseFloat(maxLeverage.toFixed(2))
|
|
3954
|
+
});
|
|
3955
|
+
}
|
|
3956
|
+
}
|
|
3957
|
+
return results.sort((a, b) => b.netSpread - a.netSpread);
|
|
3958
|
+
}
|
|
3959
|
+
async _getLstYields() {
|
|
3960
|
+
if (_AaveClient._lstYieldCache && Date.now() - _AaveClient._lstYieldCache.ts < _AaveClient.LST_CACHE_TTL) {
|
|
3961
|
+
return _AaveClient._lstYieldCache.data;
|
|
3962
|
+
}
|
|
3963
|
+
const yields = {};
|
|
3964
|
+
try {
|
|
3965
|
+
const resp = await fetch("https://yields.llama.fi/pools", {
|
|
3966
|
+
headers: { "User-Agent": "agether-sdk/1.0" },
|
|
3967
|
+
signal: AbortSignal.timeout(1e4)
|
|
3968
|
+
});
|
|
3969
|
+
if (!resp.ok) return yields;
|
|
3970
|
+
const data = await resp.json();
|
|
3971
|
+
const pools = data?.data ?? [];
|
|
3972
|
+
for (const [morphoSymbol, mapping] of Object.entries(_AaveClient.LST_PROJECT_MAP)) {
|
|
3973
|
+
const matchingPools = pools.filter(
|
|
3974
|
+
(p) => p.project === mapping.project && p.symbol?.toUpperCase() === mapping.symbol && ["Ethereum", "Base"].includes(p.chain)
|
|
3975
|
+
);
|
|
3976
|
+
if (matchingPools.length > 0) {
|
|
3977
|
+
const best = matchingPools.reduce(
|
|
3978
|
+
(a, b) => (b.tvlUsd ?? 0) > (a.tvlUsd ?? 0) ? b : a
|
|
3979
|
+
);
|
|
3980
|
+
if (best.apy !== void 0 && best.apy > 0) {
|
|
3981
|
+
yields[morphoSymbol] = parseFloat(best.apy.toFixed(4));
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
} catch (e) {
|
|
3986
|
+
console.warn("[aave] Failed to fetch LST yields:", e instanceof Error ? e.message : e);
|
|
3987
|
+
}
|
|
3988
|
+
_AaveClient._lstYieldCache = { data: yields, ts: Date.now() };
|
|
3989
|
+
return yields;
|
|
3990
|
+
}
|
|
3716
3991
|
_resolveReserve(symbolOrAddress) {
|
|
3717
3992
|
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3718
3993
|
const bySymbol = reserves.find((r) => r.symbol.toLowerCase() === symbolOrAddress.toLowerCase());
|
|
@@ -3726,6 +4001,23 @@ var _AaveClient = class _AaveClient extends AgentAccountClient {
|
|
|
3726
4001
|
}
|
|
3727
4002
|
};
|
|
3728
4003
|
_AaveClient.CACHE_TTL = 6e4;
|
|
4004
|
+
// ─── DeFi Llama LST Yields (shared logic) ─────────────────────────────
|
|
4005
|
+
_AaveClient.LST_PROJECT_MAP = {
|
|
4006
|
+
"wstETH": { project: "lido", symbol: "STETH" },
|
|
4007
|
+
"cbETH": { project: "coinbase-wrapped-staked-eth", symbol: "CBETH" },
|
|
4008
|
+
"rETH": { project: "rocket-pool", symbol: "RETH" },
|
|
4009
|
+
"weETH": { project: "ether.fi-stake", symbol: "WEETH" },
|
|
4010
|
+
"ezETH": { project: "renzo", symbol: "EZETH" },
|
|
4011
|
+
"rsETH": { project: "kelp", symbol: "RSETH" },
|
|
4012
|
+
"swETH": { project: "swell-liquid-staking", symbol: "SWETH" },
|
|
4013
|
+
"mETH": { project: "meth-protocol", symbol: "METH" },
|
|
4014
|
+
"sfrxETH": { project: "frax-ether", symbol: "SFRXETH" },
|
|
4015
|
+
"oETH": { project: "origin-ether", symbol: "OETH" },
|
|
4016
|
+
"ETHx": { project: "stader", symbol: "ETHX" },
|
|
4017
|
+
"wBETH": { project: "binance-staked-eth", symbol: "WBETH" }
|
|
4018
|
+
};
|
|
4019
|
+
_AaveClient._lstYieldCache = null;
|
|
4020
|
+
_AaveClient.LST_CACHE_TTL = 30 * 60 * 1e3;
|
|
3729
4021
|
var AaveClient = _AaveClient;
|
|
3730
4022
|
|
|
3731
4023
|
// src/clients/ScoringClient.ts
|