@agether/sdk 2.12.1 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -58,6 +58,7 @@ var init_abis = __esm({
58
58
  "function exists(uint256 agentId) view returns (bool)",
59
59
  "function register() returns (uint256 agentId)",
60
60
  "function register(string agentURI) returns (uint256 agentId)",
61
+ "function setAgentURI(uint256 agentId, string newURI)",
61
62
  "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)"
62
63
  ];
63
64
  AGETHER_4337_FACTORY_ABI = [
@@ -289,8 +290,9 @@ var init_MorphoClient = __esm({
289
290
  erc20Iface = new import_ethers.ethers.Interface(ERC20_ABI);
290
291
  MorphoClient = class {
291
292
  constructor(config) {
293
+ /** Market params cache: keyed by market uniqueKey (bytes32 hash) */
292
294
  this._marketCache = /* @__PURE__ */ new Map();
293
- /** Dynamic token registry: symbol (uppercase) → { address, symbol, decimals } */
295
+ /** Dynamic token registry: symbol (uppercase) or address (lowercase) → { address, symbol, decimals } */
294
296
  this._tokenCache = /* @__PURE__ */ new Map();
295
297
  this._discoveredAt = 0;
296
298
  if (!config.agentId) {
@@ -393,21 +395,23 @@ var init_MorphoClient = __esm({
393
395
  // Market Discovery (Morpho GraphQL API)
394
396
  // ════════════════════════════════════════════════════════
395
397
  /**
396
- * Fetch USDC borrow markets on Base from Morpho API.
397
- * Caches results for 5 minutes.
398
+ * Fetch available markets on the current chain from Morpho API.
399
+ * Caches results for 5 minutes. Supports all loan tokens (not just USDC).
400
+ *
401
+ * @param forceRefresh - bypass cache TTL
402
+ * @param filter - optional filter by loan token and/or collateral token
398
403
  */
399
- async getMarkets(forceRefresh = false) {
404
+ async getMarkets(forceRefresh = false, filter) {
400
405
  if (!forceRefresh && this._discoveredMarkets && Date.now() - this._discoveredAt < 3e5) {
401
- return this._discoveredMarkets;
406
+ return filter ? this._applyMarketFilter(this._discoveredMarkets, filter) : this._discoveredMarkets;
402
407
  }
403
408
  const chainId = this.config.chainId;
404
- const usdcAddr = this.config.contracts.usdc.toLowerCase();
405
409
  const query = `{
406
410
  markets(
407
411
  first: 50
408
412
  orderBy: SupplyAssetsUsd
409
413
  orderDirection: Desc
410
- where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"] }
414
+ where: { chainId_in: [${chainId}] }
411
415
  ) {
412
416
  items {
413
417
  uniqueKey
@@ -440,14 +444,14 @@ var init_MorphoClient = __esm({
440
444
  }));
441
445
  this._discoveredAt = Date.now();
442
446
  for (const mi of this._discoveredMarkets) {
447
+ this._marketCache.set(mi.uniqueKey.toLowerCase(), {
448
+ loanToken: mi.loanAsset.address,
449
+ collateralToken: mi.collateralAsset.address,
450
+ oracle: mi.oracle,
451
+ irm: mi.irm,
452
+ lltv: mi.lltv
453
+ });
443
454
  if (mi.collateralAsset.address !== import_ethers.ethers.ZeroAddress) {
444
- this._marketCache.set(mi.collateralAsset.address.toLowerCase(), {
445
- loanToken: mi.loanAsset.address,
446
- collateralToken: mi.collateralAsset.address,
447
- oracle: mi.oracle,
448
- irm: mi.irm,
449
- lltv: mi.lltv
450
- });
451
455
  this._tokenCache.set(mi.collateralAsset.symbol.toUpperCase(), {
452
456
  address: mi.collateralAsset.address,
453
457
  symbol: mi.collateralAsset.symbol,
@@ -472,17 +476,24 @@ var init_MorphoClient = __esm({
472
476
  });
473
477
  }
474
478
  }
475
- return this._discoveredMarkets;
479
+ return filter ? this._applyMarketFilter(this._discoveredMarkets, filter) : this._discoveredMarkets;
476
480
  } catch (e) {
477
481
  console.warn("[agether] getMarkets failed, using cache:", e instanceof Error ? e.message : e);
478
- return this._discoveredMarkets ?? [];
482
+ const cached = this._discoveredMarkets ?? [];
483
+ return filter ? this._applyMarketFilter(cached, filter) : cached;
479
484
  }
480
485
  }
481
486
  /**
482
- * Get MarketParams for a collateral token.
483
- * Tries cache → API → onchain idToMarketParams.
487
+ * Get MarketParams for a collateral token (and optionally a specific loan token).
488
+ * Tries cache → API discovery.
489
+ *
490
+ * When `loanTokenSymbolOrAddress` is omitted, returns the most liquid market
491
+ * for that collateral (sorted by supply, typically the USDC market).
492
+ *
493
+ * @param collateralSymbolOrAddress - e.g. 'WETH', 'wstETH', or '0x4200...'
494
+ * @param loanTokenSymbolOrAddress - e.g. 'USDC', 'WETH', or '0x833589...' (optional)
484
495
  */
485
- async findMarketForCollateral(collateralSymbolOrAddress) {
496
+ async findMarketForCollateral(collateralSymbolOrAddress, loanTokenSymbolOrAddress) {
486
497
  let colAddr;
487
498
  if (collateralSymbolOrAddress.startsWith("0x")) {
488
499
  colAddr = collateralSymbolOrAddress.toLowerCase();
@@ -494,13 +505,33 @@ var init_MorphoClient = __esm({
494
505
  colAddr = collateralSymbolOrAddress.toLowerCase();
495
506
  }
496
507
  }
497
- const cached = this._marketCache.get(colAddr);
498
- if (cached) return cached;
499
- await this.getMarkets();
500
- const fromApi = this._marketCache.get(colAddr);
501
- if (fromApi) return fromApi;
508
+ let loanAddr;
509
+ if (loanTokenSymbolOrAddress) {
510
+ if (loanTokenSymbolOrAddress.startsWith("0x")) {
511
+ loanAddr = loanTokenSymbolOrAddress.toLowerCase();
512
+ } else {
513
+ try {
514
+ const resolved = await this._resolveToken(loanTokenSymbolOrAddress);
515
+ loanAddr = resolved.address.toLowerCase();
516
+ } catch {
517
+ loanAddr = loanTokenSymbolOrAddress.toLowerCase();
518
+ }
519
+ }
520
+ }
521
+ if (!this._discoveredMarkets) await this.getMarkets();
522
+ for (const m of this._discoveredMarkets ?? []) {
523
+ if (m.collateralAsset.address.toLowerCase() !== colAddr) continue;
524
+ if (loanAddr && m.loanAsset.address.toLowerCase() !== loanAddr) continue;
525
+ return {
526
+ loanToken: m.loanAsset.address,
527
+ collateralToken: m.collateralAsset.address,
528
+ oracle: m.oracle,
529
+ irm: m.irm,
530
+ lltv: m.lltv
531
+ };
532
+ }
502
533
  throw new AgetherError(
503
- `No Morpho market found for collateral ${collateralSymbolOrAddress}`,
534
+ `No Morpho market found for collateral ${collateralSymbolOrAddress}` + (loanTokenSymbolOrAddress ? ` with loan token ${loanTokenSymbolOrAddress}` : ""),
504
535
  "MARKET_NOT_FOUND"
505
536
  );
506
537
  }
@@ -535,12 +566,13 @@ var init_MorphoClient = __esm({
535
566
  const acctAddr = await this.getAccountAddress();
536
567
  const markets = await this.getMarkets();
537
568
  const positions = [];
538
- let totalDebt = 0n;
569
+ let totalDebtFloat = 0;
539
570
  for (const m of markets) {
540
571
  if (!m.collateralAsset || m.collateralAsset.address === import_ethers.ethers.ZeroAddress) continue;
541
572
  try {
542
573
  const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
543
574
  if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
575
+ const loanDecimals = m.loanAsset.decimals;
544
576
  let debt = 0n;
545
577
  if (pos.borrowShares > 0n) {
546
578
  try {
@@ -548,7 +580,7 @@ var init_MorphoClient = __esm({
548
580
  const totalBorrowShares = BigInt(mkt.totalBorrowShares);
549
581
  const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
550
582
  debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
551
- totalDebt += debt;
583
+ totalDebtFloat += parseFloat(import_ethers.ethers.formatUnits(debt, loanDecimals));
552
584
  } catch (e) {
553
585
  console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
554
586
  }
@@ -556,10 +588,11 @@ var init_MorphoClient = __esm({
556
588
  positions.push({
557
589
  marketId: m.uniqueKey,
558
590
  collateralToken: m.collateralAsset.symbol,
591
+ loanToken: m.loanAsset.symbol,
559
592
  collateral: import_ethers.ethers.formatUnits(pos.collateral, m.collateralAsset.decimals),
560
593
  borrowShares: pos.borrowShares.toString(),
561
594
  supplyShares: pos.supplyShares.toString(),
562
- debt: import_ethers.ethers.formatUnits(debt, 6)
595
+ debt: import_ethers.ethers.formatUnits(debt, loanDecimals)
563
596
  });
564
597
  } catch (e) {
565
598
  console.warn(`[agether] position read failed for market:`, e instanceof Error ? e.message : e);
@@ -569,16 +602,28 @@ var init_MorphoClient = __esm({
569
602
  return {
570
603
  agentId: this.agentId,
571
604
  agentAccount: acctAddr,
572
- totalDebt: import_ethers.ethers.formatUnits(totalDebt, 6),
605
+ totalDebt: totalDebtFloat.toFixed(6),
573
606
  positions
574
607
  };
575
608
  }
576
609
  // ════════════════════════════════════════════════════════
577
610
  // Balance & Borrowing Capacity
578
611
  // ════════════════════════════════════════════════════════
612
+ /**
613
+ * Get the balance of any ERC-20 token in the AgentAccount.
614
+ * @param symbolOrAddress - token symbol (e.g. 'USDC', 'WETH') or address
615
+ * @returns balance in raw units
616
+ */
617
+ async getTokenBalance(symbolOrAddress) {
618
+ const acctAddr = await this.getAccountAddress();
619
+ const tokenInfo = await this._resolveToken(symbolOrAddress);
620
+ const token = new import_ethers.Contract(tokenInfo.address, ERC20_ABI, this.provider);
621
+ return token.balanceOf(acctAddr);
622
+ }
579
623
  /**
580
624
  * Get the USDC balance of the AgentAccount.
581
625
  * @returns USDC balance in raw units (6 decimals)
626
+ * @deprecated Use `getTokenBalance('USDC')` instead.
582
627
  */
583
628
  async getUsdcBalance() {
584
629
  const acctAddr = await this.getAccountAddress();
@@ -586,7 +631,7 @@ var init_MorphoClient = __esm({
586
631
  return usdc.balanceOf(acctAddr);
587
632
  }
588
633
  /**
589
- * Calculate the maximum additional USDC that can be borrowed
634
+ * Calculate the maximum additional loan token that can be borrowed
590
635
  * given the agent's current collateral and debt across all markets.
591
636
  *
592
637
  * For each market with collateral deposited:
@@ -594,7 +639,7 @@ var init_MorphoClient = __esm({
594
639
  *
595
640
  * Uses the Morpho oracle to price collateral → loan token.
596
641
  *
597
- * @returns Maximum additional USDC borrowable (6 decimals)
642
+ * @returns Maximum additional borrowable per market (raw units in each market's loan token)
598
643
  */
599
644
  async getMaxBorrowable() {
600
645
  const acctAddr = await this.getAccountAddress();
@@ -627,6 +672,8 @@ var init_MorphoClient = __esm({
627
672
  totalAdditional += maxAdditional;
628
673
  byMarket.push({
629
674
  collateralToken: m.collateralAsset.symbol,
675
+ loanToken: m.loanAsset.symbol,
676
+ loanDecimals: m.loanAsset.decimals,
630
677
  maxAdditional,
631
678
  currentDebt,
632
679
  collateralValue: collateralValueInLoan
@@ -642,14 +689,16 @@ var init_MorphoClient = __esm({
642
689
  // Market Rates & Yield Estimation
643
690
  // ════════════════════════════════════════════════════════
644
691
  /**
645
- * Fetch current supply/borrow APY for a collateral market from Morpho GraphQL API.
692
+ * Fetch current supply/borrow APY for markets from Morpho GraphQL API.
646
693
  *
647
694
  * Note: On Morpho Blue, collateral does NOT earn yield directly. Supply APY
648
695
  * is what lenders earn; borrow APY is what borrowers pay.
696
+ *
697
+ * @param collateralSymbolOrAddress - filter by collateral token (optional)
698
+ * @param loanTokenSymbolOrAddress - filter by loan token (optional). Omit for all loan tokens.
649
699
  */
650
- async getMarketRates(collateralSymbolOrAddress) {
700
+ async getMarketRates(collateralSymbolOrAddress, loanTokenSymbolOrAddress) {
651
701
  const chainId = this.config.chainId;
652
- const usdcAddr = this.config.contracts.usdc.toLowerCase();
653
702
  let collateralFilter = "";
654
703
  if (collateralSymbolOrAddress) {
655
704
  let colAddr;
@@ -665,12 +714,27 @@ var init_MorphoClient = __esm({
665
714
  }
666
715
  collateralFilter = `, collateralAssetAddress_in: ["${colAddr}"]`;
667
716
  }
717
+ let loanFilter = "";
718
+ if (loanTokenSymbolOrAddress) {
719
+ let loanAddr;
720
+ if (loanTokenSymbolOrAddress.startsWith("0x")) {
721
+ loanAddr = loanTokenSymbolOrAddress.toLowerCase();
722
+ } else {
723
+ try {
724
+ const resolved = await this._resolveToken(loanTokenSymbolOrAddress);
725
+ loanAddr = resolved.address.toLowerCase();
726
+ } catch {
727
+ loanAddr = loanTokenSymbolOrAddress.toLowerCase();
728
+ }
729
+ }
730
+ loanFilter = `, loanAssetAddress_in: ["${loanAddr}"]`;
731
+ }
668
732
  const query = `{
669
733
  markets(
670
734
  first: 50
671
735
  orderBy: SupplyAssetsUsd
672
736
  orderDirection: Desc
673
- where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"]${collateralFilter} }
737
+ where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter} }
674
738
  ) {
675
739
  items {
676
740
  uniqueKey
@@ -690,17 +754,21 @@ var init_MorphoClient = __esm({
690
754
  try {
691
755
  const resp = await import_axios.default.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
692
756
  const items = resp.data?.data?.markets?.items ?? [];
693
- return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers.ethers.ZeroAddress).map((m) => ({
694
- collateralToken: m.collateralAsset.symbol,
695
- loanToken: m.loanAsset.symbol,
696
- supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
697
- borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
698
- utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
699
- totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 1e6 : 0,
700
- totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 1e6 : 0,
701
- lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
702
- marketId: m.uniqueKey
703
- }));
757
+ return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers.ethers.ZeroAddress).map((m) => {
758
+ const loanDecimals = m.loanAsset?.decimals ?? 18;
759
+ return {
760
+ collateralToken: m.collateralAsset.symbol,
761
+ loanToken: m.loanAsset.symbol,
762
+ loanDecimals,
763
+ supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
764
+ borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
765
+ utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
766
+ totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
767
+ totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
768
+ lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
769
+ marketId: m.uniqueKey
770
+ };
771
+ });
704
772
  } catch (e) {
705
773
  console.warn("[agether] getMarketRates failed:", e instanceof Error ? e.message : e);
706
774
  return [];
@@ -734,14 +802,15 @@ var init_MorphoClient = __esm({
734
802
  } else {
735
803
  try {
736
804
  const params = await this.findMarketForCollateral(collateralSymbol);
805
+ const loanDecimals = await this._getLoanTokenDecimals(params);
737
806
  const oracleContract = new import_ethers.Contract(params.oracle, [
738
807
  "function price() view returns (uint256)"
739
808
  ], this.provider);
740
809
  const oraclePrice = await oracleContract.price();
741
810
  const ORACLE_PRICE_SCALE = 10n ** 36n;
742
811
  const amountWei = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
743
- const valueInUsdc = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
744
- collateralValueUsd = Number(valueInUsdc) / 1e6;
812
+ const valueInLoan = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
813
+ collateralValueUsd = Number(valueInLoan) / 10 ** loanDecimals;
745
814
  } catch (e) {
746
815
  console.warn("[agether] oracle price fetch for yield estimation failed:", e instanceof Error ? e.message : e);
747
816
  throw new AgetherError("Cannot determine collateral value. Provide ethPriceUsd.", "PRICE_UNAVAILABLE");
@@ -762,61 +831,65 @@ var init_MorphoClient = __esm({
762
831
  // Supply-Side (Lending) — earn yield by supplying USDC
763
832
  // ════════════════════════════════════════════════════════
764
833
  /**
765
- * Supply USDC to a Morpho Blue market as a lender (earn yield).
834
+ * Supply loan token to a Morpho Blue market as a lender (earn yield).
766
835
  *
767
836
  * Unlike `supplyCollateral` (borrower-side), this is the **lender-side**:
768
- * you deposit the loanToken (USDC) into the market's supply pool and earn
837
+ * you deposit the loanToken into the market's supply pool and earn
769
838
  * interest paid by borrowers.
770
839
  *
771
- * @param usdcAmount - Amount of USDC to supply (e.g. '500')
840
+ * @param amount - Amount of loan token to supply (e.g. '500' for 500 USDC, '0.5' for 0.5 WETH)
772
841
  * @param collateralSymbol - Market collateral token to identify which market (e.g. 'WETH')
773
842
  * Optional — defaults to highest-APY market
843
+ * @param loanTokenSymbol - Loan token to filter market (e.g. 'USDC', 'WETH'). Optional.
774
844
  */
775
- async supplyAsset(usdcAmount, collateralSymbol) {
845
+ async supplyAsset(amount, collateralSymbol, loanTokenSymbol) {
776
846
  const acctAddr = await this.getAccountAddress();
777
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
778
847
  const morphoAddr = this.config.contracts.morphoBlue;
779
- const usdcAddr = this.config.contracts.usdc;
780
848
  let params;
781
849
  let usedCollateral;
782
850
  if (collateralSymbol) {
783
- params = await this.findMarketForCollateral(collateralSymbol);
851
+ params = await this.findMarketForCollateral(collateralSymbol, loanTokenSymbol);
784
852
  usedCollateral = collateralSymbol;
785
853
  } else {
786
- const rates = await this.getMarketRates();
854
+ const rates = await this.getMarketRates(void 0, loanTokenSymbol);
787
855
  if (rates.length === 0) throw new AgetherError("No markets available", "NO_MARKETS");
788
856
  const best = rates.reduce((a, b) => a.supplyApy > b.supplyApy ? a : b);
789
- params = await this.findMarketForCollateral(best.collateralToken);
857
+ params = await this.findMarketForCollateral(best.collateralToken, loanTokenSymbol);
790
858
  usedCollateral = best.collateralToken;
791
859
  }
860
+ const loanDecimals = await this._getLoanTokenDecimals(params);
861
+ const loanTokenAddr = params.loanToken;
862
+ const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
792
863
  const marketId = import_ethers.ethers.keccak256(
793
864
  import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
794
865
  ["address", "address", "address", "address", "uint256"],
795
866
  [params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
796
867
  )
797
868
  );
798
- const usdcContract = new import_ethers.Contract(usdcAddr, ERC20_ABI, this._signer);
799
- const acctBalance = await usdcContract.balanceOf(acctAddr);
800
- if (acctBalance < amount) {
801
- const shortfall = amount - acctBalance;
802
- const eoaBalance = await usdcContract.balanceOf(await this.getSignerAddress());
869
+ const loanContract = new import_ethers.Contract(loanTokenAddr, ERC20_ABI, this._signer);
870
+ const acctBalance = await loanContract.balanceOf(acctAddr);
871
+ if (acctBalance < parsedAmount) {
872
+ const shortfall = parsedAmount - acctBalance;
873
+ const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
803
874
  if (eoaBalance < shortfall) {
875
+ const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
876
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
804
877
  throw new AgetherError(
805
- `Insufficient USDC. Need ${usdcAmount}, AgentAccount has ${import_ethers.ethers.formatUnits(acctBalance, 6)}, EOA has ${import_ethers.ethers.formatUnits(eoaBalance, 6)}.`,
878
+ `Insufficient ${loanSymbol}. Need ${amount}, AgentAccount has ${import_ethers.ethers.formatUnits(acctBalance, loanDecimals)}, EOA has ${import_ethers.ethers.formatUnits(eoaBalance, loanDecimals)}.`,
806
879
  "INSUFFICIENT_BALANCE"
807
880
  );
808
881
  }
809
- const transferTx = await usdcContract.transfer(acctAddr, shortfall);
882
+ const transferTx = await loanContract.transfer(acctAddr, shortfall);
810
883
  await transferTx.wait();
811
884
  this._refreshSigner();
812
885
  }
813
- const targets = [usdcAddr, morphoAddr];
886
+ const targets = [loanTokenAddr, morphoAddr];
814
887
  const values = [0n, 0n];
815
888
  const datas = [
816
- erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
889
+ erc20Iface.encodeFunctionData("approve", [morphoAddr, parsedAmount]),
817
890
  morphoIface.encodeFunctionData("supply", [
818
891
  this._toTuple(params),
819
- amount,
892
+ parsedAmount,
820
893
  0n,
821
894
  acctAddr,
822
895
  "0x"
@@ -825,7 +898,7 @@ var init_MorphoClient = __esm({
825
898
  const receipt = await this.batch(targets, values, datas);
826
899
  return {
827
900
  tx: receipt.hash,
828
- amount: usdcAmount,
901
+ amount,
829
902
  marketId,
830
903
  collateralToken: usedCollateral,
831
904
  agentAccount: acctAddr
@@ -838,17 +911,26 @@ var init_MorphoClient = __esm({
838
911
  * @param collateralSymbol - Market collateral to identify which market
839
912
  * @param receiver - Destination address (defaults to EOA)
840
913
  */
841
- async withdrawSupply(usdcAmount, collateralSymbol, receiver) {
914
+ /**
915
+ * Withdraw supplied loan token (+ earned interest) from a Morpho Blue market.
916
+ *
917
+ * @param amount - Amount to withdraw (e.g. '100' or 'all' for full position)
918
+ * @param collateralSymbol - Market collateral to identify which market
919
+ * @param receiver - Destination address (defaults to EOA)
920
+ * @param loanTokenSymbol - Loan token to filter market (optional)
921
+ */
922
+ async withdrawSupply(amount, collateralSymbol, receiver, loanTokenSymbol) {
842
923
  const acctAddr = await this.getAccountAddress();
843
924
  const morphoAddr = this.config.contracts.morphoBlue;
844
925
  const dest = receiver || await this.getSignerAddress();
845
926
  let params;
846
927
  if (collateralSymbol) {
847
- params = await this.findMarketForCollateral(collateralSymbol);
928
+ params = await this.findMarketForCollateral(collateralSymbol, loanTokenSymbol);
848
929
  } else {
849
930
  const { params: p } = await this._findActiveSupplyMarket();
850
931
  params = p;
851
932
  }
933
+ const loanDecimals = await this._getLoanTokenDecimals(params);
852
934
  const marketId = import_ethers.ethers.keccak256(
853
935
  import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
854
936
  ["address", "address", "address", "address", "uint256"],
@@ -857,13 +939,13 @@ var init_MorphoClient = __esm({
857
939
  );
858
940
  let withdrawAssets;
859
941
  let withdrawShares;
860
- if (usdcAmount === "all") {
942
+ if (amount === "all") {
861
943
  const pos = await this.morphoBlue.position(marketId, acctAddr);
862
944
  withdrawShares = BigInt(pos.supplyShares);
863
945
  withdrawAssets = 0n;
864
946
  if (withdrawShares === 0n) throw new AgetherError("No supply position to withdraw", "NO_SUPPLY");
865
947
  } else {
866
- withdrawAssets = import_ethers.ethers.parseUnits(usdcAmount, 6);
948
+ withdrawAssets = import_ethers.ethers.parseUnits(amount, loanDecimals);
867
949
  withdrawShares = 0n;
868
950
  }
869
951
  const data = morphoIface.encodeFunctionData("withdraw", [
@@ -881,13 +963,13 @@ var init_MorphoClient = __esm({
881
963
  const totalSupplyAssets = BigInt(mkt.totalSupplyAssets);
882
964
  const totalSupplyShares = BigInt(mkt.totalSupplyShares);
883
965
  const currentAssets = totalSupplyShares > 0n ? BigInt(pos.supplyShares) * totalSupplyAssets / totalSupplyShares : 0n;
884
- remainingSupply = import_ethers.ethers.formatUnits(currentAssets, 6);
966
+ remainingSupply = import_ethers.ethers.formatUnits(currentAssets, loanDecimals);
885
967
  } catch (e) {
886
968
  console.warn("[agether] failed to read remaining supply:", e instanceof Error ? e.message : e);
887
969
  }
888
970
  return {
889
971
  tx: receipt.hash,
890
- amount: usdcAmount,
972
+ amount,
891
973
  remainingSupply,
892
974
  destination: dest
893
975
  };
@@ -960,14 +1042,13 @@ var init_MorphoClient = __esm({
960
1042
  * Computes available yield, verifies the requested amount doesn't exceed it,
961
1043
  * then withdraws from the supply position and sends directly to the recipient.
962
1044
  *
963
- * @param recipient - Address to receive the USDC
964
- * @param usdcAmount - Amount to pay from yield (e.g. '5.50')
1045
+ * @param recipient - Address to receive the loan token
1046
+ * @param amount - Amount to pay from yield (e.g. '5.50')
965
1047
  * @param collateralSymbol - Market collateral to identify which supply position
966
1048
  */
967
- async payFromYield(recipient, usdcAmount, collateralSymbol) {
1049
+ async payFromYield(recipient, amount, collateralSymbol) {
968
1050
  const acctAddr = await this.getAccountAddress();
969
1051
  const morphoAddr = this.config.contracts.morphoBlue;
970
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
971
1052
  const positions = await this.getSupplyPositions(collateralSymbol);
972
1053
  if (positions.length === 0) {
973
1054
  throw new AgetherError("No supply position found", "NO_SUPPLY");
@@ -975,17 +1056,20 @@ var init_MorphoClient = __esm({
975
1056
  const pos = positions.reduce(
976
1057
  (a, b) => parseFloat(a.earnedYield) > parseFloat(b.earnedYield) ? a : b
977
1058
  );
978
- const availableYield = import_ethers.ethers.parseUnits(pos.earnedYield, 6);
979
- if (amount > availableYield) {
1059
+ const params = await this.findMarketForCollateral(pos.collateralToken, pos.loanToken);
1060
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1061
+ const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
1062
+ const availableYield = import_ethers.ethers.parseUnits(pos.earnedYield, loanDecimals);
1063
+ if (parsedAmount > availableYield) {
1064
+ const loanSymbol = pos.loanToken;
980
1065
  throw new AgetherError(
981
- `Requested ${usdcAmount} USDC exceeds available yield of ${pos.earnedYield} USDC. Use withdrawSupply to withdraw principal.`,
1066
+ `Requested ${amount} ${loanSymbol} exceeds available yield of ${pos.earnedYield} ${loanSymbol}. Use withdrawSupply to withdraw principal.`,
982
1067
  "EXCEEDS_YIELD"
983
1068
  );
984
1069
  }
985
- const params = await this.findMarketForCollateral(pos.collateralToken);
986
1070
  const data = morphoIface.encodeFunctionData("withdraw", [
987
1071
  this._toTuple(params),
988
- amount,
1072
+ parsedAmount,
989
1073
  0n,
990
1074
  acctAddr,
991
1075
  recipient
@@ -1004,7 +1088,7 @@ var init_MorphoClient = __esm({
1004
1088
  }
1005
1089
  return {
1006
1090
  tx: receipt.hash,
1007
- yieldWithdrawn: usdcAmount,
1091
+ yieldWithdrawn: amount,
1008
1092
  recipient,
1009
1093
  remainingYield,
1010
1094
  remainingSupply
@@ -1062,28 +1146,31 @@ var init_MorphoClient = __esm({
1062
1146
  };
1063
1147
  }
1064
1148
  /**
1065
- * Borrow USDC against existing collateral.
1149
+ * Borrow loan token against existing collateral.
1066
1150
  *
1067
1151
  * AgentAccount.execute: Morpho.borrow(params, amount, 0, account, account)
1068
1152
  *
1069
- * @param usdcAmount - USDC amount (e.g. '100')
1153
+ * @param amount - Loan token amount (e.g. '100' for 100 USDC, '0.5' for 0.5 WETH)
1070
1154
  * @param tokenSymbol - collateral symbol to identify which market (default: first with collateral)
1155
+ * @param marketParams - explicit market params (optional)
1156
+ * @param loanTokenSymbol - loan token to filter market (optional, e.g. 'USDC', 'WETH')
1071
1157
  */
1072
- async borrow(usdcAmount, tokenSymbol, marketParams) {
1158
+ async borrow(amount, tokenSymbol, marketParams, loanTokenSymbol) {
1073
1159
  const acctAddr = await this.getAccountAddress();
1074
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
1075
1160
  const morphoAddr = this.config.contracts.morphoBlue;
1076
1161
  let params;
1077
1162
  let usedToken = tokenSymbol || "WETH";
1078
1163
  if (marketParams) {
1079
1164
  params = marketParams;
1080
1165
  } else if (tokenSymbol) {
1081
- params = await this.findMarketForCollateral(tokenSymbol);
1166
+ params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
1082
1167
  } else {
1083
1168
  const { params: p, symbol } = await this._findActiveMarket();
1084
1169
  params = p;
1085
1170
  usedToken = symbol;
1086
1171
  }
1172
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1173
+ const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
1087
1174
  try {
1088
1175
  const marketId = import_ethers.ethers.keccak256(
1089
1176
  import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
@@ -1107,11 +1194,14 @@ var init_MorphoClient = __esm({
1107
1194
  const totalBorrowAssets = BigInt(mktState.totalBorrowAssets);
1108
1195
  const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1109
1196
  const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
1110
- if (amount > maxAdditional) {
1111
- const maxUsd = import_ethers.ethers.formatUnits(maxAdditional, 6);
1112
- const colFormatted = import_ethers.ethers.formatUnits(pos.collateral, 18);
1197
+ if (parsedAmount > maxAdditional) {
1198
+ const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
1199
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
1200
+ const colInfo = await this._resolveToken(usedToken);
1201
+ const maxFormatted = import_ethers.ethers.formatUnits(maxAdditional, loanDecimals);
1202
+ const colFormatted = import_ethers.ethers.formatUnits(pos.collateral, colInfo.decimals);
1113
1203
  throw new AgetherError(
1114
- `Borrow of $${usdcAmount} USDC exceeds max borrowable $${maxUsd} USDC (collateral: ${colFormatted} ${usedToken}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Deposit more collateral or reduce borrow amount.`,
1204
+ `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.`,
1115
1205
  "EXCEEDS_MAX_LTV"
1116
1206
  );
1117
1207
  }
@@ -1121,7 +1211,7 @@ var init_MorphoClient = __esm({
1121
1211
  }
1122
1212
  const data = morphoIface.encodeFunctionData("borrow", [
1123
1213
  this._toTuple(params),
1124
- amount,
1214
+ parsedAmount,
1125
1215
  0n,
1126
1216
  acctAddr,
1127
1217
  acctAddr
@@ -1129,7 +1219,7 @@ var init_MorphoClient = __esm({
1129
1219
  const receipt = await this.exec(morphoAddr, data);
1130
1220
  return {
1131
1221
  tx: receipt.hash,
1132
- amount: usdcAmount,
1222
+ amount,
1133
1223
  collateralToken: usedToken,
1134
1224
  agentAccount: acctAddr
1135
1225
  };
@@ -1137,17 +1227,27 @@ var init_MorphoClient = __esm({
1137
1227
  /**
1138
1228
  * Deposit collateral AND borrow USDC in one batched transaction.
1139
1229
  *
1230
+ /**
1231
+ * Deposit collateral AND borrow loan token in one batched transaction.
1232
+ *
1140
1233
  * AgentAccount.executeBatch:
1141
1234
  * [collateral.approve, Morpho.supplyCollateral, Morpho.borrow]
1142
1235
  *
1143
1236
  * The collateral must be transferred to AgentAccount first.
1237
+ *
1238
+ * @param tokenSymbol - collateral token symbol (e.g. 'WETH')
1239
+ * @param collateralAmount - amount of collateral (e.g. '0.05')
1240
+ * @param borrowAmount - amount of loan token to borrow (e.g. '100')
1241
+ * @param marketParams - explicit market params (optional)
1242
+ * @param loanTokenSymbol - loan token to filter market (optional)
1144
1243
  */
1145
- async depositAndBorrow(tokenSymbol, collateralAmount, borrowUsdcAmount, marketParams) {
1244
+ async depositAndBorrow(tokenSymbol, collateralAmount, borrowAmount, marketParams, loanTokenSymbol) {
1146
1245
  const acctAddr = await this.getAccountAddress();
1147
1246
  const colInfo = await this._resolveToken(tokenSymbol);
1148
- const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
1247
+ const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
1248
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1149
1249
  const colWei = import_ethers.ethers.parseUnits(collateralAmount, colInfo.decimals);
1150
- const borrowWei = import_ethers.ethers.parseUnits(borrowUsdcAmount, 6);
1250
+ const borrowWei = import_ethers.ethers.parseUnits(borrowAmount, loanDecimals);
1151
1251
  const morphoAddr = this.config.contracts.morphoBlue;
1152
1252
  try {
1153
1253
  const marketId = import_ethers.ethers.keccak256(
@@ -1168,9 +1268,11 @@ var init_MorphoClient = __esm({
1168
1268
  const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1169
1269
  const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
1170
1270
  if (borrowWei > maxAdditional) {
1171
- const maxUsd = import_ethers.ethers.formatUnits(maxAdditional, 6);
1271
+ const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
1272
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
1273
+ const maxFormatted = import_ethers.ethers.formatUnits(maxAdditional, loanDecimals);
1172
1274
  throw new AgetherError(
1173
- `Borrow of $${borrowUsdcAmount} USDC exceeds max borrowable $${maxUsd} USDC (total collateral: ${import_ethers.ethers.formatUnits(totalCollateral, colInfo.decimals)} ${tokenSymbol}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Reduce borrow or increase collateral.`,
1275
+ `Borrow of ${borrowAmount} ${loanSymbol} exceeds max borrowable ${maxFormatted} ${loanSymbol} (total collateral: ${import_ethers.ethers.formatUnits(totalCollateral, colInfo.decimals)} ${tokenSymbol}, LLTV: ${Number(params.lltv) / 1e18 * 100}%). Reduce borrow or increase collateral.`,
1174
1276
  "EXCEEDS_MAX_LTV"
1175
1277
  );
1176
1278
  }
@@ -1216,36 +1318,42 @@ var init_MorphoClient = __esm({
1216
1318
  tx: receipt.hash,
1217
1319
  collateralToken: tokenSymbol,
1218
1320
  collateralAmount,
1219
- borrowAmount: borrowUsdcAmount,
1321
+ borrowAmount,
1220
1322
  agentAccount: acctAddr
1221
1323
  };
1222
1324
  }
1223
1325
  /**
1224
- * Repay borrowed USDC from AgentAccount.
1326
+ * Repay borrowed loan token from AgentAccount.
1225
1327
  *
1226
1328
  * AgentAccount.executeBatch:
1227
- * [USDC.approve(MorphoBlue), Morpho.repay(params)]
1329
+ * [loanToken.approve(MorphoBlue), Morpho.repay(params)]
1330
+ *
1331
+ * @param amount - loan token amount to repay (e.g. '50' or 'all' for full repayment)
1332
+ * @param tokenSymbol - collateral symbol to identify which market (optional)
1333
+ * @param marketParams - explicit market params (optional)
1334
+ * @param loanTokenSymbol - loan token to filter market (optional)
1228
1335
  */
1229
- async repay(usdcAmount, tokenSymbol, marketParams) {
1336
+ async repay(amount, tokenSymbol, marketParams, loanTokenSymbol) {
1230
1337
  const acctAddr = await this.getAccountAddress();
1231
1338
  const morphoAddr = this.config.contracts.morphoBlue;
1232
- const usdcAddr = this.config.contracts.usdc;
1233
1339
  let params;
1234
1340
  if (marketParams) {
1235
1341
  params = marketParams;
1236
1342
  } else if (tokenSymbol) {
1237
- params = await this.findMarketForCollateral(tokenSymbol);
1343
+ params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
1238
1344
  } else {
1239
1345
  const { params: p } = await this._findActiveMarket();
1240
1346
  params = p;
1241
1347
  }
1348
+ const loanTokenAddr = params.loanToken;
1349
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1242
1350
  let repayAssets;
1243
1351
  let repayShares;
1244
1352
  let approveAmount;
1245
- if (usdcAmount === "all") {
1353
+ if (amount === "all") {
1246
1354
  const markets = await this.getMarkets();
1247
1355
  const mkt = markets.find(
1248
- (m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase()
1356
+ (m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase() && m.loanAsset?.address.toLowerCase() === params.loanToken.toLowerCase()
1249
1357
  );
1250
1358
  if (mkt) {
1251
1359
  const pos = await this.morphoBlue.position(mkt.uniqueKey, acctAddr);
@@ -1255,33 +1363,35 @@ var init_MorphoClient = __esm({
1255
1363
  const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
1256
1364
  const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
1257
1365
  const estimated = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
1258
- approveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", 6);
1366
+ approveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", loanDecimals);
1259
1367
  } else {
1260
- repayAssets = import_ethers.ethers.parseUnits("999999", 6);
1368
+ repayAssets = import_ethers.ethers.parseUnits("999999", loanDecimals);
1261
1369
  repayShares = 0n;
1262
1370
  approveAmount = repayAssets;
1263
1371
  }
1264
1372
  } else {
1265
- repayAssets = import_ethers.ethers.parseUnits(usdcAmount, 6);
1373
+ repayAssets = import_ethers.ethers.parseUnits(amount, loanDecimals);
1266
1374
  repayShares = 0n;
1267
1375
  approveAmount = repayAssets;
1268
1376
  }
1269
- const usdcContract = new import_ethers.Contract(usdcAddr, ERC20_ABI, this._signer);
1270
- const acctBalance = await usdcContract.balanceOf(acctAddr);
1377
+ const loanContract = new import_ethers.Contract(loanTokenAddr, ERC20_ABI, this._signer);
1378
+ const acctBalance = await loanContract.balanceOf(acctAddr);
1271
1379
  if (acctBalance < approveAmount) {
1272
1380
  const shortfall = approveAmount - acctBalance;
1273
- const eoaBalance = await usdcContract.balanceOf(await this.getSignerAddress());
1381
+ const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
1274
1382
  if (eoaBalance < shortfall) {
1383
+ const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
1384
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
1275
1385
  throw new AgetherError(
1276
- `Insufficient USDC for repay. Need ${import_ethers.ethers.formatUnits(approveAmount, 6)} USDC, AgentAccount has ${import_ethers.ethers.formatUnits(acctBalance, 6)}, EOA has ${import_ethers.ethers.formatUnits(eoaBalance, 6)}.`,
1386
+ `Insufficient ${loanSymbol} for repay. Need ${import_ethers.ethers.formatUnits(approveAmount, loanDecimals)}, AgentAccount has ${import_ethers.ethers.formatUnits(acctBalance, loanDecimals)}, EOA has ${import_ethers.ethers.formatUnits(eoaBalance, loanDecimals)}.`,
1277
1387
  "INSUFFICIENT_BALANCE"
1278
1388
  );
1279
1389
  }
1280
- const transferTx = await usdcContract.transfer(acctAddr, shortfall);
1390
+ const transferTx = await loanContract.transfer(acctAddr, shortfall);
1281
1391
  await transferTx.wait();
1282
1392
  this._refreshSigner();
1283
1393
  }
1284
- const targets = [usdcAddr, morphoAddr];
1394
+ const targets = [loanTokenAddr, morphoAddr];
1285
1395
  const values = [0n, 0n];
1286
1396
  const datas = [
1287
1397
  erc20Iface.encodeFunctionData("approve", [morphoAddr, approveAmount]),
@@ -1301,7 +1411,7 @@ var init_MorphoClient = __esm({
1301
1411
  } catch (e) {
1302
1412
  console.warn("[agether] failed to read remaining debt after repay:", e instanceof Error ? e.message : e);
1303
1413
  }
1304
- return { tx: receipt.hash, amount: usdcAmount, remainingDebt };
1414
+ return { tx: receipt.hash, amount, remainingDebt };
1305
1415
  }
1306
1416
  /**
1307
1417
  * Withdraw collateral from Morpho Blue.
@@ -1315,12 +1425,13 @@ var init_MorphoClient = __esm({
1315
1425
  const colInfo = await this._resolveToken(tokenSymbol);
1316
1426
  const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
1317
1427
  const morphoAddr = this.config.contracts.morphoBlue;
1318
- const usdcAddr = this.config.contracts.usdc;
1428
+ const loanTokenAddr = params.loanToken;
1429
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1319
1430
  const dest = receiver || await this.getSignerAddress();
1320
1431
  let weiAmount;
1321
1432
  const markets = await this.getMarkets();
1322
1433
  const market = markets.find(
1323
- (m) => m.collateralAsset?.address.toLowerCase() === colInfo.address.toLowerCase()
1434
+ (m) => m.collateralAsset?.address.toLowerCase() === colInfo.address.toLowerCase() && m.loanAsset?.address.toLowerCase() === loanTokenAddr.toLowerCase()
1324
1435
  );
1325
1436
  if (amount === "all") {
1326
1437
  if (!market) throw new AgetherError("Market not found", "MARKET_NOT_FOUND");
@@ -1343,8 +1454,10 @@ var init_MorphoClient = __esm({
1343
1454
  const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
1344
1455
  const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
1345
1456
  const estimated = totalBorrowShares > 0n ? dustBorrowShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
1346
- dustApproveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", 6);
1347
- console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${import_ethers.ethers.formatUnits(dustApproveAmount, 6)} USDC \u2014 auto-repaying before withdraw`);
1457
+ dustApproveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", loanDecimals);
1458
+ const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
1459
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
1460
+ console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${import_ethers.ethers.formatUnits(dustApproveAmount, loanDecimals)} ${loanSymbol} \u2014 auto-repaying before withdraw`);
1348
1461
  }
1349
1462
  } catch (e) {
1350
1463
  console.warn("[agether] failed to check borrow shares before withdraw:", e instanceof Error ? e.message : e);
@@ -1358,19 +1471,21 @@ var init_MorphoClient = __esm({
1358
1471
  ]);
1359
1472
  let receipt;
1360
1473
  if (hasDustDebt) {
1361
- const usdcContract = new import_ethers.Contract(usdcAddr, ERC20_ABI, this._signer);
1362
- const acctBalance = await usdcContract.balanceOf(acctAddr);
1474
+ const loanContract = new import_ethers.Contract(loanTokenAddr, ERC20_ABI, this._signer);
1475
+ const acctBalance = await loanContract.balanceOf(acctAddr);
1363
1476
  if (acctBalance < dustApproveAmount) {
1364
1477
  const shortfall = dustApproveAmount - acctBalance;
1365
- const eoaBalance = await usdcContract.balanceOf(await this.getSignerAddress());
1478
+ const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
1366
1479
  if (eoaBalance >= shortfall) {
1367
- console.log(`[agether] transferring ${import_ethers.ethers.formatUnits(shortfall, 6)} USDC from EOA \u2192 AgentAccount for dust repay`);
1368
- const transferTx = await usdcContract.transfer(acctAddr, shortfall);
1480
+ const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
1481
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
1482
+ console.log(`[agether] transferring ${import_ethers.ethers.formatUnits(shortfall, loanDecimals)} ${loanSymbol} from EOA \u2192 AgentAccount for dust repay`);
1483
+ const transferTx = await loanContract.transfer(acctAddr, shortfall);
1369
1484
  await transferTx.wait();
1370
1485
  this._refreshSigner();
1371
1486
  }
1372
1487
  }
1373
- const targets = [usdcAddr, morphoAddr, morphoAddr];
1488
+ const targets = [loanTokenAddr, morphoAddr, morphoAddr];
1374
1489
  const values = [0n, 0n, 0n];
1375
1490
  const datas = [
1376
1491
  erc20Iface.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
@@ -1615,6 +1730,37 @@ var init_MorphoClient = __esm({
1615
1730
  }
1616
1731
  throw new AgetherError("No active supply position found", "NO_SUPPLY");
1617
1732
  }
1733
+ /**
1734
+ * Resolve loan token decimals from market params.
1735
+ * Uses the `_tokenCache` populated by `getMarkets()`.
1736
+ */
1737
+ async _getLoanTokenDecimals(params) {
1738
+ const tokenInfo = this._tokenCache.get(params.loanToken.toLowerCase());
1739
+ if (tokenInfo) return tokenInfo.decimals;
1740
+ await this.getMarkets();
1741
+ const fromApi = this._tokenCache.get(params.loanToken.toLowerCase());
1742
+ return fromApi?.decimals ?? 18;
1743
+ }
1744
+ /**
1745
+ * Apply client-side filter to discovered markets.
1746
+ */
1747
+ _applyMarketFilter(markets, filter) {
1748
+ return markets.filter((m) => {
1749
+ if (filter.loanToken) {
1750
+ const loanAddr = filter.loanToken.toLowerCase();
1751
+ if (m.loanAsset.address.toLowerCase() !== loanAddr && m.loanAsset.symbol.toUpperCase() !== filter.loanToken.toUpperCase()) {
1752
+ return false;
1753
+ }
1754
+ }
1755
+ if (filter.collateralToken) {
1756
+ const colAddr = filter.collateralToken.toLowerCase();
1757
+ if (m.collateralAsset.address.toLowerCase() !== colAddr && m.collateralAsset.symbol.toUpperCase() !== filter.collateralToken.toUpperCase()) {
1758
+ return false;
1759
+ }
1760
+ }
1761
+ return true;
1762
+ });
1763
+ }
1618
1764
  /**
1619
1765
  * Resolve a token symbol or address to { address, symbol, decimals }.
1620
1766
  *
@@ -1631,8 +1777,8 @@ var init_MorphoClient = __esm({
1631
1777
  const fromApi = this._tokenCache.get(key);
1632
1778
  if (fromApi) return fromApi;
1633
1779
  throw new AgetherError(
1634
- `Unknown token: ${symbolOrAddress}. No Morpho market found with this collateral.`,
1635
- "UNKNOWN_COLLATERAL"
1780
+ `Unknown token: ${symbolOrAddress}. No Morpho market found with this token.`,
1781
+ "UNKNOWN_TOKEN"
1636
1782
  );
1637
1783
  }
1638
1784
  /**
@@ -1837,6 +1983,23 @@ var init_AgetherClient = __esm({
1837
1983
  }
1838
1984
  const acctAddr = await this.agether4337Factory.getAccount(agentId);
1839
1985
  this.accountAddress = acctAddr;
1986
+ if (!acctExists) {
1987
+ const updatedMeta = JSON.stringify({
1988
+ type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
1989
+ name: options?.name || "Unnamed Agent",
1990
+ description: options?.description || "AI agent registered via @agether/sdk",
1991
+ active: true,
1992
+ wallet: `eip155:${this.config.chainId}:${acctAddr}`,
1993
+ registrations: [{
1994
+ agentId: Number(agentId),
1995
+ agentRegistry: `eip155:${this.config.chainId}:${this.config.contracts.identityRegistry}`
1996
+ }]
1997
+ });
1998
+ const finalURI = `data:application/json;base64,${Buffer.from(updatedMeta).toString("base64")}`;
1999
+ const uriTx = await this.identityRegistry.setAgentURI(agentId, finalURI);
2000
+ await uriTx.wait();
2001
+ this._refreshSigner();
2002
+ }
1840
2003
  const kyaRequired = await this.isKyaRequired();
1841
2004
  return {
1842
2005
  agentId: agentId.toString(),
@@ -1853,7 +2016,7 @@ var init_AgetherClient = __esm({
1853
2016
  async _mintNewIdentity(name, description) {
1854
2017
  const registrationFile = JSON.stringify({
1855
2018
  type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
1856
- name: name || "Unnamed Agent",
2019
+ name: name || "Agether Agent",
1857
2020
  description: description || "AI agent registered via @agether/sdk",
1858
2021
  active: true,
1859
2022
  registrations: [{