@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/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__ */ ((ChainId3) => {
7
- ChainId3[ChainId3["Ethereum"] = 1] = "Ethereum";
8
- ChainId3[ChainId3["Base"] = 8453] = "Base";
9
- ChainId3[ChainId3["BaseSepolia"] = 84532] = "BaseSepolia";
10
- ChainId3[ChainId3["Sepolia"] = 11155111] = "Sepolia";
11
- ChainId3[ChainId3["Hardhat"] = 31337] = "Hardhat";
12
- return ChainId3;
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 ethers2, Contract as Contract2 } from "ethers";
1189
- import axios2 from "axios";
1188
+ import { ethers as ethers3, Contract as Contract3 } from "ethers";
1190
1189
 
1191
- // src/utils/retry.ts
1192
- var RETRIABLE_PATTERNS = [
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 morphoIface = new ethers2.Interface(MORPHO_BLUE_ABI);
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
- // Account Management
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
- const addr = signer.address;
1327
- this._eoaAddress = addr;
1328
- return addr;
1264
+ this._eoaAddress = signer.address;
1265
+ return signer.address;
1329
1266
  }
1330
1267
  throw new AgetherError(
1331
- "EOA address not yet resolved. Call getSignerAddress() (async) first, or use a signer that exposes .address synchronously.",
1332
- "ADDRESS_NOT_RESOLVED"
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: ethers2.ZeroAddress, symbol: "N/A", decimals: 0 },
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 !== ethers2.ZeroAddress) {
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 !== ethers2.ZeroAddress) {
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(ethers2.formatUnits(debt, loanDecimals));
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: ethers2.formatUnits(collateral, m.collateralAsset.decimals),
1777
+ collateral: ethers3.formatUnits(collateral, m.collateralAsset.decimals),
1600
1778
  borrowShares: borrowShares.toString(),
1601
1779
  supplyShares: supplyShares.toString(),
1602
- debt: ethers2.formatUnits(debt, loanDecimals)
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 === ethers2.ZeroAddress) continue;
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(ethers2.formatUnits(debt, loanDecimals));
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: ethers2.formatUnits(pos.collateral, m.collateralAsset.decimals),
1808
+ collateral: ethers3.formatUnits(pos.collateral, m.collateralAsset.decimals),
1631
1809
  borrowShares: pos.borrowShares.toString(),
1632
1810
  supplyShares: pos.supplyShares.toString(),
