@agether/sdk 1.6.1 → 1.6.2
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 +25 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +348 -0
- package/dist/clients/AgentIdentityClient.d.ts +188 -0
- package/dist/clients/AgentIdentityClient.d.ts.map +1 -0
- package/dist/clients/AgentIdentityClient.js +333 -0
- package/dist/clients/AgetherClient.d.ts +63 -0
- package/dist/clients/AgetherClient.d.ts.map +1 -0
- package/dist/clients/AgetherClient.js +171 -0
- package/dist/clients/MorphoClient.d.ts +287 -0
- package/dist/clients/MorphoClient.d.ts.map +1 -0
- package/dist/clients/MorphoClient.js +951 -0
- package/dist/clients/ScoringClient.d.ts +89 -0
- package/dist/clients/ScoringClient.d.ts.map +1 -0
- package/dist/clients/ScoringClient.js +93 -0
- package/dist/clients/X402Client.d.ts +130 -0
- package/dist/clients/X402Client.d.ts.map +1 -0
- package/dist/clients/X402Client.js +301 -0
- package/dist/index.d.mts +142 -1
- package/dist/index.d.ts +142 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +348 -0
- package/dist/index.mjs +348 -0
- package/dist/types/index.d.ts +121 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +43 -0
- package/dist/utils/abis.d.ts +18 -0
- package/dist/utils/abis.d.ts.map +1 -0
- package/dist/utils/abis.js +93 -0
- package/dist/utils/config.d.ts +34 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +115 -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.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Agether CLI — Direct Morpho Blue Credit for AI Agents
|
|
4
|
+
*
|
|
5
|
+
* All commands sign transactions directly with the agent's private key.
|
|
6
|
+
* Uses MorphoClient for lending, X402Client for paid API calls.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* agether init <private-key> [--agent-id <id>] Initialize
|
|
10
|
+
* agether register [--name <n>] Register ERC-8004 + AgentAccount
|
|
11
|
+
* agether balance Check balances
|
|
12
|
+
* agether status Show Morpho positions
|
|
13
|
+
* agether score Get credit score (x402-gated)
|
|
14
|
+
* agether markets List Morpho markets
|
|
15
|
+
* agether deposit --amount 0.05 --token WETH Deposit collateral
|
|
16
|
+
* agether borrow --amount 100 Borrow USDC
|
|
17
|
+
* agether deposit-and-borrow --amount 0.05 --token WETH --borrow 100
|
|
18
|
+
* agether repay --amount 50 Repay USDC
|
|
19
|
+
* agether withdraw --amount 0.05 --token WETH Withdraw collateral
|
|
20
|
+
* agether sponsor --amount 0.05 --token WETH --agent-id 123
|
|
21
|
+
* agether fund --amount 50 Fund AgentAccount with USDC
|
|
22
|
+
* agether x402 <url> [--method GET|POST] [--body <json>]
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
package/dist/cli.js
CHANGED
|
@@ -525,6 +525,179 @@ var init_MorphoClient = __esm({
|
|
|
525
525
|
};
|
|
526
526
|
}
|
|
527
527
|
// ════════════════════════════════════════════════════════
|
|
528
|
+
// Balance & Borrowing Capacity
|
|
529
|
+
// ════════════════════════════════════════════════════════
|
|
530
|
+
/**
|
|
531
|
+
* Get the USDC balance of the AgentAccount.
|
|
532
|
+
* @returns USDC balance in raw units (6 decimals)
|
|
533
|
+
*/
|
|
534
|
+
async getUsdcBalance() {
|
|
535
|
+
const acctAddr = await this.getAccountAddress();
|
|
536
|
+
const usdc = new import_ethers.Contract(this.config.contracts.usdc, ERC20_ABI, this.provider);
|
|
537
|
+
return usdc.balanceOf(acctAddr);
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Calculate the maximum additional USDC that can be borrowed
|
|
541
|
+
* given the agent's current collateral and debt across all markets.
|
|
542
|
+
*
|
|
543
|
+
* For each market with collateral deposited:
|
|
544
|
+
* maxBorrow = (collateralValue * LLTV) - currentDebt
|
|
545
|
+
*
|
|
546
|
+
* Uses the Morpho oracle to price collateral → loan token.
|
|
547
|
+
*
|
|
548
|
+
* @returns Maximum additional USDC borrowable (6 decimals)
|
|
549
|
+
*/
|
|
550
|
+
async getMaxBorrowable() {
|
|
551
|
+
const acctAddr = await this.getAccountAddress();
|
|
552
|
+
const markets = await this.getMarkets();
|
|
553
|
+
let totalAdditional = 0n;
|
|
554
|
+
const byMarket = [];
|
|
555
|
+
for (const m of markets) {
|
|
556
|
+
if (!m.collateralAsset || m.collateralAsset.address === import_ethers.ethers.ZeroAddress) continue;
|
|
557
|
+
try {
|
|
558
|
+
const pos = await this.morphoBlue.position(m.uniqueKey, acctAddr);
|
|
559
|
+
if (pos.collateral === 0n) continue;
|
|
560
|
+
const mktState = await this.morphoBlue.market(m.uniqueKey);
|
|
561
|
+
const totalBorrowShares = BigInt(mktState.totalBorrowShares);
|
|
562
|
+
const totalBorrowAssets = BigInt(mktState.totalBorrowAssets);
|
|
563
|
+
const currentDebt = totalBorrowShares > 0n ? BigInt(pos.borrowShares) * totalBorrowAssets / totalBorrowShares : 0n;
|
|
564
|
+
let collateralValueInLoan;
|
|
565
|
+
try {
|
|
566
|
+
const oracleContract = new import_ethers.Contract(m.oracle, [
|
|
567
|
+
"function price() view returns (uint256)"
|
|
568
|
+
], this.provider);
|
|
569
|
+
const oraclePrice = await oracleContract.price();
|
|
570
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
571
|
+
collateralValueInLoan = BigInt(pos.collateral) * oraclePrice / ORACLE_PRICE_SCALE;
|
|
572
|
+
} catch {
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
const maxBorrowTotal = collateralValueInLoan * m.lltv / 10n ** 18n;
|
|
576
|
+
const maxAdditional = maxBorrowTotal > currentDebt ? maxBorrowTotal - currentDebt : 0n;
|
|
577
|
+
totalAdditional += maxAdditional;
|
|
578
|
+
byMarket.push({
|
|
579
|
+
collateralToken: m.collateralAsset.symbol,
|
|
580
|
+
maxAdditional,
|
|
581
|
+
currentDebt,
|
|
582
|
+
collateralValue: collateralValueInLoan
|
|
583
|
+
});
|
|
584
|
+
} catch {
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
return { total: totalAdditional, byMarket };
|
|
589
|
+
}
|
|
590
|
+
// ════════════════════════════════════════════════════════
|
|
591
|
+
// Market Rates & Yield Estimation
|
|
592
|
+
// ════════════════════════════════════════════════════════
|
|
593
|
+
/**
|
|
594
|
+
* Fetch current supply/borrow APY for a collateral market from Morpho GraphQL API.
|
|
595
|
+
*
|
|
596
|
+
* Note: On Morpho Blue, collateral does NOT earn yield directly. Supply APY
|
|
597
|
+
* is what lenders earn; borrow APY is what borrowers pay.
|
|
598
|
+
*/
|
|
599
|
+
async getMarketRates(collateralSymbolOrAddress) {
|
|
600
|
+
const chainId = this.config.chainId;
|
|
601
|
+
const usdcAddr = this.config.contracts.usdc.toLowerCase();
|
|
602
|
+
let collateralFilter = "";
|
|
603
|
+
if (collateralSymbolOrAddress) {
|
|
604
|
+
const colInfo = BASE_COLLATERALS[collateralSymbolOrAddress];
|
|
605
|
+
const colAddr = (colInfo?.address ?? collateralSymbolOrAddress).toLowerCase();
|
|
606
|
+
collateralFilter = `, collateralAssetAddress_in: ["${colAddr}"]`;
|
|
607
|
+
}
|
|
608
|
+
const query = `{
|
|
609
|
+
markets(
|
|
610
|
+
first: 50
|
|
611
|
+
orderBy: SupplyAssetsUsd
|
|
612
|
+
orderDirection: Desc
|
|
613
|
+
where: { chainId_in: [${chainId}], loanAssetAddress_in: ["${usdcAddr}"]${collateralFilter} }
|
|
614
|
+
) {
|
|
615
|
+
items {
|
|
616
|
+
uniqueKey
|
|
617
|
+
lltv
|
|
618
|
+
loanAsset { address symbol decimals }
|
|
619
|
+
collateralAsset { address symbol decimals }
|
|
620
|
+
state {
|
|
621
|
+
borrowAssets
|
|
622
|
+
supplyAssets
|
|
623
|
+
utilization
|
|
624
|
+
supplyApy
|
|
625
|
+
borrowApy
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}`;
|
|
630
|
+
try {
|
|
631
|
+
const resp = await import_axios.default.post(MORPHO_API_URL, { query }, { timeout: 1e4 });
|
|
632
|
+
const items = resp.data?.data?.markets?.items ?? [];
|
|
633
|
+
return items.filter((m) => m.collateralAsset?.address && m.collateralAsset.address !== import_ethers.ethers.ZeroAddress).map((m) => ({
|
|
634
|
+
collateralToken: m.collateralAsset.symbol,
|
|
635
|
+
loanToken: m.loanAsset.symbol,
|
|
636
|
+
supplyApy: m.state?.supplyApy ? Number(m.state.supplyApy) : 0,
|
|
637
|
+
borrowApy: m.state?.borrowApy ? Number(m.state.borrowApy) : 0,
|
|
638
|
+
utilization: m.state?.utilization ? Number(m.state.utilization) : 0,
|
|
639
|
+
totalSupplyUsd: m.state?.supplyAssets ? Number(m.state.supplyAssets) / 1e6 : 0,
|
|
640
|
+
totalBorrowUsd: m.state?.borrowAssets ? Number(m.state.borrowAssets) / 1e6 : 0,
|
|
641
|
+
lltv: `${(Number(m.lltv) / 1e16).toFixed(0)}%`,
|
|
642
|
+
marketId: m.uniqueKey
|
|
643
|
+
}));
|
|
644
|
+
} catch {
|
|
645
|
+
return [];
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Estimate theoretical yield for a given collateral amount over a period.
|
|
650
|
+
*
|
|
651
|
+
* ⚠️ IMPORTANT: On Morpho Blue, collateral does NOT earn yield directly.
|
|
652
|
+
* This estimates what the collateral WOULD earn if it were instead supplied
|
|
653
|
+
* as a lender (not used as collateral). This is a theoretical upper bound
|
|
654
|
+
* useful for setting spending caps.
|
|
655
|
+
*
|
|
656
|
+
* @param collateralSymbol - e.g. 'WETH'
|
|
657
|
+
* @param amount - collateral amount in human-readable (e.g. '1.5')
|
|
658
|
+
* @param periodDays - estimation period in days (default: 1)
|
|
659
|
+
* @param ethPriceUsd - ETH price in USD for value conversion (if not provided, uses oracle)
|
|
660
|
+
* @returns Estimated yield in USD for the period
|
|
661
|
+
*/
|
|
662
|
+
async getYieldEstimate(collateralSymbol, amount, periodDays = 1, ethPriceUsd) {
|
|
663
|
+
const colInfo = BASE_COLLATERALS[collateralSymbol];
|
|
664
|
+
if (!colInfo) throw new AgetherError(`Unknown collateral: ${collateralSymbol}`, "UNKNOWN_COLLATERAL");
|
|
665
|
+
const rates = await this.getMarketRates(collateralSymbol);
|
|
666
|
+
if (rates.length === 0) {
|
|
667
|
+
throw new AgetherError(`No market found for ${collateralSymbol}`, "MARKET_NOT_FOUND");
|
|
668
|
+
}
|
|
669
|
+
const market = rates[0];
|
|
670
|
+
const supplyApy = market.supplyApy;
|
|
671
|
+
let collateralValueUsd;
|
|
672
|
+
if (ethPriceUsd) {
|
|
673
|
+
collateralValueUsd = parseFloat(amount) * ethPriceUsd;
|
|
674
|
+
} else {
|
|
675
|
+
try {
|
|
676
|
+
const params = await this.findMarketForCollateral(collateralSymbol);
|
|
677
|
+
const oracleContract = new import_ethers.Contract(params.oracle, [
|
|
678
|
+
"function price() view returns (uint256)"
|
|
679
|
+
], this.provider);
|
|
680
|
+
const oraclePrice = await oracleContract.price();
|
|
681
|
+
const ORACLE_PRICE_SCALE = 10n ** 36n;
|
|
682
|
+
const amountWei = import_ethers.ethers.parseUnits(amount, colInfo.decimals);
|
|
683
|
+
const valueInUsdc = amountWei * oraclePrice / ORACLE_PRICE_SCALE;
|
|
684
|
+
collateralValueUsd = Number(valueInUsdc) / 1e6;
|
|
685
|
+
} catch {
|
|
686
|
+
throw new AgetherError("Cannot determine collateral value. Provide ethPriceUsd.", "PRICE_UNAVAILABLE");
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
const estimatedYieldUsd = collateralValueUsd * supplyApy * (periodDays / 365);
|
|
690
|
+
return {
|
|
691
|
+
collateralToken: collateralSymbol,
|
|
692
|
+
amount,
|
|
693
|
+
periodDays,
|
|
694
|
+
theoreticalSupplyApy: supplyApy,
|
|
695
|
+
estimatedYieldUsd,
|
|
696
|
+
collateralValueUsd,
|
|
697
|
+
disclaimer: "Collateral on Morpho Blue does NOT earn yield directly. This estimates what it WOULD earn if supplied as a lender instead. Use as a theoretical spending cap."
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
// ════════════════════════════════════════════════════════
|
|
528
701
|
// Lending Operations (all via AgentAccount.executeBatch)
|
|
529
702
|
// ════════════════════════════════════════════════════════
|
|
530
703
|
/**
|
|
@@ -924,6 +1097,9 @@ var init_X402Client = __esm({
|
|
|
924
1097
|
const client = new import_client.x402Client();
|
|
925
1098
|
(0, import_client2.registerExactEvmScheme)(client, { signer });
|
|
926
1099
|
this.paidFetch = (0, import_fetch.wrapFetchWithPayment)(fetch, client);
|
|
1100
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1101
|
+
const dailyLimit = config.dailySpendLimitUsdc ? BigInt(Math.round(parseFloat(config.dailySpendLimitUsdc) * 1e6)) : 0n;
|
|
1102
|
+
this._spendingTracker = { date: today, totalBorrowed: 0n, dailyLimit };
|
|
927
1103
|
}
|
|
928
1104
|
async get(url, opts) {
|
|
929
1105
|
return this.request(url, { ...opts, method: "GET" });
|
|
@@ -939,6 +1115,82 @@ var init_X402Client = __esm({
|
|
|
939
1115
|
getAddress() {
|
|
940
1116
|
return this.address;
|
|
941
1117
|
}
|
|
1118
|
+
/** Get the current spending tracker state */
|
|
1119
|
+
getSpendingTracker() {
|
|
1120
|
+
this._resetTrackerIfNewDay();
|
|
1121
|
+
return { ...this._spendingTracker };
|
|
1122
|
+
}
|
|
1123
|
+
/** Get remaining daily spending allowance in USDC (human-readable) */
|
|
1124
|
+
getRemainingDailyAllowance() {
|
|
1125
|
+
this._resetTrackerIfNewDay();
|
|
1126
|
+
if (this._spendingTracker.dailyLimit === 0n) return "unlimited";
|
|
1127
|
+
const remaining = this._spendingTracker.dailyLimit - this._spendingTracker.totalBorrowed;
|
|
1128
|
+
return (Number(remaining > 0n ? remaining : 0n) / 1e6).toFixed(2);
|
|
1129
|
+
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Pay with auto-draw: Make an x402 request with automatic Morpho borrowing.
|
|
1132
|
+
*
|
|
1133
|
+
* Flow:
|
|
1134
|
+
* 1. Check USDC balance on AgentAccount
|
|
1135
|
+
* 2. Probe the URL to discover payment amount (if 402)
|
|
1136
|
+
* 3. If insufficient USDC, calculate deficit
|
|
1137
|
+
* 4. Check spending limit
|
|
1138
|
+
* 5. Borrow from Morpho via MorphoClient
|
|
1139
|
+
* 6. Proceed with x402 payment
|
|
1140
|
+
*/
|
|
1141
|
+
async payWithAutoDraw(url, opts) {
|
|
1142
|
+
const { morphoClient, ...fetchOpts } = opts || {};
|
|
1143
|
+
if (!this.config.autoDraw || !morphoClient) {
|
|
1144
|
+
return this.request(url, fetchOpts);
|
|
1145
|
+
}
|
|
1146
|
+
try {
|
|
1147
|
+
const usdcBalance = await morphoClient.getUsdcBalance();
|
|
1148
|
+
console.log(` [auto-draw] AgentAccount USDC balance: ${(Number(usdcBalance) / 1e6).toFixed(2)}`);
|
|
1149
|
+
const paymentAmount = await this._probePaymentAmount(url, fetchOpts);
|
|
1150
|
+
if (paymentAmount !== null) {
|
|
1151
|
+
console.log(` [auto-draw] Payment required: ${(Number(paymentAmount) / 1e6).toFixed(6)} USDC`);
|
|
1152
|
+
const bufferStr = this.config.autoDrawBuffer || "0.5";
|
|
1153
|
+
const buffer = BigInt(Math.round(parseFloat(bufferStr) * 1e6));
|
|
1154
|
+
const needed = paymentAmount + buffer;
|
|
1155
|
+
if (usdcBalance < needed) {
|
|
1156
|
+
const deficit = needed - usdcBalance;
|
|
1157
|
+
console.log(` [auto-draw] Insufficient balance. Need to borrow ${(Number(deficit) / 1e6).toFixed(2)} USDC`);
|
|
1158
|
+
const limitCheck = await this._checkSpendingLimit(deficit, morphoClient);
|
|
1159
|
+
if (!limitCheck.allowed) {
|
|
1160
|
+
return {
|
|
1161
|
+
success: false,
|
|
1162
|
+
error: `Auto-draw blocked: ${limitCheck.reason}`
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
const maxBorrowable = await morphoClient.getMaxBorrowable();
|
|
1166
|
+
if (maxBorrowable.total < deficit) {
|
|
1167
|
+
return {
|
|
1168
|
+
success: false,
|
|
1169
|
+
error: `Auto-draw failed: insufficient collateral. Need ${(Number(deficit) / 1e6).toFixed(2)} USDC but can only borrow ${(Number(maxBorrowable.total) / 1e6).toFixed(2)} USDC more.`
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
const borrowAmount = (Number(deficit) / 1e6).toFixed(6);
|
|
1173
|
+
console.log(` [auto-draw] Borrowing ${borrowAmount} USDC from Morpho...`);
|
|
1174
|
+
const borrowResult = await morphoClient.borrow(borrowAmount);
|
|
1175
|
+
console.log(` [auto-draw] Borrow tx: ${borrowResult.tx}`);
|
|
1176
|
+
this._trackSpending(deficit);
|
|
1177
|
+
const result = await this.request(url, fetchOpts);
|
|
1178
|
+
return {
|
|
1179
|
+
...result,
|
|
1180
|
+
autoDrawInfo: {
|
|
1181
|
+
borrowed: borrowAmount,
|
|
1182
|
+
borrowTx: borrowResult.tx,
|
|
1183
|
+
reason: `USDC balance insufficient (had ${(Number(usdcBalance) / 1e6).toFixed(2)}, needed ${(Number(needed) / 1e6).toFixed(2)})`
|
|
1184
|
+
}
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
return this.request(url, fetchOpts);
|
|
1189
|
+
} catch (error) {
|
|
1190
|
+
console.log(` [auto-draw] Auto-draw check failed: ${error instanceof Error ? error.message : String(error)}. Proceeding with normal request.`);
|
|
1191
|
+
return this.request(url, fetchOpts);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
942
1194
|
// ──────────── Core request — @x402/fetch handles 402 automatically ────────────
|
|
943
1195
|
async request(url, options) {
|
|
944
1196
|
try {
|
|
@@ -988,6 +1240,102 @@ var init_X402Client = __esm({
|
|
|
988
1240
|
};
|
|
989
1241
|
}
|
|
990
1242
|
}
|
|
1243
|
+
// ──────────── Auto-Draw Helpers ────────────
|
|
1244
|
+
/**
|
|
1245
|
+
* Probe a URL to discover payment requirements without paying.
|
|
1246
|
+
* Makes a request and parses the 402 PAYMENT-REQUIRED header.
|
|
1247
|
+
* @returns Payment amount in raw USDC units (6 decimals), or null if not a 402.
|
|
1248
|
+
*/
|
|
1249
|
+
async _probePaymentAmount(url, options) {
|
|
1250
|
+
try {
|
|
1251
|
+
const response = await fetch(url, {
|
|
1252
|
+
...options,
|
|
1253
|
+
headers: {
|
|
1254
|
+
...options?.headers,
|
|
1255
|
+
"X-Agent-Id": this.config.agentId || ""
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
if (response.status !== 402) return null;
|
|
1259
|
+
const paymentHeader = response.headers.get("X-PAYMENT") || response.headers.get("PAYMENT-REQUIRED");
|
|
1260
|
+
if (!paymentHeader) return null;
|
|
1261
|
+
try {
|
|
1262
|
+
const decoded = JSON.parse(Buffer.from(paymentHeader, "base64").toString("utf-8"));
|
|
1263
|
+
const requirements = Array.isArray(decoded) ? decoded : decoded.accepts || [decoded];
|
|
1264
|
+
if (requirements.length > 0) {
|
|
1265
|
+
const amount = requirements[0].maxAmountRequired || requirements[0].amount;
|
|
1266
|
+
if (amount) {
|
|
1267
|
+
return BigInt(amount);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
} catch {
|
|
1271
|
+
}
|
|
1272
|
+
return null;
|
|
1273
|
+
} catch {
|
|
1274
|
+
return null;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
/** Reset spending tracker if it's a new day */
|
|
1278
|
+
_resetTrackerIfNewDay() {
|
|
1279
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1280
|
+
if (this._spendingTracker.date !== today) {
|
|
1281
|
+
this._spendingTracker = {
|
|
1282
|
+
date: today,
|
|
1283
|
+
totalBorrowed: 0n,
|
|
1284
|
+
dailyLimit: this._spendingTracker.dailyLimit
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
/** Track a new spending amount */
|
|
1289
|
+
_trackSpending(amount) {
|
|
1290
|
+
this._resetTrackerIfNewDay();
|
|
1291
|
+
this._spendingTracker.totalBorrowed += amount;
|
|
1292
|
+
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Check if a borrow amount is within spending limits.
|
|
1295
|
+
* Considers both fixed daily limits and yield-limited spending.
|
|
1296
|
+
*/
|
|
1297
|
+
async _checkSpendingLimit(amount, morphoClient) {
|
|
1298
|
+
this._resetTrackerIfNewDay();
|
|
1299
|
+
if (this.config.yieldLimitedSpending) {
|
|
1300
|
+
try {
|
|
1301
|
+
const status = await morphoClient.getStatus();
|
|
1302
|
+
let totalDailyYieldUsdc = 0;
|
|
1303
|
+
for (const pos of status.positions) {
|
|
1304
|
+
if (parseFloat(pos.collateral) > 0) {
|
|
1305
|
+
try {
|
|
1306
|
+
const estimate = await morphoClient.getYieldEstimate(
|
|
1307
|
+
pos.collateralToken,
|
|
1308
|
+
pos.collateral,
|
|
1309
|
+
1
|
|
1310
|
+
// 1 day
|
|
1311
|
+
);
|
|
1312
|
+
totalDailyYieldUsdc += estimate.estimatedYieldUsd;
|
|
1313
|
+
} catch {
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
const yieldLimit = BigInt(Math.round(totalDailyYieldUsdc * 1e6));
|
|
1318
|
+
const newTotal = this._spendingTracker.totalBorrowed + amount;
|
|
1319
|
+
if (yieldLimit > 0n && newTotal > yieldLimit) {
|
|
1320
|
+
return {
|
|
1321
|
+
allowed: false,
|
|
1322
|
+
reason: `Yield-limited spending exceeded. Daily yield cap: $${(Number(yieldLimit) / 1e6).toFixed(2)}, already spent: $${(Number(this._spendingTracker.totalBorrowed) / 1e6).toFixed(2)}, requested: $${(Number(amount) / 1e6).toFixed(2)}`
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
} catch {
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
if (this._spendingTracker.dailyLimit > 0n) {
|
|
1329
|
+
const newTotal = this._spendingTracker.totalBorrowed + amount;
|
|
1330
|
+
if (newTotal > this._spendingTracker.dailyLimit) {
|
|
1331
|
+
return {
|
|
1332
|
+
allowed: false,
|
|
1333
|
+
reason: `Daily spending limit exceeded. Limit: $${(Number(this._spendingTracker.dailyLimit) / 1e6).toFixed(2)}, already spent: $${(Number(this._spendingTracker.totalBorrowed) / 1e6).toFixed(2)}, requested: $${(Number(amount) / 1e6).toFixed(2)}`
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
return { allowed: true };
|
|
1338
|
+
}
|
|
991
1339
|
};
|
|
992
1340
|
}
|
|
993
1341
|
});
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AgentIdentityClient - Integration with ag0 (ERC-8004)
|
|
3
|
+
*
|
|
4
|
+
* ERC-8004 Contract Addresses:
|
|
5
|
+
* - Sepolia IdentityRegistry: 0x8004A818BFB912233c491871b3d84c89A494BD9e
|
|
6
|
+
* - Sepolia ReputationRegistry: 0x8004B663056A597Dffe9eCcC1965A193B7388713
|
|
7
|
+
*
|
|
8
|
+
* SDKs:
|
|
9
|
+
* - TypeScript: https://github.com/agent0lab/agent0-ts
|
|
10
|
+
* - Python: https://github.com/agent0lab/agent0-py
|
|
11
|
+
*
|
|
12
|
+
* Docs: https://sdk.ag0.xyz/docs
|
|
13
|
+
*/
|
|
14
|
+
import { Signer } from 'ethers';
|
|
15
|
+
import { AgetherConfig } from '../types';
|
|
16
|
+
export declare const ERC8004_SEPOLIA: {
|
|
17
|
+
identityRegistry: string;
|
|
18
|
+
reputationRegistry: string;
|
|
19
|
+
};
|
|
20
|
+
export interface AgentIdentityClientOptions {
|
|
21
|
+
config: AgetherConfig;
|
|
22
|
+
signer: Signer;
|
|
23
|
+
/** Optional: Use ag0 TypeScript SDK instead of direct contracts */
|
|
24
|
+
useAg0SDK?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface AgentMetadata {
|
|
27
|
+
name: string;
|
|
28
|
+
description: string;
|
|
29
|
+
image?: string;
|
|
30
|
+
endpoints?: {
|
|
31
|
+
name: string;
|
|
32
|
+
endpoint: string;
|
|
33
|
+
version?: string;
|
|
34
|
+
}[];
|
|
35
|
+
x402Support?: boolean;
|
|
36
|
+
active?: boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface FeedbackInput {
|
|
39
|
+
agentId: bigint;
|
|
40
|
+
value: number;
|
|
41
|
+
decimals?: number;
|
|
42
|
+
tag1?: string;
|
|
43
|
+
tag2?: string;
|
|
44
|
+
endpoint?: string;
|
|
45
|
+
feedbackURI?: string;
|
|
46
|
+
}
|
|
47
|
+
export interface ReputationSummary {
|
|
48
|
+
count: number;
|
|
49
|
+
totalValue: number;
|
|
50
|
+
averageValue: number;
|
|
51
|
+
clients: string[];
|
|
52
|
+
}
|
|
53
|
+
export declare class AgentIdentityClient {
|
|
54
|
+
readonly config: AgetherConfig;
|
|
55
|
+
private signer;
|
|
56
|
+
private identityRegistry;
|
|
57
|
+
private reputationRegistry;
|
|
58
|
+
constructor(options: AgentIdentityClientOptions);
|
|
59
|
+
/**
|
|
60
|
+
* Register a new agent (minimal - no metadata)
|
|
61
|
+
*/
|
|
62
|
+
register(): Promise<{
|
|
63
|
+
agentId: bigint;
|
|
64
|
+
txHash: string;
|
|
65
|
+
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Register agent with IPFS/HTTP URI to metadata JSON
|
|
68
|
+
* @param agentURI URI pointing to agent metadata (ipfs:// or https://)
|
|
69
|
+
*/
|
|
70
|
+
registerWithURI(agentURI: string): Promise<{
|
|
71
|
+
agentId: bigint;
|
|
72
|
+
txHash: string;
|
|
73
|
+
}>;
|
|
74
|
+
/**
|
|
75
|
+
* Check if the signer already owns an ERC-8004 identity token.
|
|
76
|
+
* Returns true if balanceOf > 0, false otherwise.
|
|
77
|
+
* Note: Cannot determine the specific agentId without enumeration —
|
|
78
|
+
* use agether init <pk> --agent-id <id> if you know your agentId.
|
|
79
|
+
*/
|
|
80
|
+
hasExistingIdentity(): Promise<boolean>;
|
|
81
|
+
/**
|
|
82
|
+
* Register only if no identity exists; otherwise throw.
|
|
83
|
+
* Prevents accidental double-registration.
|
|
84
|
+
*/
|
|
85
|
+
registerOrGet(): Promise<{
|
|
86
|
+
agentId: bigint;
|
|
87
|
+
txHash: string | null;
|
|
88
|
+
existing: boolean;
|
|
89
|
+
}>;
|
|
90
|
+
/**
|
|
91
|
+
* Register with URI only if no identity exists; otherwise throw.
|
|
92
|
+
* Prevents accidental double-registration.
|
|
93
|
+
*/
|
|
94
|
+
registerOrGetWithURI(agentURI: string): Promise<{
|
|
95
|
+
agentId: bigint;
|
|
96
|
+
txHash: string | null;
|
|
97
|
+
existing: boolean;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Register agent with URI and on-chain metadata
|
|
101
|
+
*/
|
|
102
|
+
registerWithMetadata(agentURI: string, metadata: {
|
|
103
|
+
key: string;
|
|
104
|
+
value: string;
|
|
105
|
+
}[]): Promise<{
|
|
106
|
+
agentId: bigint;
|
|
107
|
+
txHash: string;
|
|
108
|
+
}>;
|
|
109
|
+
/**
|
|
110
|
+
* Get agent owner address
|
|
111
|
+
*/
|
|
112
|
+
getOwner(agentId: bigint): Promise<string>;
|
|
113
|
+
/**
|
|
114
|
+
* Get agent URI (metadata JSON location)
|
|
115
|
+
*/
|
|
116
|
+
getAgentURI(agentId: bigint): Promise<string>;
|
|
117
|
+
/**
|
|
118
|
+
* Update agent URI
|
|
119
|
+
*/
|
|
120
|
+
setAgentURI(agentId: bigint, newURI: string): Promise<string>;
|
|
121
|
+
/**
|
|
122
|
+
* Set on-chain metadata (key-value)
|
|
123
|
+
*/
|
|
124
|
+
setMetadata(agentId: bigint, key: string, value: string): Promise<string>;
|
|
125
|
+
/**
|
|
126
|
+
* Get on-chain metadata
|
|
127
|
+
*/
|
|
128
|
+
getMetadata(agentId: bigint, key: string): Promise<string>;
|
|
129
|
+
/**
|
|
130
|
+
* Transfer agent to new owner
|
|
131
|
+
*/
|
|
132
|
+
transfer(agentId: bigint, to: string): Promise<string>;
|
|
133
|
+
/**
|
|
134
|
+
* Fetch and parse agent metadata from URI
|
|
135
|
+
*/
|
|
136
|
+
fetchAgentMetadata(agentId: bigint): Promise<AgentMetadata | null>;
|
|
137
|
+
/**
|
|
138
|
+
* Give feedback to an agent
|
|
139
|
+
*/
|
|
140
|
+
giveFeedback(input: FeedbackInput): Promise<string>;
|
|
141
|
+
/**
|
|
142
|
+
* Give positive feedback (shorthand)
|
|
143
|
+
*/
|
|
144
|
+
givePosisitiveFeedback(agentId: bigint, value?: number, tags?: {
|
|
145
|
+
tag1?: string;
|
|
146
|
+
tag2?: string;
|
|
147
|
+
}): Promise<string>;
|
|
148
|
+
/**
|
|
149
|
+
* Give negative feedback (e.g., for defaults)
|
|
150
|
+
*/
|
|
151
|
+
giveNegativeFeedback(agentId: bigint, value?: number, tags?: {
|
|
152
|
+
tag1?: string;
|
|
153
|
+
tag2?: string;
|
|
154
|
+
}): Promise<string>;
|
|
155
|
+
/**
|
|
156
|
+
* Record credit default in reputation system
|
|
157
|
+
*/
|
|
158
|
+
recordCreditDefault(agentId: bigint, creditLineId: bigint): Promise<string>;
|
|
159
|
+
/**
|
|
160
|
+
* Get reputation summary for an agent
|
|
161
|
+
*/
|
|
162
|
+
getReputation(agentId: bigint, tag1?: string, tag2?: string): Promise<ReputationSummary>;
|
|
163
|
+
/**
|
|
164
|
+
* Check if agent has negative credit reputation
|
|
165
|
+
*/
|
|
166
|
+
hasNegativeCreditReputation(agentId: bigint): Promise<boolean>;
|
|
167
|
+
/**
|
|
168
|
+
* Verify agent is eligible for Agether credit
|
|
169
|
+
* Checks:
|
|
170
|
+
* 1. Agent exists in ERC-8004 registry
|
|
171
|
+
* 2. Agent has no negative credit reputation
|
|
172
|
+
*/
|
|
173
|
+
verifyForCredit(agentId: bigint): Promise<{
|
|
174
|
+
eligible: boolean;
|
|
175
|
+
reason?: string;
|
|
176
|
+
owner?: string;
|
|
177
|
+
reputation?: ReputationSummary;
|
|
178
|
+
}>;
|
|
179
|
+
private parseAgentIdFromReceipt;
|
|
180
|
+
/**
|
|
181
|
+
* Get contract addresses
|
|
182
|
+
*/
|
|
183
|
+
getContractAddresses(): {
|
|
184
|
+
identity: string;
|
|
185
|
+
reputation: string;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=AgentIdentityClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AgentIdentityClient.d.ts","sourceRoot":"","sources":["../../src/clients/AgentIdentityClient.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA0CzC,eAAO,MAAM,eAAe;;;CAG3B,CAAC;AAEF,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,aAAa,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,EAAE,CAAC;IACJ,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,qBAAa,mBAAmB;IAC9B,SAAgB,MAAM,EAAE,aAAa,CAAC;IACtC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,kBAAkB,CAAkB;gBAEhC,OAAO,EAAE,0BAA0B;IAc/C;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAQ9D;;;OAGG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAQrF;;;;;OAKG;IACG,mBAAmB,IAAI,OAAO,CAAC,OAAO,CAAC;IAU7C;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAS7F;;;OAGG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IASpH;;OAEG;IACG,oBAAoB,CACxB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,GACzC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAgB/C;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAIhD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAInD;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAMnE;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAU/E;;OAEG;IACG,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKhE;;OAEG;IACG,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAO5D;;OAEG;IACG,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAsBxE;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAuBzD;;OAEG;IACG,sBAAsB,CAC1B,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAY,EACnB,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1C,OAAO,CAAC,MAAM,CAAC;IAQlB;;OAEG;IACG,oBAAoB,CACxB,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAa,EACpB,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1C,OAAO,CAAC,MAAM,CAAC;IAQlB;;OAEG;IACG,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUjF;;OAEG;IACG,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,MAAW,EACjB,IAAI,GAAE,MAAW,GAChB,OAAO,CAAC,iBAAiB,CAAC;IA+B7B;;OAEG;IACG,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAOpE;;;;;OAKG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC;QAC9C,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,UAAU,CAAC,EAAE,iBAAiB,CAAC;KAChC,CAAC;IA8BF,OAAO,CAAC,uBAAuB;IAoB/B;;OAEG;IACH,oBAAoB,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE;CAMjE"}
|