@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.js
CHANGED
|
@@ -36,6 +36,8 @@ __export(index_exports, {
|
|
|
36
36
|
AGETHER_8004_SCORER_ABI: () => AGETHER_8004_SCORER_ABI,
|
|
37
37
|
AGETHER_8004_VALIDATION_MODULE_ABI: () => AGETHER_8004_VALIDATION_MODULE_ABI,
|
|
38
38
|
AGETHER_HOOK_MULTIPLEXER_ABI: () => AGETHER_HOOK_MULTIPLEXER_ABI,
|
|
39
|
+
AaveClient: () => AaveClient,
|
|
40
|
+
AgentAccountClient: () => AgentAccountClient,
|
|
39
41
|
AgentIdentityClient: () => AgentIdentityClient,
|
|
40
42
|
AgentNotApprovedError: () => AgentNotApprovedError,
|
|
41
43
|
AgetherClient: () => AgetherClient,
|
|
@@ -79,13 +81,13 @@ var import_ethers = require("ethers");
|
|
|
79
81
|
var import_axios = __toESM(require("axios"));
|
|
80
82
|
|
|
81
83
|
// src/types/index.ts
|
|
82
|
-
var ChainId = /* @__PURE__ */ ((
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return
|
|
84
|
+
var ChainId = /* @__PURE__ */ ((ChainId4) => {
|
|
85
|
+
ChainId4[ChainId4["Ethereum"] = 1] = "Ethereum";
|
|
86
|
+
ChainId4[ChainId4["Base"] = 8453] = "Base";
|
|
87
|
+
ChainId4[ChainId4["BaseSepolia"] = 84532] = "BaseSepolia";
|
|
88
|
+
ChainId4[ChainId4["Sepolia"] = 11155111] = "Sepolia";
|
|
89
|
+
ChainId4[ChainId4["Hardhat"] = 31337] = "Hardhat";
|
|
90
|
+
return ChainId4;
|
|
89
91
|
})(ChainId || {});
|
|
90
92
|
var AgetherError = class extends Error {
|
|
91
93
|
constructor(message, code, details) {
|
|
@@ -1261,67 +1263,14 @@ var AgetherClient = class _AgetherClient {
|
|
|
1261
1263
|
};
|
|
1262
1264
|
|
|
1263
1265
|
// src/clients/MorphoClient.ts
|
|
1264
|
-
var
|
|
1265
|
-
var import_axios2 = __toESM(require("axios"));
|
|
1266
|
-
|
|
1267
|
-
// src/utils/retry.ts
|
|
1268
|
-
var RETRIABLE_PATTERNS = [
|
|
1269
|
-
"ECONNRESET",
|
|
1270
|
-
"ECONNREFUSED",
|
|
1271
|
-
"ENOTFOUND",
|
|
1272
|
-
"ETIMEDOUT",
|
|
1273
|
-
"fetch failed",
|
|
1274
|
-
"network error",
|
|
1275
|
-
"socket hang up",
|
|
1276
|
-
"rate limit",
|
|
1277
|
-
"429",
|
|
1278
|
-
"502",
|
|
1279
|
-
"503",
|
|
1280
|
-
"504",
|
|
1281
|
-
"timeout"
|
|
1282
|
-
];
|
|
1283
|
-
function isRetriable(error) {
|
|
1284
|
-
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
1285
|
-
return RETRIABLE_PATTERNS.some((p) => msg.includes(p.toLowerCase()));
|
|
1286
|
-
}
|
|
1287
|
-
async function withRetry(fn, options = {}) {
|
|
1288
|
-
const {
|
|
1289
|
-
maxRetries = 3,
|
|
1290
|
-
baseDelay = 1e3,
|
|
1291
|
-
maxDelay = 15e3,
|
|
1292
|
-
onRetry
|
|
1293
|
-
} = options;
|
|
1294
|
-
let lastError;
|
|
1295
|
-
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1296
|
-
try {
|
|
1297
|
-
return await fn();
|
|
1298
|
-
} catch (error) {
|
|
1299
|
-
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1300
|
-
if (attempt >= maxRetries || !isRetriable(error)) {
|
|
1301
|
-
throw lastError;
|
|
1302
|
-
}
|
|
1303
|
-
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
|
|
1304
|
-
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
1305
|
-
onRetry?.(attempt, lastError);
|
|
1306
|
-
await new Promise((resolve) => setTimeout(resolve, jitter));
|
|
1307
|
-
}
|
|
1308
|
-
}
|
|
1309
|
-
throw lastError;
|
|
1310
|
-
}
|
|
1266
|
+
var import_ethers3 = require("ethers");
|
|
1311
1267
|
|
|
1312
|
-
// src/clients/
|
|
1313
|
-
var
|
|
1268
|
+
// src/clients/AgentAccountClient.ts
|
|
1269
|
+
var import_ethers2 = require("ethers");
|
|
1314
1270
|
var MODE_SINGLE2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
|
|
1315
1271
|
var MODE_BATCH = "0x0100000000000000000000000000000000000000000000000000000000000000";
|
|
1316
|
-
var
|
|
1317
|
-
var erc20Iface2 = new import_ethers2.ethers.Interface(ERC20_ABI);
|
|
1318
|
-
var _MorphoClient = class _MorphoClient {
|
|
1272
|
+
var AgentAccountClient = class {
|
|
1319
1273
|
constructor(config) {
|
|
1320
|
-
/** Market params cache: keyed by market uniqueKey (bytes32 hash) */
|
|
1321
|
-
this._marketCache = /* @__PURE__ */ new Map();
|
|
1322
|
-
/** Dynamic token registry: symbol (uppercase) or address (lowercase) → { address, symbol, decimals } */
|
|
1323
|
-
this._tokenCache = /* @__PURE__ */ new Map();
|
|
1324
|
-
this._discoveredAt = 0;
|
|
1325
1274
|
if (!config.agentId) {
|
|
1326
1275
|
throw new AgetherError(
|
|
1327
1276
|
"agentId is required. Use AgetherClient.register() first to get an agentId.",
|
|
@@ -1356,13 +1305,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1356
1305
|
}
|
|
1357
1306
|
const addrs = { ...defaultCfg.contracts, ...config.contracts };
|
|
1358
1307
|
this.agether4337Factory = new import_ethers2.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
1359
|
-
this.morphoBlue = new import_ethers2.Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
1360
1308
|
this.entryPoint = new import_ethers2.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
|
|
1361
1309
|
}
|
|
1362
|
-
//
|
|
1363
|
-
|
|
1364
|
-
// ════════════════════════════════════════════════════════
|
|
1365
|
-
/** Resolve the AgentAccount address (cached, with retry for flaky RPCs). */
|
|
1310
|
+
// ─── Account Management ───────────────────────────────────────────────
|
|
1311
|
+
/** Resolve the AgentAccount (Safe) address. Cached after first call. */
|
|
1366
1312
|
async getAccountAddress() {
|
|
1367
1313
|
if (this._accountAddress) return this._accountAddress;
|
|
1368
1314
|
const MAX_RETRIES = 3;
|
|
@@ -1388,26 +1334,260 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1388
1334
|
getAgentId() {
|
|
1389
1335
|
return this.agentId;
|
|
1390
1336
|
}
|
|
1391
|
-
/**
|
|
1392
|
-
* Get the EOA wallet address (synchronous, best-effort).
|
|
1393
|
-
*
|
|
1394
|
-
* For the `privateKey` path this always works. For the `signer` path
|
|
1395
|
-
* it works if the signer exposes `.address` synchronously (e.g. ethers.Wallet).
|
|
1396
|
-
* If the address has not been resolved yet, throws — call `getSignerAddress()` first.
|
|
1397
|
-
*/
|
|
1337
|
+
/** Get the EOA wallet address (synchronous). */
|
|
1398
1338
|
getWalletAddress() {
|
|
1399
1339
|
if (this._eoaAddress) return this._eoaAddress;
|
|
1400
1340
|
const signer = this._signer;
|
|
1401
1341
|
if (signer.address && typeof signer.address === "string") {
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
return addr;
|
|
1342
|
+
this._eoaAddress = signer.address;
|
|
1343
|
+
return signer.address;
|
|
1405
1344
|
}
|
|
1406
1345
|
throw new AgetherError(
|
|
1407
|
-
"EOA address not
|
|
1408
|
-
"
|
|
1346
|
+
"EOA address not available synchronously. Call getSignerAddress() first.",
|
|
1347
|
+
"NO_EOA_ADDRESS"
|
|
1409
1348
|
);
|
|
1410
1349
|
}
|
|
1350
|
+
/** Get EOA wallet address (async, works for all signer types). */
|
|
1351
|
+
async getSignerAddress() {
|
|
1352
|
+
if (this._eoaAddress) return this._eoaAddress;
|
|
1353
|
+
const addr = await this._signer.getAddress();
|
|
1354
|
+
this._eoaAddress = addr;
|
|
1355
|
+
return addr;
|
|
1356
|
+
}
|
|
1357
|
+
// ─── Safe7579 Execution ───────────────────────────────────────────────
|
|
1358
|
+
/** Pack two uint128 values into a single bytes32. */
|
|
1359
|
+
_packUint128(hi, lo) {
|
|
1360
|
+
return import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(hi << 128n | lo), 32);
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
|
|
1364
|
+
*/
|
|
1365
|
+
async _submitUserOp(callData) {
|
|
1366
|
+
const sender = await this.getAccountAddress();
|
|
1367
|
+
const validatorAddr = this.config.contracts.erc8004ValidationModule;
|
|
1368
|
+
const nonceKey = BigInt(validatorAddr) << 32n;
|
|
1369
|
+
const nonce = await this.entryPoint.getNonce(sender, nonceKey);
|
|
1370
|
+
const feeData = await this.provider.getFeeData();
|
|
1371
|
+
const maxFeePerGas = feeData.maxFeePerGas ?? import_ethers2.ethers.parseUnits("0.5", "gwei");
|
|
1372
|
+
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? import_ethers2.ethers.parseUnits("0.1", "gwei");
|
|
1373
|
+
const verificationGasLimit = 500000n;
|
|
1374
|
+
const callGasLimit = 800000n;
|
|
1375
|
+
const preVerificationGas = 100000n;
|
|
1376
|
+
const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
|
|
1377
|
+
const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
|
|
1378
|
+
const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
|
|
1379
|
+
const accountBalance = await this.provider.getBalance(sender);
|
|
1380
|
+
if (accountBalance < requiredPrefund) {
|
|
1381
|
+
const topUp = requiredPrefund - accountBalance;
|
|
1382
|
+
const topUpWithBuffer = topUp * 120n / 100n;
|
|
1383
|
+
const eoaBalance = await this.provider.getBalance(
|
|
1384
|
+
this._eoaAddress ?? await this._signer.getAddress()
|
|
1385
|
+
);
|
|
1386
|
+
if (eoaBalance < topUpWithBuffer) {
|
|
1387
|
+
const needed = import_ethers2.ethers.formatEther(topUpWithBuffer);
|
|
1388
|
+
throw new AgetherError(
|
|
1389
|
+
`Insufficient ETH for gas. Need ~${needed} ETH in EOA.`,
|
|
1390
|
+
"INSUFFICIENT_GAS"
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
const tx = await this._signer.sendTransaction({ to: sender, value: topUpWithBuffer });
|
|
1394
|
+
await tx.wait();
|
|
1395
|
+
}
|
|
1396
|
+
const packedUserOp = {
|
|
1397
|
+
sender,
|
|
1398
|
+
nonce,
|
|
1399
|
+
initCode: "0x",
|
|
1400
|
+
callData,
|
|
1401
|
+
accountGasLimits,
|
|
1402
|
+
preVerificationGas,
|
|
1403
|
+
gasFees,
|
|
1404
|
+
paymasterAndData: "0x",
|
|
1405
|
+
signature: "0x"
|
|
1406
|
+
};
|
|
1407
|
+
const entryPointAddr = await this.entryPoint.getAddress();
|
|
1408
|
+
const chainId = (await this.provider.getNetwork()).chainId;
|
|
1409
|
+
const userOpHash = import_ethers2.ethers.keccak256(
|
|
1410
|
+
import_ethers2.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
1411
|
+
["bytes32", "address", "uint256"],
|
|
1412
|
+
[
|
|
1413
|
+
import_ethers2.ethers.keccak256(
|
|
1414
|
+
import_ethers2.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
1415
|
+
[
|
|
1416
|
+
"address",
|
|
1417
|
+
"uint256",
|
|
1418
|
+
"bytes32",
|
|
1419
|
+
"bytes32",
|
|
1420
|
+
"bytes32",
|
|
1421
|
+
"uint256",
|
|
1422
|
+
"bytes32",
|
|
1423
|
+
"bytes32"
|
|
1424
|
+
],
|
|
1425
|
+
[
|
|
1426
|
+
packedUserOp.sender,
|
|
1427
|
+
packedUserOp.nonce,
|
|
1428
|
+
import_ethers2.ethers.keccak256(packedUserOp.initCode),
|
|
1429
|
+
import_ethers2.ethers.keccak256(packedUserOp.callData),
|
|
1430
|
+
packedUserOp.accountGasLimits,
|
|
1431
|
+
packedUserOp.preVerificationGas,
|
|
1432
|
+
packedUserOp.gasFees,
|
|
1433
|
+
import_ethers2.ethers.keccak256(packedUserOp.paymasterAndData)
|
|
1434
|
+
]
|
|
1435
|
+
)
|
|
1436
|
+
),
|
|
1437
|
+
entryPointAddr,
|
|
1438
|
+
chainId
|
|
1439
|
+
]
|
|
1440
|
+
)
|
|
1441
|
+
);
|
|
1442
|
+
const signature = await this._signer.signMessage(import_ethers2.ethers.getBytes(userOpHash));
|
|
1443
|
+
packedUserOp.signature = signature;
|
|
1444
|
+
const handleOpsTx = await this.entryPoint.handleOps(
|
|
1445
|
+
[
|
|
1446
|
+
[
|
|
1447
|
+
packedUserOp.sender,
|
|
1448
|
+
packedUserOp.nonce,
|
|
1449
|
+
packedUserOp.initCode,
|
|
1450
|
+
packedUserOp.callData,
|
|
1451
|
+
packedUserOp.accountGasLimits,
|
|
1452
|
+
packedUserOp.preVerificationGas,
|
|
1453
|
+
packedUserOp.gasFees,
|
|
1454
|
+
packedUserOp.paymasterAndData,
|
|
1455
|
+
packedUserOp.signature
|
|
1456
|
+
]
|
|
1457
|
+
],
|
|
1458
|
+
this._eoaAddress ?? await this._signer.getAddress()
|
|
1459
|
+
);
|
|
1460
|
+
const receipt = await handleOpsTx.wait();
|
|
1461
|
+
const epIface = new import_ethers2.ethers.Interface(ENTRYPOINT_V07_ABI);
|
|
1462
|
+
for (const log of receipt.logs) {
|
|
1463
|
+
try {
|
|
1464
|
+
const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
|
|
1465
|
+
if (parsed?.name === "UserOperationEvent") {
|
|
1466
|
+
if (!parsed.args.success) {
|
|
1467
|
+
let revertMsg = "UserOp inner execution reverted";
|
|
1468
|
+
for (const rLog of receipt.logs) {
|
|
1469
|
+
try {
|
|
1470
|
+
const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
|
|
1471
|
+
if (rParsed?.name === "UserOperationRevertReason") {
|
|
1472
|
+
const reason = rParsed.args.revertReason;
|
|
1473
|
+
try {
|
|
1474
|
+
if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
|
|
1475
|
+
const decoded = import_ethers2.ethers.AbiCoder.defaultAbiCoder().decode(["string"], "0x" + reason.slice(10));
|
|
1476
|
+
revertMsg = `UserOp reverted: ${decoded[0]}`;
|
|
1477
|
+
} else {
|
|
1478
|
+
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
1479
|
+
}
|
|
1480
|
+
} catch {
|
|
1481
|
+
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
1482
|
+
}
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1485
|
+
} catch {
|
|
1486
|
+
continue;
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
|
|
1490
|
+
}
|
|
1491
|
+
}
|
|
1492
|
+
} catch (e) {
|
|
1493
|
+
if (e instanceof AgetherError) throw e;
|
|
1494
|
+
continue;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return receipt;
|
|
1498
|
+
}
|
|
1499
|
+
/**
|
|
1500
|
+
* Execute a single call via Safe7579 account through ERC-4337 UserOp.
|
|
1501
|
+
*/
|
|
1502
|
+
async executeSingle(target, data, value = 0n) {
|
|
1503
|
+
const valueHex = import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(value), 32);
|
|
1504
|
+
const executionCalldata = import_ethers2.ethers.concat([target, valueHex, data]);
|
|
1505
|
+
const safe7579Iface = new import_ethers2.ethers.Interface(SAFE7579_ACCOUNT_ABI);
|
|
1506
|
+
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
|
|
1507
|
+
return this._submitUserOp(callData);
|
|
1508
|
+
}
|
|
1509
|
+
/**
|
|
1510
|
+
* Execute multiple calls via Safe7579 account in one atomic batch.
|
|
1511
|
+
*/
|
|
1512
|
+
async executeBatch(targets, values, datas) {
|
|
1513
|
+
const executions = targets.map((t, i) => [t, values[i], datas[i]]);
|
|
1514
|
+
const executionCalldata = import_ethers2.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
1515
|
+
["(address,uint256,bytes)[]"],
|
|
1516
|
+
[executions]
|
|
1517
|
+
);
|
|
1518
|
+
const safe7579Iface = new import_ethers2.ethers.Interface(SAFE7579_ACCOUNT_ABI);
|
|
1519
|
+
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_BATCH, executionCalldata]);
|
|
1520
|
+
return this._submitUserOp(callData);
|
|
1521
|
+
}
|
|
1522
|
+
};
|
|
1523
|
+
|
|
1524
|
+
// src/clients/MorphoClient.ts
|
|
1525
|
+
var import_axios2 = __toESM(require("axios"));
|
|
1526
|
+
|
|
1527
|
+
// src/utils/retry.ts
|
|
1528
|
+
var RETRIABLE_PATTERNS = [
|
|
1529
|
+
"ECONNRESET",
|
|
1530
|
+
"ECONNREFUSED",
|
|
1531
|
+
"ENOTFOUND",
|
|
1532
|
+
"ETIMEDOUT",
|
|
1533
|
+
"fetch failed",
|
|
1534
|
+
"network error",
|
|
1535
|
+
"socket hang up",
|
|
1536
|
+
"rate limit",
|
|
1537
|
+
"429",
|
|
1538
|
+
"502",
|
|
1539
|
+
"503",
|
|
1540
|
+
"504",
|
|
1541
|
+
"timeout"
|
|
1542
|
+
];
|
|
1543
|
+
function isRetriable(error) {
|
|
1544
|
+
const msg = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
|
|
1545
|
+
return RETRIABLE_PATTERNS.some((p) => msg.includes(p.toLowerCase()));
|
|
1546
|
+
}
|
|
1547
|
+
async function withRetry(fn, options = {}) {
|
|
1548
|
+
const {
|
|
1549
|
+
maxRetries = 3,
|
|
1550
|
+
baseDelay = 1e3,
|
|
1551
|
+
maxDelay = 15e3,
|
|
1552
|
+
onRetry
|
|
1553
|
+
} = options;
|
|
1554
|
+
let lastError;
|
|
1555
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
1556
|
+
try {
|
|
1557
|
+
return await fn();
|
|
1558
|
+
} catch (error) {
|
|
1559
|
+
lastError = error instanceof Error ? error : new Error(String(error));
|
|
1560
|
+
if (attempt >= maxRetries || !isRetriable(error)) {
|
|
1561
|
+
throw lastError;
|
|
1562
|
+
}
|
|
1563
|
+
const delay = Math.min(baseDelay * Math.pow(2, attempt - 1), maxDelay);
|
|
1564
|
+
const jitter = delay * (0.5 + Math.random() * 0.5);
|
|
1565
|
+
onRetry?.(attempt, lastError);
|
|
1566
|
+
await new Promise((resolve) => setTimeout(resolve, jitter));
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
throw lastError;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
// src/clients/MorphoClient.ts
|
|
1573
|
+
var MORPHO_API_URL2 = "https://api.morpho.org/graphql";
|
|
1574
|
+
var morphoIface = new import_ethers3.ethers.Interface(MORPHO_BLUE_ABI);
|
|
1575
|
+
var erc20Iface2 = new import_ethers3.ethers.Interface(ERC20_ABI);
|
|
1576
|
+
var _MorphoClient = class _MorphoClient extends AgentAccountClient {
|
|
1577
|
+
constructor(config) {
|
|
1578
|
+
super(config);
|
|
1579
|
+
// Cached state
|
|
1580
|
+
/** Market params cache: keyed by market uniqueKey (bytes32 hash) */
|
|
1581
|
+
this._marketCache = /* @__PURE__ */ new Map();
|
|
1582
|
+
/** Dynamic token registry: symbol (uppercase) or address (lowercase) → { address, symbol, decimals } */
|
|
1583
|
+
this._tokenCache = /* @__PURE__ */ new Map();
|
|
1584
|
+
this._discoveredAt = 0;
|
|
1585
|
+
const addrs = { ...this.config.contracts, ...config.contracts };
|
|
1586
|
+
this.morphoBlue = new import_ethers3.Contract(addrs.morphoBlue, MORPHO_BLUE_ABI, this.provider);
|
|
1587
|
+
}
|
|
1588
|
+
// ════════════════════════════════════════════════════════
|
|
1589
|
+
// Account Management
|
|
1590
|
+
// ════════════════════════════════════════════════════════
|
|
1411
1591
|
/**
|
|
1412
1592
|
* Resolve the EOA signer address (async, works with all signer types).
|
|
1413
1593
|
* Result is cached after the first call.
|
|
@@ -1464,7 +1644,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1464
1644
|
this._discoveredMarkets = items.map((m) => ({
|
|
1465
1645
|
uniqueKey: m.uniqueKey,
|
|
1466
1646
|
loanAsset: m.loanAsset,
|
|
1467
|
-
collateralAsset: m.collateralAsset ?? { address:
|
|
1647
|
+
collateralAsset: m.collateralAsset ?? { address: import_ethers3.ethers.ZeroAddress, symbol: "N/A", decimals: 0 },
|
|
1468
1648
|
oracle: m.oracleAddress,
|
|
1469
1649
|
irm: m.irmAddress,
|
|
1470
1650
|
lltv: BigInt(m.lltv),
|
|
@@ -1481,7 +1661,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1481
1661
|
irm: mi.irm,
|
|
1482
1662
|
lltv: mi.lltv
|
|
1483
1663
|
});
|
|
1484
|
-
if (mi.collateralAsset.address !==
|
|
1664
|
+
if (mi.collateralAsset.address !== import_ethers3.ethers.ZeroAddress) {
|
|
1485
1665
|
this._tokenCache.set(mi.collateralAsset.symbol.toUpperCase(), {
|
|
1486
1666
|
address: mi.collateralAsset.address,
|
|
1487
1667
|
symbol: mi.collateralAsset.symbol,
|
|
@@ -1493,7 +1673,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1493
1673
|
decimals: mi.collateralAsset.decimals
|
|
1494
1674
|
});
|
|
1495
1675
|
}
|
|
1496
|
-
if (mi.loanAsset.address !==
|
|
1676
|
+
if (mi.loanAsset.address !== import_ethers3.ethers.ZeroAddress) {
|
|
1497
1677
|
this._tokenCache.set(mi.loanAsset.symbol.toUpperCase(), {
|
|
1498
1678
|
address: mi.loanAsset.address,
|
|
1499
1679
|
symbol: mi.loanAsset.symbol,
|
|
@@ -1663,7 +1843,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1663
1843
|
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
1664
1844
|
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
1665
1845
|
debt = totalBorrowShares > 0n ? (borrowShares * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1666
|
-
totalDebtFloat += parseFloat(
|
|
1846
|
+
totalDebtFloat += parseFloat(import_ethers3.ethers.formatUnits(debt, loanDecimals));
|
|
1667
1847
|
} catch (e) {
|
|
1668
1848
|
console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
|
|
1669
1849
|
}
|
|
@@ -1672,17 +1852,17 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1672
1852
|
marketId: m.uniqueKey,
|
|
1673
1853
|
collateralToken: m.collateralAsset.symbol,
|
|
1674
1854
|
loanToken: m.loanAsset.symbol,
|
|
1675
|
-
collateral:
|
|
1855
|
+
collateral: import_ethers3.ethers.formatUnits(collateral, m.collateralAsset.decimals),
|
|
1676
1856
|
borrowShares: borrowShares.toString(),
|
|
1677
1857
|
supplyShares: supplyShares.toString(),
|
|
1678
|
-
debt:
|
|
1858
|
+
debt: import_ethers3.ethers.formatUnits(debt, loanDecimals)
|
|
1679
1859
|
});
|
|
1680
1860
|
}
|
|
1681
1861
|
} catch (e) {
|
|
1682
1862
|
console.warn("[agether] marketPositions API failed, falling back to market scan:", e instanceof Error ? e.message : e);
|
|
1683
1863
|
const markets = await this.getMarkets();
|
|
1684
1864
|
for (const m of markets) {
|
|
1685
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
1865
|
+
if (!m.collateralAsset || m.collateralAsset.address === import_ethers3.ethers.ZeroAddress) continue;
|
|
1686
1866
|
try {
|
|
1687
1867
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
1688
1868
|
if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
|
|
@@ -1694,7 +1874,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1694
1874
|
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
1695
1875
|
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
1696
1876
|
debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1697
|
-
totalDebtFloat += parseFloat(
|
|
1877
|
+
totalDebtFloat += parseFloat(import_ethers3.ethers.formatUnits(debt, loanDecimals));
|
|
1698
1878
|
} catch (e2) {
|
|
1699
1879
|
console.warn(`[agether] debt calc failed:`, e2 instanceof Error ? e2.message : e2);
|
|
1700
1880
|
}
|
|
@@ -1703,10 +1883,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1703
1883
|
marketId: m.uniqueKey,
|
|
1704
1884
|
collateralToken: m.collateralAsset.symbol,
|
|
1705
1885
|
loanToken: m.loanAsset.symbol,
|
|
1706
|
-
collateral:
|
|
1886
|
+
collateral: import_ethers3.ethers.formatUnits(pos.collateral, m.collateralAsset.decimals),
|
|
1707
1887
|
borrowShares: pos.borrowShares.toString(),
|
|
1708
1888
|
supplyShares: pos.supplyShares.toString(),
|
|
1709
|
-
debt:
|
|
1889
|
+
debt: import_ethers3.ethers.formatUnits(debt, loanDecimals)
|
|
1710
1890
|
});
|
|
1711
1891
|
} catch (e2) {
|
|
1712
1892
|
console.warn(`[agether] position read failed:`, e2 instanceof Error ? e2.message : e2);
|
|
@@ -1732,7 +1912,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1732
1912
|
async getTokenBalance(symbolOrAddress) {
|
|
1733
1913
|
const acctAddr = await this.getAccountAddress();
|
|
1734
1914
|
const tokenInfo = await this._resolveToken(symbolOrAddress);
|
|
1735
|
-
const token = new
|
|
1915
|
+
const token = new import_ethers3.Contract(tokenInfo.address, ERC20_ABI, this.provider);
|
|
1736
1916
|
return token.balanceOf(acctAddr);
|
|
1737
1917
|
}
|
|
1738
1918
|
/**
|
|
@@ -1742,7 +1922,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1742
1922
|
*/
|
|
1743
1923
|
async getUsdcBalance() {
|
|
1744
1924
|
const acctAddr = await this.getAccountAddress();
|
|
1745
|
-
const usdc = new
|
|
1925
|
+
const usdc = new import_ethers3.Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
1746
1926
|
return usdc.balanceOf(acctAddr);
|
|
1747
1927
|
}
|
|
1748
1928
|
/**
|
|
@@ -1762,7 +1942,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1762
1942
|
let totalAdditional = 0n;
|
|
1763
1943
|
const byMarket = [];
|
|
1764
1944
|
for (const m of markets) {
|
|
1765
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
1945
|
+
if (!m.collateralAsset || m.collateralAsset.address === import_ethers3.ethers.ZeroAddress) continue;
|
|
1766
1946
|
try {
|
|
1767
1947
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
1768
1948
|
if (pos.collateral === 0n) continue;
|
|
@@ -1772,7 +1952,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1772
1952
|
const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1773
1953
|
let collateralValueInLoan;
|
|
1774
1954
|
try {
|
|
1775
|
-
const oracleContract = new
|
|
1955
|
+
const oracleContract = new import_ethers3.Contract(m.oracle, [
|
|
1776
1956
|
"function price() view returns (uint256)"
|
|
1777
1957
|
], this.provider);
|
|
1778
1958
|
const oraclePrice = await oracleContract.price();
|
|
@@ -1878,7 +2058,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1878
2058
|
const sym = loanTokenSymbolOrAddress.toUpperCase();
|
|
1879
2059
|
items = items.filter((m) => m.loanAsset?.symbol?.toUpperCase() === sym);
|
|
1880
2060
|
}
|
|
1881
|
-
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !==
|
|
2061
|
+
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers3.ethers.ZeroAddress).map((m) => {
|
|
1882
2062
|
const loanDecimals = m.loanAsset?.decimals ?? 18;
|
|
1883
2063
|
return {
|
|
1884
2064
|
collateralToken: m.collateralAsset.symbol,
|
|
@@ -1939,7 +2119,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1939
2119
|
{ maxRetries: 3, onRetry: (n, e) => console.warn(`[agether] Morpho API retry ${n}:`, e.message) }
|
|
1940
2120
|
);
|
|
1941
2121
|
let items = resp.data?.data?.markets?.items ?? [];
|
|
1942
|
-
items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !==
|
|
2122
|
+
items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers3.ethers.ZeroAddress);
|
|
1943
2123
|
const searchUpper = search.toUpperCase();
|
|
1944
2124
|
if (options?.asCollateral) {
|
|
1945
2125
|
items = items.filter((m) => m.collateralAsset?.symbol?.toUpperCase() === searchUpper);
|
|
@@ -1995,10 +2175,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
1995
2175
|
if (ethBalance > 0n) {
|
|
1996
2176
|
results.push({
|
|
1997
2177
|
symbol: "ETH",
|
|
1998
|
-
address:
|
|
2178
|
+
address: import_ethers3.ethers.ZeroAddress,
|
|
1999
2179
|
decimals: 18,
|
|
2000
2180
|
balance: ethBalance,
|
|
2001
|
-
balanceFormatted:
|
|
2181
|
+
balanceFormatted: import_ethers3.ethers.formatEther(ethBalance)
|
|
2002
2182
|
});
|
|
2003
2183
|
}
|
|
2004
2184
|
} catch {
|
|
@@ -2009,7 +2189,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2009
2189
|
const batch = tokenEntries.slice(i, i + batchSize);
|
|
2010
2190
|
const checks = batch.map(async (info) => {
|
|
2011
2191
|
try {
|
|
2012
|
-
const token = new
|
|
2192
|
+
const token = new import_ethers3.Contract(info.address, ERC20_ABI, this.provider);
|
|
2013
2193
|
const balance = await token.balanceOf(acctAddr);
|
|
2014
2194
|
if (balance > 0n) {
|
|
2015
2195
|
return {
|
|
@@ -2017,7 +2197,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2017
2197
|
address: info.address,
|
|
2018
2198
|
decimals: info.decimals,
|
|
2019
2199
|
balance,
|
|
2020
|
-
balanceFormatted:
|
|
2200
|
+
balanceFormatted: import_ethers3.ethers.formatUnits(balance, info.decimals)
|
|
2021
2201
|
};
|
|
2022
2202
|
}
|
|
2023
2203
|
} catch {
|
|
@@ -2049,7 +2229,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2049
2229
|
try {
|
|
2050
2230
|
const balance = await this.getTokenBalance(collateralSymbol);
|
|
2051
2231
|
const info = await this._resolveToken(collateralSymbol);
|
|
2052
|
-
tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted:
|
|
2232
|
+
tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted: import_ethers3.ethers.formatUnits(balance, info.decimals) }];
|
|
2053
2233
|
} catch {
|
|
2054
2234
|
}
|
|
2055
2235
|
} else {
|
|
@@ -2129,12 +2309,12 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2129
2309
|
try {
|
|
2130
2310
|
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
2131
2311
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2132
|
-
const oracleContract = new
|
|
2312
|
+
const oracleContract = new import_ethers3.Contract(params.oracle, [
|
|
2133
2313
|
"function price() view returns (uint256)"
|
|
2134
2314
|
], this.provider);
|
|
2135
2315
|
const oraclePrice = await oracleContract.price();
|
|
2136
2316
|
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
2137
|
-
const amountWei =
|
|
2317
|
+
const amountWei = import_ethers3.ethers.parseUnits(amount, colInfo.decimals);
|
|
2138
2318
|
const valueInLoan = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
|
|
2139
2319
|
collateralValueUsd = Number(valueInLoan) / 10 ** loanDecimals;
|
|
2140
2320
|
} catch (e) {
|
|
@@ -2185,14 +2365,14 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2185
2365
|
}
|
|
2186
2366
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2187
2367
|
const loanTokenAddr = params.loanToken;
|
|
2188
|
-
const parsedAmount =
|
|
2189
|
-
const marketId =
|
|
2190
|
-
|
|
2368
|
+
const parsedAmount = import_ethers3.ethers.parseUnits(amount, loanDecimals);
|
|
2369
|
+
const marketId = import_ethers3.ethers.keccak256(
|
|
2370
|
+
import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
2191
2371
|
["address", "address", "address", "address", "uint256"],
|
|
2192
2372
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2193
2373
|
)
|
|
2194
2374
|
);
|
|
2195
|
-
const loanContract = new
|
|
2375
|
+
const loanContract = new import_ethers3.Contract(loanTokenAddr, ERC20_ABI, this._signer);
|
|
2196
2376
|
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2197
2377
|
if (acctBalance < parsedAmount) {
|
|
2198
2378
|
const shortfall = parsedAmount - acctBalance;
|
|
@@ -2201,7 +2381,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2201
2381
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2202
2382
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2203
2383
|
throw new AgetherError(
|
|
2204
|
-
`Insufficient ${loanSymbol}. Need ${amount}, AgentAccount has ${
|
|
2384
|
+
`Insufficient ${loanSymbol}. Need ${amount}, AgentAccount has ${import_ethers3.ethers.formatUnits(acctBalance, loanDecimals)}, EOA has ${import_ethers3.ethers.formatUnits(eoaBalance, loanDecimals)}.`,
|
|
2205
2385
|
"INSUFFICIENT_BALANCE"
|
|
2206
2386
|
);
|
|
2207
2387
|
}
|
|
@@ -2221,7 +2401,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2221
2401
|
"0x"
|
|
2222
2402
|
])
|
|
2223
2403
|
];
|
|
2224
|
-
const receipt = await this.
|
|
2404
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2225
2405
|
return {
|
|
2226
2406
|
tx: receipt.hash,
|
|
2227
2407
|
amount,
|
|
@@ -2257,8 +2437,8 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2257
2437
|
params = p;
|
|
2258
2438
|
}
|
|
2259
2439
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2260
|
-
const marketId =
|
|
2261
|
-
|
|
2440
|
+
const marketId = import_ethers3.ethers.keccak256(
|
|
2441
|
+
import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
2262
2442
|
["address", "address", "address", "address", "uint256"],
|
|
2263
2443
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2264
2444
|
)
|
|
@@ -2271,7 +2451,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2271
2451
|
withdrawAssets = 0n;
|
|
2272
2452
|
if (withdrawShares === 0n) throw new AgetherError("No supply position to withdraw", "NO_SUPPLY");
|
|
2273
2453
|
} else {
|
|
2274
|
-
withdrawAssets =
|
|
2454
|
+
withdrawAssets = import_ethers3.ethers.parseUnits(amount, loanDecimals);
|
|
2275
2455
|
withdrawShares = 0n;
|
|
2276
2456
|
}
|
|
2277
2457
|
const data = morphoIface.encodeFunctionData("withdraw", [
|
|
@@ -2281,7 +2461,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2281
2461
|
acctAddr,
|
|
2282
2462
|
dest
|
|
2283
2463
|
]);
|
|
2284
|
-
const receipt = await this.
|
|
2464
|
+
const receipt = await this.executeSingle(morphoAddr, data);
|
|
2285
2465
|
let remainingSupply = "0";
|
|
2286
2466
|
try {
|
|
2287
2467
|
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
@@ -2289,7 +2469,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2289
2469
|
const totalSupplyAssets = BigInt(mkt.totalSupplyAssets);
|
|
2290
2470
|
const totalSupplyShares = BigInt(mkt.totalSupplyShares);
|
|
2291
2471
|
const currentAssets = totalSupplyShares > 0n ? BigInt(pos.supplyShares) * totalSupplyAssets / totalSupplyShares : 0n;
|
|
2292
|
-
remainingSupply =
|
|
2472
|
+
remainingSupply = import_ethers3.ethers.formatUnits(currentAssets, loanDecimals);
|
|
2293
2473
|
} catch (e) {
|
|
2294
2474
|
console.warn("[agether] failed to read remaining supply:", e instanceof Error ? e.message : e);
|
|
2295
2475
|
}
|
|
@@ -2354,9 +2534,9 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2354
2534
|
loanToken: p.market.loanAsset.symbol,
|
|
2355
2535
|
collateralToken: p.market.collateralAsset?.symbol ?? "none",
|
|
2356
2536
|
supplyShares: p.state.supplyShares,
|
|
2357
|
-
suppliedAssets:
|
|
2358
|
-
netDeposited:
|
|
2359
|
-
earnedYield:
|
|
2537
|
+
suppliedAssets: import_ethers3.ethers.formatUnits(currentAssets, p.market.loanAsset.decimals),
|
|
2538
|
+
netDeposited: import_ethers3.ethers.formatUnits(netDeposited, p.market.loanAsset.decimals),
|
|
2539
|
+
earnedYield: import_ethers3.ethers.formatUnits(earnedYield, p.market.loanAsset.decimals),
|
|
2360
2540
|
supplyApy: p.market.state?.supplyApy ?? 0
|
|
2361
2541
|
});
|
|
2362
2542
|
}
|
|
@@ -2384,8 +2564,8 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2384
2564
|
);
|
|
2385
2565
|
const params = await this.findMarketForCollateral(pos.collateralToken, pos.loanToken);
|
|
2386
2566
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2387
|
-
const parsedAmount =
|
|
2388
|
-
const availableYield =
|
|
2567
|
+
const parsedAmount = import_ethers3.ethers.parseUnits(amount, loanDecimals);
|
|
2568
|
+
const availableYield = import_ethers3.ethers.parseUnits(pos.earnedYield, loanDecimals);
|
|
2389
2569
|
if (parsedAmount > availableYield) {
|
|
2390
2570
|
const loanSymbol = pos.loanToken;
|
|
2391
2571
|
throw new AgetherError(
|
|
@@ -2400,7 +2580,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2400
2580
|
acctAddr,
|
|
2401
2581
|
recipient
|
|
2402
2582
|
]);
|
|
2403
|
-
const receipt = await this.
|
|
2583
|
+
const receipt = await this.executeSingle(morphoAddr, data);
|
|
2404
2584
|
let remainingYield = "0";
|
|
2405
2585
|
let remainingSupply = "0";
|
|
2406
2586
|
try {
|
|
@@ -2435,16 +2615,16 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2435
2615
|
const acctAddr = await this.getAccountAddress();
|
|
2436
2616
|
const colInfo = await this._resolveToken(tokenSymbol);
|
|
2437
2617
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
2438
|
-
const weiAmount =
|
|
2618
|
+
const weiAmount = import_ethers3.ethers.parseUnits(amount, colInfo.decimals);
|
|
2439
2619
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
2440
|
-
const colToken = new
|
|
2620
|
+
const colToken = new import_ethers3.Contract(colInfo.address, ERC20_ABI, this._signer);
|
|
2441
2621
|
const acctBalance = await colToken.balanceOf(acctAddr);
|
|
2442
2622
|
if (acctBalance < weiAmount) {
|
|
2443
2623
|
const shortfall = weiAmount - acctBalance;
|
|
2444
2624
|
const eoaBalance = await colToken.balanceOf(await this.getSignerAddress());
|
|
2445
2625
|
if (eoaBalance < shortfall) {
|
|
2446
2626
|
throw new AgetherError(
|
|
2447
|
-
`Insufficient ${tokenSymbol}. Need ${amount}, AgentAccount has ${
|
|
2627
|
+
`Insufficient ${tokenSymbol}. Need ${amount}, AgentAccount has ${import_ethers3.ethers.formatUnits(acctBalance, colInfo.decimals)}, EOA has ${import_ethers3.ethers.formatUnits(eoaBalance, colInfo.decimals)}.`,
|
|
2448
2628
|
"INSUFFICIENT_BALANCE"
|
|
2449
2629
|
);
|
|
2450
2630
|
}
|
|
@@ -2463,7 +2643,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2463
2643
|
"0x"
|
|
2464
2644
|
])
|
|
2465
2645
|
];
|
|
2466
|
-
const receipt = await this.
|
|
2646
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2467
2647
|
return {
|
|
2468
2648
|
tx: receipt.hash,
|
|
2469
2649
|
collateralToken: tokenSymbol,
|
|
@@ -2496,10 +2676,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2496
2676
|
usedToken = symbol;
|
|
2497
2677
|
}
|
|
2498
2678
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2499
|
-
const parsedAmount =
|
|
2679
|
+
const parsedAmount = import_ethers3.ethers.parseUnits(amount, loanDecimals);
|
|
2500
2680
|
try {
|
|
2501
|
-
const marketId =
|
|
2502
|
-
|
|
2681
|
+
const marketId = import_ethers3.ethers.keccak256(
|
|
2682
|
+
import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
2503
2683
|
["address", "address", "address", "address", "uint256"],
|
|
2504
2684
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2505
2685
|
)
|
|
@@ -2511,7 +2691,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2511
2691
|
"NO_COLLATERAL"
|
|
2512
2692
|
);
|
|
2513
2693
|
}
|
|
2514
|
-
const oracleContract = new
|
|
2694
|
+
const oracleContract = new import_ethers3.Contract(params.oracle, ["function price() view returns (uint256)"], this.provider);
|
|
2515
2695
|
const oraclePrice = await oracleContract.price();
|
|
2516
2696
|
const collateralValueInLoan = BigInt(pos.collateral) * oraclePrice / 10n ** 36n;
|
|
2517
2697
|
const maxBorrowTotal = collateralValueInLoan * params.lltv / 10n ** 18n;
|
|
@@ -2524,8 +2704,8 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2524
2704
|
const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
2525
2705
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2526
2706
|
const colInfo = await this._resolveToken(usedToken);
|
|
2527
|
-
const maxFormatted =
|
|
2528
|
-
const colFormatted =
|
|
2707
|
+
const maxFormatted = import_ethers3.ethers.formatUnits(maxAdditional, loanDecimals);
|
|
2708
|
+
const colFormatted = import_ethers3.ethers.formatUnits(pos.collateral, colInfo.decimals);
|
|
2529
2709
|
throw new AgetherError(
|
|
2530
2710
|
`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.`,
|
|
2531
2711
|
"EXCEEDS_MAX_LTV"
|
|
@@ -2542,7 +2722,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2542
2722
|
acctAddr,
|
|
2543
2723
|
acctAddr
|
|
2544
2724
|
]);
|
|
2545
|
-
const receipt = await this.
|
|
2725
|
+
const receipt = await this.executeSingle(morphoAddr, data);
|
|
2546
2726
|
return {
|
|
2547
2727
|
tx: receipt.hash,
|
|
2548
2728
|
amount,
|
|
@@ -2572,19 +2752,19 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2572
2752
|
const colInfo = await this._resolveToken(tokenSymbol);
|
|
2573
2753
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
2574
2754
|
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
2575
|
-
const colWei =
|
|
2576
|
-
const borrowWei =
|
|
2755
|
+
const colWei = import_ethers3.ethers.parseUnits(collateralAmount, colInfo.decimals);
|
|
2756
|
+
const borrowWei = import_ethers3.ethers.parseUnits(borrowAmount, loanDecimals);
|
|
2577
2757
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
2578
2758
|
try {
|
|
2579
|
-
const marketId =
|
|
2580
|
-
|
|
2759
|
+
const marketId = import_ethers3.ethers.keccak256(
|
|
2760
|
+
import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
2581
2761
|
["address", "address", "address", "address", "uint256"],
|
|
2582
2762
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2583
2763
|
)
|
|
2584
2764
|
);
|
|
2585
2765
|
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
2586
2766
|
const totalCollateral = BigInt(pos.collateral) + colWei;
|
|
2587
|
-
const oracleContract = new
|
|
2767
|
+
const oracleContract = new import_ethers3.Contract(params.oracle, ["function price() view returns (uint256)"], this.provider);
|
|
2588
2768
|
const oraclePrice = await oracleContract.price();
|
|
2589
2769
|
const collateralValueInLoan = totalCollateral * oraclePrice / 10n ** 36n;
|
|
2590
2770
|
const maxBorrowTotal = collateralValueInLoan * params.lltv / 10n ** 18n;
|
|
@@ -2596,9 +2776,9 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2596
2776
|
if (borrowWei > maxAdditional) {
|
|
2597
2777
|
const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
2598
2778
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2599
|
-
const maxFormatted =
|
|
2779
|
+
const maxFormatted = import_ethers3.ethers.formatUnits(maxAdditional, loanDecimals);
|
|
2600
2780
|
throw new AgetherError(
|
|
2601
|
-
`Borrow of ${borrowAmount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (total collateral: ${
|
|
2781
|
+
`Borrow of ${borrowAmount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (total collateral: ${import_ethers3.ethers.formatUnits(totalCollateral, colInfo.decimals)} ${tokenSymbol}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Reduce borrow or increase collateral.`,
|
|
2602
2782
|
"EXCEEDS_MAX_LTV"
|
|
2603
2783
|
);
|
|
2604
2784
|
}
|
|
@@ -2606,14 +2786,14 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2606
2786
|
if (e instanceof AgetherError) throw e;
|
|
2607
2787
|
console.warn("[agether] depositAndBorrow pre-check failed (proceeding anyway):", e instanceof Error ? e.message : e);
|
|
2608
2788
|
}
|
|
2609
|
-
const colToken = new
|
|
2789
|
+
const colToken = new import_ethers3.Contract(colInfo.address, ERC20_ABI, this._signer);
|
|
2610
2790
|
const acctBalance = await colToken.balanceOf(acctAddr);
|
|
2611
2791
|
if (acctBalance < colWei) {
|
|
2612
2792
|
const shortfall = colWei - acctBalance;
|
|
2613
2793
|
const eoaBalance = await colToken.balanceOf(await this.getSignerAddress());
|
|
2614
2794
|
if (eoaBalance < shortfall) {
|
|
2615
2795
|
throw new AgetherError(
|
|
2616
|
-
`Insufficient ${tokenSymbol}. Need ${collateralAmount}, AgentAccount has ${
|
|
2796
|
+
`Insufficient ${tokenSymbol}. Need ${collateralAmount}, AgentAccount has ${import_ethers3.ethers.formatUnits(acctBalance, colInfo.decimals)}, EOA has ${import_ethers3.ethers.formatUnits(eoaBalance, colInfo.decimals)}.`,
|
|
2617
2797
|
"INSUFFICIENT_BALANCE"
|
|
2618
2798
|
);
|
|
2619
2799
|
}
|
|
@@ -2639,7 +2819,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2639
2819
|
acctAddr
|
|
2640
2820
|
])
|
|
2641
2821
|
];
|
|
2642
|
-
const receipt = await this.
|
|
2822
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2643
2823
|
return {
|
|
2644
2824
|
tx: receipt.hash,
|
|
2645
2825
|
collateralToken: tokenSymbol,
|
|
@@ -2689,9 +2869,9 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2689
2869
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2690
2870
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2691
2871
|
const estimated = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
2692
|
-
approveAmount = estimated > 0n ? estimated :
|
|
2872
|
+
approveAmount = estimated > 0n ? estimated : import_ethers3.ethers.parseUnits("1", loanDecimals);
|
|
2693
2873
|
} else {
|
|
2694
|
-
const marketId =
|
|
2874
|
+
const marketId = import_ethers3.ethers.keccak256(import_ethers3.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
2695
2875
|
["address", "address", "address", "address", "uint256"],
|
|
2696
2876
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
2697
2877
|
));
|
|
@@ -2701,14 +2881,14 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2701
2881
|
const onChainMkt = await this.morphoBlue.market(marketId);
|
|
2702
2882
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2703
2883
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2704
|
-
approveAmount = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n :
|
|
2884
|
+
approveAmount = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : import_ethers3.ethers.parseUnits("1", loanDecimals);
|
|
2705
2885
|
}
|
|
2706
2886
|
} else {
|
|
2707
|
-
repayAssets =
|
|
2887
|
+
repayAssets = import_ethers3.ethers.parseUnits(amount, loanDecimals);
|
|
2708
2888
|
repayShares = 0n;
|
|
2709
2889
|
approveAmount = repayAssets;
|
|
2710
2890
|
}
|
|
2711
|
-
const loanContract = new
|
|
2891
|
+
const loanContract = new import_ethers3.Contract(loanTokenAddr, ERC20_ABI, this._signer);
|
|
2712
2892
|
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2713
2893
|
const checkAmount = repayShares > 0n && repayAssets === 0n ? approveAmount * 1005n / 1000n : approveAmount;
|
|
2714
2894
|
if (acctBalance < checkAmount) {
|
|
@@ -2727,7 +2907,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2727
2907
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2728
2908
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2729
2909
|
throw new AgetherError(
|
|
2730
|
-
`Insufficient ${loanSymbol} for repay. Need ~${
|
|
2910
|
+
`Insufficient ${loanSymbol} for repay. Need ~${import_ethers3.ethers.formatUnits(checkAmount, loanDecimals)}, AgentAccount has ${import_ethers3.ethers.formatUnits(acctBalance, loanDecimals)}, EOA has ${import_ethers3.ethers.formatUnits(eoaBalance, loanDecimals)}.`,
|
|
2731
2911
|
"INSUFFICIENT_BALANCE"
|
|
2732
2912
|
);
|
|
2733
2913
|
}
|
|
@@ -2749,7 +2929,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2749
2929
|
"0x"
|
|
2750
2930
|
])
|
|
2751
2931
|
];
|
|
2752
|
-
const receipt = await this.
|
|
2932
|
+
const receipt = await this.executeBatch(targets, values, datas);
|
|
2753
2933
|
let remainingDebt = "0";
|
|
2754
2934
|
try {
|
|
2755
2935
|
const markets = await this.getMarkets(true);
|
|
@@ -2764,7 +2944,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2764
2944
|
const totalAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2765
2945
|
const totalShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2766
2946
|
const debtWei = totalShares > 0n ? shares * totalAssets / totalShares : 0n;
|
|
2767
|
-
remainingDebt =
|
|
2947
|
+
remainingDebt = import_ethers3.ethers.formatUnits(debtWei, loanDecimals);
|
|
2768
2948
|
}
|
|
2769
2949
|
}
|
|
2770
2950
|
} catch (e) {
|
|
@@ -2906,7 +3086,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2906
3086
|
weiAmount = pos.collateral;
|
|
2907
3087
|
if (weiAmount === 0n) throw new AgetherError("No collateral to withdraw", "NO_COLLATERAL");
|
|
2908
3088
|
} else {
|
|
2909
|
-
weiAmount =
|
|
3089
|
+
weiAmount = import_ethers3.ethers.parseUnits(amount, colInfo.decimals);
|
|
2910
3090
|
}
|
|
2911
3091
|
let hasDustDebt = false;
|
|
2912
3092
|
let dustBorrowShares = 0n;
|
|
@@ -2921,10 +3101,10 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2921
3101
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
2922
3102
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
2923
3103
|
const estimated = totalBorrowShares > 0n ? dustBorrowShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
2924
|
-
dustApproveAmount = estimated > 0n ? estimated :
|
|
3104
|
+
dustApproveAmount = estimated > 0n ? estimated : import_ethers3.ethers.parseUnits("1", loanDecimals);
|
|
2925
3105
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2926
3106
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2927
|
-
console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${
|
|
3107
|
+
console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${import_ethers3.ethers.formatUnits(dustApproveAmount, loanDecimals)} ${loanSymbol} \u2014 auto-repaying before withdraw`);
|
|
2928
3108
|
}
|
|
2929
3109
|
} catch (e) {
|
|
2930
3110
|
console.warn("[agether] failed to check borrow shares before withdraw:", e instanceof Error ? e.message : e);
|
|
@@ -2938,7 +3118,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2938
3118
|
]);
|
|
2939
3119
|
let receipt;
|
|
2940
3120
|
if (hasDustDebt) {
|
|
2941
|
-
const loanContract = new
|
|
3121
|
+
const loanContract = new import_ethers3.Contract(loanTokenAddr, ERC20_ABI, this._signer);
|
|
2942
3122
|
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
2943
3123
|
if (acctBalance < dustApproveAmount) {
|
|
2944
3124
|
const shortfall = dustApproveAmount - acctBalance;
|
|
@@ -2946,7 +3126,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2946
3126
|
if (eoaBalance >= shortfall) {
|
|
2947
3127
|
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
2948
3128
|
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
2949
|
-
console.log(`[agether] transferring ${
|
|
3129
|
+
console.log(`[agether] transferring ${import_ethers3.ethers.formatUnits(shortfall, loanDecimals)} ${loanSymbol} from EOA \u2192 AgentAccount for dust repay`);
|
|
2950
3130
|
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
2951
3131
|
await transferTx.wait();
|
|
2952
3132
|
this._refreshSigner();
|
|
@@ -2965,15 +3145,15 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2965
3145
|
]),
|
|
2966
3146
|
withdrawData
|
|
2967
3147
|
];
|
|
2968
|
-
receipt = await this.
|
|
3148
|
+
receipt = await this.executeBatch(targets, values, datas);
|
|
2969
3149
|
} else {
|
|
2970
|
-
receipt = await this.
|
|
3150
|
+
receipt = await this.executeSingle(morphoAddr, withdrawData);
|
|
2971
3151
|
}
|
|
2972
3152
|
let remainingCollateral = "0";
|
|
2973
3153
|
try {
|
|
2974
3154
|
if (market) {
|
|
2975
3155
|
const pos = await this.morphoBlue.position(market.uniqueKey, acctAddr);
|
|
2976
|
-
remainingCollateral =
|
|
3156
|
+
remainingCollateral = import_ethers3.ethers.formatUnits(pos.collateral, colInfo.decimals);
|
|
2977
3157
|
}
|
|
2978
3158
|
} catch (e) {
|
|
2979
3159
|
console.warn("[agether] failed to read remaining collateral after withdraw:", e instanceof Error ? e.message : e);
|
|
@@ -2981,7 +3161,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
2981
3161
|
return {
|
|
2982
3162
|
tx: receipt.hash,
|
|
2983
3163
|
token: tokenSymbol,
|
|
2984
|
-
amount: amount === "all" ?
|
|
3164
|
+
amount: amount === "all" ? import_ethers3.ethers.formatUnits(weiAmount, colInfo.decimals) : amount,
|
|
2985
3165
|
remainingCollateral,
|
|
2986
3166
|
destination: dest
|
|
2987
3167
|
};
|
|
@@ -3005,139 +3185,21 @@ var _MorphoClient = class _MorphoClient {
|
|
|
3005
3185
|
_refreshSigner() {
|
|
3006
3186
|
if (this._useExternalSigner) {
|
|
3007
3187
|
const addrs = this.config.contracts;
|
|
3008
|
-
this.agether4337Factory = new
|
|
3009
|
-
this.entryPoint = new
|
|
3188
|
+
this.agether4337Factory = new import_ethers3.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
3189
|
+
this.entryPoint = new import_ethers3.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
|
|
3010
3190
|
} else {
|
|
3011
|
-
this.provider = new
|
|
3012
|
-
const wallet = new
|
|
3191
|
+
this.provider = new import_ethers3.ethers.JsonRpcProvider(this._rpcUrl);
|
|
3192
|
+
const wallet = new import_ethers3.ethers.Wallet(this._privateKey, this.provider);
|
|
3013
3193
|
this._signer = wallet;
|
|
3014
3194
|
this._eoaAddress = wallet.address;
|
|
3015
3195
|
const addrs = this.config.contracts;
|
|
3016
|
-
this.agether4337Factory = new
|
|
3017
|
-
this.entryPoint = new
|
|
3196
|
+
this.agether4337Factory = new import_ethers3.Contract(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
|
|
3197
|
+
this.entryPoint = new import_ethers3.Contract(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
|
|
3018
3198
|
}
|
|
3019
3199
|
}
|
|
3020
3200
|
// ────────────────────────────────────────────────────────────
|
|
3021
3201
|
// ERC-4337 UserOp helpers (Safe + Safe7579 + EntryPoint v0.7)
|
|
3022
3202
|
// ────────────────────────────────────────────────────────────
|
|
3023
|
-
/**
|
|
3024
|
-
* Pack two uint128 values into a single bytes32:
|
|
3025
|
-
* bytes32 = (hi << 128) | lo
|
|
3026
|
-
*/
|
|
3027
|
-
_packUint128(hi, lo) {
|
|
3028
|
-
return import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(hi << 128n | lo), 32);
|
|
3029
|
-
}
|
|
3030
|
-
/**
|
|
3031
|
-
* Build, sign and submit a PackedUserOperation through EntryPoint.handleOps.
|
|
3032
|
-
*
|
|
3033
|
-
* @param callData – the ABI-encoded calldata for the Safe7579 account
|
|
3034
|
-
* (e.g. `execute(mode, executionCalldata)`)
|
|
3035
|
-
* @returns the transaction receipt of the handleOps call
|
|
3036
|
-
*/
|
|
3037
|
-
async _submitUserOp(callData) {
|
|
3038
|
-
const sender = await this.getAccountAddress();
|
|
3039
|
-
const validatorAddr = this.config.contracts.erc8004ValidationModule;
|
|
3040
|
-
const nonceKey = BigInt(validatorAddr) << 32n;
|
|
3041
|
-
const nonce = await this.entryPoint.getNonce(sender, nonceKey);
|
|
3042
|
-
const feeData = await this.provider.getFeeData();
|
|
3043
|
-
const maxFeePerGas = feeData.maxFeePerGas ?? import_ethers2.ethers.parseUnits("0.5", "gwei");
|
|
3044
|
-
const maxPriorityFeePerGas = feeData.maxPriorityFeePerGas ?? import_ethers2.ethers.parseUnits("0.1", "gwei");
|
|
3045
|
-
const verificationGasLimit = 500000n;
|
|
3046
|
-
const callGasLimit = 800000n;
|
|
3047
|
-
const preVerificationGas = 100000n;
|
|
3048
|
-
const accountGasLimits = this._packUint128(verificationGasLimit, callGasLimit);
|
|
3049
|
-
const gasFees = this._packUint128(maxPriorityFeePerGas, maxFeePerGas);
|
|
3050
|
-
const requiredPrefund = (verificationGasLimit + callGasLimit + preVerificationGas) * maxFeePerGas;
|
|
3051
|
-
const accountBalance = await this.provider.getBalance(sender);
|
|
3052
|
-
if (accountBalance < requiredPrefund) {
|
|
3053
|
-
const topUp = requiredPrefund - accountBalance;
|
|
3054
|
-
const topUpWithBuffer = topUp * 120n / 100n;
|
|
3055
|
-
const fundTx = await this._signer.sendTransaction({
|
|
3056
|
-
to: sender,
|
|
3057
|
-
value: topUpWithBuffer
|
|
3058
|
-
});
|
|
3059
|
-
await fundTx.wait();
|
|
3060
|
-
this._refreshSigner();
|
|
3061
|
-
}
|
|
3062
|
-
const userOp = {
|
|
3063
|
-
sender,
|
|
3064
|
-
nonce,
|
|
3065
|
-
initCode: "0x",
|
|
3066
|
-
callData,
|
|
3067
|
-
accountGasLimits,
|
|
3068
|
-
preVerificationGas,
|
|
3069
|
-
gasFees,
|
|
3070
|
-
paymasterAndData: "0x",
|
|
3071
|
-
signature: "0x"
|
|
3072
|
-
// placeholder — replaced after signing
|
|
3073
|
-
};
|
|
3074
|
-
const userOpHash = await this.entryPoint.getUserOpHash(userOp);
|
|
3075
|
-
const signature = await this._signer.signMessage(import_ethers2.ethers.getBytes(userOpHash));
|
|
3076
|
-
userOp.signature = signature;
|
|
3077
|
-
const tx = await this.entryPoint.handleOps([userOp], await this.getSignerAddress());
|
|
3078
|
-
const receipt = await tx.wait();
|
|
3079
|
-
this._refreshSigner();
|
|
3080
|
-
const epIface = new import_ethers2.ethers.Interface(ENTRYPOINT_V07_ABI);
|
|
3081
|
-
for (const log of receipt.logs) {
|
|
3082
|
-
try {
|
|
3083
|
-
const parsed = epIface.parseLog({ topics: log.topics, data: log.data });
|
|
3084
|
-
if (parsed?.name === "UserOperationEvent" && !parsed.args.success) {
|
|
3085
|
-
let revertMsg = "UserOp inner execution reverted";
|
|
3086
|
-
for (const rLog of receipt.logs) {
|
|
3087
|
-
try {
|
|
3088
|
-
const rParsed = epIface.parseLog({ topics: rLog.topics, data: rLog.data });
|
|
3089
|
-
if (rParsed?.name === "UserOperationRevertReason") {
|
|
3090
|
-
const reason = rParsed.args.revertReason;
|
|
3091
|
-
try {
|
|
3092
|
-
if (reason.length >= 10 && reason.slice(0, 10) === "0x08c379a0") {
|
|
3093
|
-
const decoded = import_ethers2.ethers.AbiCoder.defaultAbiCoder().decode(["string"], "0x" + reason.slice(10));
|
|
3094
|
-
revertMsg = `UserOp reverted: ${decoded[0]}`;
|
|
3095
|
-
} else {
|
|
3096
|
-
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
3097
|
-
}
|
|
3098
|
-
} catch {
|
|
3099
|
-
revertMsg = `UserOp reverted with data: ${reason}`;
|
|
3100
|
-
}
|
|
3101
|
-
break;
|
|
3102
|
-
}
|
|
3103
|
-
} catch {
|
|
3104
|
-
continue;
|
|
3105
|
-
}
|
|
3106
|
-
}
|
|
3107
|
-
throw new AgetherError(revertMsg, "USEROP_EXECUTION_FAILED");
|
|
3108
|
-
}
|
|
3109
|
-
} catch (e) {
|
|
3110
|
-
if (e instanceof AgetherError) throw e;
|
|
3111
|
-
continue;
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
return receipt;
|
|
3115
|
-
}
|
|
3116
|
-
/**
|
|
3117
|
-
* Execute a single call via Safe7579 account (ERC-7579 single mode)
|
|
3118
|
-
* through an ERC-4337 UserOperation.
|
|
3119
|
-
*/
|
|
3120
|
-
async exec(target, data, value = 0n) {
|
|
3121
|
-
const valueHex = import_ethers2.ethers.zeroPadValue(import_ethers2.ethers.toBeHex(value), 32);
|
|
3122
|
-
const executionCalldata = import_ethers2.ethers.concat([target, valueHex, data]);
|
|
3123
|
-
const safe7579Iface = new import_ethers2.ethers.Interface(SAFE7579_ACCOUNT_ABI);
|
|
3124
|
-
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_SINGLE2, executionCalldata]);
|
|
3125
|
-
return this._submitUserOp(callData);
|
|
3126
|
-
}
|
|
3127
|
-
/**
|
|
3128
|
-
* Execute multiple calls via Safe7579 account (ERC-7579 batch mode)
|
|
3129
|
-
* through an ERC-4337 UserOperation.
|
|
3130
|
-
*/
|
|
3131
|
-
async batch(targets, values, datas) {
|
|
3132
|
-
const executions = targets.map((t, i) => [t, values[i], datas[i]]);
|
|
3133
|
-
const executionCalldata = import_ethers2.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
3134
|
-
["(address,uint256,bytes)[]"],
|
|
3135
|
-
[executions]
|
|
3136
|
-
);
|
|
3137
|
-
const safe7579Iface = new import_ethers2.ethers.Interface(SAFE7579_ACCOUNT_ABI);
|
|
3138
|
-
const callData = safe7579Iface.encodeFunctionData("execute", [MODE_BATCH, executionCalldata]);
|
|
3139
|
-
return this._submitUserOp(callData);
|
|
3140
|
-
}
|
|
3141
3203
|
/** Convert MorphoMarketParams to Solidity tuple. */
|
|
3142
3204
|
_toTuple(p) {
|
|
3143
3205
|
return [p.loanToken, p.collateralToken, p.oracle, p.irm, p.lltv];
|
|
@@ -3187,7 +3249,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
3187
3249
|
}
|
|
3188
3250
|
const markets = await this.getMarkets();
|
|
3189
3251
|
for (const m of markets) {
|
|
3190
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
3252
|
+
if (!m.collateralAsset || m.collateralAsset.address === import_ethers3.ethers.ZeroAddress) continue;
|
|
3191
3253
|
try {
|
|
3192
3254
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
3193
3255
|
if (pos.collateral > 0n) {
|
|
@@ -3255,7 +3317,7 @@ var _MorphoClient = class _MorphoClient {
|
|
|
3255
3317
|
}
|
|
3256
3318
|
const markets = await this.getMarkets();
|
|
3257
3319
|
for (const m of markets) {
|
|
3258
|
-
if (!m.collateralAsset || m.collateralAsset.address ===
|
|
3320
|
+
if (!m.collateralAsset || m.collateralAsset.address === import_ethers3.ethers.ZeroAddress) continue;
|
|
3259
3321
|
try {
|
|
3260
3322
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
3261
3323
|
if (BigInt(pos.supplyShares) > 0n) {
|
|
@@ -3434,6 +3496,316 @@ _MorphoClient._lstYieldCache = null;
|
|
|
3434
3496
|
_MorphoClient.LST_CACHE_TTL = 30 * 60 * 1e3;
|
|
3435
3497
|
var MorphoClient = _MorphoClient;
|
|
3436
3498
|
|
|
3499
|
+
// src/clients/AaveClient.ts
|
|
3500
|
+
var import_ethers4 = require("ethers");
|
|
3501
|
+
var POOL_ABI = [
|
|
3502
|
+
"function getUserAccountData(address user) view returns (uint256 totalCollateralBase, uint256 totalDebtBase, uint256 availableBorrowsBase, uint256 currentLiquidationThreshold, uint256 currentLtv, uint256 healthFactor)",
|
|
3503
|
+
"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))",
|
|
3504
|
+
"function getReservesList() view returns (address[])",
|
|
3505
|
+
"function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode)",
|
|
3506
|
+
"function withdraw(address asset, uint256 amount, address to) returns (uint256)",
|
|
3507
|
+
"function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf)",
|
|
3508
|
+
"function repay(address asset, uint256 amount, uint256 interestRateMode, address onBehalfOf) returns (uint256)",
|
|
3509
|
+
"function setUserUseReserveAsCollateral(address asset, bool useAsCollateral)"
|
|
3510
|
+
];
|
|
3511
|
+
var ERC20_ABI2 = [
|
|
3512
|
+
"function approve(address spender, uint256 amount) returns (bool)",
|
|
3513
|
+
"function allowance(address owner, address spender) view returns (uint256)",
|
|
3514
|
+
"function balanceOf(address account) view returns (uint256)",
|
|
3515
|
+
"function decimals() view returns (uint8)",
|
|
3516
|
+
"function symbol() view returns (string)"
|
|
3517
|
+
];
|
|
3518
|
+
var ORACLE_ABI = [
|
|
3519
|
+
"function getAssetsPrices(address[] assets) view returns (uint256[])",
|
|
3520
|
+
"function BASE_CURRENCY_UNIT() view returns (uint256)"
|
|
3521
|
+
];
|
|
3522
|
+
var POOL_DATA_PROVIDER_ABI = [
|
|
3523
|
+
"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)",
|
|
3524
|
+
"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)",
|
|
3525
|
+
"function getReserveTokensAddresses(address asset) view returns (address aTokenAddress, address stableDebtTokenAddress, address variableDebtTokenAddress)",
|
|
3526
|
+
"function getAllReservesTokens() view returns (tuple(string symbol, address tokenAddress)[])"
|
|
3527
|
+
];
|
|
3528
|
+
var AAVE_ADDRESSES = {
|
|
3529
|
+
[1 /* Ethereum */]: {
|
|
3530
|
+
pool: "0x87870Bca3F3fD6335C3F4ce8392D69350B4fA4E2",
|
|
3531
|
+
oracle: "0x54586bE62E3c3580375aE3723C145253060Ca0C2",
|
|
3532
|
+
dataProvider: "0x0a16f2FCC0D44FaE41cc54e079281D84A363bECD"
|
|
3533
|
+
},
|
|
3534
|
+
[8453 /* Base */]: {
|
|
3535
|
+
pool: "0xA238Dd80C259a72e81d7e4664a9801593F98d1c5",
|
|
3536
|
+
oracle: "0x2Cc0Fc26eD4563A5ce5e8bdcfe1A2878676Ae156",
|
|
3537
|
+
dataProvider: "0x0F43731EB8d45A581f4a36DD74F5f358bc90C73A"
|
|
3538
|
+
}
|
|
3539
|
+
};
|
|
3540
|
+
var KNOWN_RESERVES = {
|
|
3541
|
+
[1 /* Ethereum */]: [
|
|
3542
|
+
{ symbol: "WETH", address: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", decimals: 18 },
|
|
3543
|
+
{ symbol: "wstETH", address: "0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0", decimals: 18 },
|
|
3544
|
+
{ symbol: "USDC", address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", decimals: 6 },
|
|
3545
|
+
{ symbol: "USDT", address: "0xdAC17F958D2ee523a2206206994597C13D831ec7", decimals: 6 },
|
|
3546
|
+
{ symbol: "DAI", address: "0x6B175474E89094C44Da98b954EedeAC495271d0F", decimals: 18 },
|
|
3547
|
+
{ symbol: "cbETH", address: "0xBe9895146f7AF43049ca1c1AE358B0541Ea49704", decimals: 18 },
|
|
3548
|
+
{ symbol: "rETH", address: "0xae78736Cd615f374D3085123A210448E74Fc6393", decimals: 18 },
|
|
3549
|
+
{ symbol: "weETH", address: "0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee", decimals: 18 }
|
|
3550
|
+
],
|
|
3551
|
+
[8453 /* Base */]: [
|
|
3552
|
+
{ symbol: "WETH", address: "0x4200000000000000000000000000000000000006", decimals: 18 },
|
|
3553
|
+
{ symbol: "wstETH", address: "0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452", decimals: 18 },
|
|
3554
|
+
{ symbol: "cbETH", address: "0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22", decimals: 18 },
|
|
3555
|
+
{ symbol: "USDC", address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", decimals: 6 },
|
|
3556
|
+
{ symbol: "USDbC", address: "0xd9aAEc86B65D86f6A7B5B1b0c42FFA531710b6CA", decimals: 6 }
|
|
3557
|
+
]
|
|
3558
|
+
};
|
|
3559
|
+
var _AaveClient = class _AaveClient extends AgentAccountClient {
|
|
3560
|
+
/**
|
|
3561
|
+
* Create an AaveClient. Takes the same config as MorphoClient — the agent's
|
|
3562
|
+
* Safe account is used for all Aave operations.
|
|
3563
|
+
*/
|
|
3564
|
+
constructor(config) {
|
|
3565
|
+
super(config);
|
|
3566
|
+
// Cache
|
|
3567
|
+
this._reserveCache = /* @__PURE__ */ new Map();
|
|
3568
|
+
this._reserveCacheTs = 0;
|
|
3569
|
+
const chainId = config.chainId ?? 1 /* Ethereum */;
|
|
3570
|
+
const addrs = AAVE_ADDRESSES[chainId];
|
|
3571
|
+
if (!addrs) {
|
|
3572
|
+
throw new AgetherError(`Aave V3 not supported on chain ${chainId}`, "UNSUPPORTED_CHAIN");
|
|
3573
|
+
}
|
|
3574
|
+
this._aaveChainId = chainId;
|
|
3575
|
+
this._pool = new import_ethers4.Contract(addrs.pool, POOL_ABI, this.provider);
|
|
3576
|
+
this._oracle = new import_ethers4.Contract(addrs.oracle, ORACLE_ABI, this.provider);
|
|
3577
|
+
this._dataProvider = new import_ethers4.Contract(addrs.dataProvider, POOL_DATA_PROVIDER_ABI, this.provider);
|
|
3578
|
+
this._poolIface = new import_ethers4.ethers.Interface(POOL_ABI);
|
|
3579
|
+
this._erc20Iface = new import_ethers4.ethers.Interface(ERC20_ABI2);
|
|
3580
|
+
}
|
|
3581
|
+
/** Get the Agent's Safe account address. */
|
|
3582
|
+
async getAccountAddress() {
|
|
3583
|
+
return super.getAccountAddress();
|
|
3584
|
+
}
|
|
3585
|
+
/** Get chainId. */
|
|
3586
|
+
get aaveChainId() {
|
|
3587
|
+
return this._aaveChainId;
|
|
3588
|
+
}
|
|
3589
|
+
// ─── Market Data (read-only, no Safe needed) ─────────────────────────
|
|
3590
|
+
async getReserves(forceRefresh = false) {
|
|
3591
|
+
if (!forceRefresh && this._reserveCache.size > 0 && Date.now() - this._reserveCacheTs < _AaveClient.CACHE_TTL) {
|
|
3592
|
+
return Array.from(this._reserveCache.values());
|
|
3593
|
+
}
|
|
3594
|
+
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3595
|
+
if (reserves.length === 0) return [];
|
|
3596
|
+
const addresses = reserves.map((r) => r.address);
|
|
3597
|
+
const prices = await this._oracle.getAssetsPrices(addresses);
|
|
3598
|
+
let baseCurrencyUnit;
|
|
3599
|
+
try {
|
|
3600
|
+
baseCurrencyUnit = await this._oracle.BASE_CURRENCY_UNIT();
|
|
3601
|
+
} catch {
|
|
3602
|
+
baseCurrencyUnit = 100000000n;
|
|
3603
|
+
}
|
|
3604
|
+
const results = [];
|
|
3605
|
+
const reserveDataPromises = reserves.map(async (reserve, i) => {
|
|
3606
|
+
try {
|
|
3607
|
+
const [reserveData, configData] = await Promise.all([
|
|
3608
|
+
this._pool.getReserveData(reserve.address),
|
|
3609
|
+
this._dataProvider.getReserveConfigurationData(reserve.address)
|
|
3610
|
+
]);
|
|
3611
|
+
const RAY = 10n ** 27n;
|
|
3612
|
+
const liquidityRate = reserveData[2];
|
|
3613
|
+
const borrowRate = reserveData[4];
|
|
3614
|
+
const supplyApy = Number(liquidityRate) / Number(RAY) * 100;
|
|
3615
|
+
const borrowApy = Number(borrowRate) / Number(RAY) * 100;
|
|
3616
|
+
const priceUsd = Number(prices[i]) / Number(baseCurrencyUnit);
|
|
3617
|
+
const ltv = Number(configData[1]) / 100;
|
|
3618
|
+
const liqThreshold = Number(configData[2]) / 100;
|
|
3619
|
+
const borrowingEnabled = configData[6];
|
|
3620
|
+
const isActive = configData[8];
|
|
3621
|
+
const info = {
|
|
3622
|
+
symbol: reserve.symbol,
|
|
3623
|
+
address: reserve.address,
|
|
3624
|
+
decimals: reserve.decimals,
|
|
3625
|
+
supplyApy,
|
|
3626
|
+
borrowApy,
|
|
3627
|
+
totalSupply: 0,
|
|
3628
|
+
totalBorrow: 0,
|
|
3629
|
+
ltv,
|
|
3630
|
+
liquidationThreshold: liqThreshold,
|
|
3631
|
+
borrowingEnabled,
|
|
3632
|
+
isActive,
|
|
3633
|
+
priceUsd
|
|
3634
|
+
};
|
|
3635
|
+
this._reserveCache.set(reserve.symbol, info);
|
|
3636
|
+
return info;
|
|
3637
|
+
} catch (err) {
|
|
3638
|
+
console.warn(`[aave] Failed to fetch reserve ${reserve.symbol}:`, err instanceof Error ? err.message : err);
|
|
3639
|
+
return null;
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3642
|
+
const settled = await Promise.all(reserveDataPromises);
|
|
3643
|
+
for (const r of settled) {
|
|
3644
|
+
if (r) results.push(r);
|
|
3645
|
+
}
|
|
3646
|
+
this._reserveCacheTs = Date.now();
|
|
3647
|
+
return results;
|
|
3648
|
+
}
|
|
3649
|
+
// ─── Account Data (reads from Safe account) ──────────────────────────
|
|
3650
|
+
async getAccountData() {
|
|
3651
|
+
const safeAddr = await this.getAccountAddress();
|
|
3652
|
+
const [totalCollateralBase, totalDebtBase, availableBorrowsBase, currentLtv, liqThreshold, healthFactor] = await this._pool.getUserAccountData(safeAddr);
|
|
3653
|
+
let baseCurrencyUnit;
|
|
3654
|
+
try {
|
|
3655
|
+
baseCurrencyUnit = await this._oracle.BASE_CURRENCY_UNIT();
|
|
3656
|
+
} catch {
|
|
3657
|
+
baseCurrencyUnit = 100000000n;
|
|
3658
|
+
}
|
|
3659
|
+
const totalCollateralUsd = Number(totalCollateralBase) / Number(baseCurrencyUnit);
|
|
3660
|
+
const totalDebtUsd = Number(totalDebtBase) / Number(baseCurrencyUnit);
|
|
3661
|
+
const availableBorrowUsd = Number(availableBorrowsBase) / Number(baseCurrencyUnit);
|
|
3662
|
+
const hf = Number(healthFactor) / 1e18;
|
|
3663
|
+
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3664
|
+
const reserveInfos = await this.getReserves();
|
|
3665
|
+
const positions = [];
|
|
3666
|
+
const posPromises = reserves.map(async (reserve) => {
|
|
3667
|
+
try {
|
|
3668
|
+
const userData = await this._dataProvider.getUserReserveData(reserve.address, safeAddr);
|
|
3669
|
+
const aTokenBal = userData[0];
|
|
3670
|
+
const stableDebt = userData[1];
|
|
3671
|
+
const variableDebt = userData[2];
|
|
3672
|
+
const usedAsCollateral = userData[8];
|
|
3673
|
+
const totalDebt = stableDebt + variableDebt;
|
|
3674
|
+
if (aTokenBal === 0n && totalDebt === 0n) return null;
|
|
3675
|
+
const reserveInfo = reserveInfos.find((r) => r.symbol === reserve.symbol);
|
|
3676
|
+
const priceUsd = reserveInfo?.priceUsd ?? 0;
|
|
3677
|
+
const divisor = 10 ** reserve.decimals;
|
|
3678
|
+
return {
|
|
3679
|
+
asset: reserve.symbol,
|
|
3680
|
+
address: reserve.address,
|
|
3681
|
+
supplied: Number(aTokenBal) / divisor,
|
|
3682
|
+
suppliedUsd: Number(aTokenBal) / divisor * priceUsd,
|
|
3683
|
+
borrowed: Number(totalDebt) / divisor,
|
|
3684
|
+
borrowedUsd: Number(totalDebt) / divisor * priceUsd,
|
|
3685
|
+
usedAsCollateral,
|
|
3686
|
+
supplyApy: reserveInfo?.supplyApy ?? 0,
|
|
3687
|
+
borrowApy: reserveInfo?.borrowApy ?? 0
|
|
3688
|
+
};
|
|
3689
|
+
} catch {
|
|
3690
|
+
return null;
|
|
3691
|
+
}
|
|
3692
|
+
});
|
|
3693
|
+
const settled = await Promise.all(posPromises);
|
|
3694
|
+
for (const p of settled) {
|
|
3695
|
+
if (p) positions.push(p);
|
|
3696
|
+
}
|
|
3697
|
+
return {
|
|
3698
|
+
totalCollateralUsd,
|
|
3699
|
+
totalDebtUsd,
|
|
3700
|
+
availableBorrowUsd,
|
|
3701
|
+
currentLtv: Number(currentLtv) / 100,
|
|
3702
|
+
liquidationThreshold: Number(liqThreshold) / 100,
|
|
3703
|
+
healthFactor: hf > 1e10 ? Infinity : hf,
|
|
3704
|
+
positions
|
|
3705
|
+
};
|
|
3706
|
+
}
|
|
3707
|
+
// ─── Write Operations (through Safe account) ─────────────────────────
|
|
3708
|
+
/**
|
|
3709
|
+
* Supply an asset to Aave V3 from the Agent's Safe account.
|
|
3710
|
+
* Batch: approve + supply in one UserOp.
|
|
3711
|
+
*/
|
|
3712
|
+
async supply(asset, amount) {
|
|
3713
|
+
const reserve = this._resolveReserve(asset);
|
|
3714
|
+
const amountWei = import_ethers4.ethers.parseUnits(amount, reserve.decimals);
|
|
3715
|
+
const safeAddr = await this.getAccountAddress();
|
|
3716
|
+
const poolAddr = await this._pool.getAddress();
|
|
3717
|
+
const approveData = this._erc20Iface.encodeFunctionData("approve", [poolAddr, amountWei]);
|
|
3718
|
+
const supplyData = this._poolIface.encodeFunctionData("supply", [reserve.address, amountWei, safeAddr, 0]);
|
|
3719
|
+
return this.executeBatch(
|
|
3720
|
+
[reserve.address, poolAddr],
|
|
3721
|
+
[0n, 0n],
|
|
3722
|
+
[approveData, supplyData]
|
|
3723
|
+
);
|
|
3724
|
+
}
|
|
3725
|
+
/**
|
|
3726
|
+
* Withdraw a supplied asset from Aave V3 to the Safe account.
|
|
3727
|
+
*/
|
|
3728
|
+
async withdraw(asset, amount, to) {
|
|
3729
|
+
const reserve = this._resolveReserve(asset);
|
|
3730
|
+
const amountWei = amount === "all" ? import_ethers4.ethers.MaxUint256 : import_ethers4.ethers.parseUnits(amount, reserve.decimals);
|
|
3731
|
+
const recipient = to ?? await this.getAccountAddress();
|
|
3732
|
+
const poolAddr = await this._pool.getAddress();
|
|
3733
|
+
const data = this._poolIface.encodeFunctionData("withdraw", [reserve.address, amountWei, recipient]);
|
|
3734
|
+
return this.executeSingle(poolAddr, data);
|
|
3735
|
+
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Borrow an asset from Aave V3 (variable rate) to the Safe account.
|
|
3738
|
+
*/
|
|
3739
|
+
async borrow(asset, amount) {
|
|
3740
|
+
const reserve = this._resolveReserve(asset);
|
|
3741
|
+
const amountWei = import_ethers4.ethers.parseUnits(amount, reserve.decimals);
|
|
3742
|
+
const safeAddr = await this.getAccountAddress();
|
|
3743
|
+
const poolAddr = await this._pool.getAddress();
|
|
3744
|
+
const data = this._poolIface.encodeFunctionData("borrow", [reserve.address, amountWei, 2, 0, safeAddr]);
|
|
3745
|
+
return this.executeSingle(poolAddr, data);
|
|
3746
|
+
}
|
|
3747
|
+
/**
|
|
3748
|
+
* Repay borrowed asset on Aave V3 from the Safe account.
|
|
3749
|
+
* Batch: approve + repay in one UserOp.
|
|
3750
|
+
*/
|
|
3751
|
+
async repay(asset, amount) {
|
|
3752
|
+
const reserve = this._resolveReserve(asset);
|
|
3753
|
+
const amountWei = amount === "all" ? import_ethers4.ethers.MaxUint256 : import_ethers4.ethers.parseUnits(amount, reserve.decimals);
|
|
3754
|
+
const safeAddr = await this.getAccountAddress();
|
|
3755
|
+
const poolAddr = await this._pool.getAddress();
|
|
3756
|
+
const approveAmount = amount === "all" ? import_ethers4.ethers.MaxUint256 : amountWei;
|
|
3757
|
+
const approveData = this._erc20Iface.encodeFunctionData("approve", [poolAddr, approveAmount]);
|
|
3758
|
+
const repayData = this._poolIface.encodeFunctionData("repay", [reserve.address, amountWei, 2, safeAddr]);
|
|
3759
|
+
return this.executeBatch(
|
|
3760
|
+
[reserve.address, poolAddr],
|
|
3761
|
+
[0n, 0n],
|
|
3762
|
+
[approveData, repayData]
|
|
3763
|
+
);
|
|
3764
|
+
}
|
|
3765
|
+
/**
|
|
3766
|
+
* Enable or disable a supplied asset as collateral.
|
|
3767
|
+
*/
|
|
3768
|
+
async setCollateral(asset, useAsCollateral) {
|
|
3769
|
+
const reserve = this._resolveReserve(asset);
|
|
3770
|
+
const poolAddr = await this._pool.getAddress();
|
|
3771
|
+
const data = this._poolIface.encodeFunctionData("setUserUseReserveAsCollateral", [reserve.address, useAsCollateral]);
|
|
3772
|
+
return this.executeSingle(poolAddr, data);
|
|
3773
|
+
}
|
|
3774
|
+
/**
|
|
3775
|
+
* Supply an asset and borrow in one atomic batch operation.
|
|
3776
|
+
*/
|
|
3777
|
+
async supplyAndBorrow(supplyAsset, supplyAmount, borrowAsset, borrowAmount) {
|
|
3778
|
+
const supplyReserve = this._resolveReserve(supplyAsset);
|
|
3779
|
+
const borrowReserve = this._resolveReserve(borrowAsset);
|
|
3780
|
+
const supplyWei = import_ethers4.ethers.parseUnits(supplyAmount, supplyReserve.decimals);
|
|
3781
|
+
const borrowWei = import_ethers4.ethers.parseUnits(borrowAmount, borrowReserve.decimals);
|
|
3782
|
+
const safeAddr = await this.getAccountAddress();
|
|
3783
|
+
const poolAddr = await this._pool.getAddress();
|
|
3784
|
+
const approveData = this._erc20Iface.encodeFunctionData("approve", [poolAddr, supplyWei]);
|
|
3785
|
+
const supplyData = this._poolIface.encodeFunctionData("supply", [supplyReserve.address, supplyWei, safeAddr, 0]);
|
|
3786
|
+
const borrowData = this._poolIface.encodeFunctionData("borrow", [borrowReserve.address, borrowWei, 2, 0, safeAddr]);
|
|
3787
|
+
return this.executeBatch(
|
|
3788
|
+
[supplyReserve.address, poolAddr, poolAddr],
|
|
3789
|
+
[0n, 0n, 0n],
|
|
3790
|
+
[approveData, supplyData, borrowData]
|
|
3791
|
+
);
|
|
3792
|
+
}
|
|
3793
|
+
// ─── Helpers ──────────────────────────────────────────────────────────
|
|
3794
|
+
_resolveReserve(symbolOrAddress) {
|
|
3795
|
+
const reserves = KNOWN_RESERVES[this._aaveChainId] ?? [];
|
|
3796
|
+
const bySymbol = reserves.find((r) => r.symbol.toLowerCase() === symbolOrAddress.toLowerCase());
|
|
3797
|
+
if (bySymbol) return bySymbol;
|
|
3798
|
+
const byAddr = reserves.find((r) => r.address.toLowerCase() === symbolOrAddress.toLowerCase());
|
|
3799
|
+
if (byAddr) return byAddr;
|
|
3800
|
+
throw new AgetherError(
|
|
3801
|
+
`Unknown Aave reserve: ${symbolOrAddress}. Known: ${reserves.map((r) => r.symbol).join(", ")}`,
|
|
3802
|
+
"UNKNOWN_RESERVE"
|
|
3803
|
+
);
|
|
3804
|
+
}
|
|
3805
|
+
};
|
|
3806
|
+
_AaveClient.CACHE_TTL = 6e4;
|
|
3807
|
+
var AaveClient = _AaveClient;
|
|
3808
|
+
|
|
3437
3809
|
// src/clients/ScoringClient.ts
|
|
3438
3810
|
var import_axios3 = __toESM(require("axios"));
|
|
3439
3811
|
|
|
@@ -3899,7 +4271,7 @@ var ScoringClient = class {
|
|
|
3899
4271
|
};
|
|
3900
4272
|
|
|
3901
4273
|
// src/clients/AgentIdentityClient.ts
|
|
3902
|
-
var
|
|
4274
|
+
var import_ethers5 = require("ethers");
|
|
3903
4275
|
var ERC8004_IDENTITY_ABI = [
|
|
3904
4276
|
// Registration
|
|
3905
4277
|
"function register() returns (uint256)",
|
|
@@ -3941,8 +4313,8 @@ var AgentIdentityClient = class {
|
|
|
3941
4313
|
this.signer = options.signer;
|
|
3942
4314
|
const identityAddr = options.config.contracts?.identityRegistry || ERC8004_SEPOLIA.identityRegistry;
|
|
3943
4315
|
const reputationAddr = options.config.contracts?.reputationRegistry || ERC8004_SEPOLIA.reputationRegistry;
|
|
3944
|
-
this.identityRegistry = new
|
|
3945
|
-
this.reputationRegistry = new
|
|
4316
|
+
this.identityRegistry = new import_ethers5.ethers.Contract(identityAddr, ERC8004_IDENTITY_ABI, this.signer);
|
|
4317
|
+
this.reputationRegistry = new import_ethers5.ethers.Contract(reputationAddr, ERC8004_REPUTATION_ABI, this.signer);
|
|
3946
4318
|
}
|
|
3947
4319
|
// ============ Identity Functions ============
|
|
3948
4320
|
/**
|
|
@@ -4010,7 +4382,7 @@ var AgentIdentityClient = class {
|
|
|
4010
4382
|
async registerWithMetadata(agentURI, metadata) {
|
|
4011
4383
|
const metadataEntries = metadata.map((m) => ({
|
|
4012
4384
|
key: m.key,
|
|
4013
|
-
value:
|
|
4385
|
+
value: import_ethers5.ethers.toUtf8Bytes(m.value)
|
|
4014
4386
|
}));
|
|
4015
4387
|
const tx = await this.identityRegistry["register(string,tuple(string,bytes)[])"](
|
|
4016
4388
|
agentURI,
|
|
@@ -4047,7 +4419,7 @@ var AgentIdentityClient = class {
|
|
|
4047
4419
|
const tx = await this.identityRegistry.setMetadata(
|
|
4048
4420
|
agentId,
|
|
4049
4421
|
key,
|
|
4050
|
-
|
|
4422
|
+
import_ethers5.ethers.toUtf8Bytes(value)
|
|
4051
4423
|
);
|
|
4052
4424
|
const receipt = await tx.wait();
|
|
4053
4425
|
return receipt.hash;
|
|
@@ -4057,7 +4429,7 @@ var AgentIdentityClient = class {
|
|
|
4057
4429
|
*/
|
|
4058
4430
|
async getMetadata(agentId, key) {
|
|
4059
4431
|
const value = await this.identityRegistry.getMetadata(agentId, key);
|
|
4060
|
-
return
|
|
4432
|
+
return import_ethers5.ethers.toUtf8String(value);
|
|
4061
4433
|
}
|
|
4062
4434
|
/**
|
|
4063
4435
|
* Transfer agent to new owner
|
|
@@ -4092,8 +4464,8 @@ var AgentIdentityClient = class {
|
|
|
4092
4464
|
* Give feedback to an agent
|
|
4093
4465
|
*/
|
|
4094
4466
|
async giveFeedback(input) {
|
|
4095
|
-
const feedbackHash =
|
|
4096
|
-
|
|
4467
|
+
const feedbackHash = import_ethers5.ethers.keccak256(
|
|
4468
|
+
import_ethers5.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
4097
4469
|
["uint256", "int128", "uint256"],
|
|
4098
4470
|
[input.agentId, input.value, Date.now()]
|
|
4099
4471
|
)
|
|
@@ -4287,6 +4659,8 @@ function rateToBps(rate) {
|
|
|
4287
4659
|
AGETHER_8004_SCORER_ABI,
|
|
4288
4660
|
AGETHER_8004_VALIDATION_MODULE_ABI,
|
|
4289
4661
|
AGETHER_HOOK_MULTIPLEXER_ABI,
|
|
4662
|
+
AaveClient,
|
|
4663
|
+
AgentAccountClient,
|
|
4290
4664
|
AgentIdentityClient,
|
|
4291
4665
|
AgentNotApprovedError,
|
|
4292
4666
|
AgetherClient,
|