@agether/sdk 2.14.0 → 2.15.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
@@ -1,5 +1,6 @@
1
1
  // src/clients/AgetherClient.ts
2
2
  import { ethers, Contract } from "ethers";
3
+ import axios from "axios";
3
4
 
4
5
  // src/types/index.ts
5
6
  var ChainId = /* @__PURE__ */ ((ChainId3) => {
@@ -296,6 +297,7 @@ function getContractAddresses(chainId) {
296
297
  // src/clients/AgetherClient.ts
297
298
  var MODE_SINGLE = "0x0000000000000000000000000000000000000000000000000000000000000000";
298
299
  var erc20Iface = new ethers.Interface(ERC20_ABI);
300
+ var MORPHO_API_URL = "https://api.morpho.org/graphql";
299
301
  var KNOWN_TOKENS = {
300
302
  [8453 /* Base */]: {
301
303
  WETH: { address: "0x4200000000000000000000000000000000000006", symbol: "WETH", decimals: 18 },
@@ -310,6 +312,17 @@ var KNOWN_TOKENS = {
310
312
  };
311
313
  var AgetherClient = class _AgetherClient {
312
314
  constructor(options) {
315
+ /**
316
+ * Resolve a token symbol or address to { address, symbol, decimals }.
317
+ *
318
+ * Resolution order:
319
+ * 1. `'USDC'` → from chain config (instant)
320
+ * 2. Well-known symbols (`'WETH'`, `'wstETH'`, `'cbETH'`) → built-in per-chain registry (instant)
321
+ * 3. Dynamic cache populated by previous Morpho API lookups (instant)
322
+ * 4. `'0x...'` address → reads decimals and symbol onchain
323
+ * 5. Morpho GraphQL `search` API → discovers any token across all Morpho markets
324
+ */
325
+ this._dynamicTokenCache = /* @__PURE__ */ new Map();
313
326
  this.config = options.config;
314
327
  this.signer = options.signer;
315
328
  this.agentId = options.agentId;
@@ -594,21 +607,10 @@ var AgetherClient = class _AgetherClient {
594
607
  }
595
608
  /**
596
609
  * Fund the Safe account with USDC from EOA.
597
- * This is a simple ERC-20 transfer (does NOT require a UserOp).
610
+ * @deprecated Use `fundAccountToken('USDC', amount)` instead.
598
611
  */
599
612
  async fundAccount(usdcAmount) {
600
- const acctAddr = await this.getAccountAddress();
601
- const usdc = new Contract(this.config.contracts.usdc, ERC20_ABI, this.signer);
602
- const amount = ethers.parseUnits(usdcAmount, 6);
603
- const tx = await usdc.transfer(acctAddr, amount);
604
- const receipt = await tx.wait();
605
- this._refreshSigner();
606
- return {
607
- txHash: receipt.hash,
608
- blockNumber: receipt.blockNumber,
609
- status: receipt.status === 1 ? "success" : "failed",
610
- gasUsed: receipt.gasUsed
611
- };
613
+ return this.fundAccountToken("USDC", usdcAmount);
612
614
  }
613
615
  // ════════════════════════════════════════════════════════
614
616
  // Withdrawals (Safe → EOA via UserOps)
@@ -660,6 +662,138 @@ var AgetherClient = class _AgetherClient {
660
662
  return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: eoaAddr };
661
663
  }
662
664
  // ════════════════════════════════════════════════════════
665
+ // Token Transfers & Approvals (AgentAccount → any address)
666
+ // ════════════════════════════════════════════════════════
667
+ /**
668
+ * Fund the AgentAccount with any ERC-20 token from EOA.
669
+ * Simple ERC-20 transfer (does NOT require a UserOp).
670
+ *
671
+ * @param tokenSymbol - Token symbol (e.g. 'USDC', 'WETH') or 0x address
672
+ * @param amount - Amount to send (human-readable, e.g. '100')
673
+ */
674
+ async fundAccountToken(tokenSymbol, amount) {
675
+ const acctAddr = await this.getAccountAddress();
676
+ const tokenInfo = await this._resolveToken(tokenSymbol);
677
+ const tokenContract = new Contract(tokenInfo.address, ERC20_ABI, this.signer);
678
+ const weiAmount = ethers.parseUnits(amount, tokenInfo.decimals);
679
+ const eoaBalance = await tokenContract.balanceOf(await this._getSignerAddress());
680
+ if (eoaBalance < weiAmount) {
681
+ throw new AgetherError(
682
+ `Insufficient ${tokenInfo.symbol}. EOA has ${ethers.formatUnits(eoaBalance, tokenInfo.decimals)}, need ${amount}.`,
683
+ "INSUFFICIENT_BALANCE"
684
+ );
685
+ }
686
+ const tx = await tokenContract.transfer(acctAddr, weiAmount);
687
+ const receipt = await tx.wait();
688
+ this._refreshSigner();
689
+ return {
690
+ txHash: receipt.hash,
691
+ blockNumber: receipt.blockNumber,
692
+ status: receipt.status === 1 ? "success" : "failed",
693
+ gasUsed: receipt.gasUsed
694
+ };
695
+ }
696
+ /**
697
+ * Transfer any ERC-20 token from AgentAccount to any address or agent.
698
+ * Executes via Safe UserOp (ERC-7579 single execution).
699
+ *
700
+ * @param tokenSymbol - Token symbol (e.g. 'USDC', 'WETH') or 0x address
701
+ * @param amount - Amount to send (e.g. '100' or 'all')
702
+ * @param to - Destination: `{ address: '0x...' }` or `{ agentId: '42' }`
703
+ */
704
+ async transferToken(tokenSymbol, amount, to) {
705
+ const acctAddr = await this.getAccountAddress();
706
+ const tokenInfo = await this._resolveToken(tokenSymbol);
707
+ const tokenContract = new Contract(tokenInfo.address, ERC20_ABI, this.signer.provider);
708
+ let toAddr;
709
+ if (to.address) {
710
+ toAddr = to.address;
711
+ } else if (to.agentId) {
712
+ toAddr = await this.agether4337Factory.getAccount(BigInt(to.agentId));
713
+ if (toAddr === ethers.ZeroAddress) {
714
+ throw new AgetherError(`Agent ${to.agentId} has no account`, "NO_ACCOUNT");
715
+ }
716
+ } else {
717
+ throw new AgetherError("Provide address or agentId as destination", "INVALID_TARGET");
718
+ }
719
+ let weiAmount;
720
+ if (amount === "all") {
721
+ weiAmount = await tokenContract.balanceOf(acctAddr);
722
+ if (weiAmount === 0n) {
723
+ throw new AgetherError(`No ${tokenInfo.symbol} in AgentAccount`, "INSUFFICIENT_BALANCE");
724
+ }
725
+ } else {
726
+ weiAmount = ethers.parseUnits(amount, tokenInfo.decimals);
727
+ }
728
+ const data = erc20Iface.encodeFunctionData("transfer", [toAddr, weiAmount]);
729
+ const receipt = await this._exec(tokenInfo.address, data);
730
+ const actualAmount = amount === "all" ? ethers.formatUnits(weiAmount, tokenInfo.decimals) : amount;
731
+ return { tx: receipt.hash, token: tokenInfo.symbol, amount: actualAmount, destination: toAddr };
732
+ }
733
+ /**
734
+ * Transfer ETH from AgentAccount to any address or agent.
735
+ * Executes via Safe UserOp.
736
+ *
737
+ * @param amount - ETH amount (e.g. '0.01' or 'all')
738
+ * @param to - Destination: `{ address: '0x...' }` or `{ agentId: '42' }`
739
+ */
740
+ async transferEth(amount, to) {
741
+ const acctAddr = await this.getAccountAddress();
742
+ let toAddr;
743
+ if (to.address) {
744
+ toAddr = to.address;
745
+ } else if (to.agentId) {
746
+ toAddr = await this.agether4337Factory.getAccount(BigInt(to.agentId));
747
+ if (toAddr === ethers.ZeroAddress) {
748
+ throw new AgetherError(`Agent ${to.agentId} has no account`, "NO_ACCOUNT");
749
+ }
750
+ } else {
751
+ throw new AgetherError("Provide address or agentId as destination", "INVALID_TARGET");
752
+ }
753
+ let weiAmount;
754
+ if (amount === "all") {
755
+ weiAmount = await this.signer.provider.getBalance(acctAddr);
756
+ if (weiAmount === 0n) throw new AgetherError("No ETH in AgentAccount", "INSUFFICIENT_BALANCE");
757
+ } else {
758
+ weiAmount = ethers.parseEther(amount);
759
+ }
760
+ const receipt = await this._exec(toAddr, "0x", weiAmount);
761
+ const actualAmount = amount === "all" ? ethers.formatEther(weiAmount) : amount;
762
+ return { tx: receipt.hash, token: "ETH", amount: actualAmount, destination: toAddr };
763
+ }
764
+ /**
765
+ * Approve a spender to use ERC-20 tokens from the AgentAccount.
766
+ * Executes via Safe UserOp (ERC-7579 single execution).
767
+ *
768
+ * @param tokenSymbol - Token symbol (e.g. 'USDC', 'WETH') or 0x address
769
+ * @param amount - Allowance amount (e.g. '1000' or 'max' for uint256 max)
770
+ * @param spender - Spender: `{ address: '0x...' }` or `{ agentId: '42' }`
771
+ */
772
+ async approveToken(tokenSymbol, amount, spender) {
773
+ const tokenInfo = await this._resolveToken(tokenSymbol);
774
+ let spenderAddr;
775
+ if (spender.address) {
776
+ spenderAddr = spender.address;
777
+ } else if (spender.agentId) {
778
+ spenderAddr = await this.agether4337Factory.getAccount(BigInt(spender.agentId));
779
+ if (spenderAddr === ethers.ZeroAddress) {
780
+ throw new AgetherError(`Agent ${spender.agentId} has no account`, "NO_ACCOUNT");
781
+ }
782
+ } else {
783
+ throw new AgetherError("Provide address or agentId as spender", "INVALID_TARGET");
784
+ }
785
+ let weiAmount;
786
+ if (amount === "max") {
787
+ weiAmount = ethers.MaxUint256;
788
+ } else {
789
+ weiAmount = ethers.parseUnits(amount, tokenInfo.decimals);
790
+ }
791
+ const data = erc20Iface.encodeFunctionData("approve", [spenderAddr, weiAmount]);
792
+ const receipt = await this._exec(tokenInfo.address, data);
793
+ const actualAmount = amount === "max" ? "unlimited" : amount;
794
+ return { tx: receipt.hash, token: tokenInfo.symbol, amount: actualAmount, spender: spenderAddr };
795
+ }
796
+ // ════════════════════════════════════════════════════════
663
797
  // Sponsorship
664
798
  // ════════════════════════════════════════════════════════
665
799
  /**
@@ -788,14 +922,6 @@ var AgetherClient = class _AgetherClient {
788
922
  }
789
923
  return this._eoaAddress;
790
924
  }
791
- /**
792
- * Resolve a token symbol or address to { address, symbol, decimals }.
793
- *
794
- * Supports:
795
- * - `'USDC'` → from chain config
796
- * - Well-known symbols (`'WETH'`, `'wstETH'`, `'cbETH'`) → built-in per-chain registry
797
- * - `'0x...'` address → reads decimals and symbol onchain
798
- */
799
925
  async _resolveToken(symbolOrAddress) {
800
926
  if (symbolOrAddress.toUpperCase() === "USDC") {
801
927
  return { address: this.config.contracts.usdc, symbol: "USDC", decimals: 6 };
@@ -803,6 +929,9 @@ var AgetherClient = class _AgetherClient {
803
929
  const chainTokens = KNOWN_TOKENS[this.config.chainId] ?? {};
804
930
  const bySymbol = chainTokens[symbolOrAddress] || chainTokens[symbolOrAddress.toUpperCase()];
805
931
  if (bySymbol) return bySymbol;
932
+ const cacheKey = symbolOrAddress.startsWith("0x") ? symbolOrAddress.toLowerCase() : symbolOrAddress.toUpperCase();
933
+ const cached = this._dynamicTokenCache.get(cacheKey);
934
+ if (cached) return cached;
806
935
  if (symbolOrAddress.startsWith("0x") && symbolOrAddress.length === 42) {
807
936
  try {
808
937
  const token = new Contract(
@@ -811,7 +940,10 @@ var AgetherClient = class _AgetherClient {
811
940
  this.signer.provider
812
941
  );
813
942
  const [decimals, symbol] = await Promise.all([token.decimals(), token.symbol()]);
814
- return { address: symbolOrAddress, symbol, decimals: Number(decimals) };
943
+ const info = { address: symbolOrAddress, symbol, decimals: Number(decimals) };
944
+ this._dynamicTokenCache.set(symbolOrAddress.toLowerCase(), info);
945
+ this._dynamicTokenCache.set(symbol.toUpperCase(), info);
946
+ return info;
815
947
  } catch (e) {
816
948
  throw new AgetherError(
817
949
  `Failed to read token at ${symbolOrAddress}: ${e instanceof Error ? e.message : e}`,
@@ -819,8 +951,53 @@ var AgetherClient = class _AgetherClient {
819
951
  );
820
952
  }
821
953
  }
954
+ try {
955
+ const chainId = this.config.chainId;
956
+ const query = `{
957
+ markets(
958
+ first: 20
959
+ where: { chainId_in: [${chainId}], search: "${symbolOrAddress}" }
960
+ ) {
961
+ items {
962
+ loanAsset { address symbol decimals }
963
+ collateralAsset { address symbol decimals }
964
+ }
965
+ }
966
+ }`;
967
+ const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
968
+ const items = resp.data?.data?.markets?.items ?? [];
969
+ const sym = symbolOrAddress.toUpperCase();
970
+ for (const m of items) {
971
+ if (m.loanAsset?.symbol?.toUpperCase() === sym) {
972
+ const info = { address: m.loanAsset.address, symbol: m.loanAsset.symbol, decimals: m.loanAsset.decimals };
973
+ this._dynamicTokenCache.set(sym, info);
974
+ this._dynamicTokenCache.set(m.loanAsset.address.toLowerCase(), info);
975
+ return info;
976
+ }
977
+ if (m.collateralAsset?.symbol?.toUpperCase() === sym) {
978
+ const info = { address: m.collateralAsset.address, symbol: m.collateralAsset.symbol, decimals: m.collateralAsset.decimals };
979
+ this._dynamicTokenCache.set(sym, info);
980
+ this._dynamicTokenCache.set(m.collateralAsset.address.toLowerCase(), info);
981
+ return info;
982
+ }
983
+ }
984
+ for (const m of items) {
985
+ if (m.loanAsset?.symbol) {
986
+ const info = { address: m.loanAsset.address, symbol: m.loanAsset.symbol, decimals: m.loanAsset.decimals };
987
+ this._dynamicTokenCache.set(m.loanAsset.symbol.toUpperCase(), info);
988
+ this._dynamicTokenCache.set(m.loanAsset.address.toLowerCase(), info);
989
+ }
990
+ if (m.collateralAsset?.symbol) {
991
+ const info = { address: m.collateralAsset.address, symbol: m.collateralAsset.symbol, decimals: m.collateralAsset.decimals };
992
+ this._dynamicTokenCache.set(m.collateralAsset.symbol.toUpperCase(), info);
993
+ this._dynamicTokenCache.set(m.collateralAsset.address.toLowerCase(), info);
994
+ }
995
+ }
996
+ } catch (e) {
997
+ console.warn("[agether] Morpho token search failed:", e instanceof Error ? e.message : e);
998
+ }
822
999
  throw new AgetherError(
823
- `Unknown token: ${symbolOrAddress}. Use a known symbol (USDC, WETH, wstETH, cbETH) or a 0x address.`,
1000
+ `Unknown token: ${symbolOrAddress}. No Morpho market found with this token.`,
824
1001
  "UNKNOWN_TOKEN"
825
1002
  );
826
1003
  }
@@ -954,8 +1131,8 @@ var AgetherClient = class _AgetherClient {
954
1131
 
955
1132
  // src/clients/MorphoClient.ts
956
1133
  import { ethers as ethers2, Contract as Contract2 } from "ethers";
957
- import axios from "axios";
958
- var MORPHO_API_URL = "https://api.morpho.org/graphql";
1134
+ import axios2 from "axios";
1135
+ var MORPHO_API_URL2 = "https://api.morpho.org/graphql";
959
1136
  var MODE_SINGLE2 = "0x0000000000000000000000000000000000000000000000000000000000000000";
960
1137
  var MODE_BATCH = "0x0100000000000000000000000000000000000000000000000000000000000000";
961
1138
  var morphoIface = new ethers2.Interface(MORPHO_BLUE_ABI);
@@ -1101,7 +1278,7 @@ var MorphoClient = class {
1101
1278
  }
1102
1279
  }`;
1103
1280
  try {
1104
- const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
1281
+ const resp = await axios2.post(MORPHO_API_URL2, { query }, { timeout: 1e4 });
1105
1282
  const items = resp.data?.data?.markets?.items ?? [];
1106
1283
  this._discoveredMarkets = items.map((m) => ({
1107
1284
  uniqueKey: m.uniqueKey,
@@ -1186,7 +1363,7 @@ var MorphoClient = class {
1186
1363
  const resolved = await this._resolveToken(loanTokenSymbolOrAddress);
1187
1364
  loanAddr = resolved.address.toLowerCase();
1188
1365
  } catch {
1189
- loanAddr = loanTokenSymbolOrAddress.toLowerCase();
1366
+ loanAddr = void 0;
1190
1367
  }
1191
1368
  }
1192
1369
  }
@@ -1194,6 +1371,7 @@ var MorphoClient = class {
1194
1371
  for (const m of this._discoveredMarkets ?? []) {
1195
1372
  if (m.collateralAsset.address.toLowerCase() !== colAddr) continue;
1196
1373
  if (loanAddr && m.loanAsset.address.toLowerCase() !== loanAddr) continue;
1374
+ if (!loanAddr && loanTokenSymbolOrAddress && m.loanAsset.symbol.toUpperCase() !== loanTokenSymbolOrAddress.toUpperCase()) continue;
1197
1375
  return {
1198
1376
  loanToken: m.loanAsset.address,
1199
1377
  collateralToken: m.collateralAsset.address,
@@ -1204,9 +1382,22 @@ var MorphoClient = class {
1204
1382
  }
1205
1383
  if (!collateralSymbolOrAddress.startsWith("0x")) {
1206
1384
  const searched = await this.searchMarkets(collateralSymbolOrAddress, { asCollateral: true });
1207
- for (const m of searched) {
1385
+ const allResults = [...searched];
1386
+ if (loanTokenSymbolOrAddress && !loanTokenSymbolOrAddress.startsWith("0x")) {
1387
+ const loanSearched = await this.searchMarkets(loanTokenSymbolOrAddress, { asLoanToken: true });
1388
+ const seen = new Set(allResults.map((r) => r.marketId));
1389
+ for (const m of loanSearched) {
1390
+ if (!seen.has(m.marketId)) allResults.push(m);
1391
+ }
1392
+ }
1393
+ for (const m of allResults) {
1394
+ if (colAddr.startsWith("0x") && m.collateralAddress.toLowerCase() !== colAddr) {
1395
+ if (m.collateralToken.toUpperCase() !== collateralSymbolOrAddress.toUpperCase()) continue;
1396
+ } else if (m.collateralToken.toUpperCase() !== collateralSymbolOrAddress.toUpperCase()) {
1397
+ continue;
1398
+ }
1208
1399
  if (loanAddr && m.loanAddress.toLowerCase() !== loanAddr) continue;
1209
- if (loanTokenSymbolOrAddress && !loanTokenSymbolOrAddress.startsWith("0x") && m.loanToken.toUpperCase() !== loanTokenSymbolOrAddress.toUpperCase()) continue;
1400
+ if (!loanAddr && loanTokenSymbolOrAddress && m.loanToken.toUpperCase() !== loanTokenSymbolOrAddress.toUpperCase()) continue;
1210
1401
  return this.getMarketParams(m.marketId);
1211
1402
  }
1212
1403
  }
@@ -1240,26 +1431,54 @@ var MorphoClient = class {
1240
1431
  };
1241
1432
  }
1242
1433
  /**
1243
- * Full status: positions across all discovered markets.
1434
+ * Full status: positions across all markets the user has interacted with.
1435
+ *
1436
+ * Uses Morpho GraphQL `marketPositions` to find ALL positions (not limited
1437
+ * to the top-500 markets), then reads onchain data for accurate debt.
1244
1438
  */
1245
1439
  async getStatus() {
1246
1440
  const acctAddr = await this.getAccountAddress();
1247
- const markets = await this.getMarkets();
1441
+ const chainId = this.config.chainId;
1248
1442
  const positions = [];
1249
1443
  let totalDebtFloat = 0;
1250
- for (const m of markets) {
1251
- if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
1252
- try {
1253
- const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
1254
- if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
1444
+ try {
1445
+ const posQuery = `{
1446
+ marketPositions(
1447
+ where: {
1448
+ userAddress_in: ["${acctAddr}"]
1449
+ chainId_in: [${chainId}]
1450
+ }
1451
+ first: 100
1452
+ ) {
1453
+ items {
1454
+ supplyShares
1455
+ borrowShares
1456
+ collateral
1457
+ market {
1458
+ uniqueKey
1459
+ loanAsset { symbol address decimals }
1460
+ collateralAsset { symbol address decimals }
1461
+ }
1462
+ }
1463
+ }
1464
+ }`;
1465
+ const resp = await axios2.post(MORPHO_API_URL2, { query: posQuery }, { timeout: 15e3 });
1466
+ const items = resp.data?.data?.marketPositions?.items ?? [];
1467
+ for (const item of items) {
1468
+ const supplyShares = BigInt(item.supplyShares ?? "0");
1469
+ const borrowShares = BigInt(item.borrowShares ?? "0");
1470
+ const collateral = BigInt(item.collateral ?? "0");
1471
+ if (collateral === 0n && borrowShares === 0n && supplyShares === 0n) continue;
1472
+ const m = item.market;
1473
+ if (!m?.collateralAsset || !m?.loanAsset) continue;
1255
1474
  const loanDecimals = m.loanAsset.decimals;
1256
1475
  let debt = 0n;
1257
- if (pos.borrowShares > 0n) {
1476
+ if (borrowShares > 0n) {
1258
1477
  try {
1259
1478
  const mkt = await this.morphoBlue.market(m.uniqueKey);
1260
1479
  const totalBorrowShares = BigInt(mkt.totalBorrowShares);
1261
1480
  const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
1262
- debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1481
+ debt = totalBorrowShares > 0n ? (borrowShares * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1263
1482
  totalDebtFloat += parseFloat(ethers2.formatUnits(debt, loanDecimals));
1264
1483
  } catch (e) {
1265
1484
  console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
@@ -1269,14 +1488,46 @@ var MorphoClient = class {
1269
1488
  marketId: m.uniqueKey,
1270
1489
  collateralToken: m.collateralAsset.symbol,
1271
1490
  loanToken: m.loanAsset.symbol,
1272
- collateral: ethers2.formatUnits(pos.collateral, m.collateralAsset.decimals),
1273
- borrowShares: pos.borrowShares.toString(),
1274
- supplyShares: pos.supplyShares.toString(),
1491
+ collateral: ethers2.formatUnits(collateral, m.collateralAsset.decimals),
1492
+ borrowShares: borrowShares.toString(),
1493
+ supplyShares: supplyShares.toString(),
1275
1494
  debt: ethers2.formatUnits(debt, loanDecimals)
1276
1495
  });
1277
- } catch (e) {
1278
- console.warn(`[agether] position read failed for market:`, e instanceof Error ? e.message : e);
1279
- continue;
1496
+ }
1497
+ } catch (e) {
1498
+ console.warn("[agether] marketPositions API failed, falling back to market scan:", e instanceof Error ? e.message : e);
1499
+ const markets = await this.getMarkets();
1500
+ for (const m of markets) {
1501
+ if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
1502
+ try {
1503
+ const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
1504
+ if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
1505
+ const loanDecimals = m.loanAsset.decimals;
1506
+ let debt = 0n;
1507
+ if (pos.borrowShares > 0n) {
1508
+ try {
1509
+ const mkt = await this.morphoBlue.market(m.uniqueKey);
1510
+ const totalBorrowShares = BigInt(mkt.totalBorrowShares);
1511
+ const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
1512
+ debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1513
+ totalDebtFloat += parseFloat(ethers2.formatUnits(debt, loanDecimals));
1514
+ } catch (e2) {
1515
+ console.warn(`[agether] debt calc failed:`, e2 instanceof Error ? e2.message : e2);
1516
+ }
1517
+ }
1518
+ positions.push({
1519
+ marketId: m.uniqueKey,
1520
+ collateralToken: m.collateralAsset.symbol,
1521
+ loanToken: m.loanAsset.symbol,
1522
+ collateral: ethers2.formatUnits(pos.collateral, m.collateralAsset.decimals),
1523
+ borrowShares: pos.borrowShares.toString(),
1524
+ supplyShares: pos.supplyShares.toString(),
1525
+ debt: ethers2.formatUnits(debt, loanDecimals)
1526
+ });
1527
+ } catch (e2) {
1528
+ console.warn(`[agether] position read failed:`, e2 instanceof Error ? e2.message : e2);
1529
+ continue;
1530
+ }
1280
1531
  }
1281
1532
  }
1282
1533
  return {
@@ -1430,7 +1681,7 @@ var MorphoClient = class {
1430
1681
  }
1431
1682
  }`;
1432
1683
  try {
1433
- const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
1684
+ const resp = await axios2.post(MORPHO_API_URL2, { query }, { timeout: 1e4 });
1434
1685
  let items = resp.data?.data?.markets?.items ?? [];
1435
1686
  if (searchTerm && collateralSymbolOrAddress && !collateralSymbolOrAddress.startsWith("0x")) {
1436
1687
  const sym = collateralSymbolOrAddress.toUpperCase();
@@ -1496,7 +1747,7 @@ var MorphoClient = class {
1496
1747
  }
1497
1748
  }`;
1498
1749
  try {
1499
- const resp = await axios.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
1750
+ const resp = await axios2.post(MORPHO_API_URL2, { query }, { timeout: 1e4 });
1500
1751
  let items = resp.data?.data?.markets?.items ?? [];
1501
1752
  items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== ethers2.ZeroAddress);
1502
1753
  const searchUpper = search.toUpperCase();
@@ -1889,7 +2140,7 @@ var MorphoClient = class {
1889
2140
  }
1890
2141
  }
1891
2142
  }`;
1892
- const posResp = await axios.post(MORPHO_API_URL, { query: positionsQuery }, { timeout: 15e3 });
2143
+ const posResp = await axios2.post(MORPHO_API_URL2, { query: positionsQuery }, { timeout: 15e3 });
1893
2144
  const user = posResp.data?.data?.userByAddress;
1894
2145
  if (!user?.marketPositions) return [];
1895
2146
  const activePositions = user.marketPositions.filter(
@@ -2563,6 +2814,46 @@ var MorphoClient = class {
2563
2814
  /** Find the first market where the agent has collateral deposited. */
2564
2815
  async _findActiveMarket() {
2565
2816
  const acctAddr = await this.getAccountAddress();
2817
+ const chainId = this.config.chainId;
2818
+ try {
2819
+ const posQuery = `{
2820
+ marketPositions(
2821
+ where: { userAddress_in: ["${acctAddr}"], chainId_in: [${chainId}] }
2822
+ first: 50
2823
+ ) {
2824
+ items {
2825
+ collateral
2826
+ market {
2827
+ uniqueKey
2828
+ oracleAddress
2829
+ irmAddress
2830
+ lltv
2831
+ loanAsset { address symbol decimals }
2832
+ collateralAsset { address symbol decimals }
2833
+ }
2834
+ }
2835
+ }
2836
+ }`;
2837
+ const resp = await axios2.post(MORPHO_API_URL2, { query: posQuery }, { timeout: 1e4 });
2838
+ const items = resp.data?.data?.marketPositions?.items ?? [];
2839
+ for (const item of items) {
2840
+ if (BigInt(item.collateral ?? "0") > 0n && item.market?.collateralAsset) {
2841
+ const m = item.market;
2842
+ return {
2843
+ params: {
2844
+ loanToken: m.loanAsset.address,
2845
+ collateralToken: m.collateralAsset.address,
2846
+ oracle: m.oracleAddress,
2847
+ irm: m.irmAddress,
2848
+ lltv: BigInt(m.lltv)
2849
+ },
2850
+ symbol: m.collateralAsset.symbol
2851
+ };
2852
+ }
2853
+ }
2854
+ } catch (e) {
2855
+ console.warn("[agether] _findActiveMarket GraphQL failed, falling back:", e instanceof Error ? e.message : e);
2856
+ }
2566
2857
  const markets = await this.getMarkets();
2567
2858
  for (const m of markets) {
2568
2859
  if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
@@ -2591,6 +2882,46 @@ var MorphoClient = class {
2591
2882
  /** Find the first market where the agent has a supply (lending) position. */
2592
2883
  async _findActiveSupplyMarket() {
2593
2884
  const acctAddr = await this.getAccountAddress();
2885
+ const chainId = this.config.chainId;
2886
+ try {
2887
+ const posQuery = `{
2888
+ marketPositions(
2889
+ where: { userAddress_in: ["${acctAddr}"], chainId_in: [${chainId}] }
2890
+ first: 50
2891
+ ) {
2892
+ items {
2893
+ supplyShares
2894
+ market {
2895
+ uniqueKey
2896
+ oracleAddress
2897
+ irmAddress
2898
+ lltv
2899
+ loanAsset { address symbol decimals }
2900
+ collateralAsset { address symbol decimals }
2901
+ }
2902
+ }
2903
+ }
2904
+ }`;
2905
+ const resp = await axios2.post(MORPHO_API_URL2, { query: posQuery }, { timeout: 1e4 });
2906
+ const items = resp.data?.data?.marketPositions?.items ?? [];
2907
+ for (const item of items) {
2908
+ if (BigInt(item.supplyShares ?? "0") > 0n && item.market?.collateralAsset) {
2909
+ const m = item.market;
2910
+ return {
2911
+ params: {
2912
+ loanToken: m.loanAsset.address,
2913
+ collateralToken: m.collateralAsset.address,
2914
+ oracle: m.oracleAddress,
2915
+ irm: m.irmAddress,
2916
+ lltv: BigInt(m.lltv)
2917
+ },
2918
+ symbol: m.collateralAsset.symbol
2919
+ };
2920
+ }
2921
+ }
2922
+ } catch (e) {
2923
+ console.warn("[agether] _findActiveSupplyMarket GraphQL failed, falling back:", e instanceof Error ? e.message : e);
2924
+ }
2594
2925
  const markets = await this.getMarkets();
2595
2926
  for (const m of markets) {
2596
2927
  if (!m.collateralAsset || m.collateralAsset.address === ethers2.ZeroAddress) continue;
@@ -2723,7 +3054,7 @@ var MorphoClient = class {
2723
3054
  }
2724
3055
  }
2725
3056
  }`;
2726
- const resp = await axios.post(MORPHO_API_URL, { query: txQuery }, { timeout: 15e3 });
3057
+ const resp = await axios2.post(MORPHO_API_URL2, { query: txQuery }, { timeout: 15e3 });
2727
3058
  const txData = resp.data?.data?.transactions;
2728
3059
  if (!txData?.items) break;
2729
3060
  for (const tx of txData.items) {
@@ -2748,7 +3079,7 @@ var MorphoClient = class {
2748
3079
  };
2749
3080
 
2750
3081
  // src/clients/ScoringClient.ts
2751
- import axios2 from "axios";
3082
+ import axios3 from "axios";
2752
3083
 
2753
3084
  // src/clients/X402Client.ts
2754
3085
  import { wrapFetchWithPayment } from "@x402/fetch";
@@ -3110,7 +3441,7 @@ var ScoringClient = class {
3110
3441
  constructor(config) {
3111
3442
  this.endpoint = config.endpoint;
3112
3443
  this.defaultChainId = config.chainId;
3113
- this.client = axios2.create({
3444
+ this.client = axios3.create({
3114
3445
  baseURL: config.endpoint,
3115
3446
  headers: { "Content-Type": "application/json" },
3116
3447
  timeout: 3e4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agether/sdk",
3
- "version": "2.14.0",
3
+ "version": "2.15.0",
4
4
  "description": "TypeScript SDK for Agether - autonomous credit for AI agents on Ethereum & Base",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",