@agether/sdk 2.12.2 → 2.14.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.d.ts +29 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +533 -161
- package/dist/clients/AgentIdentityClient.d.ts +200 -0
- package/dist/clients/AgentIdentityClient.d.ts.map +1 -0
- package/dist/clients/AgentIdentityClient.js +351 -0
- package/dist/clients/AgetherClient.d.ts +242 -0
- package/dist/clients/AgetherClient.d.ts.map +1 -0
- package/dist/clients/AgetherClient.js +736 -0
- package/dist/clients/MorphoClient.d.ts +572 -0
- package/dist/clients/MorphoClient.d.ts.map +1 -0
- package/dist/clients/MorphoClient.js +1974 -0
- package/dist/clients/ScoringClient.d.ts +103 -0
- package/dist/clients/ScoringClient.d.ts.map +1 -0
- package/dist/clients/ScoringClient.js +112 -0
- package/dist/clients/X402Client.d.ts +198 -0
- package/dist/clients/X402Client.d.ts.map +1 -0
- package/dist/clients/X402Client.js +438 -0
- package/dist/index.d.mts +175 -27
- package/dist/index.d.ts +175 -27
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +533 -161
- package/dist/index.mjs +533 -161
- package/dist/types/index.d.ts +132 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +46 -0
- package/dist/utils/abis.d.ts +29 -0
- package/dist/utils/abis.d.ts.map +1 -0
- package/dist/utils/abis.js +138 -0
- package/dist/utils/config.d.ts +36 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +168 -0
- package/dist/utils/format.d.ts +44 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +75 -0
- package/package.json +1 -1
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
|
|
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
|
-
first:
|
|
411
|
+
first: 500
|
|
409
412
|
orderBy: SupplyAssetsUsd
|
|
410
413
|
orderDirection: Desc
|
|
411
|
-
where: { chainId_in: [${chainId}]
|
|
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
|
-
|
|
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
|
|
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,41 @@ var init_MorphoClient = __esm({
|
|
|
495
505
|
colAddr = collateralSymbolOrAddress.toLowerCase();
|
|
496
506
|
}
|
|
497
507
|
}
|
|
498
|
-
|
|
499
|
-
if (
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
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
|
+
}
|
|
533
|
+
if (!collateralSymbolOrAddress.startsWith("0x")) {
|
|
534
|
+
const searched = await this.searchMarkets(collateralSymbolOrAddress, { asCollateral: true });
|
|
535
|
+
for (const m of searched) {
|
|
536
|
+
if (loanAddr && m.loanAddress.toLowerCase() !== loanAddr) continue;
|
|
537
|
+
if (loanTokenSymbolOrAddress && !loanTokenSymbolOrAddress.startsWith("0x") && m.loanToken.toUpperCase() !== loanTokenSymbolOrAddress.toUpperCase()) continue;
|
|
538
|
+
return this.getMarketParams(m.marketId);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
503
541
|
throw new AgetherError(
|
|
504
|
-
`No Morpho market found for collateral ${collateralSymbolOrAddress}
|
|
542
|
+
`No Morpho market found for collateral ${collateralSymbolOrAddress}` + (loanTokenSymbolOrAddress ? ` with loan token ${loanTokenSymbolOrAddress}` : ""),
|
|
505
543
|
"MARKET_NOT_FOUND"
|
|
506
544
|
);
|
|
507
545
|
}
|
|
@@ -536,12 +574,13 @@ var init_MorphoClient = __esm({
|
|
|
536
574
|
const acctAddr = await this.getAccountAddress();
|
|
537
575
|
const markets = await this.getMarkets();
|
|
538
576
|
const positions = [];
|
|
539
|
-
let
|
|
577
|
+
let totalDebtFloat = 0;
|
|
540
578
|
for (const m of markets) {
|
|
541
579
|
if (!m.collateralAsset || m.collateralAsset.address === import_ethers.ethers.ZeroAddress) continue;
|
|
542
580
|
try {
|
|
543
581
|
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
544
582
|
if (pos.collateral === 0n && pos.borrowShares === 0n && pos.supplyShares === 0n) continue;
|
|
583
|
+
const loanDecimals = m.loanAsset.decimals;
|
|
545
584
|
let debt = 0n;
|
|
546
585
|
if (pos.borrowShares > 0n) {
|
|
547
586
|
try {
|
|
@@ -549,7 +588,7 @@ var init_MorphoClient = __esm({
|
|
|
549
588
|
const totalBorrowShares = BigInt(mkt.totalBorrowShares);
|
|
550
589
|
const totalBorrowAssets = BigInt(mkt.totalBorrowAssets);
|
|
551
590
|
debt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
552
|
-
|
|
591
|
+
totalDebtFloat += parseFloat(import_ethers.ethers.formatUnits(debt, loanDecimals));
|
|
553
592
|
} catch (e) {
|
|
554
593
|
console.warn(`[agether] debt calc failed for market ${m.uniqueKey}:`, e instanceof Error ? e.message : e);
|
|
555
594
|
}
|
|
@@ -557,10 +596,11 @@ var init_MorphoClient = __esm({
|
|
|
557
596
|
positions.push({
|
|
558
597
|
marketId: m.uniqueKey,
|
|
559
598
|
collateralToken: m.collateralAsset.symbol,
|
|
599
|
+
loanToken: m.loanAsset.symbol,
|
|
560
600
|
collateral: import_ethers.ethers.formatUnits(pos.collateral, m.collateralAsset.decimals),
|
|
561
601
|
borrowShares: pos.borrowShares.toString(),
|
|
562
602
|
supplyShares: pos.supplyShares.toString(),
|
|
563
|
-
debt: import_ethers.ethers.formatUnits(debt,
|
|
603
|
+
debt: import_ethers.ethers.formatUnits(debt, loanDecimals)
|
|
564
604
|
});
|
|
565
605
|
} catch (e) {
|
|
566
606
|
console.warn(`[agether] position read failed for market:`, e instanceof Error ? e.message : e);
|
|
@@ -570,16 +610,28 @@ var init_MorphoClient = __esm({
|
|
|
570
610
|
return {
|
|
571
611
|
agentId: this.agentId,
|
|
572
612
|
agentAccount: acctAddr,
|
|
573
|
-
totalDebt:
|
|
613
|
+
totalDebt: totalDebtFloat.toFixed(6),
|
|
574
614
|
positions
|
|
575
615
|
};
|
|
576
616
|
}
|
|
577
617
|
// ════════════════════════════════════════════════════════
|
|
578
618
|
// Balance & Borrowing Capacity
|
|
579
619
|
// ════════════════════════════════════════════════════════
|
|
620
|
+
/**
|
|
621
|
+
* Get the balance of any ERC-20 token in the AgentAccount.
|
|
622
|
+
* @param symbolOrAddress - token symbol (e.g. 'USDC', 'WETH') or address
|
|
623
|
+
* @returns balance in raw units
|
|
624
|
+
*/
|
|
625
|
+
async getTokenBalance(symbolOrAddress) {
|
|
626
|
+
const acctAddr = await this.getAccountAddress();
|
|
627
|
+
const tokenInfo = await this._resolveToken(symbolOrAddress);
|
|
628
|
+
const token = new import_ethers.Contract(tokenInfo.address, ERC20_ABI, this.provider);
|
|
629
|
+
return token.balanceOf(acctAddr);
|
|
630
|
+
}
|
|
580
631
|
/**
|
|
581
632
|
* Get the USDC balance of the AgentAccount.
|
|
582
633
|
* @returns USDC balance in raw units (6 decimals)
|
|
634
|
+
* @deprecated Use `getTokenBalance('USDC')` instead.
|
|
583
635
|
*/
|
|
584
636
|
async getUsdcBalance() {
|
|
585
637
|
const acctAddr = await this.getAccountAddress();
|
|
@@ -587,7 +639,7 @@ var init_MorphoClient = __esm({
|
|
|
587
639
|
return usdc.balanceOf(acctAddr);
|
|
588
640
|
}
|
|
589
641
|
/**
|
|
590
|
-
* Calculate the maximum additional
|
|
642
|
+
* Calculate the maximum additional loan token that can be borrowed
|
|
591
643
|
* given the agent's current collateral and debt across all markets.
|
|
592
644
|
*
|
|
593
645
|
* For each market with collateral deposited:
|
|
@@ -595,7 +647,7 @@ var init_MorphoClient = __esm({
|
|
|
595
647
|
*
|
|
596
648
|
* Uses the Morpho oracle to price collateral → loan token.
|
|
597
649
|
*
|
|
598
|
-
* @returns Maximum additional
|
|
650
|
+
* @returns Maximum additional borrowable per market (raw units in each market's loan token)
|
|
599
651
|
*/
|
|
600
652
|
async getMaxBorrowable() {
|
|
601
653
|
const acctAddr = await this.getAccountAddress();
|
|
@@ -628,6 +680,8 @@ var init_MorphoClient = __esm({
|
|
|
628
680
|
totalAdditional += maxAdditional;
|
|
629
681
|
byMarket.push({
|
|
630
682
|
collateralToken: m.collateralAsset.symbol,
|
|
683
|
+
loanToken: m.loanAsset.symbol,
|
|
684
|
+
loanDecimals: m.loanAsset.decimals,
|
|
631
685
|
maxAdditional,
|
|
632
686
|
currentDebt,
|
|
633
687
|
collateralValue: collateralValueInLoan
|
|
@@ -643,35 +697,50 @@ var init_MorphoClient = __esm({
|
|
|
643
697
|
// Market Rates & Yield Estimation
|
|
644
698
|
// ════════════════════════════════════════════════════════
|
|
645
699
|
/**
|
|
646
|
-
* Fetch current supply/borrow APY for
|
|
700
|
+
* Fetch current supply/borrow APY for markets from Morpho GraphQL API.
|
|
647
701
|
*
|
|
648
702
|
* Note: On Morpho Blue, collateral does NOT earn yield directly. Supply APY
|
|
649
703
|
* is what lenders earn; borrow APY is what borrowers pay.
|
|
704
|
+
*
|
|
705
|
+
* @param collateralSymbolOrAddress - filter by collateral token (optional)
|
|
706
|
+
* @param loanTokenSymbolOrAddress - filter by loan token (optional). Omit for all loan tokens.
|
|
650
707
|
*/
|
|
651
|
-
async getMarketRates(collateralSymbolOrAddress) {
|
|
708
|
+
async getMarketRates(collateralSymbolOrAddress, loanTokenSymbolOrAddress) {
|
|
652
709
|
const chainId = this.config.chainId;
|
|
653
|
-
const usdcAddr = this.config.contracts.usdc.toLowerCase();
|
|
654
710
|
let collateralFilter = "";
|
|
711
|
+
let loanFilter = "";
|
|
712
|
+
let searchTerm = "";
|
|
655
713
|
if (collateralSymbolOrAddress) {
|
|
656
|
-
let colAddr;
|
|
657
714
|
if (collateralSymbolOrAddress.startsWith("0x")) {
|
|
658
|
-
|
|
715
|
+
collateralFilter = `, collateralAssetAddress_in: ["${collateralSymbolOrAddress.toLowerCase()}"]`;
|
|
659
716
|
} else {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
}
|
|
664
|
-
|
|
717
|
+
const cached = this._tokenCache.get(collateralSymbolOrAddress.toUpperCase());
|
|
718
|
+
if (cached) {
|
|
719
|
+
collateralFilter = `, collateralAssetAddress_in: ["${cached.address.toLowerCase()}"]`;
|
|
720
|
+
} else {
|
|
721
|
+
searchTerm = collateralSymbolOrAddress;
|
|
665
722
|
}
|
|
666
723
|
}
|
|
667
|
-
collateralFilter = `, collateralAssetAddress_in: ["${colAddr}"]`;
|
|
668
724
|
}
|
|
725
|
+
if (loanTokenSymbolOrAddress) {
|
|
726
|
+
if (loanTokenSymbolOrAddress.startsWith("0x")) {
|
|
727
|
+
loanFilter = `, loanAssetAddress_in: ["${loanTokenSymbolOrAddress.toLowerCase()}"]`;
|
|
728
|
+
} else {
|
|
729
|
+
const cached = this._tokenCache.get(loanTokenSymbolOrAddress.toUpperCase());
|
|
730
|
+
if (cached) {
|
|
731
|
+
loanFilter = `, loanAssetAddress_in: ["${cached.address.toLowerCase()}"]`;
|
|
732
|
+
} else {
|
|
733
|
+
searchTerm = searchTerm || loanTokenSymbolOrAddress;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
const searchClause = searchTerm ? `, search: "${searchTerm}"` : "";
|
|
669
738
|
const query = `{
|
|
670
739
|
markets(
|
|
671
|
-
first:
|
|
740
|
+
first: 100
|
|
672
741
|
orderBy: SupplyAssetsUsd
|
|
673
742
|
orderDirection: Desc
|
|
674
|
-
where: { chainId_in: [${chainId}]
|
|
743
|
+
where: { chainId_in: [${chainId}]${loanFilter}${collateralFilter}${searchClause} }
|
|
675
744
|
) {
|
|
676
745
|
items {
|
|
677
746
|
uniqueKey
|
|
@@ -690,23 +759,234 @@ var init_MorphoClient = __esm({
|
|
|
690
759
|
}`;
|
|
691
760
|
try {
|
|
692
761
|
const resp = await import_axios.default.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
762
|
+
let items = resp.data?.data?.markets?.items ?? [];
|
|
763
|
+
if (searchTerm && collateralSymbolOrAddress && !collateralSymbolOrAddress.startsWith("0x")) {
|
|
764
|
+
const sym = collateralSymbolOrAddress.toUpperCase();
|
|
765
|
+
items = items.filter((m) => m.collateralAsset?.symbol?.toUpperCase() === sym);
|
|
766
|
+
}
|
|
767
|
+
if (searchTerm && loanTokenSymbolOrAddress && !loanTokenSymbolOrAddress.startsWith("0x")) {
|
|
768
|
+
const sym = loanTokenSymbolOrAddress.toUpperCase();
|
|
769
|
+
items = items.filter((m) => m.loanAsset?.symbol?.toUpperCase() === sym);
|
|
770
|
+
}
|
|
771
|
+
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers.ethers.ZeroAddress).map((m) => {
|
|
772
|
+
const loanDecimals = m.loanAsset?.decimals ?? 18;
|
|
773
|
+
return {
|
|
774
|
+
collateralToken: m.collateralAsset.symbol,
|
|
775
|
+
loanToken: m.loanAsset.symbol,
|
|
776
|
+
loanDecimals,
|
|
777
|
+
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
778
|
+
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
779
|
+
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
780
|
+
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
781
|
+
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
782
|
+
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
783
|
+
marketId: m.uniqueKey
|
|
784
|
+
};
|
|
785
|
+
});
|
|
705
786
|
} catch (e) {
|
|
706
787
|
console.warn("[agether] getMarketRates failed:", e instanceof Error ? e.message : e);
|
|
707
788
|
return [];
|
|
708
789
|
}
|
|
709
790
|
}
|
|
791
|
+
// ════════════════════════════════════════════════════════
|
|
792
|
+
// Market Search & Wallet Discovery
|
|
793
|
+
// ════════════════════════════════════════════════════════
|
|
794
|
+
/**
|
|
795
|
+
* Search Morpho markets by token name using the Morpho GraphQL API `search` field.
|
|
796
|
+
* No hardcoded token lists — uses Morpho's built-in fuzzy search.
|
|
797
|
+
*
|
|
798
|
+
* @param search - token name or symbol (e.g. 'WETH', 'staked ETH', 'ezETH')
|
|
799
|
+
* @param options.asCollateral - only return markets where the searched token is collateral
|
|
800
|
+
* @param options.asLoanToken - only return markets where the searched token is the loan asset
|
|
801
|
+
*/
|
|
802
|
+
async searchMarkets(search, options) {
|
|
803
|
+
const chainId = this.config.chainId;
|
|
804
|
+
const query = `{
|
|
805
|
+
markets(
|
|
806
|
+
first: 100
|
|
807
|
+
orderBy: SupplyAssetsUsd
|
|
808
|
+
orderDirection: Desc
|
|
809
|
+
where: { chainId_in: [${chainId}], search: "${search}" }
|
|
810
|
+
) {
|
|
811
|
+
items {
|
|
812
|
+
uniqueKey
|
|
813
|
+
lltv
|
|
814
|
+
loanAsset { address symbol decimals }
|
|
815
|
+
collateralAsset { address symbol decimals }
|
|
816
|
+
state {
|
|
817
|
+
borrowAssets
|
|
818
|
+
supplyAssets
|
|
819
|
+
utilization
|
|
820
|
+
supplyApy
|
|
821
|
+
borrowApy
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
}`;
|
|
826
|
+
try {
|
|
827
|
+
const resp = await import_axios.default.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
|
|
828
|
+
let items = resp.data?.data?.markets?.items ?? [];
|
|
829
|
+
items = items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers.ethers.ZeroAddress);
|
|
830
|
+
const searchUpper = search.toUpperCase();
|
|
831
|
+
if (options?.asCollateral) {
|
|
832
|
+
items = items.filter((m) => m.collateralAsset?.symbol?.toUpperCase() === searchUpper);
|
|
833
|
+
}
|
|
834
|
+
if (options?.asLoanToken) {
|
|
835
|
+
items = items.filter((m) => m.loanAsset?.symbol?.toUpperCase() === searchUpper);
|
|
836
|
+
}
|
|
837
|
+
return items.map((m) => {
|
|
838
|
+
const loanDecimals = m.loanAsset?.decimals ?? 18;
|
|
839
|
+
const collateralDecimals = m.collateralAsset?.decimals ?? 18;
|
|
840
|
+
return {
|
|
841
|
+
collateralToken: m.collateralAsset.symbol,
|
|
842
|
+
loanToken: m.loanAsset.symbol,
|
|
843
|
+
loanDecimals,
|
|
844
|
+
collateralDecimals,
|
|
845
|
+
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
846
|
+
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
847
|
+
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
848
|
+
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 10 ** loanDecimals : 0,
|
|
849
|
+
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 10 ** loanDecimals : 0,
|
|
850
|
+
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
851
|
+
marketId: m.uniqueKey,
|
|
852
|
+
collateralAddress: m.collateralAsset.address,
|
|
853
|
+
loanAddress: m.loanAsset.address
|
|
854
|
+
};
|
|
855
|
+
});
|
|
856
|
+
} catch (e) {
|
|
857
|
+
console.warn("[agether] searchMarkets failed:", e instanceof Error ? e.message : e);
|
|
858
|
+
return [];
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Scan the AgentAccount wallet for all ERC-20 tokens that appear in Morpho
|
|
863
|
+
* markets on the current chain. Returns tokens where balance > 0.
|
|
864
|
+
*
|
|
865
|
+
* Uses the full market list (500 markets) to discover all relevant tokens,
|
|
866
|
+
* then checks on-chain balance for each unique token address.
|
|
867
|
+
*
|
|
868
|
+
* @returns Array of tokens with non-zero balance, sorted by balance descending.
|
|
869
|
+
*/
|
|
870
|
+
async getWalletTokenBalances() {
|
|
871
|
+
const acctAddr = await this.getAccountAddress();
|
|
872
|
+
await this.getMarkets();
|
|
873
|
+
const uniqueTokens = /* @__PURE__ */ new Map();
|
|
874
|
+
for (const [key, info] of this._tokenCache.entries()) {
|
|
875
|
+
if (key.startsWith("0x") && !uniqueTokens.has(key)) {
|
|
876
|
+
uniqueTokens.set(key, info);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
const results = [];
|
|
880
|
+
try {
|
|
881
|
+
const ethBalance = await this.provider.getBalance(acctAddr);
|
|
882
|
+
if (ethBalance > 0n) {
|
|
883
|
+
results.push({
|
|
884
|
+
symbol: "ETH",
|
|
885
|
+
address: import_ethers.ethers.ZeroAddress,
|
|
886
|
+
decimals: 18,
|
|
887
|
+
balance: ethBalance,
|
|
888
|
+
balanceFormatted: import_ethers.ethers.formatEther(ethBalance)
|
|
889
|
+
});
|
|
890
|
+
}
|
|
891
|
+
} catch {
|
|
892
|
+
}
|
|
893
|
+
const tokenEntries = Array.from(uniqueTokens.values());
|
|
894
|
+
const batchSize = 20;
|
|
895
|
+
for (let i = 0; i < tokenEntries.length; i += batchSize) {
|
|
896
|
+
const batch = tokenEntries.slice(i, i + batchSize);
|
|
897
|
+
const checks = batch.map(async (info) => {
|
|
898
|
+
try {
|
|
899
|
+
const token = new import_ethers.Contract(info.address, ERC20_ABI, this.provider);
|
|
900
|
+
const balance = await token.balanceOf(acctAddr);
|
|
901
|
+
if (balance > 0n) {
|
|
902
|
+
return {
|
|
903
|
+
symbol: info.symbol,
|
|
904
|
+
address: info.address,
|
|
905
|
+
decimals: info.decimals,
|
|
906
|
+
balance,
|
|
907
|
+
balanceFormatted: import_ethers.ethers.formatUnits(balance, info.decimals)
|
|
908
|
+
};
|
|
909
|
+
}
|
|
910
|
+
} catch {
|
|
911
|
+
}
|
|
912
|
+
return null;
|
|
913
|
+
});
|
|
914
|
+
const batchResults = await Promise.all(checks);
|
|
915
|
+
for (const r of batchResults) {
|
|
916
|
+
if (r) results.push(r);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
results.sort((a, b) => b.balance > a.balance ? 1 : b.balance < a.balance ? -1 : 0);
|
|
920
|
+
return results;
|
|
921
|
+
}
|
|
922
|
+
/**
|
|
923
|
+
* Find borrowing opportunities for the agent.
|
|
924
|
+
*
|
|
925
|
+
* - If `collateralSymbol` is provided: find all markets where that token is collateral.
|
|
926
|
+
* - If omitted: scan wallet balances and find markets for each token the agent holds.
|
|
927
|
+
*
|
|
928
|
+
* Returns markets grouped by collateral token with APY, liquidity, and balance info.
|
|
929
|
+
*
|
|
930
|
+
* @param collateralSymbol - optional, e.g. 'WETH'. If omitted, scans wallet.
|
|
931
|
+
*/
|
|
932
|
+
async findBorrowingOptions(collateralSymbol) {
|
|
933
|
+
let tokensToCheck;
|
|
934
|
+
if (collateralSymbol) {
|
|
935
|
+
tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted: "N/A" }];
|
|
936
|
+
try {
|
|
937
|
+
const balance = await this.getTokenBalance(collateralSymbol);
|
|
938
|
+
const info = await this._resolveToken(collateralSymbol);
|
|
939
|
+
tokensToCheck = [{ symbol: collateralSymbol, balanceFormatted: import_ethers.ethers.formatUnits(balance, info.decimals) }];
|
|
940
|
+
} catch {
|
|
941
|
+
}
|
|
942
|
+
} else {
|
|
943
|
+
const walletTokens = await this.getWalletTokenBalances();
|
|
944
|
+
tokensToCheck = walletTokens.filter((t) => t.symbol !== "ETH").map((t) => ({ symbol: t.symbol, balanceFormatted: t.balanceFormatted }));
|
|
945
|
+
if (tokensToCheck.length === 0) {
|
|
946
|
+
return [];
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
const results = [];
|
|
950
|
+
for (const token of tokensToCheck) {
|
|
951
|
+
const markets = await this.searchMarkets(token.symbol, { asCollateral: true });
|
|
952
|
+
if (markets.length === 0) continue;
|
|
953
|
+
results.push({
|
|
954
|
+
collateralToken: token.symbol,
|
|
955
|
+
collateralBalance: token.balanceFormatted,
|
|
956
|
+
markets: markets.map((m) => ({
|
|
957
|
+
loanToken: m.loanToken,
|
|
958
|
+
borrowApy: `${(m.borrowApy * 100).toFixed(2)}%`,
|
|
959
|
+
supplyApy: `${(m.supplyApy * 100).toFixed(2)}%`,
|
|
960
|
+
lltv: m.lltv,
|
|
961
|
+
utilization: `${(m.utilization * 100).toFixed(1)}%`,
|
|
962
|
+
availableLiquidity: `$${(m.totalSupplyUsd - m.totalBorrowUsd).toFixed(0)}`,
|
|
963
|
+
marketId: m.marketId
|
|
964
|
+
}))
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
return results;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Find supply/lending opportunities for a specific loan token.
|
|
971
|
+
*
|
|
972
|
+
* "What can I supply to earn WETH?" → shows all markets where WETH is the loan token
|
|
973
|
+
* (user supplies WETH to earn yield from borrowers).
|
|
974
|
+
*
|
|
975
|
+
* @param loanTokenSymbol - e.g. 'USDC', 'WETH'
|
|
976
|
+
*/
|
|
977
|
+
async findSupplyOptions(loanTokenSymbol) {
|
|
978
|
+
const markets = await this.searchMarkets(loanTokenSymbol, { asLoanToken: true });
|
|
979
|
+
return markets.map((m) => ({
|
|
980
|
+
collateralToken: m.collateralToken,
|
|
981
|
+
loanToken: m.loanToken,
|
|
982
|
+
supplyApy: `${(m.supplyApy * 100).toFixed(2)}%`,
|
|
983
|
+
borrowApy: `${(m.borrowApy * 100).toFixed(2)}%`,
|
|
984
|
+
lltv: m.lltv,
|
|
985
|
+
utilization: `${(m.utilization * 100).toFixed(1)}%`,
|
|
986
|
+
totalSupply: `$${m.totalSupplyUsd.toFixed(0)}`,
|
|
987
|
+
marketId: m.marketId
|
|
988
|
+
}));
|
|
989
|
+
}
|
|
710
990
|
/**
|
|
711
991
|
* Estimate theoretical yield for a given collateral amount over a period.
|
|
712
992
|
*
|
|
@@ -735,14 +1015,15 @@ var init_MorphoClient = __esm({
|
|
|
735
1015
|
} else {
|
|
736
1016
|
try {
|
|
737
1017
|
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
1018
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
738
1019
|
const oracleContract = new import_ethers.Contract(params.oracle, [
|
|
739
1020
|
"function price() view returns (uint256)"
|
|
740
1021
|
], this.provider);
|
|
741
1022
|
const oraclePrice = await oracleContract.price();
|
|
742
1023
|
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
743
1024
|
const amountWei = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
|
|
744
|
-
const
|
|
745
|
-
collateralValueUsd = Number(
|
|
1025
|
+
const valueInLoan = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
|
|
1026
|
+
collateralValueUsd = Number(valueInLoan) / 10 ** loanDecimals;
|
|
746
1027
|
} catch (e) {
|
|
747
1028
|
console.warn("[agether] oracle price fetch for yield estimation failed:", e instanceof Error ? e.message : e);
|
|
748
1029
|
throw new AgetherError("Cannot determine collateral value. Provide ethPriceUsd.", "PRICE_UNAVAILABLE");
|
|
@@ -763,61 +1044,65 @@ var init_MorphoClient = __esm({
|
|
|
763
1044
|
// Supply-Side (Lending) — earn yield by supplying USDC
|
|
764
1045
|
// ════════════════════════════════════════════════════════
|
|
765
1046
|
/**
|
|
766
|
-
* Supply
|
|
1047
|
+
* Supply loan token to a Morpho Blue market as a lender (earn yield).
|
|
767
1048
|
*
|
|
768
1049
|
* Unlike `supplyCollateral` (borrower-side), this is the **lender-side**:
|
|
769
|
-
* you deposit the loanToken
|
|
1050
|
+
* you deposit the loanToken into the market's supply pool and earn
|
|
770
1051
|
* interest paid by borrowers.
|
|
771
1052
|
*
|
|
772
|
-
* @param
|
|
1053
|
+
* @param amount - Amount of loan token to supply (e.g. '500' for 500 USDC, '0.5' for 0.5 WETH)
|
|
773
1054
|
* @param collateralSymbol - Market collateral token to identify which market (e.g. 'WETH')
|
|
774
1055
|
* Optional — defaults to highest-APY market
|
|
1056
|
+
* @param loanTokenSymbol - Loan token to filter market (e.g. 'USDC', 'WETH'). Optional.
|
|
775
1057
|
*/
|
|
776
|
-
async supplyAsset(
|
|
1058
|
+
async supplyAsset(amount, collateralSymbol, loanTokenSymbol) {
|
|
777
1059
|
const acctAddr = await this.getAccountAddress();
|
|
778
|
-
const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
|
|
779
1060
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
780
|
-
const usdcAddr = this.config.contracts.usdc;
|
|
781
1061
|
let params;
|
|
782
1062
|
let usedCollateral;
|
|
783
1063
|
if (collateralSymbol) {
|
|
784
|
-
params = await this.findMarketForCollateral(collateralSymbol);
|
|
1064
|
+
params = await this.findMarketForCollateral(collateralSymbol, loanTokenSymbol);
|
|
785
1065
|
usedCollateral = collateralSymbol;
|
|
786
1066
|
} else {
|
|
787
|
-
const rates = await this.getMarketRates();
|
|
1067
|
+
const rates = await this.getMarketRates(void 0, loanTokenSymbol);
|
|
788
1068
|
if (rates.length === 0) throw new AgetherError("No markets available", "NO_MARKETS");
|
|
789
1069
|
const best = rates.reduce((a, b) => a.supplyApy > b.supplyApy ? a : b);
|
|
790
|
-
params = await this.findMarketForCollateral(best.collateralToken);
|
|
1070
|
+
params = await this.findMarketForCollateral(best.collateralToken, loanTokenSymbol);
|
|
791
1071
|
usedCollateral = best.collateralToken;
|
|
792
1072
|
}
|
|
1073
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1074
|
+
const loanTokenAddr = params.loanToken;
|
|
1075
|
+
const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
|
|
793
1076
|
const marketId = import_ethers.ethers.keccak256(
|
|
794
1077
|
import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
795
1078
|
["address", "address", "address", "address", "uint256"],
|
|
796
1079
|
[params.loanToken, params.collateralToken, params.oracle, params.irm, params.lltv]
|
|
797
1080
|
)
|
|
798
1081
|
);
|
|
799
|
-
const
|
|
800
|
-
const acctBalance = await
|
|
801
|
-
if (acctBalance <
|
|
802
|
-
const shortfall =
|
|
803
|
-
const eoaBalance = await
|
|
1082
|
+
const loanContract = new import_ethers.Contract(loanTokenAddr, ERC20_ABI, this._signer);
|
|
1083
|
+
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
1084
|
+
if (acctBalance < parsedAmount) {
|
|
1085
|
+
const shortfall = parsedAmount - acctBalance;
|
|
1086
|
+
const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
|
|
804
1087
|
if (eoaBalance < shortfall) {
|
|
1088
|
+
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
1089
|
+
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
805
1090
|
throw new AgetherError(
|
|
806
|
-
`Insufficient
|
|
1091
|
+
`Insufficient ${loanSymbol}. Need ${amount}, AgentAccount has ${import_ethers.ethers.formatUnits(acctBalance, loanDecimals)}, EOA has ${import_ethers.ethers.formatUnits(eoaBalance, loanDecimals)}.`,
|
|
807
1092
|
"INSUFFICIENT_BALANCE"
|
|
808
1093
|
);
|
|
809
1094
|
}
|
|
810
|
-
const transferTx = await
|
|
1095
|
+
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
811
1096
|
await transferTx.wait();
|
|
812
1097
|
this._refreshSigner();
|
|
813
1098
|
}
|
|
814
|
-
const targets = [
|
|
1099
|
+
const targets = [loanTokenAddr, morphoAddr];
|
|
815
1100
|
const values = [0n, 0n];
|
|
816
1101
|
const datas = [
|
|
817
|
-
erc20Iface.encodeFunctionData("approve", [morphoAddr,
|
|
1102
|
+
erc20Iface.encodeFunctionData("approve", [morphoAddr, parsedAmount]),
|
|
818
1103
|
morphoIface.encodeFunctionData("supply", [
|
|
819
1104
|
this._toTuple(params),
|
|
820
|
-
|
|
1105
|
+
parsedAmount,
|
|
821
1106
|
0n,
|
|
822
1107
|
acctAddr,
|
|
823
1108
|
"0x"
|
|
@@ -826,7 +1111,7 @@ var init_MorphoClient = __esm({
|
|
|
826
1111
|
const receipt = await this.batch(targets, values, datas);
|
|
827
1112
|
return {
|
|
828
1113
|
tx: receipt.hash,
|
|
829
|
-
amount
|
|
1114
|
+
amount,
|
|
830
1115
|
marketId,
|
|
831
1116
|
collateralToken: usedCollateral,
|
|
832
1117
|
agentAccount: acctAddr
|
|
@@ -839,17 +1124,26 @@ var init_MorphoClient = __esm({
|
|
|
839
1124
|
* @param collateralSymbol - Market collateral to identify which market
|
|
840
1125
|
* @param receiver - Destination address (defaults to EOA)
|
|
841
1126
|
*/
|
|
842
|
-
|
|
1127
|
+
/**
|
|
1128
|
+
* Withdraw supplied loan token (+ earned interest) from a Morpho Blue market.
|
|
1129
|
+
*
|
|
1130
|
+
* @param amount - Amount to withdraw (e.g. '100' or 'all' for full position)
|
|
1131
|
+
* @param collateralSymbol - Market collateral to identify which market
|
|
1132
|
+
* @param receiver - Destination address (defaults to EOA)
|
|
1133
|
+
* @param loanTokenSymbol - Loan token to filter market (optional)
|
|
1134
|
+
*/
|
|
1135
|
+
async withdrawSupply(amount, collateralSymbol, receiver, loanTokenSymbol) {
|
|
843
1136
|
const acctAddr = await this.getAccountAddress();
|
|
844
1137
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
845
1138
|
const dest = receiver || await this.getSignerAddress();
|
|
846
1139
|
let params;
|
|
847
1140
|
if (collateralSymbol) {
|
|
848
|
-
params = await this.findMarketForCollateral(collateralSymbol);
|
|
1141
|
+
params = await this.findMarketForCollateral(collateralSymbol, loanTokenSymbol);
|
|
849
1142
|
} else {
|
|
850
1143
|
const { params: p } = await this._findActiveSupplyMarket();
|
|
851
1144
|
params = p;
|
|
852
1145
|
}
|
|
1146
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
853
1147
|
const marketId = import_ethers.ethers.keccak256(
|
|
854
1148
|
import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
855
1149
|
["address", "address", "address", "address", "uint256"],
|
|
@@ -858,13 +1152,13 @@ var init_MorphoClient = __esm({
|
|
|
858
1152
|
);
|
|
859
1153
|
let withdrawAssets;
|
|
860
1154
|
let withdrawShares;
|
|
861
|
-
if (
|
|
1155
|
+
if (amount === "all") {
|
|
862
1156
|
const pos = await this.morphoBlue.position(marketId, acctAddr);
|
|
863
1157
|
withdrawShares = BigInt(pos.supplyShares);
|
|
864
1158
|
withdrawAssets = 0n;
|
|
865
1159
|
if (withdrawShares === 0n) throw new AgetherError("No supply position to withdraw", "NO_SUPPLY");
|
|
866
1160
|
} else {
|
|
867
|
-
withdrawAssets = import_ethers.ethers.parseUnits(
|
|
1161
|
+
withdrawAssets = import_ethers.ethers.parseUnits(amount, loanDecimals);
|
|
868
1162
|
withdrawShares = 0n;
|
|
869
1163
|
}
|
|
870
1164
|
const data = morphoIface.encodeFunctionData("withdraw", [
|
|
@@ -882,13 +1176,13 @@ var init_MorphoClient = __esm({
|
|
|
882
1176
|
const totalSupplyAssets = BigInt(mkt.totalSupplyAssets);
|
|
883
1177
|
const totalSupplyShares = BigInt(mkt.totalSupplyShares);
|
|
884
1178
|
const currentAssets = totalSupplyShares > 0n ? BigInt(pos.supplyShares) * totalSupplyAssets / totalSupplyShares : 0n;
|
|
885
|
-
remainingSupply = import_ethers.ethers.formatUnits(currentAssets,
|
|
1179
|
+
remainingSupply = import_ethers.ethers.formatUnits(currentAssets, loanDecimals);
|
|
886
1180
|
} catch (e) {
|
|
887
1181
|
console.warn("[agether] failed to read remaining supply:", e instanceof Error ? e.message : e);
|
|
888
1182
|
}
|
|
889
1183
|
return {
|
|
890
1184
|
tx: receipt.hash,
|
|
891
|
-
amount
|
|
1185
|
+
amount,
|
|
892
1186
|
remainingSupply,
|
|
893
1187
|
destination: dest
|
|
894
1188
|
};
|
|
@@ -961,14 +1255,13 @@ var init_MorphoClient = __esm({
|
|
|
961
1255
|
* Computes available yield, verifies the requested amount doesn't exceed it,
|
|
962
1256
|
* then withdraws from the supply position and sends directly to the recipient.
|
|
963
1257
|
*
|
|
964
|
-
* @param recipient - Address to receive the
|
|
965
|
-
* @param
|
|
1258
|
+
* @param recipient - Address to receive the loan token
|
|
1259
|
+
* @param amount - Amount to pay from yield (e.g. '5.50')
|
|
966
1260
|
* @param collateralSymbol - Market collateral to identify which supply position
|
|
967
1261
|
*/
|
|
968
|
-
async payFromYield(recipient,
|
|
1262
|
+
async payFromYield(recipient, amount, collateralSymbol) {
|
|
969
1263
|
const acctAddr = await this.getAccountAddress();
|
|
970
1264
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
971
|
-
const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
|
|
972
1265
|
const positions = await this.getSupplyPositions(collateralSymbol);
|
|
973
1266
|
if (positions.length === 0) {
|
|
974
1267
|
throw new AgetherError("No supply position found", "NO_SUPPLY");
|
|
@@ -976,17 +1269,20 @@ var init_MorphoClient = __esm({
|
|
|
976
1269
|
const pos = positions.reduce(
|
|
977
1270
|
(a, b) => parseFloat(a.earnedYield) > parseFloat(b.earnedYield) ? a : b
|
|
978
1271
|
);
|
|
979
|
-
const
|
|
980
|
-
|
|
1272
|
+
const params = await this.findMarketForCollateral(pos.collateralToken, pos.loanToken);
|
|
1273
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1274
|
+
const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
|
|
1275
|
+
const availableYield = import_ethers.ethers.parseUnits(pos.earnedYield, loanDecimals);
|
|
1276
|
+
if (parsedAmount > availableYield) {
|
|
1277
|
+
const loanSymbol = pos.loanToken;
|
|
981
1278
|
throw new AgetherError(
|
|
982
|
-
`Requested ${
|
|
1279
|
+
`Requested ${amount} ${loanSymbol} exceeds available yield of ${pos.earnedYield} ${loanSymbol}. Use withdrawSupply to withdraw principal.`,
|
|
983
1280
|
"EXCEEDS_YIELD"
|
|
984
1281
|
);
|
|
985
1282
|
}
|
|
986
|
-
const params = await this.findMarketForCollateral(pos.collateralToken);
|
|
987
1283
|
const data = morphoIface.encodeFunctionData("withdraw", [
|
|
988
1284
|
this._toTuple(params),
|
|
989
|
-
|
|
1285
|
+
parsedAmount,
|
|
990
1286
|
0n,
|
|
991
1287
|
acctAddr,
|
|
992
1288
|
recipient
|
|
@@ -1005,7 +1301,7 @@ var init_MorphoClient = __esm({
|
|
|
1005
1301
|
}
|
|
1006
1302
|
return {
|
|
1007
1303
|
tx: receipt.hash,
|
|
1008
|
-
yieldWithdrawn:
|
|
1304
|
+
yieldWithdrawn: amount,
|
|
1009
1305
|
recipient,
|
|
1010
1306
|
remainingYield,
|
|
1011
1307
|
remainingSupply
|
|
@@ -1063,28 +1359,31 @@ var init_MorphoClient = __esm({
|
|
|
1063
1359
|
};
|
|
1064
1360
|
}
|
|
1065
1361
|
/**
|
|
1066
|
-
* Borrow
|
|
1362
|
+
* Borrow loan token against existing collateral.
|
|
1067
1363
|
*
|
|
1068
1364
|
* AgentAccount.execute: Morpho.borrow(params, amount, 0, account, account)
|
|
1069
1365
|
*
|
|
1070
|
-
* @param
|
|
1366
|
+
* @param amount - Loan token amount (e.g. '100' for 100 USDC, '0.5' for 0.5 WETH)
|
|
1071
1367
|
* @param tokenSymbol - collateral symbol to identify which market (default: first with collateral)
|
|
1368
|
+
* @param marketParams - explicit market params (optional)
|
|
1369
|
+
* @param loanTokenSymbol - loan token to filter market (optional, e.g. 'USDC', 'WETH')
|
|
1072
1370
|
*/
|
|
1073
|
-
async borrow(
|
|
1371
|
+
async borrow(amount, tokenSymbol, marketParams, loanTokenSymbol) {
|
|
1074
1372
|
const acctAddr = await this.getAccountAddress();
|
|
1075
|
-
const amount = import_ethers.ethers.parseUnits(usdcAmount, 6);
|
|
1076
1373
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
1077
1374
|
let params;
|
|
1078
1375
|
let usedToken = tokenSymbol || "WETH";
|
|
1079
1376
|
if (marketParams) {
|
|
1080
1377
|
params = marketParams;
|
|
1081
1378
|
} else if (tokenSymbol) {
|
|
1082
|
-
params = await this.findMarketForCollateral(tokenSymbol);
|
|
1379
|
+
params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
1083
1380
|
} else {
|
|
1084
1381
|
const { params: p, symbol } = await this._findActiveMarket();
|
|
1085
1382
|
params = p;
|
|
1086
1383
|
usedToken = symbol;
|
|
1087
1384
|
}
|
|
1385
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1386
|
+
const parsedAmount = import_ethers.ethers.parseUnits(amount, loanDecimals);
|
|
1088
1387
|
try {
|
|
1089
1388
|
const marketId = import_ethers.ethers.keccak256(
|
|
1090
1389
|
import_ethers.ethers.AbiCoder.defaultAbiCoder().encode(
|
|
@@ -1108,11 +1407,14 @@ var init_MorphoClient = __esm({
|
|
|
1108
1407
|
const totalBorrowAssets = BigInt(mktState.totalBorrowAssets);
|
|
1109
1408
|
const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1110
1409
|
const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
|
|
1111
|
-
if (
|
|
1112
|
-
const
|
|
1113
|
-
const
|
|
1410
|
+
if (parsedAmount > maxAdditional) {
|
|
1411
|
+
const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
1412
|
+
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
1413
|
+
const colInfo = await this._resolveToken(usedToken);
|
|
1414
|
+
const maxFormatted = import_ethers.ethers.formatUnits(maxAdditional, loanDecimals);
|
|
1415
|
+
const colFormatted = import_ethers.ethers.formatUnits(pos.collateral, colInfo.decimals);
|
|
1114
1416
|
throw new AgetherError(
|
|
1115
|
-
`Borrow of
|
|
1417
|
+
`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
1418
|
"EXCEEDS_MAX_LTV"
|
|
1117
1419
|
);
|
|
1118
1420
|
}
|
|
@@ -1122,7 +1424,7 @@ var init_MorphoClient = __esm({
|
|
|
1122
1424
|
}
|
|
1123
1425
|
const data = morphoIface.encodeFunctionData("borrow", [
|
|
1124
1426
|
this._toTuple(params),
|
|
1125
|
-
|
|
1427
|
+
parsedAmount,
|
|
1126
1428
|
0n,
|
|
1127
1429
|
acctAddr,
|
|
1128
1430
|
acctAddr
|
|
@@ -1130,7 +1432,7 @@ var init_MorphoClient = __esm({
|
|
|
1130
1432
|
const receipt = await this.exec(morphoAddr, data);
|
|
1131
1433
|
return {
|
|
1132
1434
|
tx: receipt.hash,
|
|
1133
|
-
amount
|
|
1435
|
+
amount,
|
|
1134
1436
|
collateralToken: usedToken,
|
|
1135
1437
|
agentAccount: acctAddr
|
|
1136
1438
|
};
|
|
@@ -1138,17 +1440,27 @@ var init_MorphoClient = __esm({
|
|
|
1138
1440
|
/**
|
|
1139
1441
|
* Deposit collateral AND borrow USDC in one batched transaction.
|
|
1140
1442
|
*
|
|
1443
|
+
/**
|
|
1444
|
+
* Deposit collateral AND borrow loan token in one batched transaction.
|
|
1445
|
+
*
|
|
1141
1446
|
* AgentAccount.executeBatch:
|
|
1142
1447
|
* [collateral.approve, Morpho.supplyCollateral, Morpho.borrow]
|
|
1143
1448
|
*
|
|
1144
1449
|
* The collateral must be transferred to AgentAccount first.
|
|
1450
|
+
*
|
|
1451
|
+
* @param tokenSymbol - collateral token symbol (e.g. 'WETH')
|
|
1452
|
+
* @param collateralAmount - amount of collateral (e.g. '0.05')
|
|
1453
|
+
* @param borrowAmount - amount of loan token to borrow (e.g. '100')
|
|
1454
|
+
* @param marketParams - explicit market params (optional)
|
|
1455
|
+
* @param loanTokenSymbol - loan token to filter market (optional)
|
|
1145
1456
|
*/
|
|
1146
|
-
async depositAndBorrow(tokenSymbol, collateralAmount,
|
|
1457
|
+
async depositAndBorrow(tokenSymbol, collateralAmount, borrowAmount, marketParams, loanTokenSymbol) {
|
|
1147
1458
|
const acctAddr = await this.getAccountAddress();
|
|
1148
1459
|
const colInfo = await this._resolveToken(tokenSymbol);
|
|
1149
|
-
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
1460
|
+
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
1461
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1150
1462
|
const colWei = import_ethers.ethers.parseUnits(collateralAmount, colInfo.decimals);
|
|
1151
|
-
const borrowWei = import_ethers.ethers.parseUnits(
|
|
1463
|
+
const borrowWei = import_ethers.ethers.parseUnits(borrowAmount, loanDecimals);
|
|
1152
1464
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
1153
1465
|
try {
|
|
1154
1466
|
const marketId = import_ethers.ethers.keccak256(
|
|
@@ -1169,9 +1481,11 @@ var init_MorphoClient = __esm({
|
|
|
1169
1481
|
const currentDebt = totalBorrowShares > 0n ? (BigInt(pos.borrowShares) * totalBorrowAssets + totalBorrowShares - 1n) / totalBorrowShares : 0n;
|
|
1170
1482
|
const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
|
|
1171
1483
|
if (borrowWei > maxAdditional) {
|
|
1172
|
-
const
|
|
1484
|
+
const loanInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
1485
|
+
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
1486
|
+
const maxFormatted = import_ethers.ethers.formatUnits(maxAdditional, loanDecimals);
|
|
1173
1487
|
throw new AgetherError(
|
|
1174
|
-
`Borrow of
|
|
1488
|
+
`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
1489
|
"EXCEEDS_MAX_LTV"
|
|
1176
1490
|
);
|
|
1177
1491
|
}
|
|
@@ -1217,36 +1531,42 @@ var init_MorphoClient = __esm({
|
|
|
1217
1531
|
tx: receipt.hash,
|
|
1218
1532
|
collateralToken: tokenSymbol,
|
|
1219
1533
|
collateralAmount,
|
|
1220
|
-
borrowAmount
|
|
1534
|
+
borrowAmount,
|
|
1221
1535
|
agentAccount: acctAddr
|
|
1222
1536
|
};
|
|
1223
1537
|
}
|
|
1224
1538
|
/**
|
|
1225
|
-
* Repay borrowed
|
|
1539
|
+
* Repay borrowed loan token from AgentAccount.
|
|
1226
1540
|
*
|
|
1227
1541
|
* AgentAccount.executeBatch:
|
|
1228
|
-
* [
|
|
1542
|
+
* [loanToken.approve(MorphoBlue), Morpho.repay(params)]
|
|
1543
|
+
*
|
|
1544
|
+
* @param amount - loan token amount to repay (e.g. '50' or 'all' for full repayment)
|
|
1545
|
+
* @param tokenSymbol - collateral symbol to identify which market (optional)
|
|
1546
|
+
* @param marketParams - explicit market params (optional)
|
|
1547
|
+
* @param loanTokenSymbol - loan token to filter market (optional)
|
|
1229
1548
|
*/
|
|
1230
|
-
async repay(
|
|
1549
|
+
async repay(amount, tokenSymbol, marketParams, loanTokenSymbol) {
|
|
1231
1550
|
const acctAddr = await this.getAccountAddress();
|
|
1232
1551
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
1233
|
-
const usdcAddr = this.config.contracts.usdc;
|
|
1234
1552
|
let params;
|
|
1235
1553
|
if (marketParams) {
|
|
1236
1554
|
params = marketParams;
|
|
1237
1555
|
} else if (tokenSymbol) {
|
|
1238
|
-
params = await this.findMarketForCollateral(tokenSymbol);
|
|
1556
|
+
params = await this.findMarketForCollateral(tokenSymbol, loanTokenSymbol);
|
|
1239
1557
|
} else {
|
|
1240
1558
|
const { params: p } = await this._findActiveMarket();
|
|
1241
1559
|
params = p;
|
|
1242
1560
|
}
|
|
1561
|
+
const loanTokenAddr = params.loanToken;
|
|
1562
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1243
1563
|
let repayAssets;
|
|
1244
1564
|
let repayShares;
|
|
1245
1565
|
let approveAmount;
|
|
1246
|
-
if (
|
|
1566
|
+
if (amount === "all") {
|
|
1247
1567
|
const markets = await this.getMarkets();
|
|
1248
1568
|
const mkt = markets.find(
|
|
1249
|
-
(m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase()
|
|
1569
|
+
(m) => m.collateralAsset?.address.toLowerCase() === params.collateralToken.toLowerCase() && m.loanAsset?.address.toLowerCase() === params.loanToken.toLowerCase()
|
|
1250
1570
|
);
|
|
1251
1571
|
if (mkt) {
|
|
1252
1572
|
const pos = await this.morphoBlue.position(mkt.uniqueKey, acctAddr);
|
|
@@ -1256,33 +1576,35 @@ var init_MorphoClient = __esm({
|
|
|
1256
1576
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
1257
1577
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
1258
1578
|
const estimated = totalBorrowShares > 0n ? repayShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
1259
|
-
approveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1",
|
|
1579
|
+
approveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", loanDecimals);
|
|
1260
1580
|
} else {
|
|
1261
|
-
repayAssets = import_ethers.ethers.parseUnits("999999",
|
|
1581
|
+
repayAssets = import_ethers.ethers.parseUnits("999999", loanDecimals);
|
|
1262
1582
|
repayShares = 0n;
|
|
1263
1583
|
approveAmount = repayAssets;
|
|
1264
1584
|
}
|
|
1265
1585
|
} else {
|
|
1266
|
-
repayAssets = import_ethers.ethers.parseUnits(
|
|
1586
|
+
repayAssets = import_ethers.ethers.parseUnits(amount, loanDecimals);
|
|
1267
1587
|
repayShares = 0n;
|
|
1268
1588
|
approveAmount = repayAssets;
|
|
1269
1589
|
}
|
|
1270
|
-
const
|
|
1271
|
-
const acctBalance = await
|
|
1590
|
+
const loanContract = new import_ethers.Contract(loanTokenAddr, ERC20_ABI, this._signer);
|
|
1591
|
+
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
1272
1592
|
if (acctBalance < approveAmount) {
|
|
1273
1593
|
const shortfall = approveAmount - acctBalance;
|
|
1274
|
-
const eoaBalance = await
|
|
1594
|
+
const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
|
|
1275
1595
|
if (eoaBalance < shortfall) {
|
|
1596
|
+
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
1597
|
+
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
1276
1598
|
throw new AgetherError(
|
|
1277
|
-
`Insufficient
|
|
1599
|
+
`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
1600
|
"INSUFFICIENT_BALANCE"
|
|
1279
1601
|
);
|
|
1280
1602
|
}
|
|
1281
|
-
const transferTx = await
|
|
1603
|
+
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
1282
1604
|
await transferTx.wait();
|
|
1283
1605
|
this._refreshSigner();
|
|
1284
1606
|
}
|
|
1285
|
-
const targets = [
|
|
1607
|
+
const targets = [loanTokenAddr, morphoAddr];
|
|
1286
1608
|
const values = [0n, 0n];
|
|
1287
1609
|
const datas = [
|
|
1288
1610
|
erc20Iface.encodeFunctionData("approve", [morphoAddr, approveAmount]),
|
|
@@ -1302,7 +1624,7 @@ var init_MorphoClient = __esm({
|
|
|
1302
1624
|
} catch (e) {
|
|
1303
1625
|
console.warn("[agether] failed to read remaining debt after repay:", e instanceof Error ? e.message : e);
|
|
1304
1626
|
}
|
|
1305
|
-
return { tx: receipt.hash, amount
|
|
1627
|
+
return { tx: receipt.hash, amount, remainingDebt };
|
|
1306
1628
|
}
|
|
1307
1629
|
/**
|
|
1308
1630
|
* Withdraw collateral from Morpho Blue.
|
|
@@ -1316,12 +1638,13 @@ var init_MorphoClient = __esm({
|
|
|
1316
1638
|
const colInfo = await this._resolveToken(tokenSymbol);
|
|
1317
1639
|
const params = marketParams ?? await this.findMarketForCollateral(tokenSymbol);
|
|
1318
1640
|
const morphoAddr = this.config.contracts.morphoBlue;
|
|
1319
|
-
const
|
|
1641
|
+
const loanTokenAddr = params.loanToken;
|
|
1642
|
+
const loanDecimals = await this._getLoanTokenDecimals(params);
|
|
1320
1643
|
const dest = receiver || await this.getSignerAddress();
|
|
1321
1644
|
let weiAmount;
|
|
1322
1645
|
const markets = await this.getMarkets();
|
|
1323
1646
|
const market = markets.find(
|
|
1324
|
-
(m) => m.collateralAsset?.address.toLowerCase() === colInfo.address.toLowerCase()
|
|
1647
|
+
(m) => m.collateralAsset?.address.toLowerCase() === colInfo.address.toLowerCase() && m.loanAsset?.address.toLowerCase() === loanTokenAddr.toLowerCase()
|
|
1325
1648
|
);
|
|
1326
1649
|
if (amount === "all") {
|
|
1327
1650
|
if (!market) throw new AgetherError("Market not found", "MARKET_NOT_FOUND");
|
|
@@ -1344,8 +1667,10 @@ var init_MorphoClient = __esm({
|
|
|
1344
1667
|
const totalBorrowAssets = BigInt(onChainMkt.totalBorrowAssets);
|
|
1345
1668
|
const totalBorrowShares = BigInt(onChainMkt.totalBorrowShares);
|
|
1346
1669
|
const estimated = totalBorrowShares > 0n ? dustBorrowShares * totalBorrowAssets / totalBorrowShares + 10n : 0n;
|
|
1347
|
-
dustApproveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1",
|
|
1348
|
-
|
|
1670
|
+
dustApproveAmount = estimated > 0n ? estimated : import_ethers.ethers.parseUnits("1", loanDecimals);
|
|
1671
|
+
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
1672
|
+
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
1673
|
+
console.log(`[agether] dust borrow shares detected: ${dustBorrowShares} shares \u2248 ${import_ethers.ethers.formatUnits(dustApproveAmount, loanDecimals)} ${loanSymbol} \u2014 auto-repaying before withdraw`);
|
|
1349
1674
|
}
|
|
1350
1675
|
} catch (e) {
|
|
1351
1676
|
console.warn("[agether] failed to check borrow shares before withdraw:", e instanceof Error ? e.message : e);
|
|
@@ -1359,19 +1684,21 @@ var init_MorphoClient = __esm({
|
|
|
1359
1684
|
]);
|
|
1360
1685
|
let receipt;
|
|
1361
1686
|
if (hasDustDebt) {
|
|
1362
|
-
const
|
|
1363
|
-
const acctBalance = await
|
|
1687
|
+
const loanContract = new import_ethers.Contract(loanTokenAddr, ERC20_ABI, this._signer);
|
|
1688
|
+
const acctBalance = await loanContract.balanceOf(acctAddr);
|
|
1364
1689
|
if (acctBalance < dustApproveAmount) {
|
|
1365
1690
|
const shortfall = dustApproveAmount - acctBalance;
|
|
1366
|
-
const eoaBalance = await
|
|
1691
|
+
const eoaBalance = await loanContract.balanceOf(await this.getSignerAddress());
|
|
1367
1692
|
if (eoaBalance >= shortfall) {
|
|
1368
|
-
|
|
1369
|
-
const
|
|
1693
|
+
const loanInfo = this._tokenCache.get(loanTokenAddr.toLowerCase());
|
|
1694
|
+
const loanSymbol = loanInfo?.symbol ?? "loan token";
|
|
1695
|
+
console.log(`[agether] transferring ${import_ethers.ethers.formatUnits(shortfall, loanDecimals)} ${loanSymbol} from EOA \u2192 AgentAccount for dust repay`);
|
|
1696
|
+
const transferTx = await loanContract.transfer(acctAddr, shortfall);
|
|
1370
1697
|
await transferTx.wait();
|
|
1371
1698
|
this._refreshSigner();
|
|
1372
1699
|
}
|
|
1373
1700
|
}
|
|
1374
|
-
const targets = [
|
|
1701
|
+
const targets = [loanTokenAddr, morphoAddr, morphoAddr];
|
|
1375
1702
|
const values = [0n, 0n, 0n];
|
|
1376
1703
|
const datas = [
|
|
1377
1704
|
erc20Iface.encodeFunctionData("approve", [morphoAddr, dustApproveAmount]),
|
|
@@ -1616,6 +1943,37 @@ var init_MorphoClient = __esm({
|
|
|
1616
1943
|
}
|
|
1617
1944
|
throw new AgetherError("No active supply position found", "NO_SUPPLY");
|
|
1618
1945
|
}
|
|
1946
|
+
/**
|
|
1947
|
+
* Resolve loan token decimals from market params.
|
|
1948
|
+
* Uses the `_tokenCache` populated by `getMarkets()`.
|
|
1949
|
+
*/
|
|
1950
|
+
async _getLoanTokenDecimals(params) {
|
|
1951
|
+
const tokenInfo = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
1952
|
+
if (tokenInfo) return tokenInfo.decimals;
|
|
1953
|
+
await this.getMarkets();
|
|
1954
|
+
const fromApi = this._tokenCache.get(params.loanToken.toLowerCase());
|
|
1955
|
+
return fromApi?.decimals ?? 18;
|
|
1956
|
+
}
|
|
1957
|
+
/**
|
|
1958
|
+
* Apply client-side filter to discovered markets.
|
|
1959
|
+
*/
|
|
1960
|
+
_applyMarketFilter(markets, filter) {
|
|
1961
|
+
return markets.filter((m) => {
|
|
1962
|
+
if (filter.loanToken) {
|
|
1963
|
+
const loanAddr = filter.loanToken.toLowerCase();
|
|
1964
|
+
if (m.loanAsset.address.toLowerCase() !== loanAddr && m.loanAsset.symbol.toUpperCase() !== filter.loanToken.toUpperCase()) {
|
|
1965
|
+
return false;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
if (filter.collateralToken) {
|
|
1969
|
+
const colAddr = filter.collateralToken.toLowerCase();
|
|
1970
|
+
if (m.collateralAsset.address.toLowerCase() !== colAddr && m.collateralAsset.symbol.toUpperCase() !== filter.collateralToken.toUpperCase()) {
|
|
1971
|
+
return false;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
return true;
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1619
1977
|
/**
|
|
1620
1978
|
* Resolve a token symbol or address to { address, symbol, decimals }.
|
|
1621
1979
|
*
|
|
@@ -1631,9 +1989,27 @@ var init_MorphoClient = __esm({
|
|
|
1631
1989
|
await this.getMarkets();
|
|
1632
1990
|
const fromApi = this._tokenCache.get(key);
|
|
1633
1991
|
if (fromApi) return fromApi;
|
|
1992
|
+
if (!symbolOrAddress.startsWith("0x")) {
|
|
1993
|
+
const searchResults = await this.searchMarkets(symbolOrAddress);
|
|
1994
|
+
const sym = symbolOrAddress.toUpperCase();
|
|
1995
|
+
for (const m of searchResults) {
|
|
1996
|
+
if (m.collateralToken.toUpperCase() === sym) {
|
|
1997
|
+
const info = { address: m.collateralAddress, symbol: m.collateralToken, decimals: m.collateralDecimals };
|
|
1998
|
+
this._tokenCache.set(sym, info);
|
|
1999
|
+
this._tokenCache.set(m.collateralAddress.toLowerCase(), info);
|
|
2000
|
+
return info;
|
|
2001
|
+
}
|
|
2002
|
+
if (m.loanToken.toUpperCase() === sym) {
|
|
2003
|
+
const info = { address: m.loanAddress, symbol: m.loanToken, decimals: m.loanDecimals };
|
|
2004
|
+
this._tokenCache.set(sym, info);
|
|
2005
|
+
this._tokenCache.set(m.loanAddress.toLowerCase(), info);
|
|
2006
|
+
return info;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
1634
2010
|
throw new AgetherError(
|
|
1635
|
-
`Unknown token: ${symbolOrAddress}. No Morpho market found with this
|
|
1636
|
-
"
|
|
2011
|
+
`Unknown token: ${symbolOrAddress}. No Morpho market found with this token.`,
|
|
2012
|
+
"UNKNOWN_TOKEN"
|
|
1637
2013
|
);
|
|
1638
2014
|
}
|
|
1639
2015
|
/**
|
|
@@ -1839,25 +2215,21 @@ var init_AgetherClient = __esm({
|
|
|
1839
2215
|
const acctAddr = await this.agether4337Factory.getAccount(agentId);
|
|
1840
2216
|
this.accountAddress = acctAddr;
|
|
1841
2217
|
if (!acctExists) {
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
this._refreshSigner();
|
|
1858
|
-
} catch (e) {
|
|
1859
|
-
console.warn("[agether] setAgentURI failed (non-fatal):", e instanceof Error ? e.message : e);
|
|
1860
|
-
}
|
|
2218
|
+
const updatedMeta = JSON.stringify({
|
|
2219
|
+
type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
|
|
2220
|
+
name: options?.name || "Unnamed Agent",
|
|
2221
|
+
description: options?.description || "AI agent registered via @agether/sdk",
|
|
2222
|
+
active: true,
|
|
2223
|
+
wallet: `eip155:${this.config.chainId}:${acctAddr}`,
|
|
2224
|
+
registrations: [{
|
|
2225
|
+
agentId: Number(agentId),
|
|
2226
|
+
agentRegistry: `eip155:${this.config.chainId}:${this.config.contracts.identityRegistry}`
|
|
2227
|
+
}]
|
|
2228
|
+
});
|
|
2229
|
+
const finalURI = `data:application/json;base64,${Buffer.from(updatedMeta).toString("base64")}`;
|
|
2230
|
+
const uriTx = await this.identityRegistry.setAgentURI(agentId, finalURI);
|
|
2231
|
+
await uriTx.wait();
|
|
2232
|
+
this._refreshSigner();
|
|
1861
2233
|
}
|
|
1862
2234
|
const kyaRequired = await this.isKyaRequired();
|
|
1863
2235
|
return {
|
|
@@ -1875,7 +2247,7 @@ var init_AgetherClient = __esm({
|
|
|
1875
2247
|
async _mintNewIdentity(name, description) {
|
|
1876
2248
|
const registrationFile = JSON.stringify({
|
|
1877
2249
|
type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
|
|
1878
|
-
name: name || "
|
|
2250
|
+
name: name || "Agether Agent",
|
|
1879
2251
|
description: description || "AI agent registered via @agether/sdk",
|
|
1880
2252
|
active: true,
|
|
1881
2253
|
registrations: [{
|