@agether/sdk 2.17.3 → 2.18.0
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 +428 -361
- package/dist/index.d.mts +161 -48
- package/dist/index.d.ts +161 -48
- package/dist/index.js +667 -293
- package/dist/index.mjs +665 -293
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3,13 +3,13 @@ import { ethers, Contract } from "ethers";
|
|
|
3
3
|
import axios from "axios";
|
|
4
4
|
|
|
5
5
|
// src/types/index.ts
|
|
6
|
-
var ChainId = /* @__PURE__ */ ((
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return
|
|
6
|
+
var ChainId = /* @__PURE__ */ ((ChainId4) => {
|
|
7
|
+
ChainId4[ChainId4["Ethereum"] = 1] = "Ethereum";
|
|
8
|
+
ChainId4[ChainId4["Base"] = 8453] = "Base";
|
|
9
|
+
ChainId4[ChainId4["BaseSepolia"] = 84532] = "BaseSepolia";
|
|
10
|
+
ChainId4[ChainId4["Sepolia"] = 11155111] = "Sepolia";
|
|
11
|
+
ChainId4[ChainId4["Hardhat"] = 31337] = "Hardhat";
|
|
12
|
+
return ChainId4;
|
|
13
13
|
})(ChainId || {});
|
|
14
14
|
var AgetherError = class extends Error {
|
|
15
15
|
constructor(message, code, details) {
|
|
@@ -1185,67 +1185,14 @@ var AgetherClient = class _AgetherClient {
|
|
|
1185
1185
|
};
|
|
1186
1186
|
|
|
1187
1187
|
// src/clients/MorphoClient.ts
|
|
1188
|
-
import { ethers as
|
|
1189
|
-
import axios2 from "axios";
|
|
1188
|
+
import { ethers as ethers3, Contract as Contract3 } from "ethers";
|
|
1190
1189
|
|
|
1191
|
-
// src/
|
|
1192
|
-
|
|
1193
|
-
"ECONNRESET",
|
|
1194
|
-
"ECONNREFUSED",
|
|
1195
|
-
"ENOTFOUND",
|
|
1196
|
-
"ETIMEDOUT",
|
|
1197
|
-
"fetch failed",
|
|
1198
|
-
"network error",
|
|
1199
|
-
"socket hang up",
|
|
1200
|
-
"rate limit",
|
|
1201
|
-
"429",
|
|
1202
|
-
"502",
|
|
1203
|
-
"503",
|
|
1204
|
-
"504",
|
|
1205
|
-
"timeout"
|
|
1206
|
-
];
|
|
1207
|
-
function isRetriable(error) {
|
|
1208
|
-
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
1209
|
-
return RETRIABLE_PATTERNS.some((p) => msg.includes(p.toLowerCase()));
|
|
1210
|
-
}
|
|
1211
|
-
async function withRetry(fn, options = {}) {
|
|
1212
|
-
const {
|
|
1213
|
-
maxRetries = 3,
|
|
1214
|
-
baseDelay = 1e3,
|
|
1215
|
-
maxDelay = 15e3,
|
|
1216
|
-
onRetry
|
|
1217
|
-
} = options;
|
|
1218
|
-
let lastError;
|
|
1219
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1220
|
-
try {
|
|
1221
|
-
return await fn();
|
|
1222
|
-
} catch (error) {
|
|
1223
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1224
|
-
if (attempt >= maxRetries || !isRetriable(error)) {
|
|
1225
|
-
throw lastError;
|
|
1226
|
-
}
|
|
1227
|
-
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
|
|
1228
|
-
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
1229
|
-
onRetry?.(attempt, lastError);
|
|
1230
|
-
await new Promise((resolve) => setTimeout(resolve, jitter));
|
|
1231
|
-
}
|
|
1232
|
-
}
|
|
1233
|
-
throw lastError;
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
// src/clients/MorphoClient.ts
|
|
1237
|
-
var MORPHO_API_URL2 = "https://api.morpho.org/graphql";
|
|
1190
|
+
// src/clients/AgentAccountClient.ts
|
|
1191
|
+
import { ethers as ethers2, Contract as Contract2 } from "ethers";
|
|
1238
1192
|
var MODE_SINGLE2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
1239
1193
|
var MODE_BATCH = "0x0100000000000000000000000000000000000000000000000000000000000000";
|
|
1240
|
-
var
|
|
1241
|
-
var erc20Iface2 = new ethers2.Interface(ERC20_ABI);
|
|
1242
|
-
var _MorphoClient = class _MorphoClient {
|
|
1194
|
+
var AgentAccountClient = class {
|
|
1243
1195
|
constructor(config) {
|
|
1244
|
-
/** Market params cache: keyed by market uniqueKey (bytes32 hash) */
|
|
1245
|
-
this._marketCache = /* @__PURE__ */ new Map();
|
|
1246
|
-
/** Dynamic token registry: symbol (uppercase) or address (lowercase) → { address, symbol, decimals } */
|
|
1247
|
-
this._tokenCache = /* @__PURE__ */ new Map();
|
|
1248
|
-
this._discoveredAt = 0;
|
|
1249
1196
|
if (!config.agentId) {
|
|
1250
1197
|
throw new AgetherError(
|
|
1251
1198
|
"agentId is required. Use AgetherClient.register() first to get an agentId.",
|
|
@@ -1280,13 +1227,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1280
1227
|
}
|
|
1281
1228
|
const addrs = { ...defaultCfg.contracts, ...config.contracts };
|
|
1282
1229
|
this.agether4337Factory = new Contract2(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
1283
|
-
this.morphoBlue = new Contract2(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
1284
1230
|
this.entryPoint = new Contract2(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
|
|
1285
1231
|
}
|
|
1286
|
-
//
|
|
1287
|
-
|
|
1288
|
-
// ════════════════════════════════════════════════════════
|
|
1289
|
-
/** Resolve the AgentAccount address (cached, with retry for flaky RPCs). */
|
|
1232
|
+
// ─── Account Management ───────────────────────────────────────────────
|
|
1233
|
+
/** Resolve the AgentAccount (Safe) address. Cached after first call. */
|
|
1290
1234
|
async getAccountAddress() {
|
|
1291
1235
|
if (this._accountAddress) return this._accountAddress;
|
|
1292
1236
|
const MAX_RETRIES = 3;
|
|
@@ -1312,26 +1256,260 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1312
1256
|
getAgentId() {
|
|
1313
1257
|
return this.agentId;
|
|
1314
1258
|
}
|
|
1315
|
-
/**
|
|
1316
|
-
* Get the EOA wallet address (synchronous, best-effort).
|
|
1317
|
-
*
|
|
1318
|
-
* For the `privateKey` path this always works. For the `signer` path
|
|
1319
|
-
* it works if the signer exposes `.address` synchronously (e.g. ethers.Wallet).
|
|
1320
|
-
* If the address has not been resolved yet, throws — call `getSignerAddress()` first.
|
|
1321
|
-
*/
|
|
1259
|
+
/** Get the EOA wallet address (synchronous). */
|
|
1322
1260
|
getWalletAddress() {
|
|
1323
1261
|
if (this._eoaAddress) return this._eoaAddress;
|
|
1324
1262
|
const signer = this._signer;
|
|
1325
1263
|
if (signer.address && typeof signer.address === "string") {
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
return addr;
|
|
1264
|
+
this._eoaAddress = signer.address;
|
|
1265
|
+
return signer.address;
|
|
1329
1266
|
}
|
|
1330
1267
|
throw new AgetherError(
|
|
1331
|
-
"EOA address not
|
|
1332
|
-
"
|
|
1268
|
+
"EOA address not available synchronously. Call getSignerAddress() first.",
|
|
1269
|
+
"NO_EOA_ADDRESS"
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
/** Get EOA wallet address (async, works for all signer types). */
|
|
1273
|
+
async getSignerAddress() {
|
|
1274
|
+
if (this._eoaAddress) return this._eoaAddress;
|
|
1275
|
+
const addr = await this._signer.getAddress();
|
|
1276
|
+
this._eoaAddress = addr;
|
|
1277
|
+
return addr;
|
|
1278
|
+
}
|
|
1279
|
+
// ─── Safe7579 Execution ───────────────────────────────────────────────
|
|
1280
|
+
/** Pack two uint128 values into a single bytes32. */
|
|
1281
|
+
_packUint128(hi, lo) {
|
|
1282
|
+
return ethers2.zeroPadValue(ethers2.toBeHex(hi << 128n | lo), 32);
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
|
|
1286
|
+
*/
|
|
1287
|
+
async _submitUserOp(callData) {
|
|
1288
|
+
const sender = await this.getAccountAddress();
|
|
1289
|
+
const validatorAddr = this.config.contracts.erc8004ValidationModule;
|
|
1290
|
+
const nonceKey = BigInt(validatorAddr) << 32n;
|
|
1291
|
+
const nonce = await this.entryPoint.getNonce(sender, nonceKey);
|
|
1292
|
+
const feeData = await this.provider.getFeeData();
|
|
1293
|
+
const maxFeePerGas = feeData.maxFeePerGas ?? ethers2.parseUnits("0.5", "gwei");
|
|
1294
|
+
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? ethers2.parseUnits("0.1", "gwei");
|
|
1295
|
+
const verificationGasLimit = 500000n;
|
|
1296
|
+
const callGasLimit = 800000n;
|
|
1297
|
+
const preVerificationGas = 100000n;
|
|
1298
|
+
const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
|
|
1299
|
+
const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
|
|
1300
|
+
const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
|
|
1301
|
+
const accountBalance = await this.provider.getBalance(sender);
|
|
1302
|
+
if (accountBalance < requiredPrefund) {
|
|
1303
|
+
const topUp = requiredPrefund - accountBalance;
|
|
1304
|
+
const topUpWithBuffer = topUp * 120n / 100n;
|
|
1305
|
+
const eoaBalance = await this.provider.getBalance(
|
|
1306
|
+
this._eoaAddress ?? await this._signer.getAddress()
|
|
1307
|
+
);
|
|
1308
|
+
if (eoaBalance < topUpWithBuffer) {
|
|
1309
|
+
const needed = ethers2.formatEther(topUpWithBuffer);
|
|
1310
|
+
throw new AgetherError(
|
|
1311
|
+
`Insufficient ETH for gas. Need ~${needed} ETH in EOA.`,
|
|
1312
|
+
"INSUFFICIENT_GAS"
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1315
|
+
const tx = await this._signer.sendTransaction({ to: sender, value: topUpWithBuffer });
|
|
1316
|
+
await tx.wait();
|
|
1317
|
+
}
|
|
1318
|
+
const packedUserOp = {
|
|
1319
|
+
sender,
|
|
1320
|
+
nonce,
|
|
1321
|
+
initCode: "0x",
|
|
1322
|
+
callData,
|
|
1323
|
+
accountGasLimits,
|
|
1324
|
+
preVerificationGas,
|
|
1325
|
+
gasFees,
|
|
1326
|
+
paymasterAndData: "0x",
|
|
1327
|
+
signature: "0x"
|
|
1328
|
+
};
|
|
1329
|
+
const entryPointAddr = await this.entryPoint.getAddress();
|
|
1330
|
+
const chainId = (await this.provider.getNetwork()).chainId;
|
|
1331
|
+
const userOpHash = ethers2.keccak256(
|
|
1332
|
+
ethers2.AbiCoder.defaultAbiCoder().encode(
|
|
1333
|
+
["bytes32", "address", "uint256"],
|
|
1334
|
+
[
|
|
1335
|
+
ethers2.keccak256(
|
|
1336
|
+
ethers2.AbiCoder.defaultAbiCoder().encode(
|
|
1337
|
+
[
|
|
1338
|
+
"address",
|
|
1339
|
+
"uint256",
|
|
1340
|
+
"bytes32",
|
|
1341
|
+
"bytes32",
|
|
1342
|
+
"bytes32",
|
|
1343
|
+
"uint256",
|
|
1344
|
+
"bytes32",
|
|
1345
|
+
"bytes32"
|
|
1346
|
+
],
|
|
1347
|
+
[
|
|
1348
|
+
packedUserOp.sender,
|
|
1349
|
+
packedUserOp.nonce,
|
|
1350
|
+
ethers2.keccak256(packedUserOp.initCode),
|
|
1351
|
+
ethers2.keccak256(packedUserOp.callData),
|
|
1352
|
+
packedUserOp.accountGasLimits,
|
|
1353
|
+
packedUserOp.preVerificationGas,
|
|
1354
|
+
packedUserOp.gasFees,
|
|
1355
|
+
ethers2.keccak256(packedUserOp.paymasterAndData)
|
|
1356
|
+
]
|
|
1357
|
+
)
|
|
1358
|
+
),
|
|
1359
|
+
entryPointAddr,
|
|
1360
|
+
chainId
|
|
1361
|
+
]
|
|
1362
|
+
)
|
|
1333
1363
|
);
|
|
1364
|
+
const signature = await this._signer.signMessage(ethers2.getBytes(userOpHash));
|
|
1365
|
+
packedUserOp.signature = signature;
|
|
1366
|
+
const handleOpsTx = await this.entryPoint.handleOps(
|
|
1367
|
+
[
|
|
1368
|
+
[
|
|
1369
|
+
packedUserOp.sender,
|
|
1370
|
+
packedUserOp.nonce,
|
|
1371
|
+
packedUserOp.initCode,
|
|
1372
|
+
packedUserOp.callData,
|
|
1373
|
+
packedUserOp.accountGasLimits,
|
|
1374
|
+
packedUserOp.preVerificationGas,
|
|
1375
|
+
packedUserOp.gasFees,
|
|
1376
|
+
packedUserOp.paymasterAndData,
|
|
1377
|
+
packedUserOp.signature
|
|
1378
|
+
]
|
|
1379
|
+
],
|
|
1380
|
+
this._eoaAddress ?? await this._signer.getAddress()
|
|
1381
|
+
);
|
|
1382
|
+
const receipt = await handleOpsTx.wait();
|
|
1383
|
+
const epIface = new ethers2.Interface(ENTRYPOINT_V07_ABI);
|
|
1384
|
+
for (const log of receipt.logs) {
|
|
1385
|
+
try {
|
|
1386
|
+
const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
|
|
1387
|
+
if (parsed?.name === "UserOperationEvent") {
|
|
1388
|
+
if (!parsed.args.success) {
|
|
1389
|
+
let revertMsg = "UserOp inner execution reverted";
|
|
1390
|
+
for (const rLog of receipt.logs) {
|
|
1391
|
+
try {
|
|
1392
|
+
const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
|
|
1393
|
+
if (rParsed?.name === "UserOperationRevertReason") {
|
|
1394
|
+
const reason = rParsed.args.revertReason;
|
|
1395
|
+
try {
|
|
1396
|
+
if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
|
|
1397
|
+
const decoded = ethers2.AbiCoder.defaultAbiCoder().decode(["string"], "0x" + reason.slice(10));
|
|
1398
|
+
revertMsg = `UserOp reverted: ${decoded[0]}`;
|
|
1399
|
+
} else {
|
|
1400
|
+
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
1401
|
+
}
|
|
1402
|
+
} catch {
|
|
1403
|
+
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
1404
|
+
}
|
|
1405
|
+
break;
|
|
1406
|
+
}
|
|
1407
|
+
} catch {
|
|
1408
|
+
continue;
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
} catch (e) {
|
|
1415
|
+
if (e instanceof AgetherError) throw e;
|
|
1416
|
+
continue;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
return receipt;
|
|
1334
1420
|
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Execute a single call via Safe7579 account through ERC-4337 UserOp.
|
|
1423
|
+
*/
|
|
1424
|
+
async executeSingle(target, data, value = 0n) {
|
|
1425
|
+
const valueHex = ethers2.zeroPadValue(ethers2.toBeHex(value), 32);
|
|
1426
|
+
const executionCalldata = ethers2.concat([target, valueHex, data]);
|
|
1427
|
+
const safe7579Iface = new ethers2.Interface(SAFE7579_ACCOUNT_ABI);
|
|
1428
|
+
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
|
|
1429
|
+
return this._submitUserOp(callData);
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Execute multiple calls via Safe7579 account in one atomic batch.
|
|
1433
|
+
*/
|
|
1434
|
+
async executeBatch(targets, values, datas) {
|
|
1435
|
+
const executions = targets.map((t, i) => [t, values[i], datas[i]]);
|
|
1436
|
+
const executionCalldata = ethers2.AbiCoder.defaultAbiCoder().encode(
|
|
1437
|
+
["(address,uint256,bytes)[]"],
|
|
1438
|
+
[executions]
|
|
1439
|
+
);
|
|
1440
|
+
const safe7579Iface = new ethers2.Interface(SAFE7579_ACCOUNT_ABI);
|
|
1441
|
+
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_BATCH, executionCalldata]);
|
|
1442
|
+
return this._submitUserOp(callData);
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
|
|
1446
|
+
// src/clients/MorphoClient.ts
|
|
1447
|
+
import axios2 from "axios";
|
|
1448
|
+
|
|
1449
|
+
// src/utils/retry.ts
|
|
1450
|
+
var RETRIABLE_PATTERNS = [
|
|
1451
|
+
"ECONNRESET",
|
|
1452
|
+
"ECONNREFUSED",
|
|
1453
|
+
"ENOTFOUND",
|
|
1454
|
+
"ETIMEDOUT",
|
|
1455
|
+
"fetch failed",
|
|
1456
|
+
"network error",
|
|
1457
|
+
"socket hang up",
|
|
1458
|
+
"rate limit",
|
|
1459
|
+
"429",
|
|
1460
|
+
"502",
|
|
1461
|
+
"503",
|
|
1462
|
+
"504",
|
|
1463
|
+
"timeout"
|
|
1464
|
+
];
|
|
1465
|
+
function isRetriable(error) {
|
|
1466
|
+
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
1467
|
+
return RETRIABLE_PATTERNS.some((p) => msg.includes(p.toLowerCase()));
|
|
1468
|
+
}
|
|
1469
|
+
async function withRetry(fn, options = {}) {
|
|
1470
|
+
const {
|
|
1471
|
+
maxRetries = 3,
|
|
1472
|
+
baseDelay = 1e3,
|
|
1473
|
+
maxDelay = 15e3,
|
|
1474
|
+
onRetry
|
|
1475
|
+
} = options;
|
|
1476
|
+
let lastError;
|
|
1477
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1478
|
+
try {
|
|
1479
|
+
return await fn();
|
|
1480
|
+
} catch (error) {
|
|
1481
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1482
|
+
if (attempt >= maxRetries || !isRetriable(error)) {
|
|
1483
|
+
throw lastError;
|
|
1484
|
+
}
|
|
1485
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
|
|
1486
|
+
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
1487
|
+
onRetry?.(attempt, lastError);
|
|
1488
|
+
await new Promise((resolve) => setTimeout(resolve, jitter));
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
throw lastError;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
// src/clients/MorphoClient.ts
|
|
1495
|
+
var MORPHO_API_URL2 = "https://api.morpho.org/graphql";
|
|
1496
|
+
var morphoIface = new ethers3.Interface(MORPHO_BLUE_ABI);
|
|
1497
|
+
var erc20Iface2 = new ethers3.Interface(ERC20_ABI);
|
|
1498
|
+
var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
1499
|
+
constructor(config) {
|
|
1500
|
+
super(config);
|
|
1501
|
+
// Cached state
|
|
1502
|
+
/** Market params cache: keyed by market uniqueKey (bytes32 hash) */
|
|
1503
|
+
this._marketCache = /* @__PURE__ */ new Map();
|
|
1504
|
+
/** Dynamic token registry: symbol (uppercase) or address (lowercase) → { address, symbol, decimals } */
|
|
1505
|
+
this._tokenCache = /* @__PURE__ */ new Map();
|
|
1506
|
+
this._discoveredAt = 0;
|
|
1507
|
+
const addrs = { ...this.config.contracts, ...config.contracts };
|
|
1508
|
+
this.morphoBlue = new Contract3(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
1509
|
+
}
|
|
1510
|
+
// ════════════════════════════════════════════════════════
|
|
1511
|
+
// Account Management
|
|
1512
|
+
// ════════════════════════════════════════════════════════
|
|
1335
1513
|
/**
|
|
1336
1514
|
* Resolve the EOA signer address (async, works with all signer types).
|
|
1337
1515
|
* Result is cached after the first call.
|
|
@@ -1388,7 +1566,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1388
1566
|
this._discoveredMarkets = items.map((m) => ({
|
|
1389
1567
|
uniqueKey: m.uniqueKey,
|
|
1390
1568
|
loanAsset: m.loanAsset,
|
|
1391
|
-
collateralAsset: m.collateralAsset ?? { address:
|
|
1569
|
+
collateralAsset: m.collateralAsset ?? { address: ethers3.ZeroAddress, symbol: "N/A", decimals: 0 },
|
|
1392
1570
|
oracle: m.oracleAddress,
|
|
1393
1571
|
irm: m.irmAddress,
|
|
1394
1572
|
lltv: BigInt(m.lltv),
|
|
@@ -1405,7 +1583,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1405
1583
|
irm: mi.irm,
|
|
1406
1584
|
lltv: mi.lltv
|
|
1407
1585
|
});
|
|
1408
|
-
if (mi.collateralAsset.address !==
|
|
1586
|
+
if (mi.collateralAsset.address !== ethers3.ZeroAddress) {
|
|
1409
1587
|
this._tokenCache.set(mi.collateralAsset.symbol.toUpperCase(), {
|
|
1410
1588
|
address: mi.collateralAsset.address,
|
|
1411
1589
|
symbol: mi.collateralAsset.symbol,
|
|
@@ -1417,7 +1595,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1417
1595
|
decimals: mi.collateralAsset.decimals
|
|
1418
1596
|
});
|
|
1419
1597
|
}
|
|
1420
|
-
if (mi.loanAsset.address !==
|
|
1598
|
+
if (mi.loanAsset.address !== ethers3.ZeroAddress) {
|
|
1421
1599
|
this._tokenCache.set(mi.loanAsset.symbol.toUpperCase(), {
|
|
1422
1600
|
address: mi.loanAsset.address,
|
|
1423
1601
|
symbol: mi.loanAsset.symbol,
|
|
@@ -1587,7 +1765,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1587
1765
|
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
1588
1766
|
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
1589
1767
|
debt = totalBorrowShares > 0n ? (borrowShares * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1590
|
-
totalDebtFloat += parseFloat(
|
|
1768
|
+
totalDebtFloat += parseFloat(ethers3.formatUnits(debt, loanDecimals));
|
|
1591
1769
|
} catch (e) {
|
|
1592
1770
|
console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
|
|
1593
1771
|
}
|
|
@@ -1596,17 +1774,17 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1596
1774
|
marketId: m.uniqueKey,
|
|
1597
1775
|
collateralToken: m.collateralAsset.symbol,
|
|
1598
1776
|
loanToken: m.loanAsset.symbol,
|
|
1599
|
-
collateral:
|
|
1777
|
+
collateral: ethers3.formatUnits(collateral, m.collateralAsset.decimals),
|
|
1600
1778
|
borrowShares: borrowShares.toString(),
|
|
1601
1779
|
supplyShares: supplyShares.toString(),
|
|
1602
|
-
debt:
|
|
1780
|
+
debt: ethers3.formatUnits(debt, loanDecimals)
|
|
1603
1781
|
});
|
|
1604
1782
|
}
|
|
1605
1783
|
} catch (e) {
|
|
1606
1784
|
console.warn("[agether] marketPositions API failed, falling back to market scan:", e instanceof Error ? e.message : e);
|
|
1607
1785
|
const markets = await this.getMarkets();
|
|
1608
1786
|
for (const m of markets) {
|
|
1609
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
1787
|
+
if (!m.collateralAsset || m.collateralAsset.address === ethers3.ZeroAddress) continue;
|
|
1610
1788
|
try {
|
|
1611
1789
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
1612
1790
|
if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
|
|
@@ -1618,7 +1796,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1618
1796
|
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
1619
1797
|
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
1620
1798
|
debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1621
|
-
totalDebtFloat += parseFloat(
|
|
1799
|
+
totalDebtFloat += parseFloat(ethers3.formatUnits(debt, loanDecimals));
|
|
1622
1800
|
} catch (e2) {
|
|
1623
1801
|
console.warn(`[agether] debt calc failed:`, e2 instanceof Error ? e2.message : e2);
|
|
1624
1802
|
}
|
|
@@ -1627,10 +1805,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1627
1805
|
marketId: m.uniqueKey,
|
|
1628
1806
|
collateralToken: m.collateralAsset.symbol,
|
|
1629
1807
|
loanToken: m.loanAsset.symbol,
|
|
1630
|
-
collateral:
|
|
1808
|
+
collateral: ethers3.formatUnits(pos.collateral, m.collateralAsset.decimals),
|
|
1631
1809
|
borrowShares: pos.borrowShares.toString(),
|
|
1632
1810
|
supplyShares: pos.supplyShares.toString(),
|
|
1633
|
-
debt:
|
|
1811
|
+
debt: ethers3.formatUnits(debt, loanDecimals)
|
|
1634
1812
|
});
|
|
1635
1813
|
} catch (e2) {
|
|
1636
1814
|
console.warn(`[agether] position read failed:`, e2 instanceof Error ? e2.message : e2);
|
|
@@ -1656,7 +1834,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1656
1834
|
async getTokenBalance(symbolOrAddress) {
|
|
1657
1835
|
const acctAddr = await this.getAccountAddress();
|
|
1658
1836
|
const tokenInfo = await this._resolveToken(symbolOrAddress);
|
|
1659
|
-
const token = new
|
|
1837
|
+
const token = new Contract3(tokenInfo.address, ERC20_ABI, this.provider);
|
|
1660
1838
|
return token.balanceOf(acctAddr);
|
|
1661
1839
|
}
|
|
1662
1840
|
/**
|
|
@@ -1666,7 +1844,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1666
1844
|
*/
|
|
1667
1845
|
async getUsdcBalance() {
|
|
1668
1846
|
const acctAddr = await this.getAccountAddress();
|
|
1669
|
-
const usdc = new
|
|
1847
|
+
const usdc = new Contract3(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
1670
1848
|
return usdc.balanceOf(acctAddr);
|
|
1671
1849
|
}
|
|
1672
1850
|
/**
|
|
@@ -1686,7 +1864,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1686
1864
|
let totalAdditional = 0n;
|
|
1687
1865
|
const byMarket = [];
|
|
1688
1866
|
for (const m of markets) {
|
|
1689
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
1867
|
+
if (!m.collateralAsset || m.collateralAsset.address === ethers3.ZeroAddress) continue;
|
|
1690
1868
|
try {
|
|
1691
1869
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
1692
1870
|
if (pos.collateral === 0n) continue;
|
|
@@ -1696,7 +1874,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1696
1874
|
const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1697
1875
|
let collateralValueInLoan;
|
|
1698
1876
|
try {
|
|
1699
|
-
const oracleContract = new
|
|
1877
|
+
const oracleContract = new Contract3(m.oracle, [
|
|
1700
1878
|
"function price() view returns (uint256)"
|
|
1701
1879
|
], this.provider);
|
|
1702
1880
|
const oraclePrice = await oracleContract.price();
|
|
@@ -1802,7 +1980,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1802
1980
|
const sym = loanTokenSymbolOrAddress.toUpperCase();
|
|
1803
1981
|
items = items.filter((m) => m.loanAsset?.symbol?.toUpperCase() === sym);
|
|
1804
1982
|
}
|
|
1805
|
-
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !==
|
|
1983
|
+
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== ethers3.ZeroAddress).map((m) => {
|
|
1806
1984
|
const loanDecimals = m.loanAsset?.decimals ?? 18;
|
|
1807
1985
|
return {
|
|
1808
1986
|
collateralToken: m.collateralAsset.symbol,
|
|
@@ -1863,7 +2041,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1863
2041
|
{ maxRetries: 3, onRetry: (n, e) => console.warn(`[agether] Morpho API retry ${n}:`, e.message) }
|
|
1864
2042
|
);
|
|
1865
2043
|
let items = resp.data?.data?.markets?.items ?? [];
|
|
1866
|
-
items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !==
|
|
2044
|
+
items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== ethers3.ZeroAddress);
|
|
1867
2045
|
const searchUpper = search.toUpperCase();
|
|
1868
2046
|
if (options?.asCollateral) {
|
|
1869
2047
|
items = items.filter((m) => m.collateralAsset?.symbol?.toUpperCase() === searchUpper);
|
|
@@ -1919,10 +2097,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1919
2097
|
if (ethBalance > 0n) {
|
|
1920
2098
|
results.push({
|
|
1921
2099
|
symbol: "ETH",
|
|
1922
|
-
address:
|
|
2100
|
+
address: ethers3.ZeroAddress,
|
|
1923
2101
|
decimals: 18,
|
|
1924
2102
|
balance: ethBalance,
|
|
1925
|
-
balanceFormatted:
|
|
2103
|
+
balanceFormatted: ethers3.formatEther(ethBalance)
|
|
1926
2104
|
});
|
|
1927
2105
|
}
|
|
1928
2106
|
} catch {
|
|
@@ -1933,7 +2111,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1933
2111
|
const batch = tokenEntries.slice(i, i + batchSize);
|
|
1934
2112
|
const checks = batch.map(async (info) => {
|
|
1935
2113
|
try {
|
|
1936
|
-
const token = new
|
|
2114
|
+
const token = new Contract3(info.address, ERC20_ABI, this.provider);
|
|
1937
2115
|
const balance = await token.balanceOf(acctAddr);
|
|
1938
2116
|
if (balance > 0n) {
|
|
1939
2117
|
return {
|
|
@@ -1941,7 +2119,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1941
2119
|
address: info.address,
|
|
1942
2120
|
decimals: info.decimals,
|
|
1943
2121
|
balance,
|
|
1944
|
-
balanceFormatted:
|
|
2122
|
+
balanceFormatted: ethers3.formatUnits(balance, info.decimals)
|
|
1945
2123
|
};
|
|
1946
2124
|
}
|
|
1947
2125
|
} catch {
|
|
@@ -1973,7 +2151,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1973
2151
|
try {
|
|
1974
2152
|
const balance = await this.getTokenBalance(collateralSymbol);
|
|
1975
2153
|
const info = await this._resolveToken(collateralSymbol);
|
|
1976
|
-
tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted:
|
|
2154
|
+
tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted: ethers3.formatUnits(balance, info.decimals) }];
|
|
1977
2155
|
} catch {
|
|
1978
2156
|
}
|
|
1979
2157
|
} else {
|
|
@@ -2053,12 +2231,12 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2053
2231
|
try {
|
|
2054
2232
|
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
2055
2233
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2056
|
-
const oracleContract = new
|
|
2234
|
+
const oracleContract = new Contract3(params.oracle, [
|
|
2057
2235
|
"function price() view returns (uint256)"
|
|
2058
2236
|
], this.provider);
|
|
2059
2237
|
const oraclePrice = await oracleContract.price();
|
|
2060
2238
|
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
2061
|
-
const amountWei =
|
|
2239
|
+
const amountWei = ethers3.parseUnits(amount, colInfo.decimals);
|
|
2062
2240
|
const valueInLoan = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
|
|
2063
2241
|
collateralValueUsd = Number(valueInLoan) / 10 ** loanDecimals;
|
|
2064
2242
|
} catch (e) {
|
|
@@ -2109,14 +2287,14 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2109
2287
|
}
|
|
2110
2288
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2111
2289
|
const loanTokenAddr = params.loanToken;
|
|
2112
|
-
const parsedAmount =
|
|
2113
|
-
const marketId =
|
|
2114
|
-
|
|
2290
|
+
const parsedAmount = ethers3.parseUnits(amount, loanDecimals);
|
|
2291
|
+
const marketId = ethers3.keccak256(
|
|
2292
|
+
ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
2115
2293
|
["address", "address", "address", "address", "uint256"],
|
|
2116
2294
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2117
2295
|
)
|
|
2118
2296
|
);
|
|
2119
|
-
const loanContract = new
|
|
2297
|
+
const loanContract = new Contract3(loanTokenAddr, ERC20_ABI, this._signer);
|
|
2120
2298
|
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2121
2299
|
if (acctBalance < parsedAmount) {
|
|
2122
2300
|
const shortfall = parsedAmount - acctBalance;
|
|
@@ -2125,7 +2303,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2125
2303
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2126
2304
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2127
2305
|
throw new AgetherError(
|
|
2128
|
-
`Insufficient ${loanSymbol}. Need ${amount}, AgentAccount has ${
|
|
2306
|
+
`Insufficient ${loanSymbol}. Need ${amount}, AgentAccount has ${ethers3.formatUnits(acctBalance, loanDecimals)}, EOA has ${ethers3.formatUnits(eoaBalance, loanDecimals)}.`,
|
|
2129
2307
|
"INSUFFICIENT_BALANCE"
|
|
2130
2308
|
);
|
|
2131
2309
|
}
|
|
@@ -2145,7 +2323,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2145
2323
|
"0x"
|
|
2146
2324
|
])
|
|
2147
2325
|
];
|
|
2148
|
-
const receipt = await this.
|
|
2326
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2149
2327
|
return {
|
|
2150
2328
|
tx: receipt.hash,
|
|
2151
2329
|
amount,
|
|
@@ -2181,8 +2359,8 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2181
2359
|
params = p;
|
|
2182
2360
|
}
|
|
2183
2361
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2184
|
-
const marketId =
|
|
2185
|
-
|
|
2362
|
+
const marketId = ethers3.keccak256(
|
|
2363
|
+
ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
2186
2364
|
["address", "address", "address", "address", "uint256"],
|
|
2187
2365
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2188
2366
|
)
|
|
@@ -2195,7 +2373,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2195
2373
|
withdrawAssets = 0n;
|
|
2196
2374
|
if (withdrawShares === 0n) throw new AgetherError("No supply position to withdraw", "NO_SUPPLY");
|
|
2197
2375
|
} else {
|
|
2198
|
-
withdrawAssets =
|
|
2376
|
+
withdrawAssets = ethers3.parseUnits(amount, loanDecimals);
|
|
2199
2377
|
withdrawShares = 0n;
|
|
2200
2378
|
}
|
|
2201
2379
|
const data = morphoIface.encodeFunctionData("withdraw", [
|
|
@@ -2205,7 +2383,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2205
2383
|
acctAddr,
|
|
2206
2384
|
dest
|
|
2207
2385
|
]);
|
|
2208
|
-
const receipt = await this.
|
|
2386
|
+
const receipt = await this.executeSingle(morphoAddr, data);
|
|
2209
2387
|
let remainingSupply = "0";
|
|
2210
2388
|
try {
|
|
2211
2389
|
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
@@ -2213,7 +2391,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2213
2391
|
const totalSupplyAssets = BigInt(mkt.totalSupplyAssets);
|
|
2214
2392
|
const totalSupplyShares = BigInt(mkt.totalSupplyShares);
|
|
2215
2393
|
const currentAssets = totalSupplyShares > 0n ? BigInt(pos.supplyShares) * totalSupplyAssets / totalSupplyShares : 0n;
|
|
2216
|
-
remainingSupply =
|
|
2394
|
+
remainingSupply = ethers3.formatUnits(currentAssets, loanDecimals);
|
|
2217
2395
|
} catch (e) {
|
|
2218
2396
|
console.warn("[agether] failed to read remaining supply:", e instanceof Error ? e.message : e);
|
|
2219
2397
|
}
|
|
@@ -2278,9 +2456,9 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2278
2456
|
loanToken: p.market.loanAsset.symbol,
|
|
2279
2457
|
collateralToken: p.market.collateralAsset?.symbol ?? "none",
|
|
2280
2458
|
supplyShares: p.state.supplyShares,
|
|
2281
|
-
suppliedAssets:
|
|
2282
|
-
netDeposited:
|
|
2283
|
-
earnedYield:
|
|
2459
|
+
suppliedAssets: ethers3.formatUnits(currentAssets, p.market.loanAsset.decimals),
|
|
2460
|
+
netDeposited: ethers3.formatUnits(netDeposited, p.market.loanAsset.decimals),
|
|
2461
|
+
earnedYield: ethers3.formatUnits(earnedYield, p.market.loanAsset.decimals),
|
|
2284
2462
|
supplyApy: p.market.state?.supplyApy ?? 0
|
|
2285
2463
|
});
|
|
2286
2464
|
}
|
|
@@ -2308,8 +2486,8 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2308
2486
|
);
|
|
2309
2487
|
const params = await this.findMarketForCollateral(pos.collateralToken, pos.loanToken);
|
|
2310
2488
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2311
|
-
const parsedAmount =
|
|
2312
|
-
const availableYield =
|
|
2489
|
+
const parsedAmount = ethers3.parseUnits(amount, loanDecimals);
|
|
2490
|
+
const availableYield = ethers3.parseUnits(pos.earnedYield, loanDecimals);
|
|
2313
2491
|
if (parsedAmount > availableYield) {
|
|
2314
2492
|
const loanSymbol = pos.loanToken;
|
|
2315
2493
|
throw new AgetherError(
|
|
@@ -2324,7 +2502,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2324
2502
|
acctAddr,
|
|
2325
2503
|
recipient
|
|
2326
2504
|
]);
|
|
2327
|
-
const receipt = await this.
|
|
2505
|
+
const receipt = await this.executeSingle(morphoAddr, data);
|
|
2328
2506
|
let remainingYield = "0";
|
|
2329
2507
|
let remainingSupply = "0";
|
|
2330
2508
|
try {
|
|
@@ -2359,16 +2537,16 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2359
2537
|
const acctAddr = await this.getAccountAddress();
|
|
2360
2538
|
const colInfo = await this._resolveToken(tokenSymbol);
|
|
2361
2539
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
2362
|
-
const weiAmount =
|
|
2540
|
+
const weiAmount = ethers3.parseUnits(amount, colInfo.decimals);
|
|
2363
2541
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
2364
|
-
const colToken = new
|
|
2542
|
+
const colToken = new Contract3(colInfo.address, ERC20_ABI, this._signer);
|
|
2365
2543
|
const acctBalance = await colToken.balanceOf(acctAddr);
|
|
2366
2544
|
if (acctBalance < weiAmount) {
|
|
2367
2545
|
const shortfall = weiAmount - acctBalance;
|
|
2368
2546
|
const eoaBalance = await colToken.balanceOf(await this.getSignerAddress());
|
|
2369
2547
|
if (eoaBalance < shortfall) {
|
|
2370
2548
|
throw new AgetherError(
|
|
2371
|
-
`Insufficient ${tokenSymbol}. Need ${amount}, AgentAccount has ${
|
|
2549
|
+
`Insufficient ${tokenSymbol}. Need ${amount}, AgentAccount has ${ethers3.formatUnits(acctBalance, colInfo.decimals)}, EOA has ${ethers3.formatUnits(eoaBalance, colInfo.decimals)}.`,
|
|
2372
2550
|
"INSUFFICIENT_BALANCE"
|
|
2373
2551
|
);
|
|
2374
2552
|
}
|
|
@@ -2387,7 +2565,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2387
2565
|
"0x"
|
|
2388
2566
|
])
|
|
2389
2567
|
];
|
|
2390
|
-
const receipt = await this.
|
|
2568
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2391
2569
|
return {
|
|
2392
2570
|
tx: receipt.hash,
|
|
2393
2571
|
collateralToken: tokenSymbol,
|
|
@@ -2420,10 +2598,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2420
2598
|
usedToken = symbol;
|
|
2421
2599
|
}
|
|
2422
2600
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2423
|
-
const parsedAmount =
|
|
2601
|
+
const parsedAmount = ethers3.parseUnits(amount, loanDecimals);
|
|
2424
2602
|
try {
|
|
2425
|
-
const marketId =
|
|
2426
|
-
|
|
2603
|
+
const marketId = ethers3.keccak256(
|
|
2604
|
+
ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
2427
2605
|
["address", "address", "address", "address", "uint256"],
|
|
2428
2606
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2429
2607
|
)
|
|
@@ -2435,7 +2613,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2435
2613
|
"NO_COLLATERAL"
|
|
2436
2614
|
);
|
|
2437
2615
|
}
|
|
2438
|
-
const oracleContract = new
|
|
2616
|
+
const oracleContract = new Contract3(params.oracle, ["function price() view returns (uint256)"], this.provider);
|
|
2439
2617
|
const oraclePrice = await oracleContract.price();
|
|
2440
2618
|
const collateralValueInLoan = BigInt(pos.collateral) * oraclePrice / 10n ** 36n;
|
|
2441
2619
|
const maxBorrowTotal = collateralValueInLoan * params.lltv / 10n ** 18n;
|
|
@@ -2448,8 +2626,8 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2448
2626
|
const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
2449
2627
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2450
2628
|
const colInfo = await this._resolveToken(usedToken);
|
|
2451
|
-
const maxFormatted =
|
|
2452
|
-
const colFormatted =
|
|
2629
|
+
const maxFormatted = ethers3.formatUnits(maxAdditional, loanDecimals);
|
|
2630
|
+
const colFormatted = ethers3.formatUnits(pos.collateral, colInfo.decimals);
|
|
2453
2631
|
throw new AgetherError(
|
|
2454
2632
|
`Borrow of ${amount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (collateral: ${colFormatted} ${usedToken}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Deposit more collateral or reduce borrow amount.`,
|
|
2455
2633
|
"EXCEEDS_MAX_LTV"
|
|
@@ -2466,7 +2644,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2466
2644
|
acctAddr,
|
|
2467
2645
|
acctAddr
|
|
2468
2646
|
]);
|
|
2469
|
-
const receipt = await this.
|
|
2647
|
+
const receipt = await this.executeSingle(morphoAddr, data);
|
|
2470
2648
|
return {
|
|
2471
2649
|
tx: receipt.hash,
|
|
2472
2650
|
amount,
|
|
@@ -2496,19 +2674,19 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2496
2674
|
const colInfo = await this._resolveToken(tokenSymbol);
|
|
2497
2675
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
2498
2676
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2499
|
-
const colWei =
|
|
2500
|
-
const borrowWei =
|
|
2677
|
+
const colWei = ethers3.parseUnits(collateralAmount, colInfo.decimals);
|
|
2678
|
+
const borrowWei = ethers3.parseUnits(borrowAmount, loanDecimals);
|
|
2501
2679
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
2502
2680
|
try {
|
|
2503
|
-
const marketId =
|
|
2504
|
-
|
|
2681
|
+
const marketId = ethers3.keccak256(
|
|
2682
|
+
ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
2505
2683
|
["address", "address", "address", "address", "uint256"],
|
|
2506
2684
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2507
2685
|
)
|
|
2508
2686
|
);
|
|
2509
2687
|
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
2510
2688
|
const totalCollateral = BigInt(pos.collateral) + colWei;
|
|
2511
|
-
const oracleContract = new
|
|
2689
|
+
const oracleContract = new Contract3(params.oracle, ["function price() view returns (uint256)"], this.provider);
|
|
2512
2690
|
const oraclePrice = await oracleContract.price();
|
|
2513
2691
|
const collateralValueInLoan = totalCollateral * oraclePrice / 10n ** 36n;
|
|
2514
2692
|
const maxBorrowTotal = collateralValueInLoan * params.lltv / 10n ** 18n;
|
|
@@ -2520,9 +2698,9 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2520
2698
|
if (borrowWei > maxAdditional) {
|
|
2521
2699
|
const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
2522
2700
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2523
|
-
const maxFormatted =
|
|
2701
|
+
const maxFormatted = ethers3.formatUnits(maxAdditional, loanDecimals);
|
|
2524
2702
|
throw new AgetherError(
|
|
2525
|
-
`Borrow of ${borrowAmount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (total collateral: ${
|
|
2703
|
+
`Borrow of ${borrowAmount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (total collateral: ${ethers3.formatUnits(totalCollateral, colInfo.decimals)} ${tokenSymbol}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Reduce borrow or increase collateral.`,
|
|
2526
2704
|
"EXCEEDS_MAX_LTV"
|
|
2527
2705
|
);
|
|
2528
2706
|
}
|
|
@@ -2530,14 +2708,14 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2530
2708
|
if (e instanceof AgetherError) throw e;
|
|
2531
2709
|
console.warn("[agether] depositAndBorrow pre-check failed (proceeding anyway):", e instanceof Error ? e.message : e);
|
|
2532
2710
|
}
|
|
2533
|
-
const colToken = new
|
|
2711
|
+
const colToken = new Contract3(colInfo.address, ERC20_ABI, this._signer);
|
|
2534
2712
|
const acctBalance = await colToken.balanceOf(acctAddr);
|
|
2535
2713
|
if (acctBalance < colWei) {
|
|
2536
2714
|
const shortfall = colWei - acctBalance;
|
|
2537
2715
|
const eoaBalance = await colToken.balanceOf(await this.getSignerAddress());
|
|
2538
2716
|
if (eoaBalance < shortfall) {
|
|
2539
2717
|
throw new AgetherError(
|
|
2540
|
-
`Insufficient ${tokenSymbol}. Need ${collateralAmount}, AgentAccount has ${
|
|
2718
|
+
`Insufficient ${tokenSymbol}. Need ${collateralAmount}, AgentAccount has ${ethers3.formatUnits(acctBalance, colInfo.decimals)}, EOA has ${ethers3.formatUnits(eoaBalance, colInfo.decimals)}.`,
|
|
2541
2719
|
"INSUFFICIENT_BALANCE"
|
|
2542
2720
|
);
|
|
2543
2721
|
}
|
|
@@ -2563,7 +2741,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2563
2741
|
acctAddr
|
|
2564
2742
|
])
|
|
2565
2743
|
];
|
|
2566
|
-
const receipt = await this.
|
|
2744
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2567
2745
|
return {
|
|
2568
2746
|
tx: receipt.hash,
|
|
2569
2747
|
collateralToken: tokenSymbol,
|
|
@@ -2613,9 +2791,9 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2613
2791
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2614
2792
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2615
2793
|
const estimated = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
2616
|
-
approveAmount = estimated > 0n ? estimated :
|
|
2794
|
+
approveAmount = estimated > 0n ? estimated : ethers3.parseUnits("1", loanDecimals);
|
|
2617
2795
|
} else {
|
|
2618
|
-
const marketId =
|
|
2796
|
+
const marketId = ethers3.keccak256(ethers3.AbiCoder.defaultAbiCoder().encode(
|
|
2619
2797
|
["address", "address", "address", "address", "uint256"],
|
|
2620
2798
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2621
2799
|
));
|
|
@@ -2625,14 +2803,14 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2625
2803
|
const onChainMkt = await this.morphoBlue.market(marketId);
|
|
2626
2804
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2627
2805
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2628
|
-
approveAmount = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n :
|
|
2806
|
+
approveAmount = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : ethers3.parseUnits("1", loanDecimals);
|
|
2629
2807
|
}
|
|
2630
2808
|
} else {
|
|
2631
|
-
repayAssets =
|
|
2809
|
+
repayAssets = ethers3.parseUnits(amount, loanDecimals);
|
|
2632
2810
|
repayShares = 0n;
|
|
2633
2811
|
approveAmount = repayAssets;
|
|
2634
2812
|
}
|
|
2635
|
-
const loanContract = new
|
|
2813
|
+
const loanContract = new Contract3(loanTokenAddr, ERC20_ABI, this._signer);
|
|
2636
2814
|
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2637
2815
|
const checkAmount = repayShares > 0n && repayAssets === 0n ? approveAmount * 1005n / 1000n : approveAmount;
|
|
2638
2816
|
if (acctBalance < checkAmount) {
|
|
@@ -2651,7 +2829,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2651
2829
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2652
2830
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2653
2831
|
throw new AgetherError(
|
|
2654
|
-
`Insufficient ${loanSymbol} for repay. Need ~${
|
|
2832
|
+
`Insufficient ${loanSymbol} for repay. Need ~${ethers3.formatUnits(checkAmount, loanDecimals)}, AgentAccount has ${ethers3.formatUnits(acctBalance, loanDecimals)}, EOA has ${ethers3.formatUnits(eoaBalance, loanDecimals)}.`,
|
|
2655
2833
|
"INSUFFICIENT_BALANCE"
|
|
2656
2834
|
);
|
|
2657
2835
|
}
|
|
@@ -2673,7 +2851,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2673
2851
|
"0x"
|
|
2674
2852
|
])
|
|
2675
2853
|
];
|
|
2676
|
-
const receipt = await this.
|
|
2854
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2677
2855
|
let remainingDebt = "0";
|
|
2678
2856
|
try {
|
|
2679
2857
|
const markets = await this.getMarkets(true);
|
|
@@ -2688,7 +2866,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2688
2866
|
const totalAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2689
2867
|
const totalShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2690
2868
|
const debtWei = totalShares > 0n ? shares * totalAssets / totalShares : 0n;
|
|
2691
|
-
remainingDebt =
|
|
2869
|
+
remainingDebt = ethers3.formatUnits(debtWei, loanDecimals);
|
|
2692
2870
|
}
|
|
2693
2871
|
}
|
|
2694
2872
|
} catch (e) {
|
|
@@ -2830,7 +3008,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2830
3008
|
weiAmount = pos.collateral;
|
|
2831
3009
|
if (weiAmount === 0n) throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
2832
3010
|
} else {
|
|
2833
|
-
weiAmount =
|
|
3011
|
+
weiAmount = ethers3.parseUnits(amount, colInfo.decimals);
|
|
2834
3012
|
}
|
|
2835
3013
|
let hasDustDebt = false;
|
|
2836
3014
|
let dustBorrowShares = 0n;
|
|
@@ -2845,10 +3023,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2845
3023
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2846
3024
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2847
3025
|
const estimated = totalBorrowShares > 0n ? dustBorrowShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
2848
|
-
dustApproveAmount = estimated > 0n ? estimated :
|
|
3026
|
+
dustApproveAmount = estimated > 0n ? estimated : ethers3.parseUnits("1", loanDecimals);
|
|
2849
3027
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2850
3028
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2851
|
-
console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${
|
|
3029
|
+
console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${ethers3.formatUnits(dustApproveAmount, loanDecimals)} ${loanSymbol} \u2014 auto-repaying before withdraw`);
|
|
2852
3030
|
}
|
|
2853
3031
|
} catch (e) {
|
|
2854
3032
|
console.warn("[agether] failed to check borrow shares before withdraw:", e instanceof Error ? e.message : e);
|
|
@@ -2862,7 +3040,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2862
3040
|
]);
|
|
2863
3041
|
let receipt;
|
|
2864
3042
|
if (hasDustDebt) {
|
|
2865
|
-
const loanContract = new
|
|
3043
|
+
const loanContract = new Contract3(loanTokenAddr, ERC20_ABI, this._signer);
|
|
2866
3044
|
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2867
3045
|
if (acctBalance < dustApproveAmount) {
|
|
2868
3046
|
const shortfall = dustApproveAmount - acctBalance;
|
|
@@ -2870,7 +3048,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2870
3048
|
if (eoaBalance >= shortfall) {
|
|
2871
3049
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2872
3050
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2873
|
-
console.log(`[agether] transferring ${
|
|
3051
|
+
console.log(`[agether] transferring ${ethers3.formatUnits(shortfall, loanDecimals)} ${loanSymbol} from EOA \u2192 AgentAccount for dust repay`);
|
|
2874
3052
|
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
2875
3053
|
await transferTx.wait();
|
|
2876
3054
|
this._refreshSigner();
|
|
@@ -2889,15 +3067,15 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2889
3067
|
]),
|
|
2890
3068
|
withdrawData
|
|
2891
3069
|
];
|
|
2892
|
-
receipt = await this.
|
|
3070
|
+
receipt = await this.executeBatch(targets, values, datas);
|
|
2893
3071
|
} else {
|
|
2894
|
-
receipt = await this.
|
|
3072
|
+
receipt = await this.executeSingle(morphoAddr, withdrawData);
|
|
2895
3073
|
}
|
|
2896
3074
|
let remainingCollateral = "0";
|
|
2897
3075
|
try {
|
|
2898
3076
|
if (market) {
|
|
2899
3077
|
const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
|
|
2900
|
-
remainingCollateral =
|
|
3078
|
+
remainingCollateral = ethers3.formatUnits(pos.collateral, colInfo.decimals);
|
|
2901
3079
|
}
|
|
2902
3080
|
} catch (e) {
|
|
2903
3081
|
console.warn("[agether] failed to read remaining collateral after withdraw:", e instanceof Error ? e.message : e);
|
|
@@ -2905,7 +3083,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2905
3083
|
return {
|
|
2906
3084
|
tx: receipt.hash,
|
|
2907
3085
|
token: tokenSymbol,
|
|
2908
|
-
amount: amount === "all" ?
|
|
3086
|
+
amount: amount === "all" ? ethers3.formatUnits(weiAmount, colInfo.decimals) : amount,
|
|
2909
3087
|
remainingCollateral,
|
|
2910
3088
|
destination: dest
|
|
2911
3089
|
};
|
|
@@ -2929,139 +3107,21 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2929
3107
|
_refreshSigner() {
|
|
2930
3108
|
if (this._useExternalSigner) {
|
|
2931
3109
|
const addrs = this.config.contracts;
|
|
2932
|
-
this.agether4337Factory = new
|
|
2933
|
-
this.entryPoint = new
|
|
3110
|
+
this.agether4337Factory = new Contract3(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
3111
|
+
this.entryPoint = new Contract3(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
|
|
2934
3112
|
} else {
|
|
2935
|
-
this.provider = new
|
|
2936
|
-
const wallet = new
|
|
3113
|
+
this.provider = new ethers3.JsonRpcProvider(this._rpcUrl);
|
|
3114
|
+
const wallet = new ethers3.Wallet(this._privateKey, this.provider);
|
|
2937
3115
|
this._signer = wallet;
|
|
2938
3116
|
this._eoaAddress = wallet.address;
|
|
2939
3117
|
const addrs = this.config.contracts;
|
|
2940
|
-
this.agether4337Factory = new
|
|
2941
|
-
this.entryPoint = new
|
|
3118
|
+
this.agether4337Factory = new Contract3(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
3119
|
+
this.entryPoint = new Contract3(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
|
|
2942
3120
|
}
|
|
2943
3121
|
}
|
|
2944
3122
|
// ────────────────────────────────────────────────────────────
|
|
2945
3123
|
// ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
|
|
2946
3124
|
// ────────────────────────────────────────────────────────────
|
|
2947
|
-
/**
|
|
2948
|
-
* Pack two uint128 values into a single bytes32:
|
|
2949
|
-
* bytes32 = (hi << 128) | lo
|
|
2950
|
-
*/
|
|
2951
|
-
_packUint128(hi, lo) {
|
|
2952
|
-
return ethers2.zeroPadValue(ethers2.toBeHex(hi << 128n | lo), 32);
|
|
2953
|
-
}
|
|
2954
|
-
/**
|
|
2955
|
-
* Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
|
|
2956
|
-
*
|
|
2957
|
-
* @param callData – the ABI-encoded calldata for the Safe7579 account
|
|
2958
|
-
* (e.g. `execute(mode, executionCalldata)`)
|
|
2959
|
-
* @returns the transaction receipt of the handleOps call
|
|
2960
|
-
*/
|
|
2961
|
-
async _submitUserOp(callData) {
|
|
2962
|
-
const sender = await this.getAccountAddress();
|
|
2963
|
-
const validatorAddr = this.config.contracts.erc8004ValidationModule;
|
|
2964
|
-
const nonceKey = BigInt(validatorAddr) << 32n;
|
|
2965
|
-
const nonce = await this.entryPoint.getNonce(sender, nonceKey);
|
|
2966
|
-
const feeData = await this.provider.getFeeData();
|
|
2967
|
-
const maxFeePerGas = feeData.maxFeePerGas ?? ethers2.parseUnits("0.5", "gwei");
|
|
2968
|
-
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? ethers2.parseUnits("0.1", "gwei");
|
|
2969
|
-
const verificationGasLimit = 500000n;
|
|
2970
|
-
const callGasLimit = 800000n;
|
|
2971
|
-
const preVerificationGas = 100000n;
|
|
2972
|
-
const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
|
|
2973
|
-
const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
|
|
2974
|
-
const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
|
|
2975
|
-
const accountBalance = await this.provider.getBalance(sender);
|
|
2976
|
-
if (accountBalance < requiredPrefund) {
|
|
2977
|
-
const topUp = requiredPrefund - accountBalance;
|
|
2978
|
-
const topUpWithBuffer = topUp * 120n / 100n;
|
|
2979
|
-
const fundTx = await this._signer.sendTransaction({
|
|
2980
|
-
to: sender,
|
|
2981
|
-
value: topUpWithBuffer
|
|
2982
|
-
});
|
|
2983
|
-
await fundTx.wait();
|
|
2984
|
-
this._refreshSigner();
|
|
2985
|
-
}
|
|
2986
|
-
const userOp = {
|
|
2987
|
-
sender,
|
|
2988
|
-
nonce,
|
|
2989
|
-
initCode: "0x",
|
|
2990
|
-
callData,
|
|
2991
|
-
accountGasLimits,
|
|
2992
|
-
preVerificationGas,
|
|
2993
|
-
gasFees,
|
|
2994
|
-
paymasterAndData: "0x",
|
|
2995
|
-
signature: "0x"
|
|
2996
|
-
// placeholder — replaced after signing
|
|
2997
|
-
};
|
|
2998
|
-
const userOpHash = await this.entryPoint.getUserOpHash(userOp);
|
|
2999
|
-
const signature = await this._signer.signMessage(ethers2.getBytes(userOpHash));
|
|
3000
|
-
userOp.signature = signature;
|
|
3001
|
-
const tx = await this.entryPoint.handleOps([userOp], await this.getSignerAddress());
|
|
3002
|
-
const receipt = await tx.wait();
|
|
3003
|
-
this._refreshSigner();
|
|
3004
|
-
const epIface = new ethers2.Interface(ENTRYPOINT_V07_ABI);
|
|
3005
|
-
for (const log of receipt.logs) {
|
|
3006
|
-
try {
|
|
3007
|
-
const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
|
|
3008
|
-
if (parsed?.name === "UserOperationEvent" && !parsed.args.success) {
|
|
3009
|
-
let revertMsg = "UserOp inner execution reverted";
|
|
3010
|
-
for (const rLog of receipt.logs) {
|
|
3011
|
-
try {
|
|
3012
|
-
const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
|
|
3013
|
-
if (rParsed?.name === "UserOperationRevertReason") {
|
|
3014
|
-
const reason = rParsed.args.revertReason;
|
|
3015
|
-
try {
|
|
3016
|
-
if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
|
|
3017
|
-
const decoded = ethers2.AbiCoder.defaultAbiCoder().decode(["string"], "0x" + reason.slice(10));
|
|
3018
|
-
revertMsg = `UserOp reverted: ${decoded[0]}`;
|
|
3019
|
-
} else {
|
|
3020
|
-
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
3021
|
-
}
|
|
3022
|
-
} catch {
|
|
3023
|
-
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
3024
|
-
}
|
|
3025
|
-
break;
|
|
3026
|
-
}
|
|
3027
|
-
} catch {
|
|
3028
|
-
continue;
|
|
3029
|
-
}
|
|
3030
|
-
}
|
|
3031
|
-
throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
|
|
3032
|
-
}
|
|
3033
|
-
} catch (e) {
|
|
3034
|
-
if (e instanceof AgetherError) throw e;
|
|
3035
|
-
continue;
|
|
3036
|
-
}
|
|
3037
|
-
}
|
|
3038
|
-
return receipt;
|
|
3039
|
-
}
|
|
3040
|
-
/**
|
|
3041
|
-
* Execute a single call via Safe7579 account (ERC-7579 single mode)
|
|
3042
|
-
* through an ERC-4337 UserOperation.
|
|
3043
|
-
*/
|
|
3044
|
-
async exec(target, data, value = 0n) {
|
|
3045
|
-
const valueHex = ethers2.zeroPadValue(ethers2.toBeHex(value), 32);
|
|
3046
|
-
const executionCalldata = ethers2.concat([target, valueHex, data]);
|
|
3047
|
-
const safe7579Iface = new ethers2.Interface(SAFE7579_ACCOUNT_ABI);
|
|
3048
|
-
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
|
|
3049
|
-
return this._submitUserOp(callData);
|
|
3050
|
-
}
|
|
3051
|
-
/**
|
|
3052
|
-
* Execute multiple calls via Safe7579 account (ERC-7579 batch mode)
|
|
3053
|
-
* through an ERC-4337 UserOperation.
|
|
3054
|
-
*/
|
|
3055
|
-
async batch(targets, values, datas) {
|
|
3056
|
-
const executions = targets.map((t, i) => [t, values[i], datas[i]]);
|
|
3057
|
-
const executionCalldata = ethers2.AbiCoder.defaultAbiCoder().encode(
|
|
3058
|
-
["(address,uint256,bytes)[]"],
|
|
3059
|
-
[executions]
|
|
3060
|
-
);
|
|
3061
|
-
const safe7579Iface = new ethers2.Interface(SAFE7579_ACCOUNT_ABI);
|
|
3062
|
-
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_BATCH, executionCalldata]);
|
|
3063
|
-
return this._submitUserOp(callData);
|
|
3064
|
-
}
|
|
3065
3125
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
3066
3126
|
_toTuple(p) {
|
|
3067
3127
|
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
|
@@ -3111,7 +3171,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
3111
3171
|
}
|
|
3112
3172
|
const markets = await this.getMarkets();
|
|
3113
3173
|
for (const m of markets) {
|
|
3114
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
3174
|
+
if (!m.collateralAsset || m.collateralAsset.address === ethers3.ZeroAddress) continue;
|
|
3115
3175
|
try {
|
|
3116
3176
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
3117
3177
|
if (pos.collateral > 0n) {
|
|
@@ -3179,7 +3239,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
3179
3239
|
}
|
|
3180
3240
|
const markets = await this.getMarkets();
|
|
3181
3241
|
for (const m of markets) {
|
|
3182
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
3242
|
+
if (!m.collateralAsset || m.collateralAsset.address === ethers3.ZeroAddress) continue;
|
|
3183
3243
|
try {
|
|
3184
3244
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
3185
3245
|
if (BigInt(pos.supplyShares) > 0n) {
|
|
@@ -3358,6 +3418,316 @@ _MorphoClient._lstYieldCache = null;
|
|
|
3358
3418
|
_MorphoClient.LST_CACHE_TTL = 30 * 60 * 1e3;
|
|
3359
3419
|
var MorphoClient = _MorphoClient;
|
|
3360
3420
|
|
|
3421
|
+
// src/clients/AaveClient.ts
|
|
3422
|
+
import { ethers as ethers4, Contract as Contract4 } from "ethers";
|
|
3423
|
+
var POOL_ABI = [
|
|
3424
|
+
"function getUserAccountData(address user) view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 currentLtv, uint256 healthFactor)",
|
|
3425
|
+
"function getReserveData(address asset) view returns (tuple(uint256 configuration, uint128 liquidityIndex, uint128 currentLiquidityRate, uint128 variableBorrowIndex, uint128 currentVariableBorrowRate, uint128 currentStableBorrowRate, uint40 lastUpdateTimestamp, uint16 id, address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress, address interestRateStrategyAddress, uint128 accruedToTreasury, uint128 unbacked, uint128 isolationModeTotalDebt))",
|
|
3426
|
+
"function getReservesList() view returns (address[])",
|
|
3427
|
+
"function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)",
|
|
3428
|
+
"function withdraw(address asset, uint256 amount, address to) returns (uint256)",
|
|
3429
|
+
"function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)",
|
|
3430
|
+
"function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) returns (uint256)",
|
|
3431
|
+
"function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)"
|
|
3432
|
+
];
|
|
3433
|
+
var ERC20_ABI2 = [
|
|
3434
|
+
"function approve(address spender, uint256 amount) returns (bool)",
|
|
3435
|
+
"function allowance(address owner, address spender) view returns (uint256)",
|
|
3436
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
3437
|
+
"function decimals() view returns (uint8)",
|
|
3438
|
+
"function symbol() view returns (string)"
|
|
3439
|
+
];
|
|
3440
|
+
var ORACLE_ABI = [
|
|
3441
|
+
"function getAssetsPrices(address[] assets) view returns (uint256[])",
|
|
3442
|
+
"function BASE_CURRENCY_UNIT() view returns (uint256)"
|
|
3443
|
+
];
|
|
3444
|
+
var POOL_DATA_PROVIDER_ABI = [
|
|
3445
|
+
"function getReserveConfigurationData(address asset) view returns (uint256 decimals, uint256 ltv, uint256 liquidationThreshold, uint256 liquidationBonus, uint256 reserveFactor, bool usageAsCollateralEnabled, bool borrowingEnabled, bool stableBorrowRateEnabled, bool isActive, bool isFrozen)",
|
|
3446
|
+
"function getUserReserveData(address asset, address user) view returns (uint256 currentATokenBalance, uint256 currentStableDebt, uint256 currentVariableDebt, uint256 principalStableDebt, uint256 scaledVariableDebt, uint256 stableBorrowRate, uint256 liquidityRate, uint40 stableRateLastUpdated, bool usageAsCollateralEnabled)",
|
|
3447
|
+
"function getReserveTokensAddresses(address asset) view returns (address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress)",
|
|
3448
|
+
"function getAllReservesTokens() view returns (tuple(string symbol, address tokenAddress)[])"
|
|
3449
|
+
];
|
|
3450
|
+
var AAVE_ADDRESSES = {
|
|
3451
|
+
[1 /* Ethereum */]: {
|
|
3452
|
+
pool: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
|
|
3453
|
+
oracle: "0x54586bE62E3c3580375aE3723C145253060Ca0C2",
|
|
3454
|
+
dataProvider: "0x0a16f2FCC0D44FaE41cc54e079281D84A363bECD"
|
|
3455
|
+
},
|
|
3456
|
+
[8453 /* Base */]: {
|
|
3457
|
+
pool: "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
|
|
3458
|
+
oracle: "0x2Cc0Fc26eD4563A5ce5e8bdcfe1A2878676Ae156",
|
|
3459
|
+
dataProvider: "0x0F43731EB8d45A581f4a36DD74F5f358bc90C73A"
|
|
3460
|
+
}
|
|
3461
|
+
};
|
|
3462
|
+
var KNOWN_RESERVES = {
|
|
3463
|
+
[1 /* Ethereum */]: [
|
|
3464
|
+
{ symbol: "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: 18 },
|
|
3465
|
+
{ symbol: "wstETH", address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", decimals: 18 },
|
|
3466
|
+
{ symbol: "USDC", address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", decimals: 6 },
|
|
3467
|
+
{ symbol: "USDT", address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6 },
|
|
3468
|
+
{ symbol: "DAI", address: "0x6B175474E89094C44Da98b954EedeAC495271d0F", decimals: 18 },
|
|
3469
|
+
{ symbol: "cbETH", address: "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", decimals: 18 },
|
|
3470
|
+
{ symbol: "rETH", address: "0xae78736Cd615f374D3085123A210448E74Fc6393", decimals: 18 },
|
|
3471
|
+
{ symbol: "weETH", address: "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", decimals: 18 }
|
|
3472
|
+
],
|
|
3473
|
+
[8453 /* Base */]: [
|
|
3474
|
+
{ symbol: "WETH", address: "0x4200000000000000000000000000000000000006", decimals: 18 },
|
|
3475
|
+
{ symbol: "wstETH", address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", decimals: 18 },
|
|
3476
|
+
{ symbol: "cbETH", address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", decimals: 18 },
|
|
3477
|
+
{ symbol: "USDC", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", decimals: 6 },
|
|
3478
|
+
{ symbol: "USDbC", address: "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA", decimals: 6 }
|
|
3479
|
+
]
|
|
3480
|
+
};
|
|
3481
|
+
var _AaveClient = class _AaveClient extends AgentAccountClient {
|
|
3482
|
+
/**
|
|
3483
|
+
* Create an AaveClient. Takes the same config as MorphoClient — the agent's
|
|
3484
|
+
* Safe account is used for all Aave operations.
|
|
3485
|
+
*/
|
|
3486
|
+
constructor(config) {
|
|
3487
|
+
super(config);
|
|
3488
|
+
// Cache
|
|
3489
|
+
this._reserveCache = /* @__PURE__ */ new Map();
|
|
3490
|
+
this._reserveCacheTs = 0;
|
|
3491
|
+
const chainId = config.chainId ?? 1 /* Ethereum */;
|
|
3492
|
+
const addrs = AAVE_ADDRESSES[chainId];
|
|
3493
|
+
if (!addrs) {
|
|
3494
|
+
throw new AgetherError(`Aave V3 not supported on chain ${chainId}`, "UNSUPPORTED_CHAIN");
|
|
3495
|
+
}
|
|
3496
|
+
this._aaveChainId = chainId;
|
|
3497
|
+
this._pool = new Contract4(addrs.pool, POOL_ABI, this.provider);
|
|
3498
|
+
this._oracle = new Contract4(addrs.oracle, ORACLE_ABI, this.provider);
|
|
3499
|
+
this._dataProvider = new Contract4(addrs.dataProvider, POOL_DATA_PROVIDER_ABI, this.provider);
|
|
3500
|
+
this._poolIface = new ethers4.Interface(POOL_ABI);
|
|
3501
|
+
this._erc20Iface = new ethers4.Interface(ERC20_ABI2);
|
|
3502
|
+
}
|
|
3503
|
+
/** Get the Agent's Safe account address. */
|
|
3504
|
+
async getAccountAddress() {
|
|
3505
|
+
return super.getAccountAddress();
|
|
3506
|
+
}
|
|
3507
|
+
/** Get chainId. */
|
|
3508
|
+
get aaveChainId() {
|
|
3509
|
+
return this._aaveChainId;
|
|
3510
|
+
}
|
|
3511
|
+
// ─── Market Data (read-only, no Safe needed) ─────────────────────────
|
|
3512
|
+
async getReserves(forceRefresh = false) {
|
|
3513
|
+
if (!forceRefresh && this._reserveCache.size > 0 && Date.now() - this._reserveCacheTs < _AaveClient.CACHE_TTL) {
|
|
3514
|
+
return Array.from(this._reserveCache.values());
|
|
3515
|
+
}
|
|
3516
|
+
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3517
|
+
if (reserves.length === 0) return [];
|
|
3518
|
+
const addresses = reserves.map((r) => r.address);
|
|
3519
|
+
const prices = await this._oracle.getAssetsPrices(addresses);
|
|
3520
|
+
let baseCurrencyUnit;
|
|
3521
|
+
try {
|
|
3522
|
+
baseCurrencyUnit = await this._oracle.BASE_CURRENCY_UNIT();
|
|
3523
|
+
} catch {
|
|
3524
|
+
baseCurrencyUnit = 100000000n;
|
|
3525
|
+
}
|
|
3526
|
+
const results = [];
|
|
3527
|
+
const reserveDataPromises = reserves.map(async (reserve, i) => {
|
|
3528
|
+
try {
|
|
3529
|
+
const [reserveData, configData] = await Promise.all([
|
|
3530
|
+
this._pool.getReserveData(reserve.address),
|
|
3531
|
+
this._dataProvider.getReserveConfigurationData(reserve.address)
|
|
3532
|
+
]);
|
|
3533
|
+
const RAY = 10n ** 27n;
|
|
3534
|
+
const liquidityRate = reserveData[2];
|
|
3535
|
+
const borrowRate = reserveData[4];
|
|
3536
|
+
const supplyApy = Number(liquidityRate) / Number(RAY) * 100;
|
|
3537
|
+
const borrowApy = Number(borrowRate) / Number(RAY) * 100;
|
|
3538
|
+
const priceUsd = Number(prices[i]) / Number(baseCurrencyUnit);
|
|
3539
|
+
const ltv = Number(configData[1]) / 100;
|
|
3540
|
+
const liqThreshold = Number(configData[2]) / 100;
|
|
3541
|
+
const borrowingEnabled = configData[6];
|
|
3542
|
+
const isActive = configData[8];
|
|
3543
|
+
const info = {
|
|
3544
|
+
symbol: reserve.symbol,
|
|
3545
|
+
address: reserve.address,
|
|
3546
|
+
decimals: reserve.decimals,
|
|
3547
|
+
supplyApy,
|
|
3548
|
+
borrowApy,
|
|
3549
|
+
totalSupply: 0,
|
|
3550
|
+
totalBorrow: 0,
|
|
3551
|
+
ltv,
|
|
3552
|
+
liquidationThreshold: liqThreshold,
|
|
3553
|
+
borrowingEnabled,
|
|
3554
|
+
isActive,
|
|
3555
|
+
priceUsd
|
|
3556
|
+
};
|
|
3557
|
+
this._reserveCache.set(reserve.symbol, info);
|
|
3558
|
+
return info;
|
|
3559
|
+
} catch (err) {
|
|
3560
|
+
console.warn(`[aave] Failed to fetch reserve ${reserve.symbol}:`, err instanceof Error ? err.message : err);
|
|
3561
|
+
return null;
|
|
3562
|
+
}
|
|
3563
|
+
});
|
|
3564
|
+
const settled = await Promise.all(reserveDataPromises);
|
|
3565
|
+
for (const r of settled) {
|
|
3566
|
+
if (r) results.push(r);
|
|
3567
|
+
}
|
|
3568
|
+
this._reserveCacheTs = Date.now();
|
|
3569
|
+
return results;
|
|
3570
|
+
}
|
|
3571
|
+
// ─── Account Data (reads from Safe account) ──────────────────────────
|
|
3572
|
+
async getAccountData() {
|
|
3573
|
+
const safeAddr = await this.getAccountAddress();
|
|
3574
|
+
const [totalCollateralBase, totalDebtBase, availableBorrowsBase, currentLtv, liqThreshold, healthFactor] = await this._pool.getUserAccountData(safeAddr);
|
|
3575
|
+
let baseCurrencyUnit;
|
|
3576
|
+
try {
|
|
3577
|
+
baseCurrencyUnit = await this._oracle.BASE_CURRENCY_UNIT();
|
|
3578
|
+
} catch {
|
|
3579
|
+
baseCurrencyUnit = 100000000n;
|
|
3580
|
+
}
|
|
3581
|
+
const totalCollateralUsd = Number(totalCollateralBase) / Number(baseCurrencyUnit);
|
|
3582
|
+
const totalDebtUsd = Number(totalDebtBase) / Number(baseCurrencyUnit);
|
|
3583
|
+
const availableBorrowUsd = Number(availableBorrowsBase) / Number(baseCurrencyUnit);
|
|
3584
|
+
const hf = Number(healthFactor) / 1e18;
|
|
3585
|
+
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3586
|
+
const reserveInfos = await this.getReserves();
|
|
3587
|
+
const positions = [];
|
|
3588
|
+
const posPromises = reserves.map(async (reserve) => {
|
|
3589
|
+
try {
|
|
3590
|
+
const userData = await this._dataProvider.getUserReserveData(reserve.address, safeAddr);
|
|
3591
|
+
const aTokenBal = userData[0];
|
|
3592
|
+
const stableDebt = userData[1];
|
|
3593
|
+
const variableDebt = userData[2];
|
|
3594
|
+
const usedAsCollateral = userData[8];
|
|
3595
|
+
const totalDebt = stableDebt + variableDebt;
|
|
3596
|
+
if (aTokenBal === 0n && totalDebt === 0n) return null;
|
|
3597
|
+
const reserveInfo = reserveInfos.find((r) => r.symbol === reserve.symbol);
|
|
3598
|
+
const priceUsd = reserveInfo?.priceUsd ?? 0;
|
|
3599
|
+
const divisor = 10 ** reserve.decimals;
|
|
3600
|
+
return {
|
|
3601
|
+
asset: reserve.symbol,
|
|
3602
|
+
address: reserve.address,
|
|
3603
|
+
supplied: Number(aTokenBal) / divisor,
|
|
3604
|
+
suppliedUsd: Number(aTokenBal) / divisor * priceUsd,
|
|
3605
|
+
borrowed: Number(totalDebt) / divisor,
|
|
3606
|
+
borrowedUsd: Number(totalDebt) / divisor * priceUsd,
|
|
3607
|
+
usedAsCollateral,
|
|
3608
|
+
supplyApy: reserveInfo?.supplyApy ?? 0,
|
|
3609
|
+
borrowApy: reserveInfo?.borrowApy ?? 0
|
|
3610
|
+
};
|
|
3611
|
+
} catch {
|
|
3612
|
+
return null;
|
|
3613
|
+
}
|
|
3614
|
+
});
|
|
3615
|
+
const settled = await Promise.all(posPromises);
|
|
3616
|
+
for (const p of settled) {
|
|
3617
|
+
if (p) positions.push(p);
|
|
3618
|
+
}
|
|
3619
|
+
return {
|
|
3620
|
+
totalCollateralUsd,
|
|
3621
|
+
totalDebtUsd,
|
|
3622
|
+
availableBorrowUsd,
|
|
3623
|
+
currentLtv: Number(currentLtv) / 100,
|
|
3624
|
+
liquidationThreshold: Number(liqThreshold) / 100,
|
|
3625
|
+
healthFactor: hf > 1e10 ? Infinity : hf,
|
|
3626
|
+
positions
|
|
3627
|
+
};
|
|
3628
|
+
}
|
|
3629
|
+
// ─── Write Operations (through Safe account) ─────────────────────────
|
|
3630
|
+
/**
|
|
3631
|
+
* Supply an asset to Aave V3 from the Agent's Safe account.
|
|
3632
|
+
* Batch: approve + supply in one UserOp.
|
|
3633
|
+
*/
|
|
3634
|
+
async supply(asset, amount) {
|
|
3635
|
+
const reserve = this._resolveReserve(asset);
|
|
3636
|
+
const amountWei = ethers4.parseUnits(amount, reserve.decimals);
|
|
3637
|
+
const safeAddr = await this.getAccountAddress();
|
|
3638
|
+
const poolAddr = await this._pool.getAddress();
|
|
3639
|
+
const approveData = this._erc20Iface.encodeFunctionData("approve", [poolAddr, amountWei]);
|
|
3640
|
+
const supplyData = this._poolIface.encodeFunctionData("supply", [reserve.address, amountWei, safeAddr, 0]);
|
|
3641
|
+
return this.executeBatch(
|
|
3642
|
+
[reserve.address, poolAddr],
|
|
3643
|
+
[0n, 0n],
|
|
3644
|
+
[approveData, supplyData]
|
|
3645
|
+
);
|
|
3646
|
+
}
|
|
3647
|
+
/**
|
|
3648
|
+
* Withdraw a supplied asset from Aave V3 to the Safe account.
|
|
3649
|
+
*/
|
|
3650
|
+
async withdraw(asset, amount, to) {
|
|
3651
|
+
const reserve = this._resolveReserve(asset);
|
|
3652
|
+
const amountWei = amount === "all" ? ethers4.MaxUint256 : ethers4.parseUnits(amount, reserve.decimals);
|
|
3653
|
+
const recipient = to ?? await this.getAccountAddress();
|
|
3654
|
+
const poolAddr = await this._pool.getAddress();
|
|
3655
|
+
const data = this._poolIface.encodeFunctionData("withdraw", [reserve.address, amountWei, recipient]);
|
|
3656
|
+
return this.executeSingle(poolAddr, data);
|
|
3657
|
+
}
|
|
3658
|
+
/**
|
|
3659
|
+
* Borrow an asset from Aave V3 (variable rate) to the Safe account.
|
|
3660
|
+
*/
|
|
3661
|
+
async borrow(asset, amount) {
|
|
3662
|
+
const reserve = this._resolveReserve(asset);
|
|
3663
|
+
const amountWei = ethers4.parseUnits(amount, reserve.decimals);
|
|
3664
|
+
const safeAddr = await this.getAccountAddress();
|
|
3665
|
+
const poolAddr = await this._pool.getAddress();
|
|
3666
|
+
const data = this._poolIface.encodeFunctionData("borrow", [reserve.address, amountWei, 2, 0, safeAddr]);
|
|
3667
|
+
return this.executeSingle(poolAddr, data);
|
|
3668
|
+
}
|
|
3669
|
+
/**
|
|
3670
|
+
* Repay borrowed asset on Aave V3 from the Safe account.
|
|
3671
|
+
* Batch: approve + repay in one UserOp.
|
|
3672
|
+
*/
|
|
3673
|
+
async repay(asset, amount) {
|
|
3674
|
+
const reserve = this._resolveReserve(asset);
|
|
3675
|
+
const amountWei = amount === "all" ? ethers4.MaxUint256 : ethers4.parseUnits(amount, reserve.decimals);
|
|
3676
|
+
const safeAddr = await this.getAccountAddress();
|
|
3677
|
+
const poolAddr = await this._pool.getAddress();
|
|
3678
|
+
const approveAmount = amount === "all" ? ethers4.MaxUint256 : amountWei;
|
|
3679
|
+
const approveData = this._erc20Iface.encodeFunctionData("approve", [poolAddr, approveAmount]);
|
|
3680
|
+
const repayData = this._poolIface.encodeFunctionData("repay", [reserve.address, amountWei, 2, safeAddr]);
|
|
3681
|
+
return this.executeBatch(
|
|
3682
|
+
[reserve.address, poolAddr],
|
|
3683
|
+
[0n, 0n],
|
|
3684
|
+
[approveData, repayData]
|
|
3685
|
+
);
|
|
3686
|
+
}
|
|
3687
|
+
/**
|
|
3688
|
+
* Enable or disable a supplied asset as collateral.
|
|
3689
|
+
*/
|
|
3690
|
+
async setCollateral(asset, useAsCollateral) {
|
|
3691
|
+
const reserve = this._resolveReserve(asset);
|
|
3692
|
+
const poolAddr = await this._pool.getAddress();
|
|
3693
|
+
const data = this._poolIface.encodeFunctionData("setUserUseReserveAsCollateral", [reserve.address, useAsCollateral]);
|
|
3694
|
+
return this.executeSingle(poolAddr, data);
|
|
3695
|
+
}
|
|
3696
|
+
/**
|
|
3697
|
+
* Supply an asset and borrow in one atomic batch operation.
|
|
3698
|
+
*/
|
|
3699
|
+
async supplyAndBorrow(supplyAsset, supplyAmount, borrowAsset, borrowAmount) {
|
|
3700
|
+
const supplyReserve = this._resolveReserve(supplyAsset);
|
|
3701
|
+
const borrowReserve = this._resolveReserve(borrowAsset);
|
|
3702
|
+
const supplyWei = ethers4.parseUnits(supplyAmount, supplyReserve.decimals);
|
|
3703
|
+
const borrowWei = ethers4.parseUnits(borrowAmount, borrowReserve.decimals);
|
|
3704
|
+
const safeAddr = await this.getAccountAddress();
|
|
3705
|
+
const poolAddr = await this._pool.getAddress();
|
|
3706
|
+
const approveData = this._erc20Iface.encodeFunctionData("approve", [poolAddr, supplyWei]);
|
|
3707
|
+
const supplyData = this._poolIface.encodeFunctionData("supply", [supplyReserve.address, supplyWei, safeAddr, 0]);
|
|
3708
|
+
const borrowData = this._poolIface.encodeFunctionData("borrow", [borrowReserve.address, borrowWei, 2, 0, safeAddr]);
|
|
3709
|
+
return this.executeBatch(
|
|
3710
|
+
[supplyReserve.address, poolAddr, poolAddr],
|
|
3711
|
+
[0n, 0n, 0n],
|
|
3712
|
+
[approveData, supplyData, borrowData]
|
|
3713
|
+
);
|
|
3714
|
+
}
|
|
3715
|
+
// ─── Helpers ──────────────────────────────────────────────────────────
|
|
3716
|
+
_resolveReserve(symbolOrAddress) {
|
|
3717
|
+
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3718
|
+
const bySymbol = reserves.find((r) => r.symbol.toLowerCase() === symbolOrAddress.toLowerCase());
|
|
3719
|
+
if (bySymbol) return bySymbol;
|
|
3720
|
+
const byAddr = reserves.find((r) => r.address.toLowerCase() === symbolOrAddress.toLowerCase());
|
|
3721
|
+
if (byAddr) return byAddr;
|
|
3722
|
+
throw new AgetherError(
|
|
3723
|
+
`Unknown Aave reserve: ${symbolOrAddress}. Known: ${reserves.map((r) => r.symbol).join(", ")}`,
|
|
3724
|
+
"UNKNOWN_RESERVE"
|
|
3725
|
+
);
|
|
3726
|
+
}
|
|
3727
|
+
};
|
|
3728
|
+
_AaveClient.CACHE_TTL = 6e4;
|
|
3729
|
+
var AaveClient = _AaveClient;
|
|
3730
|
+
|
|
3361
3731
|
// src/clients/ScoringClient.ts
|
|
3362
3732
|
import axios3 from "axios";
|
|
3363
3733
|
|
|
@@ -3823,7 +4193,7 @@ var ScoringClient = class {
|
|
|
3823
4193
|
};
|
|
3824
4194
|
|
|
3825
4195
|
// src/clients/AgentIdentityClient.ts
|
|
3826
|
-
import { ethers as
|
|
4196
|
+
import { ethers as ethers5 } from "ethers";
|
|
3827
4197
|
var ERC8004_IDENTITY_ABI = [
|
|
3828
4198
|
// Registration
|
|
3829
4199
|
"function register() returns (uint256)",
|
|
@@ -3865,8 +4235,8 @@ var AgentIdentityClient = class {
|
|
|
3865
4235
|
this.signer = options.signer;
|
|
3866
4236
|
const identityAddr = options.config.contracts?.identityRegistry || ERC8004_SEPOLIA.identityRegistry;
|
|
3867
4237
|
const reputationAddr = options.config.contracts?.reputationRegistry || ERC8004_SEPOLIA.reputationRegistry;
|
|
3868
|
-
this.identityRegistry = new
|
|
3869
|
-
this.reputationRegistry = new
|
|
4238
|
+
this.identityRegistry = new ethers5.Contract(identityAddr, ERC8004_IDENTITY_ABI, this.signer);
|
|
4239
|
+
this.reputationRegistry = new ethers5.Contract(reputationAddr, ERC8004_REPUTATION_ABI, this.signer);
|
|
3870
4240
|
}
|
|
3871
4241
|
// ============ Identity Functions ============
|
|
3872
4242
|
/**
|
|
@@ -3934,7 +4304,7 @@ var AgentIdentityClient = class {
|
|
|
3934
4304
|
async registerWithMetadata(agentURI, metadata) {
|
|
3935
4305
|
const metadataEntries = metadata.map((m) => ({
|
|
3936
4306
|
key: m.key,
|
|
3937
|
-
value:
|
|
4307
|
+
value: ethers5.toUtf8Bytes(m.value)
|
|
3938
4308
|
}));
|
|
3939
4309
|
const tx = await this.identityRegistry["register(string,tuple(string,bytes)[])"](
|
|
3940
4310
|
agentURI,
|
|
@@ -3971,7 +4341,7 @@ var AgentIdentityClient = class {
|
|
|
3971
4341
|
const tx = await this.identityRegistry.setMetadata(
|
|
3972
4342
|
agentId,
|
|
3973
4343
|
key,
|
|
3974
|
-
|
|
4344
|
+
ethers5.toUtf8Bytes(value)
|
|
3975
4345
|
);
|
|
3976
4346
|
const receipt = await tx.wait();
|
|
3977
4347
|
return receipt.hash;
|
|
@@ -3981,7 +4351,7 @@ var AgentIdentityClient = class {
|
|
|
3981
4351
|
*/
|
|
3982
4352
|
async getMetadata(agentId, key) {
|
|
3983
4353
|
const value = await this.identityRegistry.getMetadata(agentId, key);
|
|
3984
|
-
return
|
|
4354
|
+
return ethers5.toUtf8String(value);
|
|
3985
4355
|
}
|
|
3986
4356
|
/**
|
|
3987
4357
|
* Transfer agent to new owner
|
|
@@ -4016,8 +4386,8 @@ var AgentIdentityClient = class {
|
|
|
4016
4386
|
* Give feedback to an agent
|
|
4017
4387
|
*/
|
|
4018
4388
|
async giveFeedback(input) {
|
|
4019
|
-
const feedbackHash =
|
|
4020
|
-
|
|
4389
|
+
const feedbackHash = ethers5.keccak256(
|
|
4390
|
+
ethers5.AbiCoder.defaultAbiCoder().encode(
|
|
4021
4391
|
["uint256", "int128", "uint256"],
|
|
4022
4392
|
[input.agentId, input.value, Date.now()]
|
|
4023
4393
|
)
|
|
@@ -4210,6 +4580,8 @@ export {
|
|
|
4210
4580
|
AGETHER_8004_SCORER_ABI,
|
|
4211
4581
|
AGETHER_8004_VALIDATION_MODULE_ABI,
|
|
4212
4582
|
AGETHER_HOOK_MULTIPLEXER_ABI,
|
|
4583
|
+
AaveClient,
|
|
4584
|
+
AgentAccountClient,
|
|
4213
4585
|
AgentIdentityClient,
|
|
4214
4586
|
AgentNotApprovedError,
|
|
4215
4587
|
AgetherClient,
|