1633
- debt: ethers2.formatUnits(debt, loanDecimals)
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 Contract2(tokenInfo.address, ERC20_ABI, this.provider);
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 Contract2(this.config.contracts.usdc, ERC20_ABI, this.provider);
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 === ethers2.ZeroAddress) continue;
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 Contract2(m.oracle, [
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 !== ethers2.ZeroAddress).map((m) => {
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 !== ethers2.ZeroAddress);
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: ethers2.ZeroAddress,
2100
+ address: ethers3.ZeroAddress,
1923
2101
  decimals: 18,
1924
2102
  balance: ethBalance,
1925
- balanceFormatted: ethers2.formatEther(ethBalance)
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 Contract2(info.address, ERC20_ABI, this.provider);
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: ethers2.formatUnits(balance, info.decimals)
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: ethers2.formatUnits(balance, info.decimals) }];
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 Contract2(params.oracle, [
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 = ethers2.parseUnits(amount, colInfo.decimals);
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 = ethers2.parseUnits(amount, loanDecimals);
2113
- const marketId = ethers2.keccak256(
2114
- ethers2.AbiCoder.defaultAbiCoder().encode(
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 Contract2(loanTokenAddr, ERC20_ABI, this._signer);
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 ${ethers2.formatUnits(acctBalance, loanDecimals)}, EOA has ${ethers2.formatUnits(eoaBalance, loanDecimals)}.`,
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.batch(targets, values, datas);
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 = ethers2.keccak256(
2185
- ethers2.AbiCoder.defaultAbiCoder().encode(
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 = ethers2.parseUnits(amount, loanDecimals);
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.exec(morphoAddr, data);
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 = ethers2.formatUnits(currentAssets, loanDecimals);
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: ethers2.formatUnits(currentAssets, p.market.loanAsset.decimals),
2282
- netDeposited: ethers2.formatUnits(netDeposited, p.market.loanAsset.decimals),
2283
- earnedYield: ethers2.formatUnits(earnedYield, p.market.loanAsset.decimals),
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 = ethers2.parseUnits(amount, loanDecimals);
2312
- const availableYield = ethers2.parseUnits(pos.earnedYield, loanDecimals);
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.exec(morphoAddr, data);
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 = ethers2.parseUnits(amount, colInfo.decimals);
2540
+ const weiAmount = ethers3.parseUnits(amount, colInfo.decimals);
2363
2541
  const morphoAddr = this.config.contracts.morphoBlue;
2364
- const colToken = new Contract2(colInfo.address, ERC20_ABI, this._signer);
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 ${ethers2.formatUnits(acctBalance, colInfo.decimals)}, EOA has ${ethers2.formatUnits(eoaBalance, colInfo.decimals)}.`,
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.batch(targets, values, datas);
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 = ethers2.parseUnits(amount, loanDecimals);
2601
+ const parsedAmount = ethers3.parseUnits(amount, loanDecimals);
2424
2602
  try {
2425
- const marketId = ethers2.keccak256(
2426
- ethers2.AbiCoder.defaultAbiCoder().encode(
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 Contract2(params.oracle, ["function price() view returns (uint256)"], this.provider);
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 = ethers2.formatUnits(maxAdditional, loanDecimals);
2452
- const colFormatted = ethers2.formatUnits(pos.collateral, colInfo.decimals);
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.exec(morphoAddr, data);
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 = ethers2.parseUnits(collateralAmount, colInfo.decimals);
2500
- const borrowWei = ethers2.parseUnits(borrowAmount, loanDecimals);
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 = ethers2.keccak256(
2504
- ethers2.AbiCoder.defaultAbiCoder().encode(
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 Contract2(params.oracle, ["function price() view returns (uint256)"], this.provider);
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 = ethers2.formatUnits(maxAdditional, loanDecimals);
2701
+ const maxFormatted = ethers3.formatUnits(maxAdditional, loanDecimals);
2524
2702
  throw new AgetherError(
2525
- `Borrow of ${borrowAmount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (total collateral: ${ethers2.formatUnits(totalCollateral, colInfo.decimals)} ${tokenSymbol}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Reduce borrow or increase 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 Contract2(colInfo.address, ERC20_ABI, this._signer);
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 ${ethers2.formatUnits(acctBalance, colInfo.decimals)}, EOA has ${ethers2.formatUnits(eoaBalance, colInfo.decimals)}.`,
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.batch(targets, values, datas);
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 : ethers2.parseUnits("1", loanDecimals);
2794
+ approveAmount = estimated > 0n ? estimated : ethers3.parseUnits("1", loanDecimals);
2617
2795
  } else {
2618
- const marketId = ethers2.keccak256(ethers2.AbiCoder.defaultAbiCoder().encode(
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 : ethers2.parseUnits("1", loanDecimals);
2806
+ approveAmount = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : ethers3.parseUnits("1", loanDecimals);
2629
2807
  }
2630
2808
  } else {
2631
- repayAssets = ethers2.parseUnits(amount, loanDecimals);
2809
+ repayAssets = ethers3.parseUnits(amount, loanDecimals);
2632
2810
  repayShares = 0n;
2633
2811
  approveAmount = repayAssets;
2634
2812
  }
2635
- const loanContract = new Contract2(loanTokenAddr, ERC20_ABI, this._signer);
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 ~${ethers2.formatUnits(checkAmount, loanDecimals)}, AgentAccount has ${ethers2.formatUnits(acctBalance, loanDecimals)}, EOA has ${ethers2.formatUnits(eoaBalance, loanDecimals)}.`,
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.batch(targets, values, datas);
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 = ethers2.formatUnits(debtWei, loanDecimals);
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 = ethers2.parseUnits(amount, colInfo.decimals);
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 : ethers2.parseUnits("1", loanDecimals);
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 ${ethers2.formatUnits(dustApproveAmount, loanDecimals)} ${loanSymbol} \u2014 auto-repaying before withdraw`);
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 Contract2(loanTokenAddr, ERC20_ABI, this._signer);
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 ${ethers2.formatUnits(shortfall, loanDecimals)} ${loanSymbol} from EOA \u2192 AgentAccount for dust repay`);
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.batch(targets, values, datas);
3070
+ receipt = await this.executeBatch(targets, values, datas);
2893
3071
  } else {
2894
- receipt = await this.exec(morphoAddr, withdrawData);
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 = ethers2.formatUnits(pos.collateral, colInfo.decimals);
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" ? ethers2.formatUnits(weiAmount, colInfo.decimals) : amount,
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 Contract2(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
2933
- this.entryPoint = new Contract2(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
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 ethers2.JsonRpcProvider(this._rpcUrl);
2936
- const wallet = new ethers2.Wallet(this._privateKey, this.provider);
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 Contract2(addrs.agether4337Factory, ACCOUNT_FACTORY_ABI, this._signer);
2941
- this.entryPoint = new Contract2(addrs.entryPoint, ENTRYPOINT_V07_ABI, this._signer);
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 === ethers2.ZeroAddress) continue;
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 === ethers2.ZeroAddress) continue;
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 ethers3 } from "ethers";
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 ethers3.Contract(identityAddr, ERC8004_IDENTITY_ABI, this.signer);
3869
- this.reputationRegistry = new ethers3.Contract(reputationAddr, ERC8004_REPUTATION_ABI, this.signer);
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: ethers3.toUtf8Bytes(m.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
- ethers3.toUtf8Bytes(value)
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 ethers3.toUtf8String(value);
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 = ethers3.keccak256(
4020
- ethers3.AbiCoder.defaultAbiCoder().encode(
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,