@agether/sdk 2.13.0 → 2.14.1

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
@@ -1080,7 +1080,7 @@ var MorphoClient = class {
1080
1080
  const chainId = this.config.chainId;
1081
1081
  const query = `{
1082
1082
  markets(
1083
- first: 50
1083
+ first: 500
1084
1084
  orderBy: SupplyAssetsUsd
1085
1085
  orderDirection: Desc
1086
1086
  where: { chainId_in: [${chainId}] }
@@ -1186,7 +1186,7 @@ var MorphoClient = class {
1186
1186
  const resolved = await this._resolveToken(loanTokenSymbolOrAddress);
1187
1187
  loanAddr = resolved.address.toLowerCase();
1188
1188
  } catch {
1189
- loanAddr = loanTokenSymbolOrAddress.toLowerCase();
1189
+ loanAddr = void 0;
1190
1190
  }
1191
1191
  }
1192
1192
  }
@@ -1194,6 +1194,7 @@ var MorphoClient = class {
1194
1194
  for (const m of this._discoveredMarkets ?? []) {
1195
1195
  if (m.collateralAsset.address.toLowerCase() !== colAddr) continue;
1196
1196
  if (loanAddr && m.loanAsset.address.toLowerCase() !== loanAddr) continue;
1197
+ if (!loanAddr && loanTokenSymbolOrAddress && m.loanAsset.symbol.toUpperCase() !== loanTokenSymbolOrAddress.toUpperCase()) continue;
1197
1198
  return {
1198
1199
  loanToken: m.loanAsset.address,
1199
1200
  collateralToken: m.collateralAsset.address,
@@ -1202,6 +1203,27 @@ var MorphoClient = class {
1202
1203
  lltv: m.lltv
1203
1204
  };
1204
1205
  }
1206
+ if (!collateralSymbolOrAddress.startsWith("0x")) {
1207
+ const searched = await this.searchMarkets(collateralSymbolOrAddress, { asCollateral: true });
1208
+ const allResults = [...searched];
1209
+ if (loanTokenSymbolOrAddress && !loanTokenSymbolOrAddress.startsWith("0x")) {
1210
+ const loanSearched = await this.searchMarkets(loanTokenSymbolOrAddress, { asLoanToken: true });
1211
+ const seen = new Set(allResults.map((r) => r.marketId));
1212
+ for (const m of loanSearched) {
1213
+ if (!seen.has(m.marketId)) allResults.push(m);
1214
+ }
1215
+ }
1216
+ for (const m of allResults) {
1217
+ if (colAddr.startsWith("0x") && m.collateralAddress.toLowerCase() !== colAddr) {
1218
+ if (m.collateralToken.toUpperCase() !== collateralSymbolOrAddress.toUpperCase()) continue;
1219
+ } else if (m.collateralToken.toUpperCase() !== collateralSymbolOrAddress.toUpperCase()) {
1220
+ continue;
1221
+ }
1222
+ if (loanAddr && m.loanAddress.toLowerCase() !== loanAddr) continue;
1223
+ if (!loanAddr && loanTokenSymbolOrAddress && m.loanToken.toUpperCase() !== loanTokenSymbolOrAddress.toUpperCase()) continue;
1224
+ return this.getMarketParams(m.marketId);
1225
+ }
1226
+ }
1205
1227
  throw new AgetherError(
1206
1228
  `No Morpho market found for collateral ${collateralSymbolOrAddress}` + (loanTokenSymbolOrAddress ? ` with loan token ${loanTokenSymbolOrAddress}` : ""),
1207
1229
  "MARKET_NOT_FOUND"
@@ -1232,26 +1254,54 @@ var MorphoClient = class {
1232
1254
  };
1233
1255
  }
1234
1256
  /**
1235
- * Full status: positions across all discovered markets.
1257
+ * Full status: positions across all markets the user has interacted with.
1258
+ *
1259
+ * Uses Morpho GraphQL `marketPositions` to find ALL positions (not limited
1260
+ * to the top-500 markets), then reads onchain data for accurate debt.
1236
1261
  */
1237
1262
  async getStatus() {
1238
1263
  const acctAddr = await this.getAccountAddress();
1239
- const markets = await this.getMarkets();
1264
+ const chainId = this.config.chainId;
1240
1265
  const positions = [];
1241
1266
  let totalDebtFloat = 0;
1242
- for (const m of markets) {
1243
- if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
1244
- try {
1245
- const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
1246
- if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
1267
+ try {
1268
+ const posQuery = `{
1269
+ marketPositions(
1270
+ where: {
1271
+ userAddress_in: ["${acctAddr}"]
1272
+ chainId_in: [${chainId}]
1273
+ }
1274
+ first: 100
1275
+ ) {
1276
+ items {
1277
+ supplyShares
1278
+ borrowShares
1279
+ collateral
1280
+ market {
1281
+ uniqueKey
1282
+ loanAsset { symbol address decimals }
1283
+ collateralAsset { symbol address decimals }
1284
+ }
1285
+ }
1286
+ }
1287
+ }`;
1288
+ const resp = await axios.post(MORPHO_API_URL, { query: posQuery }, { timeout: 15e3 });
1289
+ const items = resp.data?.data?.marketPositions?.items ?? [];
1290
+ for (const item of items) {
1291
+ const supplyShares = BigInt(item.supplyShares ?? "0");
1292
+ const borrowShares = BigInt(item.borrowShares ?? "0");
1293
+ const collateral = BigInt(item.collateral ?? "0");
1294
+ if (collateral === 0n && borrowShares === 0n && supplyShares === 0n) continue;
1295
+ const m = item.market;
1296
+ if (!m?.collateralAsset || !m?.loanAsset) continue;
1247
1297
  const loanDecimals = m.loanAsset.decimals;
1248
1298
  let debt = 0n;
1249
- if (pos.borrowShares > 0n) {
1299
+ if (borrowShares > 0n) {
1250
1300
  try {
1251
1301
  const mkt = await this.morphoBlue.market(m.uniqueKey);
1252
1302
  const totalBorrowShares = BigInt(mkt.totalBorrowShares);
1253
1303
  const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
1254
- debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1304
+ debt = totalBorrowShares > 0n ? (borrowShares * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1255
1305
  totalDebtFloat += parseFloat(ethers2.formatUnits(debt, loanDecimals));
1256
1306
  } catch (e) {
1257
1307
  console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
@@ -1261,14 +1311,46 @@ var MorphoClient = class {
1261
1311
  marketId: m.uniqueKey,
1262
1312
  collateralToken: m.collateralAsset.symbol,
1263
1313
  loanToken: m.loanAsset.symbol,
1264
- collateral: ethers2.formatUnits(pos.collateral, m.collateralAsset.decimals),
1265
- borrowShares: pos.borrowShares.toString(),
1266
- supplyShares: pos.supplyShares.toString(),
1314
+ collateral: ethers2.formatUnits(collateral, m.collateralAsset.decimals),
1315
+ borrowShares: borrowShares.toString(),
1316
+ supplyShares: supplyShares.toString(),
1267
1317
  debt: ethers2.formatUnits(debt, loanDecimals)
1268
1318
  });
1269
- } catch (e) {
1270
- console.warn(`[agether] position read failed for market:`, e instanceof Error ? e.message : e);
1271
- continue;
1319
+ }
1320
+ } catch (e) {
1321
+ console.warn("[agether] marketPositions API failed, falling back to market scan:", e instanceof Error ? e.message : e);
1322
+ const markets = await this.getMarkets();
1323
+ for (const m of markets) {
1324
+ if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
1325
+ try {
1326
+ const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
1327
+ if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
1328
+ const loanDecimals = m.loanAsset.decimals;
1329
+ let debt = 0n;
1330
+ if (pos.borrowShares > 0n) {
1331
+ try {
1332
+ const mkt = await this.morphoBlue.market(m.uniqueKey);
1333
+ const totalBorrowShares = BigInt(mkt.totalBorrowShares);
1334
+ const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
1335
+ debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1336
+ totalDebtFloat += parseFloat(ethers2.formatUnits(debt, loanDecimals));
1337
+ } catch (e2) {
1338
+ console.warn(`[agether] debt calc failed:`, e2 instanceof Error ? e2.message : e2);
1339
+ }
1340
+ }
1341
+ positions.push({
1342
+ marketId: m.uniqueKey,
1343
+ collateralToken: m.collateralAsset.symbol,
1344
+ loanToken: m.loanAsset.symbol,
1345
+ collateral: ethers2.formatUnits(pos.collateral, m.collateralAsset.decimals),
1346
+ borrowShares: pos.borrowShares.toString(),
1347
+ supplyShares: pos.supplyShares.toString(),
1348
+ debt: ethers2.formatUnits(debt, loanDecimals)
1349
+ });
1350
+ } catch (e2) {
1351
+ console.warn(`[agether] position read failed:`, e2 instanceof Error ? e2.message : e2);
1352
+ continue;
1353
+ }
1272
1354
  }
1273
1355
  }
1274
1356
  return {
@@ -1372,41 +1454,39 @@ var MorphoClient = class {
1372
1454
  async getMarketRates(collateralSymbolOrAddress, loanTokenSymbolOrAddress) {
1373
1455
  const chainId = this.config.chainId;
1374
1456
  let collateralFilter = "";
1457
+ let loanFilter = "";
1458
+ let searchTerm = "";
1375
1459
  if (collateralSymbolOrAddress) {
1376
- let colAddr;
1377
1460
  if (collateralSymbolOrAddress.startsWith("0x")) {
1378
- colAddr = collateralSymbolOrAddress.toLowerCase();
1461
+ collateralFilter = `, collateralAssetAddress_in: ["${collateralSymbolOrAddress.toLowerCase()}"]`;
1379
1462
  } else {
1380
- try {
1381
- const resolved = await this._resolveToken(collateralSymbolOrAddress);
1382
- colAddr = resolved.address.toLowerCase();
1383
- } catch {
1384
- colAddr = collateralSymbolOrAddress.toLowerCase();
1463
+ const cached = this._tokenCache.get(collateralSymbolOrAddress.toUpperCase());
1464
+ if (cached) {
1465
+ collateralFilter = `, collateralAssetAddress_in: ["${cached.address.toLowerCase()}"]`;
1466
+ } else {
1467
+ searchTerm = collateralSymbolOrAddress;
1385
1468
  }
1386
1469
  }
1387
- collateralFilter = `, collateralAssetAddress_in: ["${colAddr}"]`;
1388
1470
  }
1389
- let loanFilter = "";
1390
1471
  if (loanTokenSymbolOrAddress) {
1391
- let loanAddr;
1392
1472
  if (loanTokenSymbolOrAddress.startsWith("0x")) {
1393
- loanAddr = loanTokenSymbolOrAddress.toLowerCase();
1473
+ loanFilter = `, loanAssetAddress_in: ["${loanTokenSymbolOrAddress.toLowerCase()}"]`;
1394
1474
  } else {
1395
- try {
1396
- const resolved = await this._resolveToken(loanTokenSymbolOrAddress);
1397
- loanAddr = resolved.address.toLowerCase();
1398
- } catch {
1399
- loanAddr = loanTokenSymbolOrAddress.toLowerCase();
1475
+ const cached = this._tokenCache.get(loanTokenSymbolOrAddress.toUpperCase());
1476
+ if (cached) {
1477
+ loanFilter = `, loanAssetAddress_in: ["${cached.address.toLowerCase()}"]`;
1478
+ } else {
1479
+ searchTerm = searchTerm || loanTokenSymbolOrAddress;
1400
1480
  }
1401
1481
  }
1402
- loanFilter = `, loanAssetAddress_in: ["${loanAddr}"]`;
1403
1482
  }
1483
+ const searchClause = searchTerm ? `, search: "${searchTerm}"` : "";
1404
1484
  const query = `{
1405
1485
  markets(
1406
- first: 50
1486
+ first: 100
1407
1487
  orderBy: SupplyAssetsUsd
1408
1488
  orderDirection: Desc
1409
- where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter} }
1489
+ where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter}${searchClause} }
1410
1490
  ) {
1411
1491
  items {
1412
1492
  uniqueKey
@@ -1425,7 +1505,15 @@ var MorphoClient = class {
1425
1505
  }`;
1426
1506
  try {
1427
1507
  const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
1428
- const items = resp.data?.data?.markets?.items ?? [];
1508
+ let items = resp.data?.data?.markets?.items ?? [];
1509
+ if (searchTerm && collateralSymbolOrAddress && !collateralSymbolOrAddress.startsWith("0x")) {
1510
+ const sym = collateralSymbolOrAddress.toUpperCase();
1511
+ items = items.filter((m) => m.collateralAsset?.symbol?.toUpperCase() === sym);
1512
+ }
1513
+ if (searchTerm && loanTokenSymbolOrAddress && !loanTokenSymbolOrAddress.startsWith("0x")) {
1514
+ const sym = loanTokenSymbolOrAddress.toUpperCase();
1515
+ items = items.filter((m) => m.loanAsset?.symbol?.toUpperCase() === sym);
1516
+ }
1429
1517
  return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== ethers2.ZeroAddress).map((m) => {
1430
1518
  const loanDecimals = m.loanAsset?.decimals ?? 18;
1431
1519
  return {
@@ -1446,6 +1534,205 @@ var MorphoClient = class {
1446
1534
  return [];
1447
1535
  }
1448
1536
  }
1537
+ // ════════════════════════════════════════════════════════
1538
+ // Market Search & Wallet Discovery
1539
+ // ════════════════════════════════════════════════════════
1540
+ /**
1541
+ * Search Morpho markets by token name using the Morpho GraphQL API `search` field.
1542
+ * No hardcoded token lists — uses Morpho's built-in fuzzy search.
1543
+ *
1544
+ * @param search - token name or symbol (e.g. 'WETH', 'staked ETH', 'ezETH')
1545
+ * @param options.asCollateral - only return markets where the searched token is collateral
1546
+ * @param options.asLoanToken - only return markets where the searched token is the loan asset
1547
+ */
1548
+ async searchMarkets(search, options) {
1549
+ const chainId = this.config.chainId;
1550
+ const query = `{
1551
+ markets(
1552
+ first: 100
1553
+ orderBy: SupplyAssetsUsd
1554
+ orderDirection: Desc
1555
+ where: { chainId_in: [${chainId}], search: "${search}" }
1556
+ ) {
1557
+ items {
1558
+ uniqueKey
1559
+ lltv
1560
+ loanAsset { address symbol decimals }
1561
+ collateralAsset { address symbol decimals }
1562
+ state {
1563
+ borrowAssets
1564
+ supplyAssets
1565
+ utilization
1566
+ supplyApy
1567
+ borrowApy
1568
+ }
1569
+ }
1570
+ }
1571
+ }`;
1572
+ try {
1573
+ const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
1574
+ let items = resp.data?.data?.markets?.items ?? [];
1575
+ items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== ethers2.ZeroAddress);
1576
+ const searchUpper = search.toUpperCase();
1577
+ if (options?.asCollateral) {
1578
+ items = items.filter((m) => m.collateralAsset?.symbol?.toUpperCase() === searchUpper);
1579
+ }
1580
+ if (options?.asLoanToken) {
1581
+ items = items.filter((m) => m.loanAsset?.symbol?.toUpperCase() === searchUpper);
1582
+ }
1583
+ return items.map((m) => {
1584
+ const loanDecimals = m.loanAsset?.decimals ?? 18;
1585
+ const collateralDecimals = m.collateralAsset?.decimals ?? 18;
1586
+ return {
1587
+ collateralToken: m.collateralAsset.symbol,
1588
+ loanToken: m.loanAsset.symbol,
1589
+ loanDecimals,
1590
+ collateralDecimals,
1591
+ supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
1592
+ borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
1593
+ utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
1594
+ totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
1595
+ totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
1596
+ lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
1597
+ marketId: m.uniqueKey,
1598
+ collateralAddress: m.collateralAsset.address,
1599
+ loanAddress: m.loanAsset.address
1600
+ };
1601
+ });
1602
+ } catch (e) {
1603
+ console.warn("[agether] searchMarkets failed:", e instanceof Error ? e.message : e);
1604
+ return [];
1605
+ }
1606
+ }
1607
+ /**
1608
+ * Scan the AgentAccount wallet for all ERC-20 tokens that appear in Morpho
1609
+ * markets on the current chain. Returns tokens where balance > 0.
1610
+ *
1611
+ * Uses the full market list (500 markets) to discover all relevant tokens,
1612
+ * then checks on-chain balance for each unique token address.
1613
+ *
1614
+ * @returns Array of tokens with non-zero balance, sorted by balance descending.
1615
+ */
1616
+ async getWalletTokenBalances() {
1617
+ const acctAddr = await this.getAccountAddress();
1618
+ await this.getMarkets();
1619
+ const uniqueTokens = /* @__PURE__ */ new Map();
1620
+ for (const [key, info] of this._tokenCache.entries()) {
1621
+ if (key.startsWith("0x") && !uniqueTokens.has(key)) {
1622
+ uniqueTokens.set(key, info);
1623
+ }
1624
+ }
1625
+ const results = [];
1626
+ try {
1627
+ const ethBalance = await this.provider.getBalance(acctAddr);
1628
+ if (ethBalance > 0n) {
1629
+ results.push({
1630
+ symbol: "ETH",
1631
+ address: ethers2.ZeroAddress,
1632
+ decimals: 18,
1633
+ balance: ethBalance,
1634
+ balanceFormatted: ethers2.formatEther(ethBalance)
1635
+ });
1636
+ }
1637
+ } catch {
1638
+ }
1639
+ const tokenEntries = Array.from(uniqueTokens.values());
1640
+ const batchSize = 20;
1641
+ for (let i = 0; i < tokenEntries.length; i += batchSize) {
1642
+ const batch = tokenEntries.slice(i, i + batchSize);
1643
+ const checks = batch.map(async (info) => {
1644
+ try {
1645
+ const token = new Contract2(info.address, ERC20_ABI, this.provider);
1646
+ const balance = await token.balanceOf(acctAddr);
1647
+ if (balance > 0n) {
1648
+ return {
1649
+ symbol: info.symbol,
1650
+ address: info.address,
1651
+ decimals: info.decimals,
1652
+ balance,
1653
+ balanceFormatted: ethers2.formatUnits(balance, info.decimals)
1654
+ };
1655
+ }
1656
+ } catch {
1657
+ }
1658
+ return null;
1659
+ });
1660
+ const batchResults = await Promise.all(checks);
1661
+ for (const r of batchResults) {
1662
+ if (r) results.push(r);
1663
+ }
1664
+ }
1665
+ results.sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
1666
+ return results;
1667
+ }
1668
+ /**
1669
+ * Find borrowing opportunities for the agent.
1670
+ *
1671
+ * - If `collateralSymbol` is provided: find all markets where that token is collateral.
1672
+ * - If omitted: scan wallet balances and find markets for each token the agent holds.
1673
+ *
1674
+ * Returns markets grouped by collateral token with APY, liquidity, and balance info.
1675
+ *
1676
+ * @param collateralSymbol - optional, e.g. 'WETH'. If omitted, scans wallet.
1677
+ */
1678
+ async findBorrowingOptions(collateralSymbol) {
1679
+ let tokensToCheck;
1680
+ if (collateralSymbol) {
1681
+ tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted: "N/A" }];
1682
+ try {
1683
+ const balance = await this.getTokenBalance(collateralSymbol);
1684
+ const info = await this._resolveToken(collateralSymbol);
1685
+ tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted: ethers2.formatUnits(balance, info.decimals) }];
1686
+ } catch {
1687
+ }
1688
+ } else {
1689
+ const walletTokens = await this.getWalletTokenBalances();
1690
+ tokensToCheck = walletTokens.filter((t) => t.symbol !== "ETH").map((t) => ({ symbol: t.symbol, balanceFormatted: t.balanceFormatted }));
1691
+ if (tokensToCheck.length === 0) {
1692
+ return [];
1693
+ }
1694
+ }
1695
+ const results = [];
1696
+ for (const token of tokensToCheck) {
1697
+ const markets = await this.searchMarkets(token.symbol, { asCollateral: true });
1698
+ if (markets.length === 0) continue;
1699
+ results.push({
1700
+ collateralToken: token.symbol,
1701
+ collateralBalance: token.balanceFormatted,
1702
+ markets: markets.map((m) => ({
1703
+ loanToken: m.loanToken,
1704
+ borrowApy: `${(m.borrowApy * 100).toFixed(2)}%`,
1705
+ supplyApy: `${(m.supplyApy * 100).toFixed(2)}%`,
1706
+ lltv: m.lltv,
1707
+ utilization: `${(m.utilization * 100).toFixed(1)}%`,
1708
+ availableLiquidity: `$${(m.totalSupplyUsd - m.totalBorrowUsd).toFixed(0)}`,
1709
+ marketId: m.marketId
1710
+ }))
1711
+ });
1712
+ }
1713
+ return results;
1714
+ }
1715
+ /**
1716
+ * Find supply/lending opportunities for a specific loan token.
1717
+ *
1718
+ * "What can I supply to earn WETH?" → shows all markets where WETH is the loan token
1719
+ * (user supplies WETH to earn yield from borrowers).
1720
+ *
1721
+ * @param loanTokenSymbol - e.g. 'USDC', 'WETH'
1722
+ */
1723
+ async findSupplyOptions(loanTokenSymbol) {
1724
+ const markets = await this.searchMarkets(loanTokenSymbol, { asLoanToken: true });
1725
+ return markets.map((m) => ({
1726
+ collateralToken: m.collateralToken,
1727
+ loanToken: m.loanToken,
1728
+ supplyApy: `${(m.supplyApy * 100).toFixed(2)}%`,
1729
+ borrowApy: `${(m.borrowApy * 100).toFixed(2)}%`,
1730
+ lltv: m.lltv,
1731
+ utilization: `${(m.utilization * 100).toFixed(1)}%`,
1732
+ totalSupply: `$${m.totalSupplyUsd.toFixed(0)}`,
1733
+ marketId: m.marketId
1734
+ }));
1735
+ }
1449
1736
  /**
1450
1737
  * Estimate theoretical yield for a given collateral amount over a period.
1451
1738
  *
@@ -2350,6 +2637,46 @@ var MorphoClient = class {
2350
2637
  /** Find the first market where the agent has collateral deposited. */
2351
2638
  async _findActiveMarket() {
2352
2639
  const acctAddr = await this.getAccountAddress();
2640
+ const chainId = this.config.chainId;
2641
+ try {
2642
+ const posQuery = `{
2643
+ marketPositions(
2644
+ where: { userAddress_in: ["${acctAddr}"], chainId_in: [${chainId}] }
2645
+ first: 50
2646
+ ) {
2647
+ items {
2648
+ collateral
2649
+ market {
2650
+ uniqueKey
2651
+ oracleAddress
2652
+ irmAddress
2653
+ lltv
2654
+ loanAsset { address symbol decimals }
2655
+ collateralAsset { address symbol decimals }
2656
+ }
2657
+ }
2658
+ }
2659
+ }`;
2660
+ const resp = await axios.post(MORPHO_API_URL, { query: posQuery }, { timeout: 1e4 });
2661
+ const items = resp.data?.data?.marketPositions?.items ?? [];
2662
+ for (const item of items) {
2663
+ if (BigInt(item.collateral ?? "0") > 0n && item.market?.collateralAsset) {
2664
+ const m = item.market;
2665
+ return {
2666
+ params: {
2667
+ loanToken: m.loanAsset.address,
2668
+ collateralToken: m.collateralAsset.address,
2669
+ oracle: m.oracleAddress,
2670
+ irm: m.irmAddress,
2671
+ lltv: BigInt(m.lltv)
2672
+ },
2673
+ symbol: m.collateralAsset.symbol
2674
+ };
2675
+ }
2676
+ }
2677
+ } catch (e) {
2678
+ console.warn("[agether] _findActiveMarket GraphQL failed, falling back:", e instanceof Error ? e.message : e);
2679
+ }
2353
2680
  const markets = await this.getMarkets();
2354
2681
  for (const m of markets) {
2355
2682
  if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
@@ -2378,6 +2705,46 @@ var MorphoClient = class {
2378
2705
  /** Find the first market where the agent has a supply (lending) position. */
2379
2706
  async _findActiveSupplyMarket() {
2380
2707
  const acctAddr = await this.getAccountAddress();
2708
+ const chainId = this.config.chainId;
2709
+ try {
2710
+ const posQuery = `{
2711
+ marketPositions(
2712
+ where: { userAddress_in: ["${acctAddr}"], chainId_in: [${chainId}] }
2713
+ first: 50
2714
+ ) {
2715
+ items {
2716
+ supplyShares
2717
+ market {
2718
+ uniqueKey
2719
+ oracleAddress
2720
+ irmAddress
2721
+ lltv
2722
+ loanAsset { address symbol decimals }
2723
+ collateralAsset { address symbol decimals }
2724
+ }
2725
+ }
2726
+ }
2727
+ }`;
2728
+ const resp = await axios.post(MORPHO_API_URL, { query: posQuery }, { timeout: 1e4 });
2729
+ const items = resp.data?.data?.marketPositions?.items ?? [];
2730
+ for (const item of items) {
2731
+ if (BigInt(item.supplyShares ?? "0") > 0n && item.market?.collateralAsset) {
2732
+ const m = item.market;
2733
+ return {
2734
+ params: {
2735
+ loanToken: m.loanAsset.address,
2736
+ collateralToken: m.collateralAsset.address,
2737
+ oracle: m.oracleAddress,
2738
+ irm: m.irmAddress,
2739
+ lltv: BigInt(m.lltv)
2740
+ },
2741
+ symbol: m.collateralAsset.symbol
2742
+ };
2743
+ }
2744
+ }
2745
+ } catch (e) {
2746
+ console.warn("[agether] _findActiveSupplyMarket GraphQL failed, falling back:", e instanceof Error ? e.message : e);
2747
+ }
2381
2748
  const markets = await this.getMarkets();
2382
2749
  for (const m of markets) {
2383
2750
  if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
@@ -2448,6 +2815,24 @@ var MorphoClient = class {
2448
2815
  await this.getMarkets();
2449
2816
  const fromApi = this._tokenCache.get(key);
2450
2817
  if (fromApi) return fromApi;
2818
+ if (!symbolOrAddress.startsWith("0x")) {
2819
+ const searchResults = await this.searchMarkets(symbolOrAddress);
2820
+ const sym = symbolOrAddress.toUpperCase();
2821
+ for (const m of searchResults) {
2822
+ if (m.collateralToken.toUpperCase() === sym) {
2823
+ const info = { address: m.collateralAddress, symbol: m.collateralToken, decimals: m.collateralDecimals };
2824
+ this._tokenCache.set(sym, info);
2825
+ this._tokenCache.set(m.collateralAddress.toLowerCase(), info);
2826
+ return info;
2827
+ }
2828
+ if (m.loanToken.toUpperCase() === sym) {
2829
+ const info = { address: m.loanAddress, symbol: m.loanToken, decimals: m.loanDecimals };
2830
+ this._tokenCache.set(sym, info);
2831
+ this._tokenCache.set(m.loanAddress.toLowerCase(), info);
2832
+ return info;
2833
+ }
2834
+ }
2835
+ }
2451
2836
  throw new AgetherError(
2452
2837
  `Unknown token: ${symbolOrAddress}. No Morpho market found with this token.`,
2453
2838
  "UNKNOWN_TOKEN"