@agether/sdk 2.12.2 → 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
@@ -290,8 +290,9 @@ var init_MorphoClient = __esm({
290
290
  erc20Iface = new import_ethers.ethers.Interface(ERC20_ABI);
291
291
  MorphoClient = class {
292
292
  constructor(config) {
293
+ /** Market params cache: keyed by market uniqueKey (bytes32 hash) */
293
294
  this._marketCache = /* @__PURE__ */ new Map();
294
- /** Dynamic token registry: symbol (uppercase) → { address, symbol, decimals } */
295
+ /** Dynamic token registry: symbol (uppercase) or address (lowercase) → { address, symbol, decimals } */
295
296
  this._tokenCache = /* @__PURE__ */ new Map();
296
297
  this._discoveredAt = 0;
297
298
  if (!config.agentId) {
@@ -394,21 +395,23 @@ var init_MorphoClient = __esm({
394
395
  // Market Discovery (Morpho GraphQL API)
395
396
  // ════════════════════════════════════════════════════════
396
397
  /**
397
- * Fetch USDC borrow markets on Base from Morpho API.
398
- * 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
399
403
  */
400
- async getMarkets(forceRefresh = false) {
404
+ async getMarkets(forceRefresh = false, filter) {
401
405
  if (!forceRefresh && this._discoveredMarkets && Date.now() - this._discoveredAt < 3e5) {
402
- return this._discoveredMarkets;
406
+ return filter ? this._applyMarketFilter(this._discoveredMarkets, filter) : this._discoveredMarkets;
403
407
  }
404
408
  const chainId = this.config.chainId;
405
- const usdcAddr = this.config.contracts.usdc.toLowerCase();
406
409
  const query = `{
407
410
  markets(
408
411
  first: 50
409
412
  orderBy: SupplyAssetsUsd
410
413
  orderDirection: Desc
411
- where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"] }
414
+ where: { chainId_in: [${chainId}] }
412
415
  ) {
413
416
  items {
414
417
  uniqueKey
@@ -441,14 +444,14 @@ var init_MorphoClient = __esm({
441
444
  }));
442
445
  this._discoveredAt = Date.now();
443
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
+ });
444
454
  if (mi.collateralAsset.address !== import_ethers.ethers.ZeroAddress) {
445
- this._marketCache.set(mi.collateralAsset.address.toLowerCase(), {
446
- loanToken: mi.loanAsset.address,
447
- collateralToken: mi.collateralAsset.address,
448
- oracle: mi.oracle,
449
- irm: mi.irm,
450
- lltv: mi.lltv
451
- });
452
455
  this._tokenCache.set(mi.collateralAsset.symbol.toUpperCase(), {
453
456
  address: mi.collateralAsset.address,
454
457
  symbol: mi.collateralAsset.symbol,
@@ -473,17 +476,24 @@ var init_MorphoClient = __esm({
473
476
  });
474
477
  }
475
478
  }
476
- return this._discoveredMarkets;
479
+ return filter ? this._applyMarketFilter(this._discoveredMarkets, filter) : this._discoveredMarkets;
477
480
  } catch (e) {
478
481
  console.warn("[agether] getMarkets failed, using cache:", e instanceof Error ? e.message : e);
479
- return this._discoveredMarkets ?? [];
482
+ const cached = this._discoveredMarkets ?? [];
483
+ return filter ? this._applyMarketFilter(cached, filter) : cached;
480
484
  }
481
485
  }
482
486
  /**
483
- * Get MarketParams for a collateral token.
484
- * 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)
485
495
  */
486
- async findMarketForCollateral(collateralSymbolOrAddress) {
496
+ async findMarketForCollateral(collateralSymbolOrAddress, loanTokenSymbolOrAddress) {
487
497
  let colAddr;
488
498
  if (collateralSymbolOrAddress.startsWith("0x")) {
489
499
  colAddr = collateralSymbolOrAddress.toLowerCase();
@@ -495,13 +505,33 @@ var init_MorphoClient = __esm({
495
505
  colAddr = collateralSymbolOrAddress.toLowerCase();
496
506
  }
497
507
  }
498
- const cached = this._marketCache.get(colAddr);
499
- if (cached) return cached;
500
- await this.getMarkets();
501
- const fromApi = this._marketCache.get(colAddr);
502
- 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
+ }
503
533
  throw new AgetherError(
504
- `No Morpho market found for collateral ${collateralSymbolOrAddress}`,
534
+ `No Morpho market found for collateral ${collateralSymbolOrAddress}` + (loanTokenSymbolOrAddress ? ` with loan token ${loanTokenSymbolOrAddress}` : ""),
505
535
  "MARKET_NOT_FOUND"
506
536
  );
507
537
  }
@@ -536,12 +566,13 @@ var init_MorphoClient = __esm({
536
566
  const acctAddr = await this.getAccountAddress();
537
567
  const markets = await this.getMarkets();
538
568
  const positions = [];
539
- let totalDebt = 0n;
569
+ let totalDebtFloat = 0;
540
570
  for (const m of markets) {
541
571
  if (!m.collateralAsset || m.collateralAsset.address === import_ethers.ethers.ZeroAddress) continue;
542
572
  try {
543
573
  const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
544
574
  if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
575
+ const loanDecimals = m.loanAsset.decimals;
545
576
  let debt = 0n;
546
577
  if (pos.borrowShares > 0n) {
547
578
  try {
@@ -549,7 +580,7 @@ var init_MorphoClient = __esm({
549
580
  const totalBorrowShares = BigInt(mkt.totalBorrowShares);
550
581
  const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
551
582
  debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
552
- totalDebt += debt;
583
+ totalDebtFloat += parseFloat(import_ethers.ethers.formatUnits(debt, loanDecimals));
553
584
  } catch (e) {
554
585
  console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
555
586
  }
@@ -557,10 +588,11 @@ var init_MorphoClient = __esm({
557
588
  positions.push({
558
589
  marketId: m.uniqueKey,
559
590
  collateralToken: m.collateralAsset.symbol,
591
+ loanToken: m.loanAsset.symbol,
560
592
  collateral: import_ethers.ethers.formatUnits(pos.collateral, m.collateralAsset.decimals),
561
593
  borrowShares: pos.borrowShares.toString(),
562
594
  supplyShares: pos.supplyShares.toString(),
563
- debt: import_ethers.ethers.formatUnits(debt, 6)
595
+ debt: import_ethers.ethers.formatUnits(debt, loanDecimals)
564
596
  });
565
597
  } catch (e) {
566
598
  console.warn(`[agether] position read failed for market:`, e instanceof Error ? e.message : e);
@@ -570,16 +602,28 @@ var init_MorphoClient = __esm({
570
602
  return {
571
603
  agentId: this.agentId,
572
604
  agentAccount: acctAddr,
573
- totalDebt: import_ethers.ethers.formatUnits(totalDebt, 6),
605
+ totalDebt: totalDebtFloat.toFixed(6),
574
606
  positions
575
607
  };
576
608
  }
577
609
  // ════════════════════════════════════════════════════════
578
610
  // Balance & Borrowing Capacity
579
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
+ }
580
623
  /**
581
624
  * Get the USDC balance of the AgentAccount.
582
625
  * @returns USDC balance in raw units (6 decimals)
626
+ * @deprecated Use `getTokenBalance('USDC')` instead.
583
627
  */
584
628
  async getUsdcBalance() {
585
629
  const acctAddr = await this.getAccountAddress();
@@ -587,7 +631,7 @@ var init_MorphoClient = __esm({
587
631
  return usdc.balanceOf(acctAddr);
588
632
  }
589
633
  /**
590
- * Calculate the maximum additional USDC that can be borrowed
634
+ * Calculate the maximum additional loan token that can be borrowed
591
635
  * given the agent's current collateral and debt across all markets.
592
636
  *
593
637
  * For each market with collateral deposited:
@@ -595,7 +639,7 @@ var init_MorphoClient = __esm({
595
639
  *
596
640
  * Uses the Morpho oracle to price collateral → loan token.
597
641
  *
598
- * @returns Maximum additional USDC borrowable (6 decimals)
642
+ * @returns Maximum additional borrowable per market (raw units in each market's loan token)
599
643
  */
600
644
  async getMaxBorrowable() {
601
645
  const acctAddr = await this.getAccountAddress();
@@ -628,6 +672,8 @@ var init_MorphoClient = __esm({
628
672
  totalAdditional += maxAdditional;
629
673
  byMarket.push({
630
674
  collateralToken: m.collateralAsset.symbol,
675
+ loanToken: m.loanAsset.symbol,
676
+ loanDecimals: m.loanAsset.decimals,
631
677
  maxAdditional,
632
678
  currentDebt,
633
679
  collateralValue: collateralValueInLoan
@@ -643,14 +689,16 @@ var init_MorphoClient = __esm({
643
689
  // Market Rates & Yield Estimation
644
690
  // ════════════════════════════════════════════════════════
645
691
  /**
646
- * 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.
647
693
  *
648
694
  * Note: On Morpho Blue, collateral does NOT earn yield directly. Supply APY
649
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.
650
699
  */
651
- async getMarketRates(collateralSymbolOrAddress) {
700
+ async getMarketRates(collateralSymbolOrAddress, loanTokenSymbolOrAddress) {
652
701
  const chainId = this.config.chainId;
653
- const usdcAddr = this.config.contracts.usdc.toLowerCase();
654
702
  let collateralFilter = "";
655
703
  if (collateralSymbolOrAddress) {
656
704
  let colAddr;
@@ -666,12 +714,27 @@ var init_MorphoClient = __esm({
666
714
  }
667
715
  collateralFilter = `, collateralAssetAddress_in: ["${colAddr}"]`;
668
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
+ }
669
732
  const query = `{
670
733
  markets(
671
734
  first: 50
672
735
  orderBy: SupplyAssetsUsd
673
736
  orderDirection: Desc
674
- where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"]${collateralFilter} }
737
+ where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter} }
675
738
  ) {
676
739
  items {
677
740
  uniqueKey
@@ -691,17 +754,21 @@ var init_MorphoClient = __esm({
691
754
  try {
692
755
  const resp = await import_axios.default.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
693
756
  const items = resp.data?.data?.markets?.items ?? [];
694
- return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers.ethers.ZeroAddress).map((m) => ({
695
- collateralToken: m.collateralAsset.symbol,
696
- loanToken: m.loanAsset.symbol,
697
- supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
698
- borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
699
- utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
700
- totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 1e6 : 0,
701
- totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 1e6 : 0,
702
- lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
703
- marketId: m.uniqueKey
704
- }));
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
+ });
705
772
  } catch (e) {
706
773
  console.warn("[agether] getMarketRates failed:", e instanceof Error ? e.message : e);
707
774
  return [];
@@ -735,14 +802,15 @@ var init_MorphoClient = __esm({
735
802
  } else {
736
803
  try {
737
804
  const params = await this.findMarketForCollateral(collateralSymbol);
805
+ const loanDecimals = await this._getLoanTokenDecimals(params);
738
806
  const oracleContract = new import_ethers.Contract(params.oracle, [
739
807
  "function price() view returns (uint256)"
740
808
  ], this.provider);
741
809
  const oraclePrice = await oracleContract.price();
742
810
  const ORACLE_PRICE_SCALE = 10n ** 36n;
743
811
  const amountWei = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
744
- const valueInUsdc = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
745
- collateralValueUsd = Number(valueInUsdc) / 1e6;
812
+ const valueInLoan = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
813
+ collateralValueUsd = Number(valueInLoan) / 10 ** loanDecimals;
746
814
  } catch (e) {
747
815
  console.warn("[agether] oracle price fetch for yield estimation failed:", e instanceof Error ? e.message : e);
748
816
  throw new AgetherError("Cannot determine collateral value. Provide ethPriceUsd.", "PRICE_UNAVAILABLE");
@@ -763,61 +831,65 @@ var init_MorphoClient = __esm({
763
831
  // Supply-Side (Lending) — earn yield by supplying USDC
764
832
  // ════════════════════════════════════════════════════════
765
833
  /**
766
- * 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).
767
835
  *
768
836
  * Unlike `supplyCollateral` (borrower-side), this is the **lender-side**:
769
- * 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
770
838
  * interest paid by borrowers.
771
839
  *
772
- * @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)
773
841
  * @param collateralSymbol - Market collateral token to identify which market (e.g. 'WETH')
774
842
  * Optional — defaults to highest-APY market
843
+ * @param loanTokenSymbol - Loan token to filter market (e.g. 'USDC', 'WETH'). Optional.
775
844
  */
776
- async supplyAsset(usdcAmount, collateralSymbol) {
845
+ async supplyAsset(amount, collateralSymbol, loanTokenSymbol) {
777
846
  const acctAddr = await this.getAccountAddress();
778
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
779
847
  const morphoAddr = this.config.contracts.morphoBlue;
780
- const usdcAddr = this.config.contracts.usdc;
781
848
  let params;
782
849
  let usedCollateral;
783
850
  if (collateralSymbol) {
784
- params = await this.findMarketForCollateral(collateralSymbol);
851
+ params = await this.findMarketForCollateral(collateralSymbol, loanTokenSymbol);
785
852
  usedCollateral = collateralSymbol;
786
853
  } else {
787
- const rates = await this.getMarketRates();
854
+ const rates = await this.getMarketRates(void 0, loanTokenSymbol);
788
855
  if (rates.length === 0) throw new AgetherError("No markets available", "NO_MARKETS");
789
856
  const best = rates.reduce((a, b) => a.supplyApy > b.supplyApy ? a : b);
790
- params = await this.findMarketForCollateral(best.collateralToken);
857
+ params = await this.findMarketForCollateral(best.collateralToken, loanTokenSymbol);
791
858
  usedCollateral = best.collateralToken;
792
859
  }
860
+ const loanDecimals = await this._getLoanTokenDecimals(params);
861
+ const loanTokenAddr = params.loanToken;
862
+ const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
793
863
  const marketId = import_ethers.ethers.keccak256(
794
864
  import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
795
865
  ["address", "address", "address", "address", "uint256"],
796
866
  [params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
797
867
  )
798
868
  );
799
- const usdcContract = new import_ethers.Contract(usdcAddr, ERC20_ABI, this._signer);
800
- const acctBalance = await usdcContract.balanceOf(acctAddr);
801
- if (acctBalance < amount) {
802
- const shortfall = amount - acctBalance;
803
- 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());
804
874
  if (eoaBalance < shortfall) {
875
+ const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
876
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
805
877
  throw new AgetherError(
806
- `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)}.`,
807
879
  "INSUFFICIENT_BALANCE"
808
880
  );
809
881
  }
810
- const transferTx = await usdcContract.transfer(acctAddr, shortfall);
882
+ const transferTx = await loanContract.transfer(acctAddr, shortfall);
811
883
  await transferTx.wait();
812
884
  this._refreshSigner();
813
885
  }
814
- const targets = [usdcAddr, morphoAddr];
886
+ const targets = [loanTokenAddr, morphoAddr];
815
887
  const values = [0n, 0n];
816
888
  const datas = [
817
- erc20Iface.encodeFunctionData("approve", [morphoAddr, amount]),
889
+ erc20Iface.encodeFunctionData("approve", [morphoAddr, parsedAmount]),
818
890
  morphoIface.encodeFunctionData("supply", [
819
891
  this._toTuple(params),
820
- amount,
892
+ parsedAmount,
821
893
  0n,
822
894
  acctAddr,
823
895
  "0x"
@@ -826,7 +898,7 @@ var init_MorphoClient = __esm({
826
898
  const receipt = await this.batch(targets, values, datas);
827
899
  return {
828
900
  tx: receipt.hash,
829
- amount: usdcAmount,
901
+ amount,
830
902
  marketId,
831
903
  collateralToken: usedCollateral,
832
904
  agentAccount: acctAddr
@@ -839,17 +911,26 @@ var init_MorphoClient = __esm({
839
911
  * @param collateralSymbol - Market collateral to identify which market
840
912
  * @param receiver - Destination address (defaults to EOA)
841
913
  */
842
- 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) {
843
923
  const acctAddr = await this.getAccountAddress();
844
924
  const morphoAddr = this.config.contracts.morphoBlue;
845
925
  const dest = receiver || await this.getSignerAddress();
846
926
  let params;
847
927
  if (collateralSymbol) {
848
- params = await this.findMarketForCollateral(collateralSymbol);
928
+ params = await this.findMarketForCollateral(collateralSymbol, loanTokenSymbol);
849
929
  } else {
850
930
  const { params: p } = await this._findActiveSupplyMarket();
851
931
  params = p;
852
932
  }
933
+ const loanDecimals = await this._getLoanTokenDecimals(params);
853
934
  const marketId = import_ethers.ethers.keccak256(
854
935
  import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
855
936
  ["address", "address", "address", "address", "uint256"],
@@ -858,13 +939,13 @@ var init_MorphoClient = __esm({
858
939
  );
859
940
  let withdrawAssets;
860
941
  let withdrawShares;
861
- if (usdcAmount === "all") {
942
+ if (amount === "all") {
862
943
  const pos = await this.morphoBlue.position(marketId, acctAddr);
863
944
  withdrawShares = BigInt(pos.supplyShares);
864
945
  withdrawAssets = 0n;
865
946
  if (withdrawShares === 0n) throw new AgetherError("No supply position to withdraw", "NO_SUPPLY");
866
947
  } else {
867
- withdrawAssets = import_ethers.ethers.parseUnits(usdcAmount, 6);
948
+ withdrawAssets = import_ethers.ethers.parseUnits(amount, loanDecimals);
868
949
  withdrawShares = 0n;
869
950
  }
870
951
  const data = morphoIface.encodeFunctionData("withdraw", [
@@ -882,13 +963,13 @@ var init_MorphoClient = __esm({
882
963
  const totalSupplyAssets = BigInt(mkt.totalSupplyAssets);
883
964
  const totalSupplyShares = BigInt(mkt.totalSupplyShares);
884
965
  const currentAssets = totalSupplyShares > 0n ? BigInt(pos.supplyShares) * totalSupplyAssets / totalSupplyShares : 0n;
885
- remainingSupply = import_ethers.ethers.formatUnits(currentAssets, 6);
966
+ remainingSupply = import_ethers.ethers.formatUnits(currentAssets, loanDecimals);
886
967
  } catch (e) {
887
968
  console.warn("[agether] failed to read remaining supply:", e instanceof Error ? e.message : e);
888
969
  }
889
970
  return {
890
971
  tx: receipt.hash,
891
- amount: usdcAmount,
972
+ amount,
892
973
  remainingSupply,
893
974
  destination: dest
894
975
  };
@@ -961,14 +1042,13 @@ var init_MorphoClient = __esm({
961
1042
  * Computes available yield, verifies the requested amount doesn't exceed it,
962
1043
  * then withdraws from the supply position and sends directly to the recipient.
963
1044
  *
964
- * @param recipient - Address to receive the USDC
965
- * @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')
966
1047
  * @param collateralSymbol - Market collateral to identify which supply position
967
1048
  */
968
- async payFromYield(recipient, usdcAmount, collateralSymbol) {
1049
+ async payFromYield(recipient, amount, collateralSymbol) {
969
1050
  const acctAddr = await this.getAccountAddress();
970
1051
  const morphoAddr = this.config.contracts.morphoBlue;
971
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
972
1052
  const positions = await this.getSupplyPositions(collateralSymbol);
973
1053
  if (positions.length === 0) {
974
1054
  throw new AgetherError("No supply position found", "NO_SUPPLY");
@@ -976,17 +1056,20 @@ var init_MorphoClient = __esm({
976
1056
  const pos = positions.reduce(
977
1057
  (a, b) => parseFloat(a.earnedYield) > parseFloat(b.earnedYield) ? a : b
978
1058
  );
979
- const availableYield = import_ethers.ethers.parseUnits(pos.earnedYield, 6);
980
- 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;
981
1065
  throw new AgetherError(
982
- `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.`,
983
1067
  "EXCEEDS_YIELD"
984
1068
  );
985
1069
  }
986
- const params = await this.findMarketForCollateral(pos.collateralToken);
987
1070
  const data = morphoIface.encodeFunctionData("withdraw", [
988
1071
  this._toTuple(params),
989
- amount,
1072
+ parsedAmount,
990
1073
  0n,
991
1074
  acctAddr,
992
1075
  recipient
@@ -1005,7 +1088,7 @@ var init_MorphoClient = __esm({
1005
1088
  }
1006
1089
  return {
1007
1090
  tx: receipt.hash,
1008
- yieldWithdrawn: usdcAmount,
1091
+ yieldWithdrawn: amount,
1009
1092
  recipient,
1010
1093
  remainingYield,
1011
1094
  remainingSupply
@@ -1063,28 +1146,31 @@ var init_MorphoClient = __esm({
1063
1146
  };
1064
1147
  }
1065
1148
  /**
1066
- * Borrow USDC against existing collateral.
1149
+ * Borrow loan token against existing collateral.
1067
1150
  *
1068
1151
  * AgentAccount.execute: Morpho.borrow(params, amount, 0, account, account)
1069
1152
  *
1070
- * @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)
1071
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')
1072
1157
  */
1073
- async borrow(usdcAmount, tokenSymbol, marketParams) {
1158
+ async borrow(amount, tokenSymbol, marketParams, loanTokenSymbol) {
1074
1159
  const acctAddr = await this.getAccountAddress();
1075
- const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
1076
1160
  const morphoAddr = this.config.contracts.morphoBlue;
1077
1161
  let params;
1078
1162
  let usedToken = tokenSymbol || "WETH";
1079
1163
  if (marketParams) {
1080
1164
  params = marketParams;
1081
1165
  } else if (tokenSymbol) {
1082
- params = await this.findMarketForCollateral(tokenSymbol);
1166
+ params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
1083
1167
  } else {
1084
1168
  const { params: p, symbol } = await this._findActiveMarket();
1085
1169
  params = p;
1086
1170
  usedToken = symbol;
1087
1171
  }
1172
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1173
+ const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
1088
1174
  try {
1089
1175
  const marketId = import_ethers.ethers.keccak256(
1090
1176
  import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
@@ -1108,11 +1194,14 @@ var init_MorphoClient = __esm({
1108
1194
  const totalBorrowAssets = BigInt(mktState.totalBorrowAssets);
1109
1195
  const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1110
1196
  const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
1111
- if (amount > maxAdditional) {
1112
- const maxUsd = import_ethers.ethers.formatUnits(maxAdditional, 6);
1113
- 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);
1114
1203
  throw new AgetherError(
1115
- `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.`,
1116
1205
  "EXCEEDS_MAX_LTV"
1117
1206
  );
1118
1207
  }
@@ -1122,7 +1211,7 @@ var init_MorphoClient = __esm({
1122
1211
  }
1123
1212
  const data = morphoIface.encodeFunctionData("borrow", [
1124
1213
  this._toTuple(params),
1125
- amount,
1214
+ parsedAmount,
1126
1215
  0n,
1127
1216
  acctAddr,
1128
1217
  acctAddr
@@ -1130,7 +1219,7 @@ var init_MorphoClient = __esm({
1130
1219
  const receipt = await this.exec(morphoAddr, data);
1131
1220
  return {
1132
1221
  tx: receipt.hash,
1133
- amount: usdcAmount,
1222
+ amount,
1134
1223
  collateralToken: usedToken,
1135
1224
  agentAccount: acctAddr
1136
1225
  };
@@ -1138,17 +1227,27 @@ var init_MorphoClient = __esm({
1138
1227
  /**
1139
1228
  * Deposit collateral AND borrow USDC in one batched transaction.
1140
1229
  *
1230
+ /**
1231
+ * Deposit collateral AND borrow loan token in one batched transaction.
1232
+ *
1141
1233
  * AgentAccount.executeBatch:
1142
1234
  * [collateral.approve, Morpho.supplyCollateral, Morpho.borrow]
1143
1235
  *
1144
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)
1145
1243
  */
1146
- async depositAndBorrow(tokenSymbol, collateralAmount, borrowUsdcAmount, marketParams) {
1244
+ async depositAndBorrow(tokenSymbol, collateralAmount, borrowAmount, marketParams, loanTokenSymbol) {
1147
1245
  const acctAddr = await this.getAccountAddress();
1148
1246
  const colInfo = await this._resolveToken(tokenSymbol);
1149
- const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
1247
+ const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
1248
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1150
1249
  const colWei = import_ethers.ethers.parseUnits(collateralAmount, colInfo.decimals);
1151
- const borrowWei = import_ethers.ethers.parseUnits(borrowUsdcAmount, 6);
1250
+ const borrowWei = import_ethers.ethers.parseUnits(borrowAmount, loanDecimals);
1152
1251
  const morphoAddr = this.config.contracts.morphoBlue;
1153
1252
  try {
1154
1253
  const marketId = import_ethers.ethers.keccak256(
@@ -1169,9 +1268,11 @@ var init_MorphoClient = __esm({
1169
1268
  const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
1170
1269
  const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
1171
1270
  if (borrowWei > maxAdditional) {
1172
- 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);
1173
1274
  throw new AgetherError(
1174
- `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.`,
1175
1276
  "EXCEEDS_MAX_LTV"
1176
1277
  );
1177
1278
  }
@@ -1217,36 +1318,42 @@ var init_MorphoClient = __esm({
1217
1318
  tx: receipt.hash,
1218
1319
  collateralToken: tokenSymbol,
1219
1320
  collateralAmount,
1220
- borrowAmount: borrowUsdcAmount,
1321
+ borrowAmount,
1221
1322
  agentAccount: acctAddr
1222
1323
  };
1223
1324
  }
1224
1325
  /**
1225
- * Repay borrowed USDC from AgentAccount.
1326
+ * Repay borrowed loan token from AgentAccount.
1226
1327
  *
1227
1328
  * AgentAccount.executeBatch:
1228
- * [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)
1229
1335
  */
1230
- async repay(usdcAmount, tokenSymbol, marketParams) {
1336
+ async repay(amount, tokenSymbol, marketParams, loanTokenSymbol) {
1231
1337
  const acctAddr = await this.getAccountAddress();
1232
1338
  const morphoAddr = this.config.contracts.morphoBlue;
1233
- const usdcAddr = this.config.contracts.usdc;
1234
1339
  let params;
1235
1340
  if (marketParams) {
1236
1341
  params = marketParams;
1237
1342
  } else if (tokenSymbol) {
1238
- params = await this.findMarketForCollateral(tokenSymbol);
1343
+ params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
1239
1344
  } else {
1240
1345
  const { params: p } = await this._findActiveMarket();
1241
1346
  params = p;
1242
1347
  }
1348
+ const loanTokenAddr = params.loanToken;
1349
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1243
1350
  let repayAssets;
1244
1351
  let repayShares;
1245
1352
  let approveAmount;
1246
- if (usdcAmount === "all") {
1353
+ if (amount === "all") {
1247
1354
  const markets = await this.getMarkets();
1248
1355
  const mkt = markets.find(
1249
- (m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase()
1356
+ (m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase() && m.loanAsset?.address.toLowerCase() === params.loanToken.toLowerCase()
1250
1357
  );
1251
1358
  if (mkt) {
1252
1359
  const pos = await this.morphoBlue.position(mkt.uniqueKey, acctAddr);
@@ -1256,33 +1363,35 @@ var init_MorphoClient = __esm({
1256
1363
  const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
1257
1364
  const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
1258
1365
  const estimated = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
1259
- approveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", 6);
1366
+ approveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", loanDecimals);
1260
1367
  } else {
1261
- repayAssets = import_ethers.ethers.parseUnits("999999", 6);
1368
+ repayAssets = import_ethers.ethers.parseUnits("999999", loanDecimals);
1262
1369
  repayShares = 0n;
1263
1370
  approveAmount = repayAssets;
1264
1371
  }
1265
1372
  } else {
1266
- repayAssets = import_ethers.ethers.parseUnits(usdcAmount, 6);
1373
+ repayAssets = import_ethers.ethers.parseUnits(amount, loanDecimals);
1267
1374
  repayShares = 0n;
1268
1375
  approveAmount = repayAssets;
1269
1376
  }
1270
- const usdcContract = new import_ethers.Contract(usdcAddr, ERC20_ABI, this._signer);
1271
- 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);
1272
1379
  if (acctBalance < approveAmount) {
1273
1380
  const shortfall = approveAmount - acctBalance;
1274
- const eoaBalance = await usdcContract.balanceOf(await this.getSignerAddress());
1381
+ const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
1275
1382
  if (eoaBalance < shortfall) {
1383
+ const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
1384
+ const loanSymbol = loanInfo?.symbol ?? "loan token";
1276
1385
  throw new AgetherError(
1277
- `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)}.`,
1278
1387
  "INSUFFICIENT_BALANCE"
1279
1388
  );
1280
1389
  }
1281
- const transferTx = await usdcContract.transfer(acctAddr, shortfall);
1390
+ const transferTx = await loanContract.transfer(acctAddr, shortfall);
1282
1391
  await transferTx.wait();
1283
1392
  this._refreshSigner();
1284
1393
  }
1285
- const targets = [usdcAddr, morphoAddr];
1394
+ const targets = [loanTokenAddr, morphoAddr];
1286
1395
  const values = [0n, 0n];
1287
1396
  const datas = [
1288
1397
  erc20Iface.encodeFunctionData("approve", [morphoAddr, approveAmount]),
@@ -1302,7 +1411,7 @@ var init_MorphoClient = __esm({
1302
1411
  } catch (e) {
1303
1412
  console.warn("[agether] failed to read remaining debt after repay:", e instanceof Error ? e.message : e);
1304
1413
  }
1305
- return { tx: receipt.hash, amount: usdcAmount, remainingDebt };
1414
+ return { tx: receipt.hash, amount, remainingDebt };
1306
1415
  }
1307
1416
  /**
1308
1417
  * Withdraw collateral from Morpho Blue.
@@ -1316,12 +1425,13 @@ var init_MorphoClient = __esm({
1316
1425
  const colInfo = await this._resolveToken(tokenSymbol);
1317
1426
  const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
1318
1427
  const morphoAddr = this.config.contracts.morphoBlue;
1319
- const usdcAddr = this.config.contracts.usdc;
1428
+ const loanTokenAddr = params.loanToken;
1429
+ const loanDecimals = await this._getLoanTokenDecimals(params);
1320
1430
  const dest = receiver || await this.getSignerAddress();
1321
1431
  let weiAmount;
1322
1432
  const markets = await this.getMarkets();
1323
1433
  const market = markets.find(
1324
- (m) => m.collateralAsset?.address.toLowerCase() === colInfo.address.toLowerCase()
1434
+ (m) => m.collateralAsset?.address.toLowerCase() === colInfo.address.toLowerCase() && m.loanAsset?.address.toLowerCase() === loanTokenAddr.toLowerCase()
1325
1435
  );
1326
1436
  if (amount === "all") {
1327
1437
  if (!market) throw new AgetherError("Market not found", "MARKET_NOT_FOUND");
@@ -1344,8 +1454,10 @@ var init_MorphoClient = __esm({
1344
1454
  const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
1345
1455
  const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
1346
1456
  const estimated = totalBorrowShares > 0n ? dustBorrowShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
1347
- dustApproveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", 6);
1348
- 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`);
1349
1461
  }
1350
1462
  } catch (e) {
1351
1463
  console.warn("[agether] failed to check borrow shares before withdraw:", e instanceof Error ? e.message : e);
@@ -1359,19 +1471,21 @@ var init_MorphoClient = __esm({
1359
1471
  ]);
1360
1472
  let receipt;
1361
1473
  if (hasDustDebt) {
1362
- const usdcContract = new import_ethers.Contract(usdcAddr, ERC20_ABI, this._signer);
1363
- 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);
1364
1476
  if (acctBalance < dustApproveAmount) {
1365
1477
  const shortfall = dustApproveAmount - acctBalance;
1366
- const eoaBalance = await usdcContract.balanceOf(await this.getSignerAddress());
1478
+ const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
1367
1479
  if (eoaBalance >= shortfall) {
1368
- console.log(`[agether] transferring ${import_ethers.ethers.formatUnits(shortfall, 6)} USDC from EOA \u2192 AgentAccount for dust repay`);
1369
- 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);
1370
1484
  await transferTx.wait();
1371
1485
  this._refreshSigner();
1372
1486
  }
1373
1487
  }
1374
- const targets = [usdcAddr, morphoAddr, morphoAddr];
1488
+ const targets = [loanTokenAddr, morphoAddr, morphoAddr];
1375
1489
  const values = [0n, 0n, 0n];
1376
1490
  const datas = [
1377
1491
  erc20Iface.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
@@ -1616,6 +1730,37 @@ var init_MorphoClient = __esm({
1616
1730
  }
1617
1731
  throw new AgetherError("No active supply position found", "NO_SUPPLY");
1618
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
+ }
1619
1764
  /**
1620
1765
  * Resolve a token symbol or address to { address, symbol, decimals }.
1621
1766
  *
@@ -1632,8 +1777,8 @@ var init_MorphoClient = __esm({
1632
1777
  const fromApi = this._tokenCache.get(key);
1633
1778
  if (fromApi) return fromApi;
1634
1779
  throw new AgetherError(
1635
- `Unknown token: ${symbolOrAddress}. No Morpho market found with this collateral.`,
1636
- "UNKNOWN_COLLATERAL"
1780
+ `Unknown token: ${symbolOrAddress}. No Morpho market found with this token.`,
1781
+ "UNKNOWN_TOKEN"
1637
1782
  );
1638
1783
  }
1639
1784
  /**
@@ -1839,25 +1984,21 @@ var init_AgetherClient = __esm({
1839
1984
  const acctAddr = await this.agether4337Factory.getAccount(agentId);
1840
1985
  this.accountAddress = acctAddr;
1841
1986
  if (!acctExists) {
1842
- try {
1843
- const updatedMeta = JSON.stringify({
1844
- type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
1845
- name: options?.name || "Unnamed Agent",
1846
- description: options?.description || "AI agent registered via @agether/sdk",
1847
- active: true,
1848
- wallet: `eip155:${this.config.chainId}:${acctAddr}`,
1849
- registrations: [{
1850
- agentId: Number(agentId),
1851
- agentRegistry: `eip155:${this.config.chainId}:${this.config.contracts.identityRegistry}`
1852
- }]
1853
- });
1854
- const finalURI = `data:application/json;base64,${Buffer.from(updatedMeta).toString("base64")}`;
1855
- const uriTx = await this.identityRegistry.setAgentURI(agentId, finalURI);
1856
- await uriTx.wait();
1857
- this._refreshSigner();
1858
- } catch (e) {
1859
- console.warn("[agether] setAgentURI failed (non-fatal):", e instanceof Error ? e.message : e);
1860
- }
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();
1861
2002
  }
1862
2003
  const kyaRequired = await this.isKyaRequired();
1863
2004
  return {
@@ -1875,7 +2016,7 @@ var init_AgetherClient = __esm({
1875
2016
  async _mintNewIdentity(name, description) {
1876
2017
  const registrationFile = JSON.stringify({
1877
2018
  type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
1878
- name: name || "Unnamed Agent",
2019
+ name: name || "Agether Agent",
1879
2020
  description: description || "AI agent registered via @agether/sdk",
1880
2021
  active: true,
1881
2022
  registrations: [{